mirror of
https://github.com/clearlinux/docker.git
synced 2026-08-19 12:16:30 +00:00
Compare commits
601 Commits
v0.7.0-rc4
...
v0.6.7
| Author | SHA1 | Date | |
|---|---|---|---|
| 53f1bf0f99 | |||
| 9dc59797e0 | |||
| 25e443a3c7 | |||
| 33e70864a2 | |||
| d6e6214d37 | |||
| 70f1bd3104 | |||
| f7c2a00557 | |||
| 8498b44eac | |||
| e2dcfc2cf7 | |||
| 9b4c151142 | |||
| 50239e0573 | |||
| 42c23b0f04 | |||
| eec91e7941 | |||
| 3f17844b6e | |||
| bcdeb37bb6 | |||
| 362e9d6b3c | |||
| c4ab498920 | |||
| cb70eedfda | |||
| 75a7f4d90c | |||
| eaeb969138 | |||
| d7e2fc8982 | |||
| f20c738963 | |||
| fd7ab143bf | |||
| 82cdd21a34 | |||
| 2bc35287a0 | |||
| b4f7078a02 | |||
| 9e68913397 | |||
| 304a80fcd5 | |||
| 04f1d4dcdb | |||
| 171d681724 | |||
| cd4c1ac356 | |||
| b8af68a92b | |||
| 9de4590498 | |||
| 0ef6fed5c7 | |||
| 383f95bba1 | |||
| 1211065c8d | |||
| 844c13bce6 | |||
| 6014db4a7e | |||
| bf504f2afa | |||
| 61a8020e51 | |||
| 7eaa59f626 | |||
| 2cccbbdadd | |||
| b700ee006a | |||
| 0169cf15dd | |||
| 234f5ac39f | |||
| d575918038 | |||
| 66beafa9f3 | |||
| 3cbec95177 | |||
| 8e5ab5bfca | |||
| 9d867a389b | |||
| 4f9f83d6c6 | |||
| 145c2008ae | |||
| 4eaba8de91 | |||
| 434c1613a4 | |||
| 18da26c62a | |||
| aeb304b37c | |||
| 1da8c50ded | |||
| 1cd9529ad3 | |||
| f78d45863c | |||
| 3656db66d2 | |||
| 78c843c8ef | |||
| ac821f2446 | |||
| 2fe4467d73 | |||
| 194d4b9376 | |||
| 1de02a70de | |||
| 5e941f1ca0 | |||
| 511a62a099 | |||
| 256d46fe68 | |||
| 76ee860ece | |||
| 2ae1f29dfe | |||
| 4b80ec9aae | |||
| fef41ef7bf | |||
| f946a486ea | |||
| e008c7c068 | |||
| 669e4bac30 | |||
| f6362fbb0e | |||
| c1cd824570 | |||
| 4546832507 | |||
| b5934711d0 | |||
| ed8f75d25c | |||
| cfbd9ea16d | |||
| 75dd1663e0 | |||
| 3c67a28493 | |||
| 440422a963 | |||
| fc2f5758cf | |||
| fe302fbfd2 | |||
| 72d02ecdde | |||
| baa687bed2 | |||
| 30ea0bebce | |||
| 9e1da3ec9c | |||
| b76574f855 | |||
| 457375ea37 | |||
| 7e580aacec | |||
| 0e64b987e8 | |||
| bc74f65068 | |||
| 5c741ef11d | |||
| 152459b727 | |||
| f04142c1f7 | |||
| af05ab399e | |||
| 27159ce6ba | |||
| 51576069ad | |||
| d33ffe44a9 | |||
| afe230718e | |||
| 9261690593 | |||
| e12bba66ea | |||
| 92c3a319fb | |||
| 323e86032d | |||
| c06d903edd | |||
| 9a9d3239e1 | |||
| 33110ddc3f | |||
| 6341768393 | |||
| ad96d5ff04 | |||
| 492ce4c665 | |||
| 76ab8fa00f | |||
| 007964793d | |||
| bed87ea103 | |||
| 823674816e | |||
| 8d3e35cd8d | |||
| 84ed18827a | |||
| 693ff4d2ae | |||
| 596810d8db | |||
| 661a8a0e0c | |||
| 629c6e3649 | |||
| c7aaf831d7 | |||
| e9624bf715 | |||
| 2a209afe5f | |||
| c001a5af67 | |||
| 359a6f49b9 | |||
| e42144674f | |||
| 37abc07852 | |||
| 61abc3f8ac | |||
| 5fc56b6b47 | |||
| 059950b095 | |||
| 9ab85f4d12 | |||
| 3cf23b93ea | |||
| 3ba6835ead | |||
| dc13b9473f | |||
| b00d5f0185 | |||
| 8e71391572 | |||
| 077c2496ed | |||
| b94e9ed0de | |||
| 02884ee429 | |||
| 8145e57cee | |||
| c964494d31 | |||
| c6e83b8779 | |||
| 369e39aea1 | |||
| af0b2e38c3 | |||
| 87b4bb9fcc | |||
| f5e6c2d060 | |||
| f0f8462d18 | |||
| 0013aa7d9f | |||
| 1d7f22c0d4 | |||
| 6a693176d6 | |||
| 8523d5518c | |||
| 6c4393ccbb | |||
| 3885ef585b | |||
| 388057f11a | |||
| c69e6a90e4 | |||
| 71c05bb87c | |||
| 637850063c | |||
| dcc9980550 | |||
| e405337926 | |||
| 5cdb3aec50 | |||
| b314f19db8 | |||
| 353243a725 | |||
| 879aa29cb0 | |||
| 1e5ba57de3 | |||
| bc6d872841 | |||
| 981560c436 | |||
| d589cc3622 | |||
| 69a9614cb4 | |||
| e2ac0e6b80 | |||
| 01dd7e7459 | |||
| 84a3600ea8 | |||
| cb9e0aee48 | |||
| 52d3137713 | |||
| 4c7d24bc8b | |||
| 87c8437a90 | |||
| 6fab249b21 | |||
| da24945070 | |||
| ca113bb1b2 | |||
| 9ff36cb00c | |||
| 62f873aa1f | |||
| 2091b59721 | |||
| 88edba7e86 | |||
| 5fe4c9a39a | |||
| 2fc0084f6b | |||
| 7cf7dda87d | |||
| bb76157d24 | |||
| 1d9139bb89 | |||
| 8149439d95 | |||
| 402a58a75a | |||
| 9c7a8edddd | |||
| cf30b85eb1 | |||
| ccbb5d3492 | |||
| 5a1bfd9aa9 | |||
| 8cc19765b4 | |||
| 8ba8783bcc | |||
| 4ec0b51578 | |||
| 7f1b179c67 | |||
| b3974abe4f | |||
| 403f9fc357 | |||
| 498b6031b1 | |||
| f26da9638f | |||
| 126b17a0ff | |||
| 34d294c461 | |||
| 45c2b5dc1a | |||
| f56945d71b | |||
| b8e7ec1b74 | |||
| 3bbe8ee055 | |||
| 2448058ee2 | |||
| ca174ae84d | |||
| f9dd0da182 | |||
| e7fdcc15c5 | |||
| 67b0b97a8f | |||
| 310fbe7bb7 | |||
| 3f2a5912ee | |||
| 65102d6b36 | |||
| 997a32706f | |||
| 5cf6ad4565 | |||
| bf8e0277bb | |||
| 5957dd9091 | |||
| 49d7b87cfc | |||
| f417c4b099 | |||
| ef57752bce | |||
| 4f8b6c3283 | |||
| 01fea3cf11 | |||
| eba3c36b38 | |||
| 49c4231f07 | |||
| ec4657b28a | |||
| 304d39cc50 | |||
| cd4f7321c9 | |||
| 132db329d4 | |||
| 6998c3c387 | |||
| 26f846bf77 | |||
| 97c3de7e6b | |||
| b5c984f9b4 | |||
| 249f76bebd | |||
| e7df38dbd0 | |||
| efb4c800a7 | |||
| 0cbeda7391 | |||
| 1717227636 | |||
| 50dd9791f7 | |||
| 9990db2f5a | |||
| 2d1155407a | |||
| 37dcff0c13 | |||
| 38f1838e82 | |||
| 807a305f36 | |||
| cb1c90975b | |||
| 363738b8f2 | |||
| 6d420407ca | |||
| 157d99a727 | |||
| 360a694c52 | |||
| c5bc7d5158 | |||
| 16eba6bbb5 | |||
| 0dd6c6645b | |||
| 70f44d5531 | |||
| 45aba3dc95 | |||
| c22ff0296e | |||
| 00f1398f7a | |||
| 74f853a2ae | |||
| 20881f1f78 | |||
| 3108f0526e | |||
| 22ef38ee79 | |||
| 6d5b73c2a6 | |||
| b7d1d35c27 | |||
| f1aeac361a | |||
| d9fe0647cb | |||
| 059bb7a262 | |||
| ec9a9a08b8 | |||
| 8f64759881 | |||
| 2a5998baf1 | |||
| dcf0279a50 | |||
| d7928b9a67 | |||
| 15867ff430 | |||
| 3560c922b1 | |||
| 04aca7c9e3 | |||
| 6113e1d62d | |||
| cdf0cf495d | |||
| 1dc34e2b96 | |||
| 8d6df3a7e2 | |||
| e5f8ab6160 | |||
| 5c42b2b512 | |||
| d3f074494a | |||
| 434f06d03d | |||
| 5a85456d48 | |||
| 980eda4c25 | |||
| bf05eb8ac0 | |||
| f3f9f652e1 | |||
| 2205bb43ea | |||
| 5af87d1475 | |||
| 35430e8920 | |||
| 4d2ba779e1 | |||
| f1f39616eb | |||
| 4b8c41c4a2 | |||
| e88368b34c | |||
| 4d5ecdbeb4 | |||
| 114e01cdc1 | |||
| 7f7926525a | |||
| 02ddaad5d9 | |||
| 4e7cb37dcc | |||
| ca6f0aa107 | |||
| 847411a1ee | |||
| 7b17d55599 | |||
| 958b4a8757 | |||
| 714acf5ade | |||
| 962a66cd36 | |||
| f9cb6ae46a | |||
| 433c8e9c7d | |||
| ff8a4ba0aa | |||
| dcaaecc815 | |||
| 2cac813937 | |||
| fcc0ac6109 | |||
| c5d4459a02 | |||
| 1182797c6d | |||
| a482bfd715 | |||
| 8ad46ef401 | |||
| 854cc5f559 | |||
| 57cd17f656 | |||
| 99141ea3ca | |||
| 3061e9f374 | |||
| 19ad299600 | |||
| 177a2f5946 | |||
| 1f44fd8624 | |||
| c065e564fb | |||
| 342bd43b76 | |||
| b380866f44 | |||
| dc333878d2 | |||
| 261c2e23d3 | |||
| 957db15ef4 | |||
| a9ed238bb7 | |||
| 35690e76b4 | |||
| 2a0efb2324 | |||
| a4ccbc6e95 | |||
| 2824b05235 | |||
| fbfb7595b1 | |||
| b840b73b08 | |||
| 1f3cdc11ee | |||
| 95708dd35c | |||
| a51fb4dd35 | |||
| 4cbb6ce13b | |||
| 1cb4557cc8 | |||
| c33d26a8da | |||
| 5a9adfe9fb | |||
| f3685333c0 | |||
| fc45535197 | |||
| 8f27e23b4b | |||
| 4194617bfe | |||
| d8bcd1c231 | |||
| f6b4a1ec95 | |||
| 7ddd4fe66a | |||
| dcf4633e95 | |||
| b30dc8c3ea | |||
| feef16bd88 | |||
| f9901ead06 | |||
| 31638ab2ad | |||
| 33d8c736fc | |||
| 9ebac49be0 | |||
| 65ba2868d7 | |||
| a963ff5d8d | |||
| c0e51a8f27 | |||
| f2ebccb5aa | |||
| db2e2e831b | |||
| 9ee9d2f995 | |||
| 4dc156252b | |||
| 747967b4a4 | |||
| 02b5202432 | |||
| 7f07ae9e42 | |||
| a89a98e594 | |||
| 7848007c3a | |||
| 40ed10cc32 | |||
| 96d1e9bb5a | |||
| e3c49843d7 | |||
| 3e7b9763aa | |||
| 393562340c | |||
| d5891f9fb0 | |||
| 09607bb8f6 | |||
| 35044efce5 | |||
| 652f07bb59 | |||
| 54024ddd8a | |||
| b543516556 | |||
| e37a7d4981 | |||
| 7e7c931d2b | |||
| 3a14d4c923 | |||
| 15457febbb | |||
| df1621914b | |||
| f77bbfca56 | |||
| 87a250b711 | |||
| ccc1a5dcfb | |||
| ca2bbe716c | |||
| 13ab83a8a5 | |||
| 429c3108da | |||
| bdbb0371a7 | |||
| c1c65f972a | |||
| 4b8a176ee0 | |||
| 4dfa28fb95 | |||
| 8227ea35cf | |||
| 1099d172a2 | |||
| 1c3a674444 | |||
| 25c4c87c86 | |||
| 26f4d6bf59 | |||
| be7eb4bfcb | |||
| 5eb472025a | |||
| bdd12bb703 | |||
| ef00317a70 | |||
| 3ff845904d | |||
| ec488fa123 | |||
| d7fac67e0a | |||
| f7c40a87f3 | |||
| ee81405567 | |||
| 23b3747945 | |||
| 1c7ca51f32 | |||
| 1edde0e8a3 | |||
| 596facd124 | |||
| 4fd389eee5 | |||
| 6a9fb81c57 | |||
| 5fb6d6e47c | |||
| a4d97a4e80 | |||
| 3362aaa4df | |||
| 8fa6e2b103 | |||
| b2503a72f1 | |||
| bb662bc12c | |||
| 79bf2c2b0e | |||
| 746ba127bf | |||
| e7402ed9cc | |||
| fb4672c52c | |||
| 9420e8def7 | |||
| 4f6ce1ba9e | |||
| 2a9c18af52 | |||
| 86970d00bb | |||
| da054148dc | |||
| 0174951195 | |||
| caa7cf14c0 | |||
| 700a71e6b6 | |||
| 02e0fdee57 | |||
| baf23d3c3e | |||
| 5b75aea704 | |||
| d91e145332 | |||
| 1384db5e7f | |||
| ff147707b2 | |||
| 05430c7170 | |||
| eb79e8c5dd | |||
| b48fc96579 | |||
| e0b59ab52b | |||
| a6a274f312 | |||
| 4f5790d104 | |||
| 70c976de03 | |||
| 4947f61c20 | |||
| 1de23f1b81 | |||
| b283900764 | |||
| 82f1514895 | |||
| e47f9984f8 | |||
| b038b0cd44 | |||
| 7e8b2c3836 | |||
| dd9f4524d1 | |||
| a52e23c5e4 | |||
| 0d2924408b | |||
| 91d721aaf4 | |||
| 76afb6e73d | |||
| c0662488c7 | |||
| 971cf56d89 | |||
| 865649d7ac | |||
| 50bb4a1636 | |||
| 3c0c75bbf9 | |||
| 7f95c7aeec | |||
| 395a24ffd5 | |||
| 45d94944f3 | |||
| a13241d370 | |||
| e8491ae54c | |||
| 464ded79fc | |||
| c1ae1a0e1c | |||
| c542b2f873 | |||
| 7e691e11b0 | |||
| 1b8eef4efb | |||
| 2a29bf6245 | |||
| 0d1a825137 | |||
| 60b97576cf | |||
| 54d3b4dd28 | |||
| 8f39f0b57d | |||
| d5c7e92a9a | |||
| 110b944f45 | |||
| 13c521526d | |||
| 516cf54843 | |||
| 356af1540f | |||
| 2e6b241dc7 | |||
| 94e5081bac | |||
| e179a24ad5 | |||
| da864a845b | |||
| 640682d56c | |||
| 66a159342b | |||
| 7c882a8003 | |||
| 7d440f70fd | |||
| 0c9b319dd0 | |||
| 7c08aeeba4 | |||
| 7072d2aaca | |||
| 21161dbd51 | |||
| cf86e2bb22 | |||
| d789750851 | |||
| fb8d488896 | |||
| dbe7d67c18 | |||
| 6c863b49ef | |||
| 89fb51f606 | |||
| 256b7537e3 | |||
| c4923757f1 | |||
| 387aeb78fb | |||
| 99a9783abc | |||
| 0e24db3a68 | |||
| db99966724 | |||
| d063c8d941 | |||
| 249f5a65a5 | |||
| 494cd07f72 | |||
| 607c1a520e | |||
| bf61d41d6c | |||
| ce965b8c43 | |||
| f7a2f0b937 | |||
| 4576d0f802 | |||
| 515070d513 | |||
| 1cbdaebaa1 | |||
| ff567f8729 | |||
| 279791bc74 | |||
| b64ce8e33c | |||
| 1e704a4ddc | |||
| 31111f61e0 | |||
| 217b6070f0 | |||
| 36c26a0f0f | |||
| a675e249b1 | |||
| acc2aec988 | |||
| 0e021ed470 | |||
| b9eb5e04ae | |||
| 0e44864b66 | |||
| e661473bcd | |||
| 98c94dd4db | |||
| 656b66e51b | |||
| c9375d14fc | |||
| 489c370fcc | |||
| aa6c99aff6 | |||
| 92384649cf | |||
| c2413889bb | |||
| e81da876df | |||
| f0dbdba5c0 | |||
| 0324e567ad | |||
| ef5cf6c1ec | |||
| afaddd04f7 | |||
| 8e43db95f2 | |||
| 7a116220e7 | |||
| 894a68d2ee | |||
| dc57d4ca26 | |||
| bc8a1081b0 | |||
| 33ccd29ae7 | |||
| 2aaaf90320 | |||
| 99f1675566 | |||
| 7e4d008403 | |||
| b0515a7016 | |||
| 8ff7b70c91 | |||
| 01284cbf73 | |||
| 10e10c9573 | |||
| b73065ab33 | |||
| d93023daa9 | |||
| 81866087fe | |||
| e70030a0c3 | |||
| 3bd45824da | |||
| 13c913d883 | |||
| 92beaed066 | |||
| 6b04913e73 | |||
| 93810b289c | |||
| ea59ce60c5 | |||
| a1fc8e17a7 | |||
| f903feee03 | |||
| 26adda6c31 | |||
| 7e09c6332d | |||
| 3b0cbc59ea | |||
| 95f3f77fc4 | |||
| bba5fd4555 | |||
| 9bceae2440 | |||
| e7269b9841 | |||
| 8cf0f2dbe5 | |||
| 3e014aa662 | |||
| 333bc23f21 | |||
| 7cf1877098 | |||
| 4918769b1a | |||
| 4b7c071e9c | |||
| 4870265a9f | |||
| 43fd85eb8f | |||
| ac5bc86771 | |||
| 85956c70b5 | |||
| 8c38c30985 | |||
| 255b6aadfa | |||
| 8bce284496 | |||
| 83a2e92d47 | |||
| 3db381bf08 | |||
| f248a8e13c | |||
| c405d53b6e | |||
| bc39ac71e6 | |||
| 2110b3cca8 | |||
| 095aab9d97 | |||
| 4967f9f19c | |||
| 1043055b10 | |||
| c2912c82aa | |||
| aa3697520a | |||
| 7d95d300ab | |||
| 181b9baddd |
@@ -17,3 +17,5 @@ docs/_templates
|
||||
bundles/
|
||||
.hg/
|
||||
.git/
|
||||
vendor/pkg/
|
||||
pyenv
|
||||
|
||||
@@ -44,6 +44,7 @@ Daniel Nordberg <dnordberg@gmail.com>
|
||||
Daniel Robinson <gottagetmac@gmail.com>
|
||||
Daniel Von Fange <daniel@leancoder.com>
|
||||
Daniel YC Lin <dlin.tw@gmail.com>
|
||||
Darren Coxall <darren@darrencoxall.com>
|
||||
David Calavera <david.calavera@gmail.com>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
Deni Bertovic <deni@kset.org>
|
||||
@@ -69,12 +70,14 @@ Gabriel Monroy <gabriel@opdemand.com>
|
||||
Gareth Rushgrove <gareth@morethanseven.net>
|
||||
Greg Thornton <xdissent@me.com>
|
||||
Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
|
||||
Gurjeet Singh <gurjeet@singh.im>
|
||||
Guruprasad <lgp171188@gmail.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Hector Castro <hectcastro@gmail.com>
|
||||
Hunter Blanks <hunter@twilio.com>
|
||||
Isao Jonas <isao.jonas@gmail.com>
|
||||
James Carr <james.r.carr@gmail.com>
|
||||
James Turnbull <james@lovedthanlost.net>
|
||||
Jason McVetta <jason.mcvetta@gmail.com>
|
||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||
Jeff Lindsay <progrium@gmail.com>
|
||||
@@ -92,6 +95,7 @@ Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Joost Cassee <joost@cassee.net>
|
||||
Jordan Arentsen <blissdev@gmail.com>
|
||||
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
|
||||
Josh Poimboeuf <jpoimboe@redhat.com>
|
||||
Julien Barbier <write0@gmail.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
|
||||
Karan Lyons <karan@karanlyons.com>
|
||||
@@ -117,6 +121,7 @@ Marko Mikulicic <mmikulicic@gmail.com>
|
||||
Markus Fix <lispmeister@gmail.com>
|
||||
Martin Redmond <martin@tinychat.com>
|
||||
Matt Apperson <me@mattapperson.com>
|
||||
Mathieu Le Marec - Pasquet <kiorky@cryptelium.net>
|
||||
Matt Bachmann <bachmann.matt@gmail.com>
|
||||
Matthew Mueller <mattmuelle@gmail.com>
|
||||
Maxim Treskin <zerthurd@gmail.com>
|
||||
@@ -140,6 +145,7 @@ odk- <github@odkurzacz.org>
|
||||
Pascal Borreli <pascal@borreli.com>
|
||||
Paul Bowsher <pbowsher@globalpersonals.co.uk>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Paul Nasrat <pnasrat@gmail.com>
|
||||
Phil Spitler <pspitler@gmail.com>
|
||||
Piotr Bogdan <ppbogdan@gmail.com>
|
||||
pysqz <randomq@126.com>
|
||||
@@ -151,6 +157,7 @@ Roberto Hashioka <roberto_hashioka@hotmail.com>
|
||||
Ryan Fowler <rwfowler@gmail.com>
|
||||
Sam Alba <sam.alba@gmail.com>
|
||||
Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
|
||||
Scott Bessler <scottbessler@gmail.com>
|
||||
Sean P. Kane <skane@newrelic.com>
|
||||
Shawn Siefkas <shawn.siefkas@meredith.com>
|
||||
Shih-Yuan Lee <fourdollars@gmail.com>
|
||||
@@ -161,6 +168,7 @@ Sridatta Thatipamala <sthatipamala@gmail.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Steeve Morin <steeve.morin@gmail.com>
|
||||
Stefan Praszalowicz <stefan@greplin.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au>
|
||||
Thatcher Peskens <thatcher@dotcloud.com>
|
||||
Thermionix <bond711@gmail.com>
|
||||
Thijs Terlouw <thijsterlouw@gmail.com>
|
||||
@@ -185,4 +193,5 @@ Vladimir Kirillov <proger@wilab.org.ua>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
Wes Morgan <cap10morgan@gmail.com>
|
||||
Will Dietz <w@wdtz.org>
|
||||
Yang Bai <hamo.by@gmail.com>
|
||||
Zaiste! <oh@zaiste.net>
|
||||
|
||||
+739
-403
File diff suppressed because it is too large
Load Diff
+6
-3
@@ -1,11 +1,14 @@
|
||||
# Contributing to Docker
|
||||
|
||||
Want to hack on Docker? Awesome! Here are instructions to get you started. They are probably not perfect, please let us know if anything feels
|
||||
wrong or incomplete.
|
||||
Want to hack on Docker? Awesome! Here are instructions to get you
|
||||
started. They are probably not perfect, please let us know if anything
|
||||
feels wrong or incomplete.
|
||||
|
||||
## Build Environment
|
||||
|
||||
For instructions on setting up your development environment, please see our dedicated [dev environment setup docs](http://docs.docker.io/en/latest/contributing/devenvironment/).
|
||||
For instructions on setting up your development environment, please
|
||||
see our dedicated [dev environment setup
|
||||
docs](http://docs.docker.io/en/latest/contributing/devenvironment/).
|
||||
|
||||
## Contribution guidelines
|
||||
|
||||
|
||||
+13
-16
@@ -4,24 +4,24 @@
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker .
|
||||
# # Apparmor messes with privileged mode: disable it
|
||||
# /etc/init.d/apparmor stop ; /etc/init.d/apparmor teardown
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/dotcloud/docker -privileged -lxc-conf=lxc.aa_profile=unconfined -i -t docker bash
|
||||
#
|
||||
# docker run -v `pwd`:/go/src/github.com/dotcloud/docker -privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run -privileged -lxc-conf=lxc.aa_profile=unconfined docker hack/make.sh test
|
||||
# docker run -privileged docker hack/make.sh test
|
||||
#
|
||||
# # Publish a release:
|
||||
# docker run -privileged -lxc-conf=lxc.aa_profile=unconfined \
|
||||
# docker run -privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: Apparmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
docker-version 0.6.1
|
||||
from ubuntu:12.04
|
||||
@@ -33,25 +33,22 @@ run apt-get update
|
||||
run apt-get install -y -q curl
|
||||
run apt-get install -y -q git
|
||||
run apt-get install -y -q mercurial
|
||||
run apt-get install -y -q build-essential
|
||||
run apt-get install -y -q build-essential libsqlite3-dev
|
||||
|
||||
# Install Go from source (for eventual cross-compiling)
|
||||
env CGO_ENABLED 0
|
||||
run curl -s https://go.googlecode.com/files/go1.1.2.src.tar.gz | tar -v -C / -xz && mv /go /goroot
|
||||
run cd /goroot/src && ./make.bash
|
||||
env GOROOT /goroot
|
||||
env PATH $PATH:/goroot/bin
|
||||
# Install Go
|
||||
run curl -s https://go.googlecode.com/files/go1.2rc5.src.tar.gz | tar -v -C /usr/local -xz
|
||||
env PATH /usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
|
||||
env GOPATH /go:/go/src/github.com/dotcloud/docker/vendor
|
||||
run cd /usr/local/go/src && ./make.bash && go install -ldflags '-w -linkmode external -extldflags "-static -Wl,--unresolved-symbols=ignore-in-shared-libs"' -tags netgo -a std
|
||||
|
||||
# Ubuntu stuff
|
||||
run apt-get install -y -q ruby1.9.3 rubygems libffi-dev
|
||||
run gem install --no-rdoc --no-ri fpm
|
||||
run apt-get install -y -q reprepro dpkg-sig
|
||||
|
||||
# Install s3cmd 1.0.1 (earlier versions don't support env variables in the config)
|
||||
run apt-get install -y -q python-pip
|
||||
run pip install s3cmd
|
||||
run pip install python-magic
|
||||
run pip install s3cmd==1.1.0-beta3
|
||||
run pip install python-magic==0.4.6
|
||||
run /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY\n' > /.s3cfg
|
||||
|
||||
# Runtime dependencies
|
||||
|
||||
@@ -1,43 +1,19 @@
|
||||
Docker
|
||||
Copyright 2012-2013 dotCloud, inc.
|
||||
Copyright 2012-2013 Docker, Inc.
|
||||
|
||||
This product includes software developed at dotCloud,
|
||||
inc. (http://www.dotcloud.com).
|
||||
This product includes software developed at Docker, Inc. (http://www.docker.com).
|
||||
|
||||
This product contains software (https://github.com/kr/pty) developed
|
||||
by Keith Rarick, licensed under the MIT License.
|
||||
|
||||
The following is courtesy of our legal counsel:
|
||||
|
||||
Transfers of Docker shall be in accordance with applicable export
|
||||
controls of any country and all other applicable legal requirements.
|
||||
Docker shall not be distributed or downloaded to or in Cuba, Iran,
|
||||
North Korea, Sudan or Syria and shall not be distributed or downloaded
|
||||
to any person on the Denied Persons List administered by the U.S.
|
||||
Department of Commerce.
|
||||
|
||||
What does that mean?
|
||||
Here is a further explanation from our legal counsel:
|
||||
Use and transfer of Docker may be subject to certain restrictions by the
|
||||
United States and other governments.
|
||||
It is your responsibility to ensure that your use and/or transfer does not
|
||||
violate applicable laws.
|
||||
|
||||
Like all software products that utilize cryptography, the export and
|
||||
use of Docker is subject to the U.S. Commerce Department's Export
|
||||
Administration Regulations (EAR) because it uses or contains
|
||||
cryptography (see
|
||||
http://www.bis.doc.gov/index.php/policy-guidance/encryption). Certain
|
||||
free and open source software projects have a lightweight set of
|
||||
requirements, which can generally be met by providing email notice to
|
||||
the appropriate U.S. government agencies that their source code is
|
||||
available on a publicly available repository and making the
|
||||
appropriate statements in the README.
|
||||
For more information, please see http://www.bis.doc.gov
|
||||
|
||||
The restrictions of the EAR apply to certain denied locations
|
||||
(currently Iran, Sudan, Syria, North Korea, or Cuba) and those
|
||||
individuals on the Denied Persons List, which is available here:
|
||||
http://www.bis.doc.gov/index.php/policy-guidance/lists-of-parties-of-concern/denied-persons-list.
|
||||
If you are incorporating Docker into a new open source project, the
|
||||
EAR restrictions apply to your incorporation of Docker into your
|
||||
project in the same manner as other cryptography-enabled projects,
|
||||
such as OpenSSL, almost all Linux distributions, etc.
|
||||
|
||||
For more information, see http://www.apache.org/dev/crypto.html and/or
|
||||
seek legal counsel.
|
||||
See also http://www.apache.org/dev/crypto.html and/or seek legal counsel.
|
||||
|
||||
@@ -193,10 +193,9 @@ wrong or incomplete.
|
||||
*Brought to you courtesy of our legal counsel. For more context,
|
||||
please see the Notice document.*
|
||||
|
||||
Transfers of Docker shall be in accordance with applicable export
|
||||
controls of any country and all other applicable legal requirements.
|
||||
Docker shall not be distributed or downloaded to or in Cuba, Iran,
|
||||
North Korea, Sudan or Syria and shall not be distributed or downloaded
|
||||
to any person on the Denied Persons List administered by the U.S.
|
||||
Department of Commerce.
|
||||
Use and transfer of Docker may be subject to certain restrictions by the
|
||||
United States and other governments.
|
||||
It is your responsibility to ensure that your use and/or transfer does not
|
||||
violate applicable laws.
|
||||
|
||||
For more information, please see http://www.bis.doc.gov
|
||||
|
||||
Vendored
+119
-44
@@ -4,65 +4,135 @@
|
||||
BOX_NAME = ENV['BOX_NAME'] || "ubuntu"
|
||||
BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64.box"
|
||||
VF_BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64_vmware_fusion.box"
|
||||
AWS_BOX_URI = ENV['BOX_URI'] || "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
|
||||
AWS_REGION = ENV['AWS_REGION'] || "us-east-1"
|
||||
AWS_AMI = ENV['AWS_AMI'] || "ami-d0f89fb9"
|
||||
AWS_AMI = ENV['AWS_AMI'] || "ami-69f5a900"
|
||||
AWS_INSTANCE_TYPE = ENV['AWS_INSTANCE_TYPE'] || 't1.micro'
|
||||
|
||||
FORWARD_DOCKER_PORTS = ENV['FORWARD_DOCKER_PORTS']
|
||||
|
||||
SSH_PRIVKEY_PATH = ENV["SSH_PRIVKEY_PATH"]
|
||||
|
||||
# A script to upgrade from the 12.04 kernel to the raring backport kernel (3.8)
|
||||
# and install docker.
|
||||
$script = <<SCRIPT
|
||||
# The username to add to the docker group will be passed as the first argument
|
||||
# to the script. If nothing is passed, default to "vagrant".
|
||||
user="$1"
|
||||
if [ -z "$user" ]; then
|
||||
user=vagrant
|
||||
fi
|
||||
|
||||
# Adding an apt gpg key is idempotent.
|
||||
wget -q -O - https://get.docker.io/gpg | apt-key add -
|
||||
|
||||
# Creating the docker.list file is idempotent, but it may overrite desired
|
||||
# settings if it already exists. This could be solved with md5sum but it
|
||||
# doesn't seem worth it.
|
||||
echo 'deb http://get.docker.io/ubuntu docker main' > \
|
||||
/etc/apt/sources.list.d/docker.list
|
||||
|
||||
# Update remote package metadata. 'apt-get update' is idempotent.
|
||||
apt-get update -q
|
||||
|
||||
# Install docker. 'apt-get install' is idempotent.
|
||||
apt-get install -q -y lxc-docker
|
||||
|
||||
usermod -a -G docker "$user"
|
||||
|
||||
tmp=`mktemp -q` && {
|
||||
# Only install the backport kernel, don't bother upgrade if the backport is
|
||||
# already installed. We want parse the output of apt so we need to save it
|
||||
# with 'tee'. NOTE: The installation of the kernel will trigger dkms to
|
||||
# install vboxguest if needed.
|
||||
apt-get install -q -y --no-upgrade linux-image-generic-lts-raring | \
|
||||
tee "$tmp"
|
||||
|
||||
# Parse the number of installed packages from the output
|
||||
NUM_INST=`awk '$2 == "upgraded," && $4 == "newly" { print $3 }' "$tmp"`
|
||||
rm "$tmp"
|
||||
}
|
||||
|
||||
# If the number of installed packages is greater than 0, we want to reboot (the
|
||||
# backport kernel was installed but is not running).
|
||||
if [ "$NUM_INST" -gt 0 ];
|
||||
then
|
||||
echo "Rebooting down to activate new kernel."
|
||||
echo "/vagrant will not be mounted. Use 'vagrant halt' followed by"
|
||||
echo "'vagrant up' to ensure /vagrant is mounted."
|
||||
shutdown -r now
|
||||
fi
|
||||
SCRIPT
|
||||
|
||||
# We need to install the virtualbox guest additions *before* we do the normal
|
||||
# docker installation. As such this script is prepended to the common docker
|
||||
# install script above. This allows the install of the backport kernel to
|
||||
# trigger dkms to build the virtualbox guest module install.
|
||||
$vbox_script = <<VBOX_SCRIPT + $script
|
||||
# Install the VirtualBox guest additions if they aren't already installed.
|
||||
if [ ! -d /opt/VBoxGuestAdditions-4.3.2/ ]; then
|
||||
# Update remote package metadata. 'apt-get update' is idempotent.
|
||||
apt-get update -q
|
||||
|
||||
# Kernel Headers and dkms are required to build the vbox guest kernel
|
||||
# modules.
|
||||
apt-get install -q -y linux-headers-generic-lts-raring dkms
|
||||
|
||||
echo 'Downloading VBox Guest Additions...'
|
||||
wget -cq http://dlc.sun.com.edgesuite.net/virtualbox/4.3.2/VBoxGuestAdditions_4.3.2.iso
|
||||
|
||||
mount -o loop,ro /home/vagrant/VBoxGuestAdditions_4.3.2.iso /mnt
|
||||
/mnt/VBoxLinuxAdditions.run --nox11
|
||||
umount /mnt
|
||||
fi
|
||||
VBOX_SCRIPT
|
||||
|
||||
Vagrant::Config.run do |config|
|
||||
# Setup virtual machine box. This VM configuration code is always executed.
|
||||
config.vm.box = BOX_NAME
|
||||
config.vm.box_url = BOX_URI
|
||||
|
||||
config.ssh.forward_agent = true
|
||||
|
||||
# Provision docker and new kernel if deployment was not done.
|
||||
# It is assumed Vagrant can successfully launch the provider instance.
|
||||
if Dir.glob("#{File.dirname(__FILE__)}/.vagrant/machines/default/*/id").empty?
|
||||
# Add lxc-docker package
|
||||
pkg_cmd = "wget -q -O - https://get.docker.io/gpg | apt-key add -;" \
|
||||
"echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list;" \
|
||||
"apt-get update -qq; apt-get install -q -y --force-yes lxc-docker; "
|
||||
# Add Ubuntu raring backported kernel
|
||||
pkg_cmd << "apt-get update -qq; apt-get install -q -y linux-image-generic-lts-raring; "
|
||||
# Add guest additions if local vbox VM. As virtualbox is the default provider,
|
||||
# it is assumed it won't be explicitly stated.
|
||||
if ENV["VAGRANT_DEFAULT_PROVIDER"].nil? && ARGV.none? { |arg| arg.downcase.start_with?("--provider") }
|
||||
pkg_cmd << "apt-get install -q -y linux-headers-generic-lts-raring dkms; " \
|
||||
"echo 'Downloading VBox Guest Additions...'; " \
|
||||
"wget -q http://dlc.sun.com.edgesuite.net/virtualbox/4.2.12/VBoxGuestAdditions_4.2.12.iso; "
|
||||
# Prepare the VM to add guest additions after reboot
|
||||
pkg_cmd << "echo -e 'mount -o loop,ro /home/vagrant/VBoxGuestAdditions_4.2.12.iso /mnt\n" \
|
||||
"echo yes | /mnt/VBoxLinuxAdditions.run\numount /mnt\n" \
|
||||
"rm /root/guest_additions.sh; ' > /root/guest_additions.sh; " \
|
||||
"chmod 700 /root/guest_additions.sh; " \
|
||||
"sed -i -E 's#^exit 0#[ -x /root/guest_additions.sh ] \\&\\& /root/guest_additions.sh#' /etc/rc.local; " \
|
||||
"echo 'Installation of VBox Guest Additions is proceeding in the background.'; " \
|
||||
"echo '\"vagrant reload\" can be used in about 2 minutes to activate the new guest additions.'; "
|
||||
end
|
||||
# Add vagrant user to the docker group
|
||||
pkg_cmd << "usermod -a -G docker vagrant; "
|
||||
# Activate new kernel
|
||||
pkg_cmd << "shutdown -r +1; "
|
||||
config.vm.provision :shell, :inline => pkg_cmd
|
||||
# Use the specified private key path if it is specified and not empty.
|
||||
if SSH_PRIVKEY_PATH
|
||||
config.ssh.private_key_path = SSH_PRIVKEY_PATH
|
||||
end
|
||||
|
||||
config.ssh.forward_agent = true
|
||||
end
|
||||
|
||||
|
||||
# Providers were added on Vagrant >= 1.1.0
|
||||
#
|
||||
# NOTE: The vagrant "vm.provision" appends its arguments to a list and executes
|
||||
# them in order. If you invoke "vm.provision :shell, :inline => $script"
|
||||
# twice then vagrant will run the script two times. Unfortunately when you use
|
||||
# providers and the override argument to set up provisioners (like the vbox
|
||||
# guest extensions) they 1) don't replace the other provisioners (they append
|
||||
# to the end of the list) and 2) you can't control the order the provisioners
|
||||
# are executed (you can only append to the list). If you want the virtualbox
|
||||
# only script to run before the other script, you have to jump through a lot of
|
||||
# hoops.
|
||||
#
|
||||
# Here is my only repeatable solution: make one script that is common ($script)
|
||||
# and another script that is the virtual box guest *prepended* to the common
|
||||
# script. Only ever use "vm.provision" *one time* per provider. That means
|
||||
# every single provider has an override, and every single one configures
|
||||
# "vm.provision". Much saddness, but such is life.
|
||||
Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
|
||||
config.vm.provider :aws do |aws, override|
|
||||
aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"]
|
||||
aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
|
||||
username = "ubuntu"
|
||||
override.vm.box_url = AWS_BOX_URI
|
||||
override.vm.provision :shell, :inline => $script, :args => username
|
||||
aws.access_key_id = ENV["AWS_ACCESS_KEY"]
|
||||
aws.secret_access_key = ENV["AWS_SECRET_KEY"]
|
||||
aws.keypair_name = ENV["AWS_KEYPAIR_NAME"]
|
||||
override.ssh.private_key_path = ENV["AWS_SSH_PRIVKEY"]
|
||||
override.ssh.username = "ubuntu"
|
||||
override.ssh.username = username
|
||||
aws.region = AWS_REGION
|
||||
aws.ami = AWS_AMI
|
||||
aws.instance_type = "t1.micro"
|
||||
aws.instance_type = AWS_INSTANCE_TYPE
|
||||
end
|
||||
|
||||
config.vm.provider :rackspace do |rs|
|
||||
config.ssh.private_key_path = ENV["RS_PRIVATE_KEY"]
|
||||
config.vm.provider :rackspace do |rs, override|
|
||||
override.vm.provision :shell, :inline => $script
|
||||
rs.username = ENV["RS_USERNAME"]
|
||||
rs.api_key = ENV["RS_API_KEY"]
|
||||
rs.public_key_path = ENV["RS_PUBLIC_KEY"]
|
||||
@@ -71,20 +141,25 @@ Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
|
||||
end
|
||||
|
||||
config.vm.provider :vmware_fusion do |f, override|
|
||||
override.vm.box = BOX_NAME
|
||||
override.vm.box_url = VF_BOX_URI
|
||||
override.vm.synced_folder ".", "/vagrant", disabled: true
|
||||
override.vm.provision :shell, :inline => $script
|
||||
f.vmx["displayName"] = "docker"
|
||||
end
|
||||
|
||||
config.vm.provider :virtualbox do |vb|
|
||||
config.vm.box = BOX_NAME
|
||||
config.vm.box_url = BOX_URI
|
||||
config.vm.provider :virtualbox do |vb, override|
|
||||
override.vm.provision :shell, :inline => $vbox_script
|
||||
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
|
||||
vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
|
||||
end
|
||||
end
|
||||
|
||||
# If this is a version 1 config, virtualbox is the only option. A version 2
|
||||
# config would have already been set in the above provider section.
|
||||
Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config|
|
||||
config.vm.provision :shell, :inline => $vbox_script
|
||||
end
|
||||
|
||||
if !FORWARD_DOCKER_PORTS.nil?
|
||||
Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config|
|
||||
(49000..49900).each do |port|
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/auth"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"github.com/gorilla/mux"
|
||||
@@ -22,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
APIVERSION = 1.6
|
||||
APIVERSION = 1.7
|
||||
DEFAULTHTTPHOST = "127.0.0.1"
|
||||
DEFAULTHTTPPORT = 4243
|
||||
DEFAULTUNIXSOCKET = "/var/run/docker.sock"
|
||||
@@ -42,6 +43,9 @@ func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
|
||||
|
||||
//If we don't do this, POST method without Content-type (even with empty body) will fail
|
||||
func parseForm(r *http.Request) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
@@ -57,7 +61,10 @@ func parseMultipartForm(r *http.Request) error {
|
||||
|
||||
func httpError(w http.ResponseWriter, err error) {
|
||||
statusCode := http.StatusInternalServerError
|
||||
if strings.HasPrefix(err.Error(), "No such") {
|
||||
// FIXME: this is brittle and should not be necessary.
|
||||
// If we need to differentiate between different possible error types, we should
|
||||
// create appropriate error types with clearly defined meaning.
|
||||
if strings.Contains(err.Error(), "No such") {
|
||||
statusCode = http.StatusNotFound
|
||||
} else if strings.HasPrefix(err.Error(), "Bad parameter") {
|
||||
statusCode = http.StatusBadRequest
|
||||
@@ -69,12 +76,12 @@ func httpError(w http.ResponseWriter, err error) {
|
||||
statusCode = http.StatusUnauthorized
|
||||
} else if strings.Contains(err.Error(), "hasn't been activated") {
|
||||
statusCode = http.StatusForbidden
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
utils.Errorf("HTTP Error: statusCode=%d %s", statusCode, err.Error())
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
}
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
|
||||
@@ -135,8 +142,22 @@ func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
name := vars["name"]
|
||||
if err := srv.ContainerKill(name); err != nil {
|
||||
|
||||
signal := 0
|
||||
if r != nil {
|
||||
if s := r.Form.Get("signal"); s != "" {
|
||||
s, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signal = s
|
||||
}
|
||||
}
|
||||
if err := srv.ContainerKill(name, signal); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
@@ -172,10 +193,23 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.
|
||||
return err
|
||||
}
|
||||
|
||||
if version < 1.7 {
|
||||
outs2 := []APIImagesOld{}
|
||||
for _, ctnr := range outs {
|
||||
outs2 = append(outs2, ctnr.ToLegacy()...)
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, outs2)
|
||||
}
|
||||
return writeJSON(w, http.StatusOK, outs)
|
||||
}
|
||||
|
||||
func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if version > 1.6 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return fmt.Errorf("This is now implemented in the client.")
|
||||
}
|
||||
|
||||
if err := srv.ImagesViz(w); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -217,6 +251,7 @@ func getEvents(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
wf := utils.NewWriteFlusher(w)
|
||||
wf.Flush()
|
||||
if since != 0 {
|
||||
// If since, send previous events that happened after the timestamp
|
||||
for _, event := range srv.events {
|
||||
@@ -279,13 +314,10 @@ func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||
if err := parseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
name := vars["name"]
|
||||
ps_args := r.Form.Get("ps_args")
|
||||
procsStr, err := srv.ContainerTop(name, ps_args)
|
||||
procsStr, err := srv.ContainerTop(vars["name"], r.Form.Get("ps_args"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, procsStr)
|
||||
}
|
||||
|
||||
@@ -313,13 +345,12 @@ func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *h
|
||||
if version < 1.5 {
|
||||
outs2 := []APIContainersOld{}
|
||||
for _, ctnr := range outs {
|
||||
outs2 = append(outs2, ctnr.ToLegacy())
|
||||
outs2 = append(outs2, *ctnr.ToLegacy())
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, outs2)
|
||||
} else {
|
||||
return writeJSON(w, http.StatusOK, outs)
|
||||
}
|
||||
return writeJSON(w, http.StatusOK, outs)
|
||||
}
|
||||
|
||||
func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -445,15 +476,16 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
}
|
||||
sf := utils.NewStreamFormatter(version > 1.0)
|
||||
imgID, err := srv.ImageInsert(name, url, path, w, sf)
|
||||
err := srv.ImageInsert(name, url, path, w, sf)
|
||||
if err != nil {
|
||||
if sf.Used() {
|
||||
w.Write(sf.FormatError(err))
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return writeJSON(w, http.StatusOK, &APIID{ID: imgID})
|
||||
return nil
|
||||
}
|
||||
|
||||
func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -502,40 +534,52 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
|
||||
return nil
|
||||
}
|
||||
|
||||
func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
config := &Config{}
|
||||
out := &APIRun{}
|
||||
func getImagesGet(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
name := vars["name"]
|
||||
if version > 1.0 {
|
||||
w.Header().Set("Content-Type", "application/x-tar")
|
||||
}
|
||||
return srv.ImageExport(name, w)
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(config); err != nil {
|
||||
func postImagesLoad(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return srv.ImageLoad(r.Body)
|
||||
}
|
||||
|
||||
func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
return nil
|
||||
}
|
||||
out := &APIRun{}
|
||||
job := srv.Eng.Job("create", r.Form.Get("name"))
|
||||
if err := job.DecodeEnv(r.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resolvConf, err := utils.GetResolvConf()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
|
||||
if !job.GetenvBool("NetworkDisabled") && len(job.Getenv("Dns")) == 0 && len(srv.runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
|
||||
out.Warnings = append(out.Warnings, fmt.Sprintf("Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns))
|
||||
config.Dns = defaultDns
|
||||
job.SetenvList("Dns", defaultDns)
|
||||
}
|
||||
|
||||
id, err := srv.ContainerCreate(config)
|
||||
if err != nil {
|
||||
// Read container ID from the first line of stdout
|
||||
job.StdoutParseString(&out.ID)
|
||||
// Read warnings from stderr
|
||||
job.StderrParseLines(&out.Warnings, 0)
|
||||
if err := job.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ID = id
|
||||
|
||||
if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
|
||||
if job.GetenvInt("Memory") > 0 && !srv.runtime.capabilities.MemoryLimit {
|
||||
log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
|
||||
out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
|
||||
}
|
||||
if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
|
||||
if job.GetenvInt("Memory") > 0 && !srv.runtime.capabilities.SwapLimit {
|
||||
log.Println("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.")
|
||||
out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.")
|
||||
}
|
||||
|
||||
if !config.NetworkDisabled && srv.runtime.capabilities.IPv4ForwardingDisabled {
|
||||
if !job.GetenvBool("NetworkDisabled") && srv.runtime.capabilities.IPv4ForwardingDisabled {
|
||||
log.Println("Warning: IPv4 forwarding is disabled.")
|
||||
out.Warnings = append(out.Warnings, "IPv4 forwarding is disabled.")
|
||||
}
|
||||
@@ -570,12 +614,17 @@ func deleteContainers(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
name := vars["name"]
|
||||
|
||||
removeVolume, err := getBoolParam(r.Form.Get("v"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
removeLink, err := getBoolParam(r.Form.Get("link"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := srv.ContainerDestroy(name, removeVolume); err != nil {
|
||||
if err := srv.ContainerDestroy(name, removeVolume, removeLink); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
@@ -597,32 +646,28 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
|
||||
if imgs != nil {
|
||||
if len(imgs) != 0 {
|
||||
return writeJSON(w, http.StatusOK, imgs)
|
||||
} else {
|
||||
return fmt.Errorf("Conflict, %s wasn't deleted", name)
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return fmt.Errorf("Conflict, %s wasn't deleted", name)
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
|
||||
func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var hostConfig *HostConfig
|
||||
// allow a nil body for backwards compatibility
|
||||
if r.Body != nil {
|
||||
if matchesContentType(r.Header.Get("Content-Type"), "application/json") {
|
||||
hostConfig = &HostConfig{}
|
||||
if err := json.NewDecoder(r.Body).Decode(hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
name := vars["name"]
|
||||
if err := srv.ContainerStart(name, hostConfig); err != nil {
|
||||
job := srv.Eng.Job("start", name)
|
||||
// allow a nil body for backwards compatibility
|
||||
if r.Body != nil {
|
||||
if matchesContentType(r.Header.Get("Content-Type"), "application/json") {
|
||||
if err := job.DecodeEnv(r.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := job.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
@@ -655,6 +700,7 @@ func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
name := vars["name"]
|
||||
|
||||
status, err := srv.ContainerWait(name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -870,7 +916,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
|
||||
return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
|
||||
}
|
||||
|
||||
c, err := Tar(root, Bzip2)
|
||||
c, err := archive.Tar(root, archive.Bzip2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -885,7 +931,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err := mkBuildContext(string(dockerFile), nil)
|
||||
c, err := MkBuildContext(string(dockerFile), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -933,7 +979,7 @@ func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r *
|
||||
}
|
||||
|
||||
if copyData.Resource == "" {
|
||||
return fmt.Errorf("Resource cannot be empty")
|
||||
return fmt.Errorf("Path cannot be empty")
|
||||
}
|
||||
if copyData.Resource[0] == '/' {
|
||||
copyData.Resource = copyData.Resource[1:]
|
||||
@@ -975,7 +1021,7 @@ func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute s
|
||||
if err != nil {
|
||||
version = APIVERSION
|
||||
}
|
||||
if srv.enableCors {
|
||||
if srv.runtime.config.EnableCors {
|
||||
writeCorsHeaders(w, r)
|
||||
}
|
||||
|
||||
@@ -1002,6 +1048,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
||||
"/images/json": getImagesJSON,
|
||||
"/images/viz": getImagesViz,
|
||||
"/images/search": getImagesSearch,
|
||||
"/images/{name:.*}/get": getImagesGet,
|
||||
"/images/{name:.*}/history": getImagesHistory,
|
||||
"/images/{name:.*}/json": getImagesByName,
|
||||
"/containers/ps": getContainersJSON,
|
||||
@@ -1018,6 +1065,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
||||
"/build": postBuild,
|
||||
"/images/create": postImagesCreate,
|
||||
"/images/{name:.*}/insert": postImagesInsert,
|
||||
"/images/load": postImagesLoad,
|
||||
"/images/{name:.*}/push": postImagesPush,
|
||||
"/images/{name:.*}/tag": postImagesTag,
|
||||
"/containers/create": postContainersCreate,
|
||||
@@ -1063,6 +1111,20 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ServeRequest processes a single http request to the docker remote api.
|
||||
// FIXME: refactor this to be part of Server and not require re-creating a new
|
||||
// router each time. This requires first moving ListenAndServe into Server.
|
||||
func ServeRequest(srv *Server, apiversion float64, w http.ResponseWriter, req *http.Request) error {
|
||||
router, err := createRouter(srv, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Insert APIVERSION into the request as a convenience
|
||||
req.URL.Path = fmt.Sprintf("/v%g%s", apiversion, req.URL.Path)
|
||||
router.ServeHTTP(w, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListenAndServe(proto, addr string, srv *Server, logging bool) error {
|
||||
log.Printf("Listening for HTTP on %s (%s)\n", addr, proto)
|
||||
|
||||
|
||||
+141
-124
@@ -1,131 +1,148 @@
|
||||
package docker
|
||||
|
||||
import "encoding/json"
|
||||
import "strings"
|
||||
|
||||
type APIHistory struct {
|
||||
ID string `json:"Id"`
|
||||
Tags []string `json:",omitempty"`
|
||||
Created int64
|
||||
CreatedBy string `json:",omitempty"`
|
||||
type (
|
||||
APIHistory struct {
|
||||
ID string `json:"Id"`
|
||||
Tags []string `json:",omitempty"`
|
||||
Created int64
|
||||
CreatedBy string `json:",omitempty"`
|
||||
Size int64
|
||||
}
|
||||
|
||||
APIImages struct {
|
||||
ID string `json:"Id"`
|
||||
RepoTags []string `json:",omitempty"`
|
||||
Created int64
|
||||
Size int64
|
||||
VirtualSize int64
|
||||
ParentId string `json:",omitempty"`
|
||||
}
|
||||
|
||||
APIImagesOld struct {
|
||||
Repository string `json:",omitempty"`
|
||||
Tag string `json:",omitempty"`
|
||||
ID string `json:"Id"`
|
||||
Created int64
|
||||
Size int64
|
||||
VirtualSize int64
|
||||
}
|
||||
|
||||
APIInfo struct {
|
||||
Debug bool
|
||||
Containers int
|
||||
Images int
|
||||
NFd int `json:",omitempty"`
|
||||
NGoroutines int `json:",omitempty"`
|
||||
MemoryLimit bool `json:",omitempty"`
|
||||
SwapLimit bool `json:",omitempty"`
|
||||
IPv4Forwarding bool `json:",omitempty"`
|
||||
LXCVersion string `json:",omitempty"`
|
||||
NEventsListener int `json:",omitempty"`
|
||||
KernelVersion string `json:",omitempty"`
|
||||
IndexServerAddress string `json:",omitempty"`
|
||||
}
|
||||
|
||||
APITop struct {
|
||||
Titles []string
|
||||
Processes [][]string
|
||||
}
|
||||
|
||||
APIRmi struct {
|
||||
Deleted string `json:",omitempty"`
|
||||
Untagged string `json:",omitempty"`
|
||||
}
|
||||
|
||||
APIContainers struct {
|
||||
ID string `json:"Id"`
|
||||
Image string
|
||||
Command string
|
||||
Created int64
|
||||
Status string
|
||||
Ports []APIPort
|
||||
SizeRw int64
|
||||
SizeRootFs int64
|
||||
Names []string
|
||||
}
|
||||
|
||||
APIContainersOld struct {
|
||||
ID string `json:"Id"`
|
||||
Image string
|
||||
Command string
|
||||
Created int64
|
||||
Status string
|
||||
Ports string
|
||||
SizeRw int64
|
||||
SizeRootFs int64
|
||||
}
|
||||
|
||||
APIID struct {
|
||||
ID string `json:"Id"`
|
||||
}
|
||||
|
||||
APIRun struct {
|
||||
ID string `json:"Id"`
|
||||
Warnings []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
APIPort struct {
|
||||
PrivatePort int64
|
||||
PublicPort int64
|
||||
Type string
|
||||
IP string
|
||||
}
|
||||
|
||||
APIVersion struct {
|
||||
Version string
|
||||
GitCommit string `json:",omitempty"`
|
||||
GoVersion string `json:",omitempty"`
|
||||
}
|
||||
|
||||
APIWait struct {
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
APIAuth struct {
|
||||
Status string
|
||||
}
|
||||
|
||||
APIImageConfig struct {
|
||||
ID string `json:"Id"`
|
||||
*Config
|
||||
}
|
||||
|
||||
APICopy struct {
|
||||
Resource string
|
||||
HostPath string
|
||||
}
|
||||
)
|
||||
|
||||
func (api APIImages) ToLegacy() []APIImagesOld {
|
||||
outs := []APIImagesOld{}
|
||||
for _, repotag := range api.RepoTags {
|
||||
components := strings.SplitN(repotag, ":", 2)
|
||||
outs = append(outs, APIImagesOld{
|
||||
ID: api.ID,
|
||||
Repository: components[0],
|
||||
Tag: components[1],
|
||||
Created: api.Created,
|
||||
Size: api.Size,
|
||||
VirtualSize: api.VirtualSize,
|
||||
})
|
||||
}
|
||||
return outs
|
||||
}
|
||||
|
||||
type APIImages struct {
|
||||
Repository string `json:",omitempty"`
|
||||
Tag string `json:",omitempty"`
|
||||
ID string `json:"Id"`
|
||||
Created int64
|
||||
Size int64
|
||||
VirtualSize int64
|
||||
}
|
||||
|
||||
type APIInfo struct {
|
||||
Debug bool
|
||||
Containers int
|
||||
Images int
|
||||
NFd int `json:",omitempty"`
|
||||
NGoroutines int `json:",omitempty"`
|
||||
MemoryLimit bool `json:",omitempty"`
|
||||
SwapLimit bool `json:",omitempty"`
|
||||
IPv4Forwarding bool `json:",omitempty"`
|
||||
LXCVersion string `json:",omitempty"`
|
||||
NEventsListener int `json:",omitempty"`
|
||||
KernelVersion string `json:",omitempty"`
|
||||
IndexServerAddress string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type APITop struct {
|
||||
Titles []string
|
||||
Processes [][]string
|
||||
}
|
||||
|
||||
type APIRmi struct {
|
||||
Deleted string `json:",omitempty"`
|
||||
Untagged string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type APIContainers struct {
|
||||
ID string `json:"Id"`
|
||||
Image string
|
||||
Command string
|
||||
Created int64
|
||||
Status string
|
||||
Ports []APIPort
|
||||
SizeRw int64
|
||||
SizeRootFs int64
|
||||
}
|
||||
|
||||
func (self *APIContainers) ToLegacy() APIContainersOld {
|
||||
return APIContainersOld{
|
||||
ID: self.ID,
|
||||
Image: self.Image,
|
||||
Command: self.Command,
|
||||
Created: self.Created,
|
||||
Status: self.Status,
|
||||
Ports: displayablePorts(self.Ports),
|
||||
SizeRw: self.SizeRw,
|
||||
SizeRootFs: self.SizeRootFs,
|
||||
func (api APIContainers) ToLegacy() *APIContainersOld {
|
||||
return &APIContainersOld{
|
||||
ID: api.ID,
|
||||
Image: api.Image,
|
||||
Command: api.Command,
|
||||
Created: api.Created,
|
||||
Status: api.Status,
|
||||
Ports: displayablePorts(api.Ports),
|
||||
SizeRw: api.SizeRw,
|
||||
SizeRootFs: api.SizeRootFs,
|
||||
}
|
||||
}
|
||||
|
||||
type APIContainersOld struct {
|
||||
ID string `json:"Id"`
|
||||
Image string
|
||||
Command string
|
||||
Created int64
|
||||
Status string
|
||||
Ports string
|
||||
SizeRw int64
|
||||
SizeRootFs int64
|
||||
}
|
||||
|
||||
type APISearch struct {
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
type APIID struct {
|
||||
ID string `json:"Id"`
|
||||
}
|
||||
|
||||
type APIRun struct {
|
||||
ID string `json:"Id"`
|
||||
Warnings []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type APIPort struct {
|
||||
PrivatePort int64
|
||||
PublicPort int64
|
||||
Type string
|
||||
}
|
||||
|
||||
func (port *APIPort) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"PrivatePort": port.PrivatePort,
|
||||
"PublicPort": port.PublicPort,
|
||||
"Type": port.Type,
|
||||
})
|
||||
}
|
||||
|
||||
type APIVersion struct {
|
||||
Version string
|
||||
GitCommit string `json:",omitempty"`
|
||||
GoVersion string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type APIWait struct {
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
type APIAuth struct {
|
||||
Status string
|
||||
}
|
||||
|
||||
type APIImageConfig struct {
|
||||
ID string `json:"Id"`
|
||||
*Config
|
||||
}
|
||||
|
||||
type APICopy struct {
|
||||
Resource string
|
||||
HostPath string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJsonContentType(t *testing.T) {
|
||||
if !matchesContentType("application/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !matchesContentType("application/json; charset=utf-8", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if matchesContentType("dockerapplication/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
||||
@@ -1,4 +1,4 @@
|
||||
package docker
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
@@ -109,16 +109,17 @@ func Untar(archive io.Reader, path string) error {
|
||||
buf := make([]byte, 10)
|
||||
totalN := 0
|
||||
for totalN < 10 {
|
||||
if n, err := archive.Read(buf[totalN:]); err != nil {
|
||||
n, err := archive.Read(buf[totalN:])
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return fmt.Errorf("Tarball too short")
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
totalN += n
|
||||
utils.Debugf("[tar autodetect] n: %d", n)
|
||||
}
|
||||
totalN += n
|
||||
utils.Debugf("[tar autodetect] n: %d", n)
|
||||
}
|
||||
|
||||
compression := DetectCompression(buf)
|
||||
|
||||
utils.Debugf("Archive compression detected: %s", compression.Extension())
|
||||
@@ -1,4 +1,4 @@
|
||||
package docker
|
||||
package archive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
+2
-3
@@ -196,10 +196,9 @@ func Login(authConfig *AuthConfig, factory *utils.HTTPRequestFactory) (string, e
|
||||
if loginAgainstOfficialIndex {
|
||||
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
|
||||
"Please check your e-mail for a confirmation link.")
|
||||
} else {
|
||||
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
|
||||
"Please see the documentation of the registry " + serverAddress + " for instructions how to activate it.")
|
||||
}
|
||||
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
|
||||
"Please see the documentation of the registry " + serverAddress + " for instructions how to activate it.")
|
||||
} else if reqStatusCode == 400 {
|
||||
if string(reqBody) == "\"Username or email already exists\"" {
|
||||
req, err := factory.NewRequest("GET", serverAddress+"users/", nil)
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -29,52 +26,6 @@ func TestEncodeAuth(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
|
||||
defer os.Setenv("DOCKER_INDEX_URL", "")
|
||||
authConfig := &AuthConfig{Username: "unittester", Password: "surlautrerivejetattendrai", Email: "noise+unittester@dotcloud.com"}
|
||||
status, err := Login(authConfig, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if status != "Login Succeeded" {
|
||||
t.Fatalf("Expected status \"Login Succeeded\", found \"%s\" instead", status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateAccount(t *testing.T) {
|
||||
os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
|
||||
defer os.Setenv("DOCKER_INDEX_URL", "")
|
||||
tokenBuffer := make([]byte, 16)
|
||||
_, err := rand.Read(tokenBuffer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token := hex.EncodeToString(tokenBuffer)[:12]
|
||||
username := "ut" + token
|
||||
authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
|
||||
status, err := Login(authConfig, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedStatus := "Account created. Please use the confirmation link we sent" +
|
||||
" to your e-mail to activate it."
|
||||
if status != expectedStatus {
|
||||
t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status)
|
||||
}
|
||||
|
||||
status, err = Login(authConfig, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found nil instead")
|
||||
}
|
||||
|
||||
expectedError := "Login: Account is not Active"
|
||||
|
||||
if !strings.Contains(err.Error(), expectedError) {
|
||||
t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err)
|
||||
}
|
||||
}
|
||||
|
||||
func setupTempConfigFile() (*ConfigFile, error) {
|
||||
root, err := ioutil.TempDir("", "docker-test-auth")
|
||||
if err != nil {
|
||||
|
||||
+25
-12
@@ -3,6 +3,7 @@ package docker
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -64,6 +65,9 @@ func (b *buildFile) CmdFrom(name string) error {
|
||||
}
|
||||
b.image = image.ID
|
||||
b.config = &Config{}
|
||||
if image.Config != nil {
|
||||
b.config = image.Config
|
||||
}
|
||||
if b.config.Env == nil || len(b.config.Env) == 0 {
|
||||
b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
|
||||
}
|
||||
@@ -291,17 +295,17 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
|
||||
return fmt.Errorf("%s: no such file or directory", orig)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
if err := CopyWithTar(origPath, destPath); err != nil {
|
||||
if err := archive.CopyWithTar(origPath, destPath); err != nil {
|
||||
return err
|
||||
}
|
||||
// First try to unpack the source as an archive
|
||||
} else if err := UntarPath(origPath, destPath); err != nil {
|
||||
} else if err := archive.UntarPath(origPath, destPath); err != nil {
|
||||
utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
|
||||
// If that fails, just copy it as a regular file
|
||||
if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := CopyWithTar(origPath, destPath); err != nil {
|
||||
if err := archive.CopyWithTar(origPath, destPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -332,7 +336,7 @@ func (b *buildFile) CmdAdd(args string) error {
|
||||
|
||||
b.config.Image = b.image
|
||||
// Create the container and start it
|
||||
container, err := b.runtime.Create(b.config)
|
||||
container, _, err := b.runtime.Create(b.config, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -367,7 +371,7 @@ func (b *buildFile) run() (string, error) {
|
||||
b.config.Image = b.image
|
||||
|
||||
// Create the container and start it
|
||||
c, err := b.runtime.Create(b.config)
|
||||
c, _, err := b.runtime.Create(b.config, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -378,15 +382,21 @@ func (b *buildFile) run() (string, error) {
|
||||
c.Path = b.config.Cmd[0]
|
||||
c.Args = b.config.Cmd[1:]
|
||||
|
||||
var errCh chan error
|
||||
|
||||
if b.verbose {
|
||||
errCh = utils.Go(func() error {
|
||||
return <-c.Attach(nil, nil, b.out, b.out)
|
||||
})
|
||||
}
|
||||
|
||||
//start the container
|
||||
hostConfig := &HostConfig{}
|
||||
if err := c.Start(hostConfig); err != nil {
|
||||
if err := c.Start(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if b.verbose {
|
||||
err = <-c.Attach(nil, nil, b.out, b.out)
|
||||
if err != nil {
|
||||
if errCh != nil {
|
||||
if err := <-errCh; err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
@@ -423,10 +433,13 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
|
||||
}
|
||||
}
|
||||
|
||||
container, err := b.runtime.Create(b.config)
|
||||
container, warnings, err := b.runtime.Create(b.config, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, warning := range warnings {
|
||||
fmt.Fprintf(b.out, " ---> [Warning] %s\n", warning)
|
||||
}
|
||||
b.tmpContainers[container.ID] = struct{}{}
|
||||
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
|
||||
id = container.ID
|
||||
@@ -463,7 +476,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := Untar(context, name); err != nil {
|
||||
if err := archive.Untar(context, name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer os.RemoveAll(name)
|
||||
|
||||
+843
-243
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"net"
|
||||
)
|
||||
|
||||
// FIXME: separate runtime configuration from http api configuration
|
||||
type DaemonConfig struct {
|
||||
Pidfile string
|
||||
Root string
|
||||
AutoRestart bool
|
||||
EnableCors bool
|
||||
Dns []string
|
||||
EnableIptables bool
|
||||
BridgeIface string
|
||||
DefaultIp net.IP
|
||||
InterContainerCommunication bool
|
||||
}
|
||||
|
||||
// ConfigFromJob creates and returns a new DaemonConfig object
|
||||
// by parsing the contents of a job's environment.
|
||||
func ConfigFromJob(job *engine.Job) *DaemonConfig {
|
||||
var config DaemonConfig
|
||||
config.Pidfile = job.Getenv("Pidfile")
|
||||
config.Root = job.Getenv("Root")
|
||||
config.AutoRestart = job.GetenvBool("AutoRestart")
|
||||
config.EnableCors = job.GetenvBool("EnableCors")
|
||||
if dns := job.Getenv("Dns"); dns != "" {
|
||||
config.Dns = []string{dns}
|
||||
}
|
||||
config.EnableIptables = job.GetenvBool("EnableIptables")
|
||||
if br := job.Getenv("BridgeIface"); br != "" {
|
||||
config.BridgeIface = br
|
||||
} else {
|
||||
config.BridgeIface = DefaultNetworkBridge
|
||||
}
|
||||
config.DefaultIp = net.ParseIP(job.Getenv("DefaultIp"))
|
||||
config.InterContainerCommunication = job.GetenvBool("InterContainerCommunication")
|
||||
return &config
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareConfig(t *testing.T) {
|
||||
volumes1 := make(map[string]struct{})
|
||||
volumes1["/test1"] = struct{}{}
|
||||
config1 := Config{
|
||||
Dns: []string{"1.1.1.1", "2.2.2.2"},
|
||||
PortSpecs: []string{"1111:1111", "2222:2222"},
|
||||
Env: []string{"VAR1=1", "VAR2=2"},
|
||||
VolumesFrom: "11111111",
|
||||
Volumes: volumes1,
|
||||
}
|
||||
config2 := Config{
|
||||
Dns: []string{"0.0.0.0", "2.2.2.2"},
|
||||
PortSpecs: []string{"1111:1111", "2222:2222"},
|
||||
Env: []string{"VAR1=1", "VAR2=2"},
|
||||
VolumesFrom: "11111111",
|
||||
Volumes: volumes1,
|
||||
}
|
||||
config3 := Config{
|
||||
Dns: []string{"1.1.1.1", "2.2.2.2"},
|
||||
PortSpecs: []string{"0000:0000", "2222:2222"},
|
||||
Env: []string{"VAR1=1", "VAR2=2"},
|
||||
VolumesFrom: "11111111",
|
||||
Volumes: volumes1,
|
||||
}
|
||||
config4 := Config{
|
||||
Dns: []string{"1.1.1.1", "2.2.2.2"},
|
||||
PortSpecs: []string{"0000:0000", "2222:2222"},
|
||||
Env: []string{"VAR1=1", "VAR2=2"},
|
||||
VolumesFrom: "22222222",
|
||||
Volumes: volumes1,
|
||||
}
|
||||
volumes2 := make(map[string]struct{})
|
||||
volumes2["/test2"] = struct{}{}
|
||||
config5 := Config{
|
||||
Dns: []string{"1.1.1.1", "2.2.2.2"},
|
||||
PortSpecs: []string{"0000:0000", "2222:2222"},
|
||||
Env: []string{"VAR1=1", "VAR2=2"},
|
||||
VolumesFrom: "11111111",
|
||||
Volumes: volumes2,
|
||||
}
|
||||
if CompareConfig(&config1, &config2) {
|
||||
t.Fatalf("CompareConfig should return false, Dns are different")
|
||||
}
|
||||
if CompareConfig(&config1, &config3) {
|
||||
t.Fatalf("CompareConfig should return false, PortSpecs are different")
|
||||
}
|
||||
if CompareConfig(&config1, &config4) {
|
||||
t.Fatalf("CompareConfig should return false, VolumesFrom are different")
|
||||
}
|
||||
if CompareConfig(&config1, &config5) {
|
||||
t.Fatalf("CompareConfig should return false, Volumes are different")
|
||||
}
|
||||
if !CompareConfig(&config1, &config1) {
|
||||
t.Fatalf("CompareConfig should return true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeConfig(t *testing.T) {
|
||||
volumesImage := make(map[string]struct{})
|
||||
volumesImage["/test1"] = struct{}{}
|
||||
volumesImage["/test2"] = struct{}{}
|
||||
configImage := &Config{
|
||||
Dns: []string{"1.1.1.1", "2.2.2.2"},
|
||||
PortSpecs: []string{"1111:1111", "2222:2222"},
|
||||
Env: []string{"VAR1=1", "VAR2=2"},
|
||||
VolumesFrom: "1111",
|
||||
Volumes: volumesImage,
|
||||
}
|
||||
|
||||
volumesUser := make(map[string]struct{})
|
||||
volumesUser["/test3"] = struct{}{}
|
||||
configUser := &Config{
|
||||
Dns: []string{"3.3.3.3"},
|
||||
PortSpecs: []string{"3333:2222", "3333:3333"},
|
||||
Env: []string{"VAR2=3", "VAR3=3"},
|
||||
Volumes: volumesUser,
|
||||
}
|
||||
|
||||
if err := MergeConfig(configUser, configImage); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if len(configUser.Dns) != 3 {
|
||||
t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
|
||||
}
|
||||
for _, dns := range configUser.Dns {
|
||||
if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
|
||||
t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
|
||||
}
|
||||
}
|
||||
|
||||
if len(configUser.ExposedPorts) != 3 {
|
||||
t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
|
||||
}
|
||||
for portSpecs := range configUser.ExposedPorts {
|
||||
if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
|
||||
t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
|
||||
}
|
||||
}
|
||||
if len(configUser.Env) != 3 {
|
||||
t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
|
||||
}
|
||||
for _, env := range configUser.Env {
|
||||
if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
|
||||
t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
|
||||
}
|
||||
}
|
||||
|
||||
if len(configUser.Volumes) != 3 {
|
||||
t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
|
||||
}
|
||||
for v := range configUser.Volumes {
|
||||
if v != "/test1" && v != "/test2" && v != "/test3" {
|
||||
t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
if configUser.VolumesFrom != "1111" {
|
||||
t.Fatalf("Expected VolumesFrom to be 1111, found %s", configUser.VolumesFrom)
|
||||
}
|
||||
|
||||
ports, _, err := parsePortSpecs([]string{"0000"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
configImage2 := &Config{
|
||||
ExposedPorts: ports,
|
||||
}
|
||||
|
||||
if err := MergeConfig(configUser, configImage2); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if len(configUser.ExposedPorts) != 4 {
|
||||
t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
|
||||
}
|
||||
for portSpecs := range configUser.ExposedPorts {
|
||||
if portSpecs.Port() != "0000" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
|
||||
t.Fatalf("Expected 0000 or 1111 or 2222 or 3333, found %s", portSpecs)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+465
-332
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,161 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseLxcConfOpt(t *testing.T) {
|
||||
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
|
||||
|
||||
for _, o := range opts {
|
||||
k, v, err := parseLxcOpt(o)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if k != "lxc.utsname" {
|
||||
t.Fail()
|
||||
}
|
||||
if v != "docker" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsPrivateOnly(t *testing.T) {
|
||||
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::80"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ports) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(ports))
|
||||
t.FailNow()
|
||||
}
|
||||
if len(bindings) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(bindings))
|
||||
t.FailNow()
|
||||
}
|
||||
for k := range ports {
|
||||
if k.Proto() != "tcp" {
|
||||
t.Logf("Expected tcp got %s", k.Proto())
|
||||
t.Fail()
|
||||
}
|
||||
if k.Port() != "80" {
|
||||
t.Logf("Expected 80 got %s", k.Port())
|
||||
t.Fail()
|
||||
}
|
||||
b, exists := bindings[k]
|
||||
if !exists {
|
||||
t.Log("Binding does not exist")
|
||||
t.FailNow()
|
||||
}
|
||||
if len(b) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(b))
|
||||
t.FailNow()
|
||||
}
|
||||
s := b[0]
|
||||
if s.HostPort != "" {
|
||||
t.Logf("Expected \"\" got %s", s.HostPort)
|
||||
t.Fail()
|
||||
}
|
||||
if s.HostIp != "192.168.1.100" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsPublic(t *testing.T) {
|
||||
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100:8080:80"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ports) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(ports))
|
||||
t.FailNow()
|
||||
}
|
||||
if len(bindings) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(bindings))
|
||||
t.FailNow()
|
||||
}
|
||||
for k := range ports {
|
||||
if k.Proto() != "tcp" {
|
||||
t.Logf("Expected tcp got %s", k.Proto())
|
||||
t.Fail()
|
||||
}
|
||||
if k.Port() != "80" {
|
||||
t.Logf("Expected 80 got %s", k.Port())
|
||||
t.Fail()
|
||||
}
|
||||
b, exists := bindings[k]
|
||||
if !exists {
|
||||
t.Log("Binding does not exist")
|
||||
t.FailNow()
|
||||
}
|
||||
if len(b) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(b))
|
||||
t.FailNow()
|
||||
}
|
||||
s := b[0]
|
||||
if s.HostPort != "8080" {
|
||||
t.Logf("Expected 8080 got %s", s.HostPort)
|
||||
t.Fail()
|
||||
}
|
||||
if s.HostIp != "192.168.1.100" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsUdp(t *testing.T) {
|
||||
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::6000/udp"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ports) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(ports))
|
||||
t.FailNow()
|
||||
}
|
||||
if len(bindings) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(bindings))
|
||||
t.FailNow()
|
||||
}
|
||||
for k := range ports {
|
||||
if k.Proto() != "udp" {
|
||||
t.Logf("Expected udp got %s", k.Proto())
|
||||
t.Fail()
|
||||
}
|
||||
if k.Port() != "6000" {
|
||||
t.Logf("Expected 6000 got %s", k.Port())
|
||||
t.Fail()
|
||||
}
|
||||
b, exists := bindings[k]
|
||||
if !exists {
|
||||
t.Log("Binding does not exist")
|
||||
t.FailNow()
|
||||
}
|
||||
if len(b) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(b))
|
||||
t.FailNow()
|
||||
}
|
||||
s := b[0]
|
||||
if s.HostPort != "" {
|
||||
t.Logf("Expected \"\" got %s", s.HostPort)
|
||||
t.Fail()
|
||||
}
|
||||
if s.HostIp != "192.168.1.100" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFullName(t *testing.T) {
|
||||
name, err := getFullName("testing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if name != "/testing" {
|
||||
t.Fatalf("Expected /testing got %s", name)
|
||||
}
|
||||
if _, err := getFullName(""); err == nil {
|
||||
t.Fatal("Error should not be nil")
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
*.pyc
|
||||
@@ -1,78 +0,0 @@
|
||||
# docker-brew
|
||||
|
||||
docker-brew is a command-line tool used to build the docker standard library.
|
||||
|
||||
## Install instructions
|
||||
|
||||
1. Install python if it isn't already available on your OS of choice
|
||||
1. Install the easy_install tool (`sudo apt-get install python-setuptools`
|
||||
for Debian)
|
||||
1. Install the python package manager, `pip` (`easy_install pip`)
|
||||
1. Run the following command: `sudo pip install -r requirements.txt`
|
||||
1. You should now be able to use the `docker-brew` script as such.
|
||||
|
||||
## Basics
|
||||
|
||||
./docker-brew -h
|
||||
|
||||
Display usage and help.
|
||||
|
||||
./docker-brew
|
||||
|
||||
Default build from the default repo/branch. Images will be created under the
|
||||
`library/` namespace. Does not perform a remote push.
|
||||
|
||||
./docker-brew -n mycorp.com -b stable --push git://github.com/mycorp/docker
|
||||
|
||||
Will fetch the library definition files in the `stable` branch of the
|
||||
`git://github.com/mycorp/docker` repository and create images under the
|
||||
`mycorp.com` namespace (e.g. `mycorp.com/ubuntu`). Created images will then
|
||||
be pushed to the official docker repository (pending: support for private
|
||||
repositories)
|
||||
|
||||
## Library definition files
|
||||
|
||||
The library definition files are plain text files found in the `library/`
|
||||
subfolder of the docker repository.
|
||||
|
||||
### File names
|
||||
|
||||
The name of a definition file will determine the name of the image(s) it
|
||||
creates. For example, the `library/ubuntu` file will create images in the
|
||||
`<namespace>/ubuntu` repository. If multiple instructions are present in
|
||||
a single file, all images are expected to be created under a different tag.
|
||||
|
||||
### Instruction format
|
||||
|
||||
Each line represents a build instruction.
|
||||
There are different formats that `docker-brew` is able to parse.
|
||||
|
||||
<git-url>
|
||||
git://github.com/dotcloud/hipache
|
||||
https://github.com/dotcloud/docker.git
|
||||
|
||||
The simplest format. `docker-brew` will fetch data from the provided git
|
||||
repository from the `HEAD`of its `master` branch. Generated image will be
|
||||
tagged as `latest`. Use of this format is discouraged because there is no
|
||||
way to ensure stability.
|
||||
|
||||
<docker-tag> <git-url>
|
||||
bleeding-edge git://github.com/dotcloud/docker
|
||||
unstable https://github.com/dotcloud/docker-redis.git
|
||||
|
||||
A more advanced format. `docker-brew` will fetch data from the provided git
|
||||
repository from the `HEAD`of its `master` branch. Generated image will be
|
||||
tagged as `<docker-tag>`. Recommended if we always want to provide a snapshot
|
||||
of the latest development. Again, no way to ensure stability.
|
||||
|
||||
<docker-tag> <git-url> T:<git-tag>
|
||||
2.4.0 git://github.com/dotcloud/docker-redis T:2.4.0
|
||||
<docker-tag> <git-url> B:<git-branch>
|
||||
zfs git://github.com/dotcloud/docker B:zfs-support
|
||||
<docker-tag> <git-url> C:<git-commit-id>
|
||||
2.2.0 https://github.com/dotcloud/docker-redis.git C:a4bf8923ee4ec566d3ddc212
|
||||
|
||||
The most complete format. `docker-brew` will fetch data from the provided git
|
||||
repository from the provided reference (if it's a branch, brew will fetch its
|
||||
`HEAD`). Generated image will be tagged as `<docker-tag>`. Recommended whenever
|
||||
possible.
|
||||
@@ -1 +0,0 @@
|
||||
from brew import build_library, DEFAULT_REPOSITORY, DEFAULT_BRANCH
|
||||
@@ -1,185 +0,0 @@
|
||||
import os
|
||||
import logging
|
||||
from shutil import rmtree
|
||||
|
||||
import docker
|
||||
|
||||
import git
|
||||
|
||||
DEFAULT_REPOSITORY = 'git://github.com/dotcloud/docker'
|
||||
DEFAULT_BRANCH = 'master'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
|
||||
level='INFO')
|
||||
client = docker.Client()
|
||||
processed = {}
|
||||
processed_folders = []
|
||||
|
||||
|
||||
def build_library(repository=None, branch=None, namespace=None, push=False,
|
||||
debug=False, prefill=True, registry=None):
|
||||
dst_folder = None
|
||||
summary = Summary()
|
||||
if repository is None:
|
||||
repository = DEFAULT_REPOSITORY
|
||||
if branch is None:
|
||||
branch = DEFAULT_BRANCH
|
||||
if debug:
|
||||
logger.setLevel('DEBUG')
|
||||
|
||||
if not (repository.startswith('https://') or repository.startswith('git://')):
|
||||
logger.info('Repository provided assumed to be a local path')
|
||||
dst_folder = repository
|
||||
|
||||
try:
|
||||
client.version()
|
||||
except Exception as e:
|
||||
logger.error('Could not reach the docker daemon. Please make sure it '
|
||||
'is running.')
|
||||
logger.warning('Also make sure you have access to the docker UNIX '
|
||||
'socket (use sudo)')
|
||||
return
|
||||
|
||||
#FIXME: set destination folder and only pull latest changes instead of
|
||||
# cloning the whole repo everytime
|
||||
if not dst_folder:
|
||||
logger.info('Cloning docker repo from {0}, branch: {1}'.format(
|
||||
repository, branch))
|
||||
try:
|
||||
rep, dst_folder = git.clone_branch(repository, branch)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.error('Source repository could not be fetched. Check '
|
||||
'that the address is correct and the branch exists.')
|
||||
return
|
||||
try:
|
||||
dirlist = os.listdir(os.path.join(dst_folder, 'library'))
|
||||
except OSError as e:
|
||||
logger.error('The path provided ({0}) could not be found or didn\'t'
|
||||
'contain a library/ folder.'.format(dst_folder))
|
||||
return
|
||||
for buildfile in dirlist:
|
||||
if buildfile == 'MAINTAINERS':
|
||||
continue
|
||||
f = open(os.path.join(dst_folder, 'library', buildfile))
|
||||
linecnt = 0
|
||||
for line in f:
|
||||
linecnt = linecnt + 1
|
||||
logger.debug('{0} ---> {1}'.format(buildfile, line))
|
||||
args = line.split()
|
||||
try:
|
||||
if len(args) > 3:
|
||||
raise RuntimeError('Incorrect line format, '
|
||||
'please refer to the docs')
|
||||
|
||||
url = None
|
||||
ref = 'refs/heads/master'
|
||||
tag = None
|
||||
if len(args) == 1: # Just a URL, simple mode
|
||||
url = args[0]
|
||||
elif len(args) == 2 or len(args) == 3: # docker-tag url
|
||||
url = args[1]
|
||||
tag = args[0]
|
||||
|
||||
if len(args) == 3: # docker-tag url B:branch or T:tag
|
||||
ref = None
|
||||
if args[2].startswith('B:'):
|
||||
ref = 'refs/heads/' + args[2][2:]
|
||||
elif args[2].startswith('T:'):
|
||||
ref = 'refs/tags/' + args[2][2:]
|
||||
elif args[2].startswith('C:'):
|
||||
ref = args[2][2:]
|
||||
else:
|
||||
raise RuntimeError('Incorrect line format, '
|
||||
'please refer to the docs')
|
||||
if prefill:
|
||||
logger.debug('Pulling {0} from official repository (cache '
|
||||
'fill)'.format(buildfile))
|
||||
client.pull(buildfile)
|
||||
img = build_repo(url, ref, buildfile, tag, namespace, push,
|
||||
registry)
|
||||
summary.add_success(buildfile, (linecnt, line), img)
|
||||
processed['{0}@{1}'.format(url, ref)] = img
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
summary.add_exception(buildfile, (linecnt, line), e)
|
||||
|
||||
f.close()
|
||||
if dst_folder != repository:
|
||||
rmtree(dst_folder, True)
|
||||
for d in processed_folders:
|
||||
rmtree(d, True)
|
||||
summary.print_summary(logger)
|
||||
|
||||
|
||||
def build_repo(repository, ref, docker_repo, docker_tag, namespace, push, registry):
|
||||
docker_repo = '{0}/{1}'.format(namespace or 'library', docker_repo)
|
||||
img_id = None
|
||||
dst_folder = None
|
||||
if '{0}@{1}'.format(repository, ref) not in processed.keys():
|
||||
logger.info('Cloning {0} (ref: {1})'.format(repository, ref))
|
||||
if repository not in processed:
|
||||
rep, dst_folder = git.clone(repository, ref)
|
||||
processed[repository] = rep
|
||||
processed_folders.append(dst_folder)
|
||||
else:
|
||||
dst_folder = git.checkout(processed[repository], ref)
|
||||
if not 'Dockerfile' in os.listdir(dst_folder):
|
||||
raise RuntimeError('Dockerfile not found in cloned repository')
|
||||
logger.info('Building using dockerfile...')
|
||||
img_id, logs = client.build(path=dst_folder, quiet=True)
|
||||
else:
|
||||
img_id = processed['{0}@{1}'.format(repository, ref)]
|
||||
logger.info('Committing to {0}:{1}'.format(docker_repo,
|
||||
docker_tag or 'latest'))
|
||||
client.tag(img_id, docker_repo, docker_tag)
|
||||
if push:
|
||||
logger.info('Pushing result to registry {0}'.format(
|
||||
registry or "default"))
|
||||
if registry is not None:
|
||||
docker_repo = '{0}/{1}'.format(registry, docker_repo)
|
||||
logger.info('Also tagging {0}'.format(docker_repo))
|
||||
client.tag(img_id, docker_repo, docker_tag)
|
||||
client.push(docker_repo)
|
||||
return img_id
|
||||
|
||||
|
||||
class Summary(object):
|
||||
def __init__(self):
|
||||
self._summary = {}
|
||||
self._has_exc = False
|
||||
|
||||
def _add_data(self, image, linestr, data):
|
||||
if image not in self._summary:
|
||||
self._summary[image] = { linestr: data }
|
||||
else:
|
||||
self._summary[image][linestr] = data
|
||||
|
||||
def add_exception(self, image, line, exc):
|
||||
lineno, linestr = line
|
||||
self._add_data(image, linestr, { 'line': lineno, 'exc': str(exc) })
|
||||
self._has_exc = True
|
||||
|
||||
def add_success(self, image, line, img_id):
|
||||
lineno, linestr = line
|
||||
self._add_data(image, linestr, { 'line': lineno, 'id': img_id })
|
||||
|
||||
def print_summary(self, logger=None):
|
||||
linesep = ''.center(61, '-') + '\n'
|
||||
s = 'BREW BUILD SUMMARY\n' + linesep
|
||||
success = 'OVERALL SUCCESS: {}\n'.format(not self._has_exc)
|
||||
details = linesep
|
||||
for image, lines in self._summary.iteritems():
|
||||
details = details + '{}\n{}'.format(image, linesep)
|
||||
for linestr, data in lines.iteritems():
|
||||
details = details + '{0:2} | {1} | {2:50}\n'.format(
|
||||
data['line'],
|
||||
'KO' if 'exc' in data else 'OK',
|
||||
data['exc'] if 'exc' in data else data['id']
|
||||
)
|
||||
details = details + linesep
|
||||
if logger:
|
||||
logger.info(s + success + details)
|
||||
else:
|
||||
print s, success, details
|
||||
@@ -1,63 +0,0 @@
|
||||
import tempfile
|
||||
import logging
|
||||
|
||||
from dulwich import index
|
||||
from dulwich.client import get_transport_and_path
|
||||
from dulwich.repo import Repo
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def clone_branch(repo_url, branch="master", folder=None):
|
||||
return clone(repo_url, 'refs/heads/' + branch, folder)
|
||||
|
||||
|
||||
def clone_tag(repo_url, tag, folder=None):
|
||||
return clone(repo_url, 'refs/tags/' + tag, folder)
|
||||
|
||||
|
||||
def checkout(rep, ref=None):
|
||||
is_commit = False
|
||||
if ref is None:
|
||||
ref = 'refs/heads/master'
|
||||
elif not ref.startswith('refs/'):
|
||||
is_commit = True
|
||||
if is_commit:
|
||||
rep['HEAD'] = rep.commit(ref)
|
||||
else:
|
||||
rep['HEAD'] = rep.refs[ref]
|
||||
indexfile = rep.index_path()
|
||||
tree = rep["HEAD"].tree
|
||||
index.build_index_from_tree(rep.path, indexfile, rep.object_store, tree)
|
||||
return rep.path
|
||||
|
||||
def clone(repo_url, ref=None, folder=None):
|
||||
is_commit = False
|
||||
if ref is None:
|
||||
ref = 'refs/heads/master'
|
||||
elif not ref.startswith('refs/'):
|
||||
is_commit = True
|
||||
logger.debug("clone repo_url={0}, ref={1}".format(repo_url, ref))
|
||||
if folder is None:
|
||||
folder = tempfile.mkdtemp()
|
||||
logger.debug("folder = {0}".format(folder))
|
||||
rep = Repo.init(folder)
|
||||
client, relative_path = get_transport_and_path(repo_url)
|
||||
logger.debug("client={0}".format(client))
|
||||
|
||||
remote_refs = client.fetch(relative_path, rep)
|
||||
for k, v in remote_refs.iteritems():
|
||||
try:
|
||||
rep.refs.add_if_new(k, v)
|
||||
except:
|
||||
pass
|
||||
|
||||
if is_commit:
|
||||
rep['HEAD'] = rep.commit(ref)
|
||||
else:
|
||||
rep['HEAD'] = remote_refs[ref]
|
||||
indexfile = rep.index_path()
|
||||
tree = rep["HEAD"].tree
|
||||
index.build_index_from_tree(rep.path, indexfile, rep.object_store, tree)
|
||||
logger.debug("done")
|
||||
return rep, folder
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
try:
|
||||
import brew
|
||||
except ImportError as e:
|
||||
print str(e)
|
||||
print 'Please install the required dependencies first'
|
||||
print 'sudo pip install -r requirements.txt'
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser('Build the docker standard library')
|
||||
parser.add_argument('--push', action='store_true', default=False,
|
||||
help='Push generated repositories')
|
||||
parser.add_argument('--debug', default=False, action='store_true',
|
||||
help='Enable debugging output')
|
||||
parser.add_argument('--noprefill', default=True, action='store_false',
|
||||
dest='prefill', help='Disable cache prefill')
|
||||
parser.add_argument('-n', metavar='NAMESPACE', default='library',
|
||||
help='Namespace used for generated repositories.'
|
||||
' Default is library')
|
||||
parser.add_argument('-b', metavar='BRANCH', default=brew.DEFAULT_BRANCH,
|
||||
help='Branch in the repository where the library definition'
|
||||
' files will be fetched. Default is ' + brew.DEFAULT_BRANCH)
|
||||
parser.add_argument('repository', default=brew.DEFAULT_REPOSITORY,
|
||||
nargs='?', help='git repository containing the library definition'
|
||||
' files. Default is ' + brew.DEFAULT_REPOSITORY)
|
||||
parser.add_argument('--reg', default=None, help='Registry address to'
|
||||
' push build results to. Also sets push to true.')
|
||||
args = parser.parse_args()
|
||||
brew.build_library(args.repository, args.b, args.n,
|
||||
args.push or args.reg is not None, args.debug, args.prefill, args.reg)
|
||||
@@ -1,2 +0,0 @@
|
||||
dulwich==0.9.0
|
||||
-e git://github.com/dotcloud/docker-py.git#egg=docker-py
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
from setuptools import setup
|
||||
|
||||
ROOT_DIR = os.path.dirname(__file__)
|
||||
SOURCE_DIR = os.path.join(ROOT_DIR)
|
||||
|
||||
test_requirements = []
|
||||
setup(
|
||||
name="docker-brew",
|
||||
version='0.0.1',
|
||||
description="-",
|
||||
packages=['dockerbrew'],
|
||||
install_requires=['dulwich', 'docker'] + test_requirements,
|
||||
zip_safe=False,
|
||||
classifiers=['Development Status :: 3 - Alpha',
|
||||
'Environment :: Other Environment',
|
||||
'Intended Audience :: Developers',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Topic :: Utilities'],
|
||||
)
|
||||
@@ -426,7 +426,7 @@ _docker_run()
|
||||
|
||||
_docker_search()
|
||||
{
|
||||
COMPREPLY=( $( compgen -W "-notrunc" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "-notrunc" "-stars" "-trusted" -- "$cur" ) )
|
||||
}
|
||||
|
||||
_docker_start()
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Desktop Integration
|
||||
===================
|
||||
|
||||
The ./contrib/desktop-integration contains examples of typical dockerized
|
||||
desktop applications.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
* Data container: ./data/Dockerfile creates a data image sharing /data volume
|
||||
* Firefox: ./firefox/Dockerfile shows a way to dockerize a common multimedia application
|
||||
@@ -0,0 +1,38 @@
|
||||
# VERSION: 0.1
|
||||
# DESCRIPTION: Create data image sharing /data volume
|
||||
# AUTHOR: Daniel Mizyrycki <daniel@dotcloud.com>
|
||||
# COMMENTS:
|
||||
# This image is used as base for all data containers.
|
||||
# /data volume is owned by sysadmin.
|
||||
# USAGE:
|
||||
# # Download data Dockerfile
|
||||
# wget http://raw.github.com/dotcloud/docker/master/contrib/desktop-integration/data/Dockerfile
|
||||
#
|
||||
# # Build data image
|
||||
# docker build -t data -rm .
|
||||
#
|
||||
# # Create a data container. (eg: firefox-data)
|
||||
# docker run -name firefox-data data true
|
||||
#
|
||||
# # List data from it
|
||||
# docker run -volumes-from firefox-data busybox ls -al /data
|
||||
|
||||
docker-version 0.6.5
|
||||
|
||||
# Smallest base image, just to launch a container
|
||||
from busybox
|
||||
maintainer Daniel Mizyrycki <daniel@docker.com>
|
||||
|
||||
# Create a regular user
|
||||
run echo 'sysadmin:x:1000:1000::/data:/bin/sh' >> /etc/passwd
|
||||
run echo 'sysadmin:x:1000:' >> /etc/group
|
||||
|
||||
# Create directory for that user
|
||||
run mkdir /data
|
||||
run chown sysadmin.sysadmin /data
|
||||
|
||||
# Add content to /data. This will keep sysadmin ownership
|
||||
run touch /data/init_volume
|
||||
|
||||
# Create /data volume
|
||||
VOLUME /data
|
||||
@@ -0,0 +1,49 @@
|
||||
# VERSION: 0.7
|
||||
# DESCRIPTION: Create firefox container with its dependencies
|
||||
# AUTHOR: Daniel Mizyrycki <daniel@dotcloud.com>
|
||||
# COMMENTS:
|
||||
# This file describes how to build a Firefox container with all
|
||||
# dependencies installed. It uses native X11 unix socket and alsa
|
||||
# sound devices. Tested on Debian 7.2
|
||||
# USAGE:
|
||||
# # Download Firefox Dockerfile
|
||||
# wget http://raw.github.com/dotcloud/docker/master/contrib/desktop-integration/firefox/Dockerfile
|
||||
#
|
||||
# # Build firefox image
|
||||
# docker build -t firefox -rm .
|
||||
#
|
||||
# # Run stateful data-on-host firefox. For ephemeral, remove -v /data/firefox:/data
|
||||
# docker run -v /data/firefox:/data -v /tmp/.X11-unix:/tmp/.X11-unix \
|
||||
# -v /dev/snd:/dev/snd -lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \
|
||||
# -e DISPLAY=unix$DISPLAY firefox
|
||||
#
|
||||
# # To run stateful dockerized data containers
|
||||
# docker run -volumes-from firefox-data -v /tmp/.X11-unix:/tmp/.X11-unix \
|
||||
# -v /dev/snd:/dev/snd -lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \
|
||||
# -e DISPLAY=unix$DISPLAY firefox
|
||||
|
||||
docker-version 0.6.5
|
||||
|
||||
# Base docker image
|
||||
from tianon/debian:wheezy
|
||||
maintainer Daniel Mizyrycki <daniel@docker.com>
|
||||
|
||||
# Install firefox dependencies
|
||||
run echo "deb http://ftp.debian.org/debian/ wheezy main contrib" > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y libXrender1 libasound2 \
|
||||
libdbus-glib-1-2 libgtk2.0-0 libpango1.0-0 libxt6 wget bzip2 sudo
|
||||
|
||||
# Install Firefox
|
||||
run mkdir /application
|
||||
run cd /application; wget -O - \
|
||||
http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/25.0/linux-x86_64/en-US/firefox-25.0.tar.bz2 | tar jx
|
||||
|
||||
# create sysadmin account
|
||||
run useradd -m -d /data -p saIVpsc0EVTwA sysadmin
|
||||
run sed -Ei 's/sudo:x:27:/sudo:x:27:sysadmin/' /etc/group
|
||||
run sed -Ei 's/(\%sudo\s+ALL=\(ALL\:ALL\) )ALL/\1 NOPASSWD:ALL/' /etc/sudoers
|
||||
|
||||
# Autorun firefox. -no-remote is necessary to create a new container, as firefox
|
||||
# appears to communicate with itself through X11.
|
||||
cmd ["/bin/sh", "-c", "/usr/bin/sudo -u sysadmin -H -E /application/firefox/firefox -no-remote"]
|
||||
@@ -0,0 +1,27 @@
|
||||
#
|
||||
# This Dockerfile will create an image that allows to generate upstart and
|
||||
# systemd scripts (more to come)
|
||||
#
|
||||
# docker-version 0.6.2
|
||||
#
|
||||
|
||||
FROM ubuntu:12.10
|
||||
MAINTAINER Guillaume J. Charmes <guillaume@dotcloud.com>
|
||||
|
||||
RUN apt-get update && apt-get install -y wget git mercurial
|
||||
|
||||
# Install Go
|
||||
RUN wget --no-check-certificate https://go.googlecode.com/files/go1.1.2.linux-amd64.tar.gz -O go-1.1.2.tar.gz
|
||||
RUN tar -xzvf go-1.1.2.tar.gz && mv /go /goroot
|
||||
RUN mkdir /go
|
||||
|
||||
ENV GOROOT /goroot
|
||||
ENV GOPATH /go
|
||||
ENV PATH $GOROOT/bin:$PATH
|
||||
|
||||
RUN go get github.com/dotcloud/docker && cd /go/src/github.com/dotcloud/docker && git checkout v0.6.3
|
||||
ADD manager.go /manager/
|
||||
RUN cd /manager && go build -o /usr/bin/manager
|
||||
|
||||
ENTRYPOINT ["/usr/bin/manager"]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
FROM busybox
|
||||
MAINTAINER Guillaume J. Charmes <guillaume@dotcloud.com>
|
||||
ADD manager /usr/bin/
|
||||
ENTRYPOINT ["/usr/bin/manager"]
|
||||
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var templates = map[string]string{
|
||||
|
||||
"upstart": `description "{{.description}}"
|
||||
author "{{.author}}"
|
||||
start on filesystem and started lxc-net and started docker
|
||||
stop on runlevel [!2345]
|
||||
respawn
|
||||
exec /home/vagrant/goroot/bin/docker start -a {{.container_id}}
|
||||
`,
|
||||
|
||||
"systemd": `[Unit]
|
||||
Description={{.description}}
|
||||
Author={{.author}}
|
||||
After=docker.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/docker start -a {{.container_id}}
|
||||
ExecStop=/usr/bin/docker stop -t 2 {{.container_id}}
|
||||
|
||||
[Install]
|
||||
WantedBy=local.target
|
||||
`,
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Parse command line for custom options
|
||||
kind := flag.String("t", "upstart", "Type of manager requested")
|
||||
author := flag.String("a", "<none>", "Author of the image")
|
||||
description := flag.String("d", "<none>", "Description of the image")
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "\nUsage: manager <container id>\n\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
// We require at least the container ID
|
||||
if flag.NArg() != 1 {
|
||||
println(flag.NArg())
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
// Check that the requested process manager is supported
|
||||
if _, exists := templates[*kind]; !exists {
|
||||
panic("Unkown script template")
|
||||
}
|
||||
|
||||
// Load the requested template
|
||||
tpl, err := template.New("processManager").Parse(templates[*kind])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create stdout/stderr buffers
|
||||
bufOut := bytes.NewBuffer(nil)
|
||||
bufErr := bytes.NewBuffer(nil)
|
||||
|
||||
// Instanciate the Docker CLI
|
||||
cli := docker.NewDockerCli(nil, bufOut, bufErr, "unix", "/var/run/docker.sock")
|
||||
// Retrieve the container info
|
||||
if err := cli.CmdInspect(flag.Arg(0)); err != nil {
|
||||
// As of docker v0.6.3, CmdInspect always returns nil
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// If there is nothing in the error buffer, then the Docker daemon is there and the container has been found
|
||||
if bufErr.Len() == 0 {
|
||||
// Unmarshall the resulting container data
|
||||
c := []*docker.Container{{}}
|
||||
if err := json.Unmarshal(bufOut.Bytes(), &c); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Reset the buffers
|
||||
bufOut.Reset()
|
||||
bufErr.Reset()
|
||||
// Retrieve the info of the linked image
|
||||
if err := cli.CmdInspect(c[0].Image); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// If there is nothing in the error buffer, then the image has been found.
|
||||
if bufErr.Len() == 0 {
|
||||
// Unmarshall the resulting image data
|
||||
img := []*docker.Image{{}}
|
||||
if err := json.Unmarshal(bufOut.Bytes(), &img); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// If no author has been set, use the one from the image
|
||||
if *author == "<none>" && img[0].Author != "" {
|
||||
*author = strings.Replace(img[0].Author, "\"", "", -1)
|
||||
}
|
||||
// If no description has been set, use the comment from the image
|
||||
if *description == "<none>" && img[0].Comment != "" {
|
||||
*description = strings.Replace(img[0].Comment, "\"", "", -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Old version: Wrtie the resulting script to file
|
||||
// f, err := os.OpenFile(kind, os.O_CREATE|os.O_WRONLY, 0755)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// defer f.Close()
|
||||
|
||||
// Create a map with needed data
|
||||
data := map[string]string{
|
||||
"author": *author,
|
||||
"description": *description,
|
||||
"container_id": flag.Arg(0),
|
||||
}
|
||||
|
||||
// Process the template and output it on Stdout
|
||||
if err := tpl.Execute(os.Stdout, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo >&2 "usage: $0 [-a author] [-d description] container [manager]"
|
||||
echo >&2 " ie: $0 -a 'John Smith' 4ec9612a37cd systemd"
|
||||
echo >&2 " ie: $0 -d 'Super Cool System' 4ec9612a37cd # defaults to upstart"
|
||||
exit 1
|
||||
}
|
||||
|
||||
auth='<none>'
|
||||
desc='<none>'
|
||||
have_auth=
|
||||
have_desc=
|
||||
while getopts a:d: opt; do
|
||||
case "$opt" in
|
||||
a)
|
||||
auth="$OPTARG"
|
||||
have_auth=1
|
||||
;;
|
||||
d)
|
||||
desc="$OPTARG"
|
||||
have_desc=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $(($OPTIND - 1))
|
||||
|
||||
[ $# -ge 1 -a $# -le 2 ] || usage
|
||||
|
||||
cid="$1"
|
||||
script="${2:-upstart}"
|
||||
if [ ! -e "manager/$script" ]; then
|
||||
echo >&2 "Error: manager type '$script' is unknown (PRs always welcome!)."
|
||||
echo >&2 'The currently supported types are:'
|
||||
echo >&2 " $(cd manager && echo *)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# TODO https://github.com/dotcloud/docker/issues/734 (docker inspect formatting)
|
||||
#if command -v docker > /dev/null 2>&1; then
|
||||
# image="$(docker inspect -f '{{.Image}}' "$cid")"
|
||||
# if [ "$image" ]; then
|
||||
# if [ -z "$have_auth" ]; then
|
||||
# auth="$(docker inspect -f '{{.Author}}' "$image")"
|
||||
# fi
|
||||
# if [ -z "$have_desc" ]; then
|
||||
# desc="$(docker inspect -f '{{.Comment}}' "$image")"
|
||||
# fi
|
||||
# fi
|
||||
#fi
|
||||
|
||||
exec "manager/$script" "$cid" "$auth" "$desc"
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
cid="$1"
|
||||
auth="$2"
|
||||
desc="$3"
|
||||
|
||||
cat <<-EOF
|
||||
[Unit]
|
||||
Description=$desc
|
||||
Author=$auth
|
||||
After=docker.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/docker start -a $cid
|
||||
ExecStop=/usr/bin/docker stop -t 2 $cid
|
||||
|
||||
[Install]
|
||||
WantedBy=local.target
|
||||
EOF
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
cid="$1"
|
||||
auth="$2"
|
||||
desc="$3"
|
||||
|
||||
cat <<-EOF
|
||||
description "$(echo "$desc" | sed 's/"/\\"/g')"
|
||||
author "$(echo "$auth" | sed 's/"/\\"/g')"
|
||||
start on filesystem and started lxc-net and started docker
|
||||
stop on runlevel [!2345]
|
||||
respawn
|
||||
exec /usr/bin/docker start -a "$cid"
|
||||
EOF
|
||||
@@ -0,0 +1,13 @@
|
||||
# /etc/conf.d/docker: config file for /etc/init.d/docker
|
||||
|
||||
# where the docker daemon output gets piped
|
||||
#DOCKER_LOGFILE="/var/log/docker.log"
|
||||
|
||||
# where docker's pid get stored
|
||||
#DOCKER_PIDFILE="/run/docker.pid"
|
||||
|
||||
# where the docker daemon itself is run from
|
||||
#DOCKER_BINARY="/usr/bin/docker"
|
||||
|
||||
# any other random options you want to pass to docker
|
||||
DOCKER_OPTS=""
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/sbin/runscript
|
||||
# Copyright 1999-2013 Gentoo Foundation
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# $Header: $
|
||||
|
||||
DOCKER_LOGFILE=${DOCKER_LOGFILE:-/var/log/${SVCNAME}.log}
|
||||
DOCKER_PIDFILE=${DOCKER_PIDFILE:-/run/${SVCNAME}.pid}
|
||||
DOCKER_BINARY=${DOCKER_BINARY:-/usr/bin/docker}
|
||||
DOCKER_OPTS=${DOCKER_OPTS:-}
|
||||
|
||||
start() {
|
||||
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
|
||||
|
||||
ebegin "Starting docker daemon"
|
||||
start-stop-daemon --start --background \
|
||||
--exec "$DOCKER_BINARY" \
|
||||
--pidfile "$DOCKER_PIDFILE" \
|
||||
--stdout "$DOCKER_LOGFILE" \
|
||||
--stderr "$DOCKER_LOGFILE" \
|
||||
-- -d -p "$DOCKER_PIDFILE" \
|
||||
$DOCKER_OPTS
|
||||
eend $?
|
||||
}
|
||||
|
||||
stop() {
|
||||
ebegin "Stopping docker daemon"
|
||||
start-stop-daemon --stop \
|
||||
--exec "$DOCKER_BINARY" \
|
||||
--pidfile "$DOCKER_PIDFILE"
|
||||
eend $?
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Docker Application Container Engine
|
||||
Documentation=http://docs.docker.io
|
||||
Requires=network.target
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=/bin/mount --make-rprivate /
|
||||
ExecStart=/usr/bin/docker -d
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: docker
|
||||
# Required-Start: $syslog $remote_fs
|
||||
# Required-Stop: $syslog $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Create lightweight, portable, self-sufficient containers.
|
||||
# Description:
|
||||
# Docker is an open-source project to easily create lightweight, portable,
|
||||
# self-sufficient containers from any application. The same container that a
|
||||
# developer builds and tests on a laptop can run at scale, in production, on
|
||||
# VMs, bare metal, OpenStack clusters, public clouds and more.
|
||||
### END INIT INFO
|
||||
|
||||
BASE=$(basename $0)
|
||||
|
||||
DOCKER=/usr/bin/$BASE
|
||||
DOCKER_PIDFILE=/var/run/$BASE.pid
|
||||
DOCKER_OPTS=
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
# Get lsb functions
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
if [ -f /etc/default/$BASE ]; then
|
||||
. /etc/default/$BASE
|
||||
fi
|
||||
|
||||
# see also init_is_upstart in /lib/lsb/init-functions (which isn't available in Ubuntu 12.04, or we'd use it)
|
||||
if [ -x /sbin/initctl ] && /sbin/initctl version 2>/dev/null | /bin/grep -q upstart; then
|
||||
log_failure_msg "Docker is managed via upstart, try using service $BASE $1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check docker is present
|
||||
if [ ! -x $DOCKER ]; then
|
||||
log_failure_msg "$DOCKER not present or not executable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fail_unless_root() {
|
||||
if [ "$(id -u)" != '0' ]; then
|
||||
log_failure_msg "Docker must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
fail_unless_root
|
||||
log_begin_msg "Starting Docker: $BASE"
|
||||
mount | grep cgroup >/dev/null || mount -t cgroup none /sys/fs/cgroup 2>/dev/null
|
||||
start-stop-daemon --start --background \
|
||||
--exec "$DOCKER" \
|
||||
--pidfile "$DOCKER_PIDFILE" \
|
||||
-- -d -p "$DOCKER_PIDFILE" \
|
||||
$DOCKER_OPTS
|
||||
log_end_msg $?
|
||||
;;
|
||||
|
||||
stop)
|
||||
fail_unless_root
|
||||
log_begin_msg "Stopping Docker: $BASE"
|
||||
start-stop-daemon --stop \
|
||||
--pidfile "$DOCKER_PIDFILE"
|
||||
log_end_msg $?
|
||||
;;
|
||||
|
||||
restart)
|
||||
fail_unless_root
|
||||
docker_pid=`cat "$DOCKER_PIDFILE" 2>/dev/null`
|
||||
[ -n "$docker_pid" ] \
|
||||
&& ps -p $docker_pid > /dev/null 2>&1 \
|
||||
&& $0 stop
|
||||
$0 start
|
||||
;;
|
||||
|
||||
force-reload)
|
||||
fail_unless_root
|
||||
$0 restart
|
||||
;;
|
||||
|
||||
status)
|
||||
status_of_proc -p "$DOCKER_PIDFILE" "$DOCKER" docker
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,15 @@
|
||||
description "Docker daemon"
|
||||
|
||||
start on filesystem and started lxc-net
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
|
||||
script
|
||||
DOCKER=/usr/bin/$UPSTART_JOB
|
||||
DOCKER_OPTS=
|
||||
if [ -f /etc/default/$UPSTART_JOB ]; then
|
||||
. /etc/default/$UPSTART_JOB
|
||||
fi
|
||||
"$DOCKER" -d $DOCKER_OPTS
|
||||
end script
|
||||
@@ -62,6 +62,6 @@ mknod -m 666 ${DEV}/full c 1 7
|
||||
mknod -m 600 ${DEV}/initctl p
|
||||
mknod -m 666 ${DEV}/ptmx c 5 2
|
||||
|
||||
tar -C $ROOTFS -c . | docker import - archlinux
|
||||
tar --numeric-owner -C $ROOTFS -c . | docker import - archlinux
|
||||
docker run -i -t archlinux echo Success.
|
||||
rm -rf $ROOTFS
|
||||
|
||||
@@ -35,5 +35,5 @@ do
|
||||
cp -a /dev/$X dev
|
||||
done
|
||||
|
||||
tar -cf- . | docker import - busybox
|
||||
tar --numeric-owner -cf- . | docker import - busybox
|
||||
docker run -i -u root busybox /bin/echo Success.
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# these should match the names found at http://www.debian.org/releases/
|
||||
stableSuite='wheezy'
|
||||
testingSuite='jessie'
|
||||
unstableSuite='sid'
|
||||
|
||||
variant='minbase'
|
||||
include='iproute,iputils-ping'
|
||||
|
||||
repo="$1"
|
||||
suite="$2"
|
||||
mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
|
||||
|
||||
if [ ! "$repo" ] || [ ! "$suite" ]; then
|
||||
echo >&2 "usage: $0 repo suite [mirror]"
|
||||
echo >&2
|
||||
echo >&2 " ie: $0 tianon/debian squeeze"
|
||||
echo >&2 " $0 tianon/debian squeeze http://ftp.uk.debian.org/debian/"
|
||||
echo >&2
|
||||
echo >&2 " ie: $0 tianon/ubuntu precise"
|
||||
echo >&2 " $0 tianon/ubuntu precise http://mirrors.melbourne.co.uk/ubuntu/"
|
||||
echo >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
target="/tmp/docker-rootfs-debian-$suite-$$-$RANDOM"
|
||||
|
||||
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||
returnTo="$(pwd -P)"
|
||||
|
||||
set -x
|
||||
|
||||
# bootstrap
|
||||
mkdir -p "$target"
|
||||
sudo debootstrap --verbose --variant="$variant" --include="$include" "$suite" "$target" "$mirror"
|
||||
|
||||
cd "$target"
|
||||
|
||||
# prevent init scripts from running during install/update
|
||||
# policy-rc.d (for most scripts)
|
||||
echo $'#!/bin/sh\nexit 101' | sudo tee usr/sbin/policy-rc.d > /dev/null
|
||||
sudo chmod +x usr/sbin/policy-rc.d
|
||||
# initctl (for some pesky upstart scripts)
|
||||
sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
|
||||
sudo ln -sf /bin/true sbin/initctl
|
||||
# see https://github.com/dotcloud/docker/issues/446#issuecomment-16953173
|
||||
|
||||
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
|
||||
sudo chroot . apt-get clean
|
||||
|
||||
# while we're at it, apt is unnecessarily slow inside containers
|
||||
# this forces dpkg not to call sync() after package extraction and speeds up install
|
||||
# the benefit is huge on spinning disks, and the penalty is nonexistent on SSD or decent server virtualization
|
||||
echo 'force-unsafe-io' | sudo tee etc/dpkg/dpkg.cfg.d/02apt-speedup > /dev/null
|
||||
# we want to effectively run "apt-get clean" after every install to keep images small
|
||||
echo 'DPkg::Post-Invoke {"/bin/rm -f /var/cache/apt/archives/*.deb || true";};' | sudo tee etc/apt/apt.conf.d/no-cache > /dev/null
|
||||
|
||||
# helpful undo lines for each the above tweaks (for lack of a better home to keep track of them):
|
||||
# rm /usr/sbin/policy-rc.d
|
||||
# rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl
|
||||
# rm /etc/dpkg/dpkg.cfg.d/02apt-speedup
|
||||
# rm /etc/apt/apt.conf.d/no-cache
|
||||
|
||||
# create the image (and tag $repo:$suite)
|
||||
sudo tar -c . | docker import - $repo $suite
|
||||
|
||||
# test the image
|
||||
docker run -i -t $repo:$suite echo success
|
||||
|
||||
if [ "$suite" = "$stableSuite" -o "$suite" = 'stable' ]; then
|
||||
# tag latest
|
||||
docker tag $repo:$suite $repo latest
|
||||
|
||||
# tag the specific debian release version
|
||||
ver=$(docker run $repo:$suite cat /etc/debian_version)
|
||||
docker tag $repo:$suite $repo $ver
|
||||
fi
|
||||
|
||||
# cleanup
|
||||
cd "$returnTo"
|
||||
sudo rm -rf "$target"
|
||||
Executable
+233
@@ -0,0 +1,233 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
variant='minbase'
|
||||
include='iproute,iputils-ping'
|
||||
arch='amd64' # intentionally undocumented for now
|
||||
skipDetection=
|
||||
strictDebootstrap=
|
||||
justTar=
|
||||
|
||||
usage() {
|
||||
echo >&2
|
||||
|
||||
echo >&2 "usage: $0 [options] repo suite [mirror]"
|
||||
|
||||
echo >&2
|
||||
echo >&2 'options: (not recommended)'
|
||||
echo >&2 " -p set an http_proxy for debootstrap"
|
||||
echo >&2 " -v $variant # change default debootstrap variant"
|
||||
echo >&2 " -i $include # change default package includes"
|
||||
echo >&2 " -d # strict debootstrap (do not apply any docker-specific tweaks)"
|
||||
echo >&2 " -s # skip version detection and tagging (ie, precise also tagged as 12.04)"
|
||||
echo >&2 " # note that this will also skip adding universe and/or security/updates to sources.list"
|
||||
echo >&2 " -t # just create a tarball, especially for dockerbrew (uses repo as tarball name)"
|
||||
|
||||
echo >&2
|
||||
echo >&2 " ie: $0 username/debian squeeze"
|
||||
echo >&2 " $0 username/debian squeeze http://ftp.uk.debian.org/debian/"
|
||||
|
||||
echo >&2
|
||||
echo >&2 " ie: $0 username/ubuntu precise"
|
||||
echo >&2 " $0 username/ubuntu precise http://mirrors.melbourne.co.uk/ubuntu/"
|
||||
|
||||
echo >&2
|
||||
echo >&2 " ie: $0 -t precise.tar.bz2 precise"
|
||||
echo >&2 " $0 -t wheezy.tgz wheezy"
|
||||
echo >&2 " $0 -t wheezy-uk.tar.xz wheezy http://ftp.uk.debian.org/debian/"
|
||||
|
||||
echo >&2
|
||||
}
|
||||
|
||||
# these should match the names found at http://www.debian.org/releases/
|
||||
debianStable=wheezy
|
||||
debianUnstable=sid
|
||||
# this should match the name found at http://releases.ubuntu.com/
|
||||
ubuntuLatestLTS=precise
|
||||
|
||||
while getopts v:i:a:p:dst name; do
|
||||
case "$name" in
|
||||
p)
|
||||
http_proxy="$OPTARG"
|
||||
;;
|
||||
v)
|
||||
variant="$OPTARG"
|
||||
;;
|
||||
i)
|
||||
include="$OPTARG"
|
||||
;;
|
||||
a)
|
||||
arch="$OPTARG"
|
||||
;;
|
||||
d)
|
||||
strictDebootstrap=1
|
||||
;;
|
||||
s)
|
||||
skipDetection=1
|
||||
;;
|
||||
t)
|
||||
justTar=1
|
||||
;;
|
||||
?)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $(($OPTIND - 1))
|
||||
|
||||
repo="$1"
|
||||
suite="$2"
|
||||
mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
|
||||
|
||||
if [ ! "$repo" ] || [ ! "$suite" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# some rudimentary detection for whether we need to "sudo" our docker calls
|
||||
docker=''
|
||||
if docker version > /dev/null 2>&1; then
|
||||
docker='docker'
|
||||
elif sudo docker version > /dev/null 2>&1; then
|
||||
docker='sudo docker'
|
||||
elif command -v docker > /dev/null 2>&1; then
|
||||
docker='docker'
|
||||
else
|
||||
echo >&2 "warning: either docker isn't installed, or your current user cannot run it;"
|
||||
echo >&2 " this script is not likely to work as expected"
|
||||
sleep 3
|
||||
docker='docker' # give us a command-not-found later
|
||||
fi
|
||||
|
||||
# make sure we have an absolute path to our final tarball so we can still reference it properly after we change directory
|
||||
if [ "$justTar" ]; then
|
||||
if [ ! -d "$(dirname "$repo")" ]; then
|
||||
echo >&2 "error: $(dirname "$repo") does not exist"
|
||||
exit 1
|
||||
fi
|
||||
repo="$(cd "$(dirname "$repo")" && pwd -P)/$(basename "$repo")"
|
||||
fi
|
||||
|
||||
# will be filled in later, if [ -z "$skipDetection" ]
|
||||
lsbDist=''
|
||||
|
||||
target="/tmp/docker-rootfs-debootstrap-$suite-$$-$RANDOM"
|
||||
|
||||
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||
returnTo="$(pwd -P)"
|
||||
|
||||
set -x
|
||||
|
||||
# bootstrap
|
||||
mkdir -p "$target"
|
||||
sudo http_proxy=$http_proxy debootstrap --verbose --variant="$variant" --include="$include" --arch="$arch" "$suite" "$target" "$mirror"
|
||||
|
||||
cd "$target"
|
||||
|
||||
if [ -z "$strictDebootstrap" ]; then
|
||||
# prevent init scripts from running during install/update
|
||||
# policy-rc.d (for most scripts)
|
||||
echo $'#!/bin/sh\nexit 101' | sudo tee usr/sbin/policy-rc.d > /dev/null
|
||||
sudo chmod +x usr/sbin/policy-rc.d
|
||||
# initctl (for some pesky upstart scripts)
|
||||
sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
|
||||
sudo ln -sf /bin/true sbin/initctl
|
||||
# see https://github.com/dotcloud/docker/issues/446#issuecomment-16953173
|
||||
|
||||
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
|
||||
sudo chroot . apt-get clean
|
||||
|
||||
# while we're at it, apt is unnecessarily slow inside containers
|
||||
# this forces dpkg not to call sync() after package extraction and speeds up install
|
||||
# the benefit is huge on spinning disks, and the penalty is nonexistent on SSD or decent server virtualization
|
||||
echo 'force-unsafe-io' | sudo tee etc/dpkg/dpkg.cfg.d/02apt-speedup > /dev/null
|
||||
# we want to effectively run "apt-get clean" after every install to keep images small
|
||||
echo 'DPkg::Post-Invoke {"/bin/rm -f /var/cache/apt/archives/*.deb || true";};' | sudo tee etc/apt/apt.conf.d/no-cache > /dev/null
|
||||
|
||||
# helpful undo lines for each the above tweaks (for lack of a better home to keep track of them):
|
||||
# rm /usr/sbin/policy-rc.d
|
||||
# rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl
|
||||
# rm /etc/dpkg/dpkg.cfg.d/02apt-speedup
|
||||
# rm /etc/apt/apt.conf.d/no-cache
|
||||
|
||||
if [ -z "$skipDetection" ]; then
|
||||
# see also rudimentary platform detection in hack/install.sh
|
||||
lsbDist=''
|
||||
if [ -r etc/lsb-release ]; then
|
||||
lsbDist="$(. etc/lsb-release && echo "$DISTRIB_ID")"
|
||||
fi
|
||||
if [ -z "$lsbDist" ] && [ -r etc/debian_version ]; then
|
||||
lsbDist='Debian'
|
||||
fi
|
||||
|
||||
case "$lsbDist" in
|
||||
Debian)
|
||||
# add the updates and security repositories
|
||||
if [ "$suite" != "$debianUnstable" -a "$suite" != 'unstable' ]; then
|
||||
# ${suite}-updates only applies to non-unstable
|
||||
sudo sed -i "p; s/ $suite main$/ ${suite}-updates main/" etc/apt/sources.list
|
||||
|
||||
# same for security updates
|
||||
echo "deb http://security.debian.org/ $suite/updates main" | sudo tee -a etc/apt/sources.list > /dev/null
|
||||
fi
|
||||
;;
|
||||
Ubuntu)
|
||||
# add the universe, updates, and security repositories
|
||||
sudo sed -i "
|
||||
s/ $suite main$/ $suite main universe/; p;
|
||||
s/ $suite main/ ${suite}-updates main/; p;
|
||||
s/ $suite-updates main/ ${suite}-security main/
|
||||
" etc/apt/sources.list
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$justTar" ]; then
|
||||
# create the tarball file so it has the right permissions (ie, not root)
|
||||
touch "$repo"
|
||||
|
||||
# fill the tarball
|
||||
sudo tar --numeric-owner -caf "$repo" .
|
||||
else
|
||||
# create the image (and tag $repo:$suite)
|
||||
sudo tar --numeric-owner -c . | $docker import - $repo:$suite
|
||||
|
||||
# test the image
|
||||
$docker run -i -t $repo:$suite echo success
|
||||
|
||||
if [ -z "$skipDetection" ]; then
|
||||
case "$lsbDist" in
|
||||
Debian)
|
||||
if [ "$suite" = "$debianStable" -o "$suite" = 'stable' ] && [ -r etc/debian_version ]; then
|
||||
# tag latest
|
||||
$docker tag $repo:$suite $repo:latest
|
||||
|
||||
if [ -r etc/debian_version ]; then
|
||||
# tag the specific debian release version (which is only reasonable to tag on debian stable)
|
||||
ver=$(cat etc/debian_version)
|
||||
$docker tag $repo:$suite $repo:$ver
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
Ubuntu)
|
||||
if [ "$suite" = "$ubuntuLatestLTS" ]; then
|
||||
# tag latest
|
||||
$docker tag $repo:$suite $repo:latest
|
||||
fi
|
||||
if [ -r etc/lsb-release ]; then
|
||||
lsbRelease="$(. etc/lsb-release && echo "$DISTRIB_RELEASE")"
|
||||
if [ "$lsbRelease" ]; then
|
||||
# tag specific Ubuntu version number, if available (12.04, etc.)
|
||||
$docker tag $repo:$suite $repo:$lsbRelease
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
# cleanup
|
||||
cd "$returnTo"
|
||||
sudo rm -rf "$target"
|
||||
@@ -44,6 +44,6 @@ do
|
||||
done
|
||||
|
||||
chmod 0755 $ROOTFS # See #486
|
||||
tar -cf- . | docker import - docker-ut
|
||||
tar --numeric-owner -cf- . | docker import - docker-ut
|
||||
docker run -i -u root docker-ut /bin/echo Success.
|
||||
rm -rf $ROOTFS
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
# Vagrant-docker
|
||||
# Vagrant integration
|
||||
|
||||
This is a placeholder for the official vagrant-docker, a plugin for Vagrant (http://vagrantup.com) which exposes Docker as a provider.
|
||||
Currently there are at least 4 different projects that we are aware of that deals
|
||||
with integration with [Vagrant](http://vagrantup.com/) at different levels. One
|
||||
approach is to use Docker as a [provisioner](http://docs.vagrantup.com/v2/provisioning/index.html)
|
||||
which means you can create containers and pull base images on VMs using Docker's
|
||||
CLI and the other is to use Docker as a [provider](http://docs.vagrantup.com/v2/providers/index.html),
|
||||
meaning you can use Vagrant to control Docker containers.
|
||||
|
||||
|
||||
### Provisioners
|
||||
|
||||
* [Vocker](https://github.com/fgrehm/vocker)
|
||||
* [Ventriloquist](https://github.com/fgrehm/ventriloquist)
|
||||
|
||||
### Providers
|
||||
|
||||
* [docker-provider](https://github.com/fgrehm/docker-provider)
|
||||
* [vagrant-shell](https://github.com/destructuring/vagrant-shell)
|
||||
|
||||
@@ -20,3 +20,5 @@ highlight link dockerfileString String
|
||||
|
||||
syntax match dockerfileComment "\v^\s*#.*$"
|
||||
highlight link dockerfileComment Comment
|
||||
|
||||
set commentstring=#\ %s
|
||||
|
||||
+38
-92
@@ -4,14 +4,12 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/sysinit"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -22,7 +20,7 @@ var (
|
||||
func main() {
|
||||
if selfPath := utils.SelfPath(); selfPath == "/sbin/init" || selfPath == "/.dockerinit" {
|
||||
// Running in init mode
|
||||
docker.SysInit()
|
||||
sysinit.SysInit()
|
||||
return
|
||||
}
|
||||
// FIXME: Switch d and D ? (to be more sshd like)
|
||||
@@ -32,12 +30,17 @@ func main() {
|
||||
flAutoRestart := flag.Bool("r", true, "Restart previously running containers")
|
||||
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge. Use 'none' to disable container networking")
|
||||
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
|
||||
flGraphPath := flag.String("g", "/var/lib/docker", "Path to graph storage base dir.")
|
||||
flRoot := flag.String("g", "/var/lib/docker", "Path to use as the root of the docker runtime.")
|
||||
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.")
|
||||
flDns := flag.String("dns", "", "Set custom dns servers")
|
||||
flHosts := docker.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
|
||||
flHosts := utils.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
|
||||
flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use")
|
||||
flEnableIptables := flag.Bool("iptables", true, "Disable iptables within docker")
|
||||
flDefaultIp := flag.String("ip", "0.0.0.0", "Default ip address to use when binding a containers ports")
|
||||
flInterContainerComm := flag.Bool("icc", true, "Enable inter-container communication")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *flVersion {
|
||||
showVersion()
|
||||
return
|
||||
@@ -46,14 +49,14 @@ func main() {
|
||||
flHosts = flHosts[1:] //trick to display a nice default value in the usage
|
||||
}
|
||||
for i, flHost := range flHosts {
|
||||
flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost)
|
||||
host, err := utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost)
|
||||
if err == nil {
|
||||
flHosts[i] = host
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if *bridgeName != "" {
|
||||
docker.NetworkBridgeIface = *bridgeName
|
||||
} else {
|
||||
docker.NetworkBridgeIface = docker.DefaultNetworkBridge
|
||||
}
|
||||
if *flDebug {
|
||||
os.Setenv("DEBUG", "1")
|
||||
}
|
||||
@@ -64,14 +67,33 @@ func main() {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
if err := daemon(*pidfile, *flGraphPath, flHosts, *flAutoRestart, *flEnableCors, *flDns); err != nil {
|
||||
eng, err := engine.New(*flRoot)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Load plugin: httpapi
|
||||
job := eng.Job("initapi")
|
||||
job.Setenv("Pidfile", *pidfile)
|
||||
job.Setenv("Root", *flRoot)
|
||||
job.SetenvBool("AutoRestart", *flAutoRestart)
|
||||
job.SetenvBool("EnableCors", *flEnableCors)
|
||||
job.Setenv("Dns", *flDns)
|
||||
job.SetenvBool("EnableIptables", *flEnableIptables)
|
||||
job.Setenv("BridgeIface", *bridgeName)
|
||||
job.Setenv("DefaultIp", *flDefaultIp)
|
||||
job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
|
||||
if err := job.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Serve api
|
||||
job = eng.Job("serveapi", flHosts...)
|
||||
job.SetenvBool("Logging", true)
|
||||
if err := job.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
} else {
|
||||
if len(flHosts) > 1 {
|
||||
log.Fatal("Please specify only one -H")
|
||||
return
|
||||
}
|
||||
protoAddrParts := strings.SplitN(flHosts[0], "://", 2)
|
||||
if err := docker.ParseCommands(protoAddrParts[0], protoAddrParts[1], flag.Args()...); err != nil {
|
||||
@@ -79,7 +101,6 @@ func main() {
|
||||
os.Exit(sterr.Status)
|
||||
}
|
||||
log.Fatal(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,78 +108,3 @@ func main() {
|
||||
func showVersion() {
|
||||
fmt.Printf("Docker version %s, build %s\n", VERSION, GITCOMMIT)
|
||||
}
|
||||
|
||||
func createPidFile(pidfile string) error {
|
||||
if pidString, err := ioutil.ReadFile(pidfile); err == nil {
|
||||
pid, err := strconv.Atoi(string(pidString))
|
||||
if err == nil {
|
||||
if _, err := os.Stat(fmt.Sprintf("/proc/%d/", pid)); err == nil {
|
||||
return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file, err := os.Create(pidfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
_, err = fmt.Fprintf(file, "%d", os.Getpid())
|
||||
return err
|
||||
}
|
||||
|
||||
func removePidFile(pidfile string) {
|
||||
if err := os.Remove(pidfile); err != nil {
|
||||
log.Printf("Error removing %s: %s", pidfile, err)
|
||||
}
|
||||
}
|
||||
|
||||
func daemon(pidfile string, flGraphPath string, protoAddrs []string, autoRestart, enableCors bool, flDns string) error {
|
||||
if err := createPidFile(pidfile); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer removePidFile(pidfile)
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
|
||||
go func() {
|
||||
sig := <-c
|
||||
log.Printf("Received signal '%v', exiting\n", sig)
|
||||
removePidFile(pidfile)
|
||||
os.Exit(0)
|
||||
}()
|
||||
var dns []string
|
||||
if flDns != "" {
|
||||
dns = []string{flDns}
|
||||
}
|
||||
server, err := docker.NewServer(flGraphPath, autoRestart, enableCors, dns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chErrors := make(chan error, len(protoAddrs))
|
||||
for _, protoAddr := range protoAddrs {
|
||||
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
|
||||
if protoAddrParts[0] == "unix" {
|
||||
syscall.Unlink(protoAddrParts[1])
|
||||
} else if protoAddrParts[0] == "tcp" {
|
||||
if !strings.HasPrefix(protoAddrParts[1], "127.0.0.1") {
|
||||
log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
|
||||
}
|
||||
} else {
|
||||
log.Fatal("Invalid protocol format.")
|
||||
os.Exit(-1)
|
||||
}
|
||||
go func() {
|
||||
chErrors <- docker.ListenAndServe(protoAddrParts[0], protoAddrParts[1], server, true)
|
||||
}()
|
||||
}
|
||||
for i := 0; i < len(protoAddrs); i += 1 {
|
||||
err := <-chErrors
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/sysinit"
|
||||
)
|
||||
|
||||
var (
|
||||
GITCOMMIT string
|
||||
VERSION string
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Running in init mode
|
||||
sysinit.SysInit()
|
||||
return
|
||||
}
|
||||
+6
-1
@@ -1,11 +1,16 @@
|
||||
from ubuntu:12.04
|
||||
maintainer Nick Stinemates
|
||||
#
|
||||
# docker build -t docker:docs . && docker run -p 8000:8000 docker:docs
|
||||
#
|
||||
|
||||
run apt-get update
|
||||
run apt-get install -y python-setuptools make
|
||||
run easy_install pip
|
||||
#from docs/requirements.txt, but here to increase cacheability
|
||||
run pip install Sphinx==1.1.3
|
||||
run pip install sphinxcontrib-httpdomain==1.1.8
|
||||
add . /docs
|
||||
run pip install -r /docs/requirements.txt
|
||||
run cd /docs; make docs
|
||||
|
||||
expose 8000
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ help:
|
||||
# @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
# @echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
# @echo " text to make text files"
|
||||
# @echo " man to make manual pages"
|
||||
@echo " man to make a manual page"
|
||||
# @echo " texinfo to make Texinfo files"
|
||||
# @echo " info to make Texinfo files and run them through makeinfo"
|
||||
# @echo " gettext to make PO message catalogs"
|
||||
|
||||
+5
-4
@@ -39,8 +39,7 @@ Getting Started
|
||||
To edit and test the docs, you'll need to install the Sphinx tool and
|
||||
its dependencies. There are two main ways to install this tool:
|
||||
|
||||
Native Installation
|
||||
...................
|
||||
###Native Installation
|
||||
|
||||
* Install sphinx: `pip install sphinx`
|
||||
* Mac OS X: `[sudo] pip-2.7 install sphinx`
|
||||
@@ -48,8 +47,7 @@ Native Installation
|
||||
* Mac OS X: `[sudo] pip-2.7 install sphinxcontrib-httpdomain`
|
||||
* If pip is not available you can probably install it using your favorite package manager as **python-pip**
|
||||
|
||||
Alternative Installation: Docker Container
|
||||
..........................................
|
||||
###Alternative Installation: Docker Container
|
||||
|
||||
If you're running ``docker`` on your development machine then you may
|
||||
find it easier and cleaner to use the Dockerfile. This installs Sphinx
|
||||
@@ -59,6 +57,9 @@ docs inside the container, even starting a simple HTTP server on port
|
||||
build .`` and run the resulting image. This is the equivalent to
|
||||
``make clean server`` since each container starts clean.
|
||||
|
||||
In the ``docs/`` directory, run:
|
||||
```docker build -t docker:docs . && docker run -p 8000:8000 docker:docs```
|
||||
|
||||
Usage
|
||||
-----
|
||||
* Follow the contribution guidelines (``../CONTRIBUTING.md``)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Sphinx==1.1.3
|
||||
sphinxcontrib-httpdomain==1.1.8
|
||||
sphinxcontrib-httpdomain==1.1.9
|
||||
|
||||
@@ -26,14 +26,118 @@ Docker Remote API
|
||||
2. Versions
|
||||
===========
|
||||
|
||||
The current version of the API is 1.6
|
||||
The current version of the API is 1.7
|
||||
|
||||
Calling /images/<name>/insert is the same as calling
|
||||
/v1.6/images/<name>/insert
|
||||
/v1.7/images/<name>/insert
|
||||
|
||||
You can still call an old version of the api using
|
||||
/v1.0/images/<name>/insert
|
||||
|
||||
v1.7
|
||||
****
|
||||
|
||||
Full Documentation
|
||||
------------------
|
||||
|
||||
:doc:`docker_remote_api_v1.7`
|
||||
|
||||
What's new
|
||||
----------
|
||||
|
||||
.. http:get:: /images/json
|
||||
|
||||
The format of the json returned from this uri changed. Instead of an entry
|
||||
for each repo/tag on an image, each image is only represented once, with a
|
||||
nested attribute indicating the repo/tags that apply to that image.
|
||||
|
||||
Instead of:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"VirtualSize": 131506275,
|
||||
"Size": 131506275,
|
||||
"Created": 1365714795,
|
||||
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
|
||||
"Tag": "12.04",
|
||||
"Repository": "ubuntu"
|
||||
},
|
||||
{
|
||||
"VirtualSize": 131506275,
|
||||
"Size": 131506275,
|
||||
"Created": 1365714795,
|
||||
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
|
||||
"Tag": "latest",
|
||||
"Repository": "ubuntu"
|
||||
},
|
||||
{
|
||||
"VirtualSize": 131506275,
|
||||
"Size": 131506275,
|
||||
"Created": 1365714795,
|
||||
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
|
||||
"Tag": "precise",
|
||||
"Repository": "ubuntu"
|
||||
},
|
||||
{
|
||||
"VirtualSize": 180116135,
|
||||
"Size": 24653,
|
||||
"Created": 1364102658,
|
||||
"Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
|
||||
"Tag": "12.10",
|
||||
"Repository": "ubuntu"
|
||||
},
|
||||
{
|
||||
"VirtualSize": 180116135,
|
||||
"Size": 24653,
|
||||
"Created": 1364102658,
|
||||
"Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
|
||||
"Tag": "quantal",
|
||||
"Repository": "ubuntu"
|
||||
}
|
||||
]
|
||||
|
||||
The returned json looks like this:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"RepoTag": [
|
||||
"ubuntu:12.04",
|
||||
"ubuntu:precise",
|
||||
"ubuntu:latest"
|
||||
],
|
||||
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
|
||||
"Created": 1365714795,
|
||||
"Size": 131506275,
|
||||
"VirtualSize": 131506275
|
||||
},
|
||||
{
|
||||
"RepoTag": [
|
||||
"ubuntu:12.10",
|
||||
"ubuntu:quantal"
|
||||
],
|
||||
"ParentId": "27cf784147099545",
|
||||
"Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
|
||||
"Created": 1364102658,
|
||||
"Size": 24653,
|
||||
"VirtualSize": 180116135
|
||||
}
|
||||
]
|
||||
|
||||
.. http:get:: /images/viz
|
||||
|
||||
This URI no longer exists. The ``images -viz`` output is now generated in
|
||||
the client, using the ``/images/json`` data.
|
||||
|
||||
v1.6
|
||||
****
|
||||
|
||||
|
||||
@@ -970,28 +970,33 @@ Create a new image from a container's changes
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd": ["cat", "/world"],
|
||||
"PortSpecs":["22"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
{"Id":"596069db4bf5"}
|
||||
{"Id":"596069db4bf5"}
|
||||
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
3. Going further
|
||||
|
||||
@@ -977,32 +977,37 @@ Create a new image from a container's changes
|
||||
|
||||
.. http:post:: /commit
|
||||
|
||||
Create a new image from a container's changes
|
||||
Create a new image from a container's changes
|
||||
|
||||
**Example request**:
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd": ["cat", "/world"],
|
||||
"PortSpecs":["22"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
.. sourcecode:: http
|
||||
{"Id":"596069db4bf5"}
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
{"Id":"596069db4bf5"}
|
||||
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
3. Going further
|
||||
|
||||
@@ -985,32 +985,37 @@ Create a new image from a container's changes
|
||||
|
||||
.. http:post:: /commit
|
||||
|
||||
Create a new image from a container's changes
|
||||
Create a new image from a container's changes
|
||||
|
||||
**Example request**:
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd": ["cat", "/world"],
|
||||
"PortSpecs":["22"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
{"Id":"596069db4bf5"}
|
||||
{"Id":"596069db4bf5"}
|
||||
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
3. Going further
|
||||
|
||||
@@ -1034,32 +1034,37 @@ Create a new image from a container's changes
|
||||
|
||||
.. http:post:: /commit
|
||||
|
||||
Create a new image from a container's changes
|
||||
Create a new image from a container's changes
|
||||
|
||||
**Example request**:
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd": ["cat", "/world"],
|
||||
"PortSpecs":["22"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
{"Id":"596069db4bf5"}
|
||||
{"Id":"596069db4bf5"}
|
||||
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
Monitor Docker's events
|
||||
|
||||
@@ -943,36 +943,36 @@ Build an image from Dockerfile via stdin
|
||||
|
||||
.. http:post:: /build
|
||||
|
||||
Build an image from Dockerfile via stdin
|
||||
Build an image from Dockerfile via stdin
|
||||
|
||||
**Example request**:
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /build HTTP/1.1
|
||||
POST /build HTTP/1.1
|
||||
|
||||
{{ STREAM }}
|
||||
{{ STREAM }}
|
||||
|
||||
**Example response**:
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
{{ STREAM }}
|
||||
{{ STREAM }}
|
||||
|
||||
|
||||
The stream must be a tar archive compressed with one of the following algorithms:
|
||||
identity (no compression), gzip, bzip2, xz. The archive must include a file called
|
||||
`Dockerfile` at its root. It may include any number of other files, which will be
|
||||
accessible in the build context (See the ADD build command).
|
||||
The stream must be a tar archive compressed with one of the following algorithms:
|
||||
identity (no compression), gzip, bzip2, xz. The archive must include a file called
|
||||
`Dockerfile` at its root. It may include any number of other files, which will be
|
||||
accessible in the build context (See the ADD build command).
|
||||
|
||||
The Content-type header should be set to "application/tar".
|
||||
The Content-type header should be set to "application/tar".
|
||||
|
||||
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
|
||||
:query q: suppress verbose build output
|
||||
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
|
||||
:query q: suppress verbose build output
|
||||
:query nocache: do not use the cache when building the image
|
||||
:statuscode 200: no error
|
||||
:statuscode 200: no error
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
@@ -1069,8 +1069,8 @@ Show the docker version information
|
||||
"GoVersion":"go1.0.3"
|
||||
}
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 500: server error
|
||||
:statuscode 200: no error
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
Create a new image from a container's changes
|
||||
@@ -1084,23 +1084,28 @@ Create a new image from a container's changes
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd": ["cat", "/world"],
|
||||
"PortSpecs":["22"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
{"Id":"596069db4bf5"}
|
||||
{"Id":"596069db4bf5"}
|
||||
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
@@ -1050,32 +1050,37 @@ Create a new image from a container's changes
|
||||
|
||||
.. http:post:: /commit
|
||||
|
||||
Create a new image from a container's changes
|
||||
Create a new image from a container's changes
|
||||
|
||||
**Example request**:
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd": ["cat", "/world"],
|
||||
"PortSpecs":["22"]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
{"Id":"596069db4bf5"}
|
||||
{"Id":"596069db4bf5"}
|
||||
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
:query container: source container
|
||||
:query repo: repository
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
Monitor Docker's events
|
||||
***********************
|
||||
|
||||
@@ -13,9 +13,12 @@ Docker Remote API v1.6
|
||||
1. Brief introduction
|
||||
=====================
|
||||
|
||||
- The Remote API is replacing rcli
|
||||
- Default port in the docker daemon is 4243
|
||||
- The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr
|
||||
- The Remote API has replaced rcli
|
||||
- The daemon listens on ``unix:///var/run/docker.sock``, but you can
|
||||
:ref:`bind_docker`.
|
||||
- The API tends to be REST, but for some complex commands, like
|
||||
``attach`` or ``pull``, the HTTP connection is hijacked to transport
|
||||
``stdout, stdin`` and ``stderr``
|
||||
|
||||
2. Endpoints
|
||||
============
|
||||
@@ -118,8 +121,7 @@ Create a container
|
||||
"AttachStdin":false,
|
||||
"AttachStdout":true,
|
||||
"AttachStderr":true,
|
||||
"PortSpecs":null,
|
||||
"Privileged": false,
|
||||
"ExposedPorts":{},
|
||||
"Tty":false,
|
||||
"OpenStdin":false,
|
||||
"StdinOnce":false,
|
||||
@@ -132,7 +134,6 @@ Create a container
|
||||
"Volumes":{},
|
||||
"VolumesFrom":"",
|
||||
"WorkingDir":""
|
||||
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
@@ -148,11 +149,63 @@ Create a container
|
||||
}
|
||||
|
||||
:jsonparam config: the container's configuration
|
||||
:query name: container name to use
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 406: impossible to attach (container not running)
|
||||
:statuscode 500: server error
|
||||
|
||||
**More Complex Example request, in 2 steps.**
|
||||
**First, use create to expose a Private Port, which can be bound back to a Public Port at startup**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /containers/create HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd":[
|
||||
"/usr/sbin/sshd","-D"
|
||||
],
|
||||
"Image":"image-with-sshd",
|
||||
"ExposedPorts":{"22/tcp":{}}
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Id":"e90e34656806"
|
||||
"Warnings":[]
|
||||
}
|
||||
|
||||
**Second, start (using the ID returned above) the image we just created, mapping the ssh port 22 to something on the host**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /containers/e90e34656806/start HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"PortBindings": { "22/tcp": [{ "HostPort": "11022" }]}
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Length: 0
|
||||
|
||||
**Now you can ssh into your new container on port 11022.**
|
||||
|
||||
|
||||
|
||||
|
||||
Inspect a container
|
||||
*******************
|
||||
@@ -187,7 +240,7 @@ Inspect a container
|
||||
"AttachStdin": false,
|
||||
"AttachStdout": true,
|
||||
"AttachStderr": true,
|
||||
"PortSpecs": null,
|
||||
"ExposedPorts": {},
|
||||
"Tty": false,
|
||||
"OpenStdin": false,
|
||||
"StdinOnce": false,
|
||||
@@ -358,7 +411,12 @@ Start a container
|
||||
|
||||
{
|
||||
"Binds":["/tmp:/tmp"],
|
||||
"LxcConf":{"lxc.utsname":"docker"}
|
||||
"LxcConf":{"lxc.utsname":"docker"},
|
||||
"ContainerIDFile": "",
|
||||
"Privileged": false,
|
||||
"PortBindings": {"22/tcp": [{HostIp:"", HostPort:""}]},
|
||||
"Links": [],
|
||||
"PublishAllPorts": false
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
@@ -442,7 +500,8 @@ Kill a container
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 OK
|
||||
|
||||
|
||||
:query signal: Signal to send to the container (integer). When not set, SIGKILL is assumed and the call will waits for the container to exit.
|
||||
:statuscode 204: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
@@ -790,7 +849,7 @@ Inspect an image
|
||||
"AttachStdin":false,
|
||||
"AttachStdout":false,
|
||||
"AttachStderr":false,
|
||||
"PortSpecs":null,
|
||||
"ExposedPorts":{},
|
||||
"Tty":true,
|
||||
"OpenStdin":true,
|
||||
"StdinOnce":false,
|
||||
@@ -990,36 +1049,36 @@ Build an image from Dockerfile via stdin
|
||||
|
||||
.. http:post:: /build
|
||||
|
||||
Build an image from Dockerfile via stdin
|
||||
Build an image from Dockerfile via stdin
|
||||
|
||||
**Example request**:
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /build HTTP/1.1
|
||||
POST /build HTTP/1.1
|
||||
|
||||
{{ STREAM }}
|
||||
{{ STREAM }}
|
||||
|
||||
**Example response**:
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
{{ STREAM }}
|
||||
{{ STREAM }}
|
||||
|
||||
|
||||
The stream must be a tar archive compressed with one of the following algorithms:
|
||||
identity (no compression), gzip, bzip2, xz. The archive must include a file called
|
||||
`Dockerfile` at its root. It may include any number of other files, which will be
|
||||
accessible in the build context (See the ADD build command).
|
||||
The stream must be a tar archive compressed with one of the following algorithms:
|
||||
identity (no compression), gzip, bzip2, xz. The archive must include a file called
|
||||
`Dockerfile` at its root. It may include any number of other files, which will be
|
||||
accessible in the build context (See the ADD build command).
|
||||
|
||||
The Content-type header should be set to "application/tar".
|
||||
|
||||
The Content-type header should be set to "application/tar".
|
||||
|
||||
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
|
||||
:query q: suppress verbose build output
|
||||
:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
|
||||
:query q: suppress verbose build output
|
||||
:query nocache: do not use the cache when building the image
|
||||
:statuscode 200: no error
|
||||
:statuscode 200: no error
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
@@ -1131,7 +1190,13 @@ Create a new image from a container's changes
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Cmd": ["cat", "/world"],
|
||||
"ExposedPorts":{"22/tcp":{}}
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
@@ -1147,7 +1212,6 @@ Create a new image from a container's changes
|
||||
:query tag: tag
|
||||
:query m: commit message
|
||||
:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
|
||||
:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
|
||||
:statuscode 201: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
:title: Registry API
|
||||
:title: Remote API Client Libraries
|
||||
:description: Various client libraries available to use with the Docker remote API
|
||||
:keywords: API, Docker, index, registry, REST, documentation, clients, Python, Ruby, Javascript, Erlang, Go
|
||||
|
||||
@@ -12,26 +12,28 @@ compatibility. Please file issues with the library owners. If you
|
||||
find more library implementations, please list them in Docker doc bugs
|
||||
and we will add the libraries here.
|
||||
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Language/Framework | Name | Repository |
|
||||
+======================+================+============================================+
|
||||
| Python | docker-py | https://github.com/dotcloud/docker-py |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Ruby | docker-client | https://github.com/geku/docker-client |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Ruby | docker-api | https://github.com/swipely/docker-api |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Javascript (NodeJS) | docker.io | https://github.com/appersonlabs/docker.io |
|
||||
| | | Install via NPM: `npm install docker.io` |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Javascript | docker-js | https://github.com/dgoujard/docker-js |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui |
|
||||
| **WebUI** | | |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Java | docker-java | https://github.com/kpelykh/docker-java |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Erlang | erldocker | https://github.com/proger/erldocker |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Go | go-dockerclient| https://github.com/fsouza/go-dockerclient |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Language/Framework | Name | Repository | Status |
|
||||
+======================+================+============================================+==========+
|
||||
| Python | docker-py | https://github.com/dotcloud/docker-py | Active |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Ruby | docker-client | https://github.com/geku/docker-client | Outdated |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Ruby | docker-api | https://github.com/swipely/docker-api | Active |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Javascript (NodeJS) | docker.io | https://github.com/appersonlabs/docker.io | Active |
|
||||
| | | Install via NPM: `npm install docker.io` | |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Javascript | docker-js | https://github.com/dgoujard/docker-js | Active |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui | Active |
|
||||
| **WebUI** | | | |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Java | docker-java | https://github.com/kpelykh/docker-java | Active |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Erlang | erldocker | https://github.com/proger/erldocker | Active |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| Go | go-dockerclient| https://github.com/fsouza/go-dockerclient | Active |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
| PHP | Alvine | http://pear.alvine.io/ (alpha) | Active |
|
||||
+----------------------+----------------+--------------------------------------------+----------+
|
||||
|
||||
@@ -29,6 +29,9 @@ To list available commands, either run ``docker`` with no parameters or execute
|
||||
|
||||
Attach to a running container.
|
||||
|
||||
-nostdin=false: Do not attach stdin
|
||||
-sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
|
||||
|
||||
You can detach from the container again (and leave it running) with
|
||||
``CTRL-c`` (for a quiet exit) or ``CTRL-\`` to get a stacktrace of
|
||||
the Docker client when it quits.
|
||||
@@ -38,7 +41,7 @@ To stop a container, use ``docker stop``
|
||||
To kill the container, use ``docker kill``
|
||||
|
||||
.. _cli_attach_examples:
|
||||
|
||||
|
||||
Examples:
|
||||
~~~~~~~~~
|
||||
|
||||
@@ -52,8 +55,8 @@ Examples:
|
||||
Mem: 373572k total, 355560k used, 18012k free, 27872k buffers
|
||||
Swap: 786428k total, 0k used, 786428k free, 221740k cached
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 17200 1116 912 R 0 0.3 0:00.03 top
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 17200 1116 912 R 0 0.3 0:00.03 top
|
||||
|
||||
top - 02:05:55 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
|
||||
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
|
||||
@@ -61,8 +64,8 @@ Examples:
|
||||
Mem: 373572k total, 355244k used, 18328k free, 27872k buffers
|
||||
Swap: 786428k total, 0k used, 786428k free, 221776k cached
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
|
||||
|
||||
|
||||
top - 02:05:58 up 3:06, 0 users, load average: 0.01, 0.02, 0.05
|
||||
@@ -71,9 +74,9 @@ Examples:
|
||||
Mem: 373572k total, 355780k used, 17792k free, 27880k buffers
|
||||
Swap: 786428k total, 0k used, 786428k free, 221776k cached
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
|
||||
^C$
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
|
||||
^C$
|
||||
$ sudo docker stop $ID
|
||||
|
||||
.. _cli_build:
|
||||
@@ -85,31 +88,65 @@ Examples:
|
||||
|
||||
Usage: docker build [OPTIONS] PATH | URL | -
|
||||
Build a new container image from the source code at PATH
|
||||
-t="": Repository name (and optionally a tag) to be applied to the resulting image in case of success.
|
||||
-t="": Repository name (and optionally a tag) to be applied
|
||||
to the resulting image in case of success.
|
||||
-q=false: Suppress verbose build output.
|
||||
-no-cache: Do not use the cache when building the image.
|
||||
-rm: Remove intermediate containers after a successful build
|
||||
When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context
|
||||
|
||||
The files at PATH or URL are called the "context" of the build. The
|
||||
build process may refer to any of the files in the context, for
|
||||
example when using an :ref:`ADD <dockerfile_add>` instruction. When a
|
||||
single ``Dockerfile`` is given as URL, then no context is set. When a
|
||||
git repository is set as URL, then the repository is used as the
|
||||
context
|
||||
|
||||
.. _cli_build_examples:
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
.. seealso:: :ref:`dockerbuilder`.
|
||||
|
||||
Examples:
|
||||
~~~~~~~~~
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker build .
|
||||
Uploading context 10240 bytes
|
||||
Step 1 : FROM busybox
|
||||
Pulling repository busybox
|
||||
---> e9aa60c60128MB/2.284 MB (100%) endpoint: https://cdn-registry-1.docker.io/v1/
|
||||
Step 2 : RUN ls -lh /
|
||||
---> Running in 9c9e81692ae9
|
||||
total 24
|
||||
drwxr-xr-x 2 root root 4.0K Mar 12 2013 bin
|
||||
drwxr-xr-x 5 root root 4.0K Oct 19 00:19 dev
|
||||
drwxr-xr-x 2 root root 4.0K Oct 19 00:19 etc
|
||||
drwxr-xr-x 2 root root 4.0K Nov 15 23:34 lib
|
||||
lrwxrwxrwx 1 root root 3 Mar 12 2013 lib64 -> lib
|
||||
dr-xr-xr-x 116 root root 0 Nov 15 23:34 proc
|
||||
lrwxrwxrwx 1 root root 3 Mar 12 2013 sbin -> bin
|
||||
dr-xr-xr-x 13 root root 0 Nov 15 23:34 sys
|
||||
drwxr-xr-x 2 root root 4.0K Mar 12 2013 tmp
|
||||
drwxr-xr-x 2 root root 4.0K Nov 15 23:34 usr
|
||||
---> b35f4035db3f
|
||||
Step 3 : CMD echo Hello World
|
||||
---> Running in 02071fceb21b
|
||||
---> f52f38b7823e
|
||||
Successfully built f52f38b7823e
|
||||
|
||||
This will read the ``Dockerfile`` from the current directory. It will
|
||||
also send any other files and directories found in the current
|
||||
directory to the ``docker`` daemon.
|
||||
This example specifies that the PATH is ``.``, and so all the files in
|
||||
the local directory get tar'd and sent to the Docker daemon. The PATH
|
||||
specifies where to find the files for the "context" of the build on
|
||||
the Docker daemon. Remember that the daemon could be running on a
|
||||
remote machine and that no parsing of the Dockerfile happens at the
|
||||
client side (where you're running ``docker build``). That means that
|
||||
*all* the files at PATH get sent, not just the ones listed to
|
||||
:ref:`ADD <dockerfile_add>` in the ``Dockerfile``.
|
||||
|
||||
The transfer of context from the local machine to the Docker daemon is
|
||||
what the ``docker`` client means when you see the "Uploading context"
|
||||
message.
|
||||
|
||||
The contents of this directory would be used by ``ADD`` commands found
|
||||
within the ``Dockerfile``. This will send a lot of data to the
|
||||
``docker`` daemon if the current directory contains a lot of data. If
|
||||
the absolute path is provided instead of ``.`` then only the files and
|
||||
directories required by the ADD commands from the ``Dockerfile`` will be
|
||||
added to the context and transferred to the ``docker`` daemon.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -126,17 +163,15 @@ tag will be ``2.0``
|
||||
|
||||
This will read a ``Dockerfile`` from *stdin* without context. Due to
|
||||
the lack of a context, no contents of any local directory will be sent
|
||||
to the ``docker`` daemon. ``ADD`` doesn't work when running in this
|
||||
mode because the absence of the context provides no source files to
|
||||
copy to the container.
|
||||
|
||||
to the ``docker`` daemon. Since there is no context, a Dockerfile
|
||||
``ADD`` only works if it refers to a remote URL.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker build github.com/creack/docker-firefox
|
||||
|
||||
This will clone the Github repository and use it as context. The
|
||||
``Dockerfile`` at the root of the repository is used as
|
||||
This will clone the Github repository and use the cloned repository as
|
||||
context. The ``Dockerfile`` at the root of the repository is used as
|
||||
``Dockerfile``. Note that you can specify an arbitrary git repository
|
||||
by using the ``git://`` schema.
|
||||
|
||||
@@ -148,16 +183,35 @@ by using the ``git://`` schema.
|
||||
|
||||
::
|
||||
|
||||
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY [TAG]]
|
||||
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
|
||||
|
||||
Create a new image from a container's changes
|
||||
|
||||
-m="": Commit message
|
||||
-author="": Author (eg. "John Hannibal Smith <hannibal@a-team.com>"
|
||||
-run="": Configuration to be applied when the image is launched with `docker run`.
|
||||
(ex: '{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
|
||||
-run="": Configuration to be applied when the image is launched with `docker run`.
|
||||
(ex: -run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
|
||||
|
||||
Full -run example (multiline is ok within a single quote ``'``)
|
||||
Simple commit of an existing container
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ docker ps
|
||||
ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
c3f279d17e0a ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
|
||||
197387f1b436 ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
|
||||
$ docker commit c3f279d17e0a SvenDowideit/testimage:version3
|
||||
f5283438590d
|
||||
$ docker images | head
|
||||
REPOSITORY TAG ID CREATED SIZE
|
||||
SvenDowideit/testimage version3 f5283438590d 16 seconds ago 204.2 MB (virtual 335.7 MB)
|
||||
|
||||
|
||||
Full -run example
|
||||
.................
|
||||
|
||||
(multiline is ok within a single quote ``'``)
|
||||
|
||||
::
|
||||
|
||||
@@ -198,10 +252,15 @@ Full -run example (multiline is ok within a single quote ``'``)
|
||||
|
||||
::
|
||||
|
||||
Usage: docker cp CONTAINER:RESOURCE HOSTPATH
|
||||
Usage: docker cp CONTAINER:PATH HOSTPATH
|
||||
|
||||
Copy files/folders from the containers filesystem to the host
|
||||
path. Paths are relative to the root of the filesystem.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker cp 7bb0e258aefe:/etc/debian_version .
|
||||
$ sudo docker cp blue_frog:/etc/hosts .
|
||||
|
||||
.. _cli_diff:
|
||||
|
||||
@@ -210,9 +269,33 @@ Full -run example (multiline is ok within a single quote ``'``)
|
||||
|
||||
::
|
||||
|
||||
Usage: docker diff CONTAINER [OPTIONS]
|
||||
Usage: docker diff CONTAINER
|
||||
|
||||
List the changed files and directories in a container's filesystem
|
||||
|
||||
Inspect changes on a container's filesystem
|
||||
There are 3 events that are listed in the 'diff':
|
||||
|
||||
1. ```A``` - Add
|
||||
2. ```D``` - Delete
|
||||
3. ```C``` - Change
|
||||
|
||||
for example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker diff 7bb0e258aefe
|
||||
|
||||
C /dev
|
||||
A /dev/kmsg
|
||||
C /etc
|
||||
A /etc/mtab
|
||||
A /go
|
||||
A /go/src
|
||||
A /go/src/github.com
|
||||
A /go/src/github.com/dotcloud
|
||||
A /go/src/github.com/dotcloud/docker
|
||||
A /go/src/github.com/dotcloud/docker/.git
|
||||
....
|
||||
|
||||
.. _cli_events:
|
||||
|
||||
@@ -224,6 +307,9 @@ Full -run example (multiline is ok within a single quote ``'``)
|
||||
Usage: docker events
|
||||
|
||||
Get real time events from the server
|
||||
|
||||
-since="": Show previously created events and then stream.
|
||||
(either seconds since epoch, or date string as below)
|
||||
|
||||
.. _cli_events_example:
|
||||
|
||||
@@ -236,7 +322,7 @@ Shell 1: Listening for events
|
||||
.............................
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
$ sudo docker events
|
||||
|
||||
Shell 2: Start and Stop a Container
|
||||
@@ -256,6 +342,23 @@ Shell 1: (Again .. now showing events)
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
|
||||
|
||||
Show events in the past from a specified time
|
||||
.............................................
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker events -since 1378216169
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
|
||||
|
||||
$ sudo docker events -since '2013-09-03'
|
||||
[2013-09-03 15:49:26 +0200 CEST] 4386fb97867d: (from 12de384bfb10) start
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
|
||||
|
||||
$ sudo docker events -since '2013-09-03 15:49:29 +0200 CEST'
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) die
|
||||
[2013-09-03 15:49:29 +0200 CEST] 4386fb97867d: (from 12de384bfb10) stop
|
||||
|
||||
.. _cli_export:
|
||||
|
||||
@@ -279,6 +382,43 @@ Shell 1: (Again .. now showing events)
|
||||
|
||||
Show the history of an image
|
||||
|
||||
-notrunc=false: Don't truncate output
|
||||
-q=false: only show numeric IDs
|
||||
|
||||
To see how the docker:latest image was built:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ docker history docker
|
||||
ID CREATED CREATED BY
|
||||
docker:latest 19 hours ago /bin/sh -c #(nop) ADD . in /go/src/github.com/dotcloud/docker
|
||||
cf5f2467662d 2 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["hack/dind"]
|
||||
3538fbe372bf 2 weeks ago /bin/sh -c #(nop) WORKDIR /go/src/github.com/dotcloud/docker
|
||||
7450f65072e5 2 weeks ago /bin/sh -c #(nop) VOLUME /var/lib/docker
|
||||
b79d62b97328 2 weeks ago /bin/sh -c apt-get install -y -q lxc
|
||||
36714852a550 2 weeks ago /bin/sh -c apt-get install -y -q iptables
|
||||
8c4c706df1d6 2 weeks ago /bin/sh -c /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEYn' > /.s3cfg
|
||||
b89989433c48 2 weeks ago /bin/sh -c pip install python-magic
|
||||
a23e640d85b5 2 weeks ago /bin/sh -c pip install s3cmd
|
||||
41f54fec7e79 2 weeks ago /bin/sh -c apt-get install -y -q python-pip
|
||||
d9bc04add907 2 weeks ago /bin/sh -c apt-get install -y -q reprepro dpkg-sig
|
||||
e74f4760fa70 2 weeks ago /bin/sh -c gem install --no-rdoc --no-ri fpm
|
||||
1e43224726eb 2 weeks ago /bin/sh -c apt-get install -y -q ruby1.9.3 rubygems libffi-dev
|
||||
460953ae9d7f 2 weeks ago /bin/sh -c #(nop) ENV GOPATH=/go:/go/src/github.com/dotcloud/docker/vendor
|
||||
8b63eb1d666b 2 weeks ago /bin/sh -c #(nop) ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/goroot/bin
|
||||
3087f3bcedf2 2 weeks ago /bin/sh -c #(nop) ENV GOROOT=/goroot
|
||||
635840d198e5 2 weeks ago /bin/sh -c cd /goroot/src && ./make.bash
|
||||
439f4a0592ba 2 weeks ago /bin/sh -c curl -s https://go.googlecode.com/files/go1.1.2.src.tar.gz | tar -v -C / -xz && mv /go /goroot
|
||||
13967ed36e93 2 weeks ago /bin/sh -c #(nop) ENV CGO_ENABLED=0
|
||||
bf7424458437 2 weeks ago /bin/sh -c apt-get install -y -q build-essential
|
||||
a89ec997c3bf 2 weeks ago /bin/sh -c apt-get install -y -q mercurial
|
||||
b9f165c6e749 2 weeks ago /bin/sh -c apt-get install -y -q git
|
||||
17a64374afa7 2 weeks ago /bin/sh -c apt-get install -y -q curl
|
||||
d5e85dc5b1d8 2 weeks ago /bin/sh -c apt-get update
|
||||
13e642467c11 2 weeks ago /bin/sh -c echo 'deb http://archive.ubuntu.com/ubuntu precise main universe' > /etc/apt/sources.list
|
||||
ae6dde92a94e 2 weeks ago /bin/sh -c #(nop) MAINTAINER Solomon Hykes <solomon@dotcloud.com>
|
||||
ubuntu:12.04 6 months ago
|
||||
|
||||
.. _cli_images:
|
||||
|
||||
``images``
|
||||
@@ -290,20 +430,86 @@ Shell 1: (Again .. now showing events)
|
||||
|
||||
List images
|
||||
|
||||
-a=false: show all images
|
||||
-a=false: show all images (by default filter out the intermediate images used to build)
|
||||
-notrunc=false: Don't truncate output
|
||||
-q=false: only show numeric IDs
|
||||
-viz=false: output in graphviz format
|
||||
-tree=false: output graph in tree format
|
||||
-viz=false: output graph in graphviz format
|
||||
|
||||
Listing the most recently created images
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker images | head
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
<none> <none> 77af4d6b9913 19 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
committest latest b6fa739cedf5 19 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
<none> <none> 78a85c484f71 19 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
docker latest 30557a29d5ab 20 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
<none> <none> 0124422dd9f9 20 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
<none> <none> 18ad6fad3402 22 hours ago 23.68 MB (virtual 1.082 GB)
|
||||
<none> <none> f9f1e26352f0 23 hours ago 30.46 MB (virtual 1.089 GB)
|
||||
tryout latest 2629d1fa0b81 23 hours ago 16.4 kB (virtual 131.5 MB)
|
||||
<none> <none> 5ed6274db6ce 24 hours ago 30.44 MB (virtual 1.089 GB)
|
||||
|
||||
Listing the full length image IDs
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker images -notrunc | head
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
<none> <none> 77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182 19 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
committest latest b6fa739cedf5ea12a620a439402b6004d057da800f91c7524b5086a5e4749c9f 19 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
<none> <none> 78a85c484f71509adeaace20e72e941f6bdd2b25b4c75da8693efd9f61a37921 19 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
docker latest 30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4 20 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
<none> <none> 0124422dd9f9cf7ef15c0617cda3931ee68346455441d66ab8bdc5b05e9fdce5 20 hours ago 30.53 MB (virtual 1.089 GB)
|
||||
<none> <none> 18ad6fad340262ac2a636efd98a6d1f0ea775ae3d45240d3418466495a19a81b 22 hours ago 23.68 MB (virtual 1.082 GB)
|
||||
<none> <none> f9f1e26352f0a3ba6a0ff68167559f64f3e21ff7ada60366e2d44a04befd1d3a 23 hours ago 30.46 MB (virtual 1.089 GB)
|
||||
tryout latest 2629d1fa0b81b222fca63371ca16cbf6a0772d07759ff80e8d1369b926940074 23 hours ago 16.4 kB (virtual 131.5 MB)
|
||||
<none> <none> 5ed6274db6ceb2397844896966ea239290555e74ef307030ebb01ff91b1914df 24 hours ago 30.44 MB (virtual 1.089 GB)
|
||||
|
||||
Displaying images visually
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker images -viz | dot -Tpng -o docker.png
|
||||
$ sudo docker images -viz | dot -Tpng -o docker.png
|
||||
|
||||
.. image:: docker_images.gif
|
||||
:alt: Example inheritance graph of Docker images.
|
||||
|
||||
|
||||
Displaying image hierarchy
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker images -tree
|
||||
|
||||
|─8dbd9e392a96 Size: 131.5 MB (virtual 131.5 MB) Tags: ubuntu:12.04,ubuntu:latest,ubuntu:precise
|
||||
└─27cf78414709 Size: 180.1 MB (virtual 180.1 MB)
|
||||
└─b750fe79269d Size: 24.65 kB (virtual 180.1 MB) Tags: ubuntu:12.10,ubuntu:quantal
|
||||
|─f98de3b610d5 Size: 12.29 kB (virtual 180.1 MB)
|
||||
| └─7da80deb7dbf Size: 16.38 kB (virtual 180.1 MB)
|
||||
| └─65ed2fee0a34 Size: 20.66 kB (virtual 180.2 MB)
|
||||
| └─a2b9ea53dddc Size: 819.7 MB (virtual 999.8 MB)
|
||||
| └─a29b932eaba8 Size: 28.67 kB (virtual 999.9 MB)
|
||||
| └─e270a44f124d Size: 12.29 kB (virtual 999.9 MB) Tags: progrium/buildstep:latest
|
||||
└─17e74ac162d8 Size: 53.93 kB (virtual 180.2 MB)
|
||||
└─339a3f56b760 Size: 24.65 kB (virtual 180.2 MB)
|
||||
└─904fcc40e34d Size: 96.7 MB (virtual 276.9 MB)
|
||||
└─b1b0235328dd Size: 363.3 MB (virtual 640.2 MB)
|
||||
└─7cb05d1acb3b Size: 20.48 kB (virtual 640.2 MB)
|
||||
└─47bf6f34832d Size: 20.48 kB (virtual 640.2 MB)
|
||||
└─f165104e82ed Size: 12.29 kB (virtual 640.2 MB)
|
||||
└─d9cf85a47b7e Size: 1.911 MB (virtual 642.2 MB)
|
||||
└─3ee562df86ca Size: 17.07 kB (virtual 642.2 MB)
|
||||
└─b05fc2d00e4a Size: 24.96 kB (virtual 642.2 MB)
|
||||
└─c96a99614930 Size: 12.29 kB (virtual 642.2 MB)
|
||||
└─a6a357a48c49 Size: 12.29 kB (virtual 642.2 MB) Tags: ndj/mongodb:latest
|
||||
|
||||
.. _cli_import:
|
||||
|
||||
``import``
|
||||
@@ -311,7 +517,7 @@ Displaying images visually
|
||||
|
||||
::
|
||||
|
||||
Usage: docker import URL|- [REPOSITORY [TAG]]
|
||||
Usage: docker import URL|- [REPOSITORY[:TAG]]
|
||||
|
||||
Create a new filesystem image from the contents of a tarball
|
||||
|
||||
@@ -327,14 +533,16 @@ Examples
|
||||
Import from a remote location
|
||||
.............................
|
||||
|
||||
``$ sudo docker import http://example.com/exampleimage.tgz exampleimagerepo``
|
||||
This will create a new untagged image.
|
||||
|
||||
``$ sudo docker import http://example.com/exampleimage.tgz``
|
||||
|
||||
Import from a local file
|
||||
........................
|
||||
|
||||
Import to docker via pipe and standard in
|
||||
|
||||
``$ cat exampleimage.tgz | sudo docker import - exampleimagelocal``
|
||||
``$ cat exampleimage.tgz | sudo docker import - exampleimagelocal:new``
|
||||
|
||||
Import from a local directory
|
||||
.............................
|
||||
@@ -357,6 +565,21 @@ might not get preserved.
|
||||
|
||||
Display system-wide information.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker info
|
||||
Containers: 292
|
||||
Images: 194
|
||||
Debug mode (server): false
|
||||
Debug mode (client): false
|
||||
Fds: 22
|
||||
Goroutines: 67
|
||||
LXC Version: 0.9.0
|
||||
EventsListeners: 115
|
||||
Kernel Version: 3.8.0-33-generic
|
||||
WARNING: No swap limit support
|
||||
|
||||
|
||||
.. _cli_insert:
|
||||
|
||||
``insert``
|
||||
@@ -396,9 +619,29 @@ Insert file from github
|
||||
|
||||
::
|
||||
|
||||
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
|
||||
Usage: docker kill CONTAINER [CONTAINER...]
|
||||
|
||||
Kill a running container
|
||||
Kill a running container (Send SIGKILL)
|
||||
|
||||
The main process inside the container will be sent SIGKILL.
|
||||
|
||||
Known Issues (kill)
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* :issue:`197` indicates that ``docker kill`` may leave directories
|
||||
behind and make it difficult to remove the container.
|
||||
|
||||
.. _cli_load:
|
||||
|
||||
``load``
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
Usage: docker load < repository.tar
|
||||
|
||||
Loads a tarred repository from the standard input stream.
|
||||
Restores both images and tags.
|
||||
|
||||
.. _cli_login:
|
||||
|
||||
@@ -427,7 +670,6 @@ Insert file from github
|
||||
``logs``
|
||||
--------
|
||||
|
||||
|
||||
::
|
||||
|
||||
Usage: docker logs [OPTIONS] CONTAINER
|
||||
@@ -507,6 +749,44 @@ Insert file from github
|
||||
Usage: docker rm [OPTIONS] CONTAINER
|
||||
|
||||
Remove one or more containers
|
||||
-link="": Remove the link instead of the actual container
|
||||
|
||||
Known Issues (rm)
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* :issue:`197` indicates that ``docker kill`` may leave directories
|
||||
behind and make it difficult to remove the container.
|
||||
|
||||
|
||||
Examples:
|
||||
~~~~~~~~~
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ docker rm /redis
|
||||
/redis
|
||||
|
||||
|
||||
This will remove the container referenced under the link ``/redis``.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ docker rm -link /webapp/redis
|
||||
/webapp/redis
|
||||
|
||||
|
||||
This will remove the underlying link between ``/webapp`` and the ``/redis`` containers removing all
|
||||
network communication.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ docker rm `docker ps -a -q`
|
||||
|
||||
|
||||
This command will delete all stopped containers. The command ``docker ps -a -q`` will return all
|
||||
existing container IDs and pass them to the ``rm`` command which will delete them. Any running
|
||||
containers will not be deleted.
|
||||
|
||||
.. _cli_rmi:
|
||||
|
||||
@@ -530,7 +810,7 @@ Insert file from github
|
||||
|
||||
Run a command in a new container
|
||||
|
||||
-a=map[]: Attach to stdin, stdout or stderr.
|
||||
-a=map[]: Attach to stdin, stdout or stderr
|
||||
-c=0: CPU shares (relative weight)
|
||||
-cidfile="": Write the container ID to the file
|
||||
-d=false: Detached mode: Run container in the background, print new container id
|
||||
@@ -538,7 +818,7 @@ Insert file from github
|
||||
-h="": Container host name
|
||||
-i=false: Keep stdin open even if not attached
|
||||
-privileged=false: Give extended privileges to this container
|
||||
-m=0: Memory limit (in bytes)
|
||||
-m="": Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
|
||||
-n=true: Enable networking for this container
|
||||
-p=[]: Map a network port to the container
|
||||
-rm=false: Automatically remove the container when it exits (incompatible with -d)
|
||||
@@ -546,13 +826,18 @@ Insert file from github
|
||||
-u="": Username or UID
|
||||
-dns=[]: Set custom dns servers for the container
|
||||
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume.
|
||||
-volumes-from="": Mount all volumes from the given container.
|
||||
-entrypoint="": Overwrite the default entrypoint set by the image.
|
||||
-volumes-from="": Mount all volumes from the given container(s)
|
||||
-entrypoint="": Overwrite the default entrypoint set by the image
|
||||
-w="": Working directory inside the container
|
||||
-lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
||||
-sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
|
||||
-expose=[]: Expose a port from the container without publishing it to your host
|
||||
-link="": Add link to another container (name:alias)
|
||||
-name="": Assign the specified name to the container. If no name is specific docker will generate a random name
|
||||
-P=false: Publish all exposed ports to the host interfaces
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
--------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -586,20 +871,82 @@ use-cases, like running Docker within Docker.
|
||||
|
||||
docker run -w /path/to/dir/ -i -t ubuntu pwd
|
||||
|
||||
The ``-w`` lets the command being executed inside directory given,
|
||||
here /path/to/dir/. If the path does not exists it is created inside the
|
||||
The ``-w`` lets the command being executed inside directory given,
|
||||
here /path/to/dir/. If the path does not exists it is created inside the
|
||||
container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -v `pwd`:`pwd` -w `pwd` -i -t ubuntu pwd
|
||||
|
||||
The ``-v`` flag mounts the current working directory into the container.
|
||||
The ``-w`` lets the command being executed inside the current
|
||||
The ``-v`` flag mounts the current working directory into the container.
|
||||
The ``-w`` lets the command being executed inside the current
|
||||
working directory, by changing into the directory to the value
|
||||
returned by ``pwd``. So this combination executes the command
|
||||
using the container, but inside the current working directory.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -p 127.0.0.1:80:8080 ubuntu bash
|
||||
|
||||
This binds port ``8080`` of the container to port ``80`` on 127.0.0.1 of the
|
||||
host machine. :ref:`port_redirection` explains in detail how to manipulate ports
|
||||
in Docker.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -expose 80 ubuntu bash
|
||||
|
||||
This exposes port ``80`` of the container for use within a link without
|
||||
publishing the port to the host system's interfaces. :ref:`port_redirection`
|
||||
explains in detail how to manipulate ports in Docker.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -name console -t -i ubuntu bash
|
||||
|
||||
This will create and run a new container with the container name
|
||||
being ``console``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -link /redis:redis -name console ubuntu bash
|
||||
|
||||
The ``-link`` flag will link the container named ``/redis`` into the
|
||||
newly created container with the alias ``redis``. The new container
|
||||
can access the network and environment of the redis container via
|
||||
environment variables. The ``-name`` flag will assign the name ``console``
|
||||
to the newly created container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -volumes-from 777f7dc92da7,ba8c0c54f0f2:ro -i -t ubuntu pwd
|
||||
|
||||
The ``-volumes-from`` flag mounts all the defined volumes from the
|
||||
refrence containers. Containers can be specified by a comma seperated
|
||||
list or by repetitions of the ``-volumes-from`` argument. The container
|
||||
id may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in
|
||||
read-only or read-write mode, respectively. By default, the volumes are mounted
|
||||
in the same mode (rw or ro) as the reference container.
|
||||
|
||||
Known Issues (run -volumes-from)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* :issue:`2702`: "lxc-start: Permission denied - failed to mount"
|
||||
could indicate a permissions problem with AppArmor. Please see the
|
||||
issue for a workaround.
|
||||
|
||||
.. _cli_save:
|
||||
|
||||
``save``
|
||||
|
||||
::
|
||||
|
||||
Usage: docker save image > repository.tar
|
||||
|
||||
Streams a tarred repository to the standard output stream.
|
||||
Contains all parent layers, and all tags + versions.
|
||||
|
||||
.. _cli_search:
|
||||
|
||||
``search``
|
||||
@@ -609,8 +956,11 @@ using the container, but inside the current working directory.
|
||||
|
||||
Usage: docker search TERM
|
||||
|
||||
Searches for the TERM parameter on the Docker index and prints out
|
||||
a list of repositories that match.
|
||||
Search the docker index for images
|
||||
|
||||
-notrunc=false: Don't truncate output
|
||||
-stars=0: Only displays with at least xxx stars
|
||||
-trusted=false: Only show trusted builds
|
||||
|
||||
.. _cli_start:
|
||||
|
||||
@@ -623,6 +973,9 @@ using the container, but inside the current working directory.
|
||||
|
||||
Start a stopped container
|
||||
|
||||
-a=false: Attach container's stdout/stderr and forward all signals to the process
|
||||
-i=false: Attach container's stdin
|
||||
|
||||
.. _cli_stop:
|
||||
|
||||
``stop``
|
||||
@@ -632,10 +985,12 @@ using the container, but inside the current working directory.
|
||||
|
||||
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
|
||||
|
||||
Stop a running container
|
||||
Stop a running container (Send SIGTERM, and then SIGKILL after grace period)
|
||||
|
||||
-t=10: Number of seconds to wait for the container to stop before killing it.
|
||||
|
||||
The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL
|
||||
|
||||
.. _cli_tag:
|
||||
|
||||
``tag``
|
||||
@@ -643,7 +998,7 @@ using the container, but inside the current working directory.
|
||||
|
||||
::
|
||||
|
||||
Usage: docker tag [OPTIONS] IMAGE REPOSITORY [TAG]
|
||||
Usage: docker tag [OPTIONS] IMAGE REPOSITORY[:TAG]
|
||||
|
||||
Tag an image into a repository
|
||||
|
||||
@@ -656,7 +1011,7 @@ using the container, but inside the current working directory.
|
||||
|
||||
::
|
||||
|
||||
Usage: docker top CONTAINER
|
||||
Usage: docker top CONTAINER [ps OPTIONS]
|
||||
|
||||
Lookup the running processes of a container
|
||||
|
||||
@@ -678,6 +1033,3 @@ Show the version of the docker client, daemon, and latest released version.
|
||||
Usage: docker wait [OPTIONS] NAME
|
||||
|
||||
Block until a container stops, then print its exit code.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,11 @@ html_additional_pages = {
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinxcontrib.httpdomain']
|
||||
extensions = ['sphinxcontrib.httpdomain', 'sphinx.ext.extlinks']
|
||||
|
||||
# Configure extlinks
|
||||
extlinks = { 'issue': ('https://github.com/dotcloud/docker/issues/%s',
|
||||
'Issue ') }
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -231,7 +235,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('toctree', 'docker', u'Docker Documentation',
|
||||
('commandline/cli', 'docker', u'Docker Documentation',
|
||||
[u'Team Docker'], 1)
|
||||
]
|
||||
|
||||
|
||||
@@ -5,5 +5,21 @@
|
||||
Contributing to Docker
|
||||
======================
|
||||
|
||||
Want to hack on Docker? Awesome! The repository includes `all the instructions you need to get started <https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md>`_.
|
||||
Want to hack on Docker? Awesome!
|
||||
|
||||
The repository includes `all the instructions you need to get
|
||||
started <https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md>`_.
|
||||
|
||||
The `developer environment Dockerfile
|
||||
<https://github.com/dotcloud/docker/blob/master/Dockerfile>`_
|
||||
specifies the tools and versions used to test and build Docker.
|
||||
|
||||
If you're making changes to the documentation, see the
|
||||
`README.md <https://github.com/dotcloud/docker/blob/master/docs/README.md>`_.
|
||||
|
||||
The `documentation environment Dockerfile
|
||||
<https://github.com/dotcloud/docker/blob/master/docs/Dockerfile>`_
|
||||
specifies the tools and versions used to build the Documentation.
|
||||
|
||||
Further interesting details can be found in the `Packaging hints
|
||||
<https://github.com/dotcloud/docker/blob/master/hack/PACKAGERS.md>`_.
|
||||
|
||||
@@ -56,7 +56,7 @@ To create the Docker binary, run this command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker run -lxc-conf=lxc.aa_profile=unconfined -privileged -v `pwd`:/go/src/github.com/dotcloud/docker docker hack/make.sh binary
|
||||
sudo docker run -privileged -v `pwd`:/go/src/github.com/dotcloud/docker docker hack/make.sh binary
|
||||
|
||||
This will create the Docker binary in ``./bundles/<version>-dev/binary/``
|
||||
|
||||
@@ -64,20 +64,15 @@ This will create the Docker binary in ``./bundles/<version>-dev/binary/``
|
||||
Step 5: Run the Tests
|
||||
---------------------
|
||||
|
||||
To run the Docker test cases you first need to disable `AppArmor <https://wiki.ubuntu.com/AppArmor>`_ using the following commands
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo /etc/init.d/apparmor stop
|
||||
sudo /etc/init.d/apparmor teardown
|
||||
|
||||
To execute the test cases, run this command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker run -lxc-conf=lxc.aa_profile=unconfined -privileged -v `pwd`:/go/src/github.com/dotcloud/docker docker hack/make.sh test
|
||||
sudo docker run -privileged -v `pwd`:/go/src/github.com/dotcloud/docker docker hack/make.sh test
|
||||
|
||||
|
||||
Note: if you're running the tests in vagrant, you need to specify a dns entry in the command: `-dns 8.8.8.8`
|
||||
|
||||
If the test are successful then the tail of the output should look something like this
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -10,7 +10,7 @@ CouchDB Service
|
||||
.. include:: example_header.inc
|
||||
|
||||
Here's an example of using data volumes to share the same data between
|
||||
2 CouchDB containers. This could be used for hot upgrades, testing
|
||||
two CouchDB containers. This could be used for hot upgrades, testing
|
||||
different versions of CouchDB on the same data, etc.
|
||||
|
||||
Create first database
|
||||
@@ -20,28 +20,28 @@ Note that we're marking ``/var/lib/couchdb`` as a data volume.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
COUCH1=$(sudo docker run -d -v /var/lib/couchdb shykes/couchdb:2013-05-03)
|
||||
COUCH1=$(sudo docker run -d -p 5984 -v /var/lib/couchdb shykes/couchdb:2013-05-03)
|
||||
|
||||
Add data to the first database
|
||||
------------------------------
|
||||
|
||||
We're assuming your docker host is reachable at `localhost`. If not,
|
||||
replace `localhost` with the public IP of your docker host.
|
||||
We're assuming your Docker host is reachable at ``localhost``. If not,
|
||||
replace ``localhost`` with the public IP of your Docker host.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
HOST=localhost
|
||||
URL="http://$HOST:$(sudo docker port $COUCH1 5984)/_utils/"
|
||||
URL="http://$HOST:$(sudo docker port $COUCH1 5984 | grep -Po '\d+$')/_utils/"
|
||||
echo "Navigate to $URL in your browser, and use the couch interface to add data"
|
||||
|
||||
Create second database
|
||||
----------------------
|
||||
|
||||
This time, we're requesting shared access to $COUCH1's volumes.
|
||||
This time, we're requesting shared access to ``$COUCH1``'s volumes.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
COUCH2=$(sudo docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
|
||||
COUCH2=$(sudo docker run -d -p 5984 -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
|
||||
|
||||
Browse data on the second database
|
||||
----------------------------------
|
||||
@@ -49,8 +49,8 @@ Browse data on the second database
|
||||
.. code-block:: bash
|
||||
|
||||
HOST=localhost
|
||||
URL="http://$HOST:$(sudo docker port $COUCH2 5984)/_utils/"
|
||||
URL="http://$HOST:$(sudo docker port $COUCH2 5984 | grep -Po '\d+$')/_utils/"
|
||||
echo "Navigate to $URL in your browser. You should see the same data as in the first database"'!'
|
||||
|
||||
Congratulations, you are running 2 Couchdb containers, completely
|
||||
Congratulations, you are now running two Couchdb containers, completely
|
||||
isolated from each other *except* for their data.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
.. note::
|
||||
|
||||
This example assumes you have Docker running in daemon mode. For more information please see :ref:`running_examples`
|
||||
* This example assumes you have Docker running in daemon mode. For
|
||||
more information please see :ref:`running_examples`.
|
||||
* **If you don't like sudo** then see :ref:`dockergroup`
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ Hello World
|
||||
Running the Examples
|
||||
====================
|
||||
|
||||
All the examples assume your machine is running the docker daemon. To
|
||||
run the docker daemon in the background, simply type:
|
||||
All the examples assume your machine is running the ``docker`` daemon. To
|
||||
run the ``docker`` daemon in the background, simply type:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker -d &
|
||||
|
||||
Now you can run docker in client mode: by default all commands will be
|
||||
Now you can run Docker in client mode: by default all commands will be
|
||||
forwarded to the ``docker`` daemon via a protected Unix socket, so you
|
||||
must run as root.
|
||||
must run as the ``root`` or via the ``sudo`` command.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -38,23 +38,24 @@ Hello World
|
||||
|
||||
This is the most basic example available for using Docker.
|
||||
|
||||
Download the base image (named "ubuntu"):
|
||||
Download the base image which is named ``ubuntu``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Download an ubuntu image
|
||||
sudo docker pull ubuntu
|
||||
|
||||
Alternatively to the *ubuntu* image, you can select *busybox*, a bare
|
||||
Alternatively to the ``ubuntu`` image, you can select ``busybox``, a bare
|
||||
minimal Linux system. The images are retrieved from the Docker
|
||||
repository.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#run a simple echo command, that will echo hello world back to the console over standard out.
|
||||
sudo docker run ubuntu /bin/echo hello world
|
||||
|
||||
This command will run a simple ``echo`` command, that will echo ``hello world`` back to the console over standard out.
|
||||
|
||||
**Explanation:**
|
||||
|
||||
- **"sudo"** execute the following commands as user *root*
|
||||
@@ -100,9 +101,9 @@ we stop it.
|
||||
CONTAINER_ID=$(sudo docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done")
|
||||
|
||||
We are going to run a simple hello world daemon in a new container
|
||||
made from the *ubuntu* image.
|
||||
made from the ``ubuntu`` image.
|
||||
|
||||
- **"docker run -d "** run a command in a new container. We pass "-d"
|
||||
- **"sudo docker run -d "** run a command in a new container. We pass "-d"
|
||||
so it runs as a daemon.
|
||||
- **"ubuntu"** is the image we want to run the command inside of.
|
||||
- **"/bin/sh -c"** is the command we want to run in the container
|
||||
@@ -126,10 +127,12 @@ Check the logs make sure it is working correctly.
|
||||
|
||||
sudo docker attach $CONTAINER_ID
|
||||
|
||||
Attach to the container to see the results in realtime.
|
||||
Attach to the container to see the results in real-time.
|
||||
|
||||
- **"docker attach**" This will allow us to attach to a background
|
||||
process to see what is going on.
|
||||
- **"-sig-proxy=true"** Proxify all received signal to the process
|
||||
(even in non-tty mode)
|
||||
- **$CONTAINER_ID** The Id of the container we want to attach too.
|
||||
|
||||
Exit from the container attachment by pressing Control-C.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
:title: Docker Examples
|
||||
:description: Examples on how to use Docker
|
||||
:keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples, postgresql
|
||||
:keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples, postgresql, link
|
||||
|
||||
|
||||
.. _example_list:
|
||||
@@ -10,7 +10,7 @@ Examples
|
||||
|
||||
Here are some examples of how to use Docker to create running
|
||||
processes, starting from a very simple *Hello World* and progressing
|
||||
to more substantial services like you might find in production.
|
||||
to more substantial services like those which you might find in production.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
@@ -10,8 +10,8 @@ Building an Image with MongoDB
|
||||
.. include:: example_header.inc
|
||||
|
||||
The goal of this example is to show how you can build your own
|
||||
docker images with MongoDB preinstalled. We will do that by
|
||||
constructing a Dockerfile that downloads a base image, adds an
|
||||
Docker images with MongoDB pre-installed. We will do that by
|
||||
constructing a ``Dockerfile`` that downloads a base image, adds an
|
||||
apt source and installs the database software on Ubuntu.
|
||||
|
||||
Creating a ``Dockerfile``
|
||||
@@ -41,7 +41,7 @@ Since we want to be running the latest version of MongoDB we'll need to add the
|
||||
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/10gen.list
|
||||
|
||||
Then, we don't want Ubuntu to complain about init not being available so we'll
|
||||
divert /sbin/initctl to /bin/true so it thinks everything is working.
|
||||
divert ``/sbin/initctl`` to ``/bin/true`` so it thinks everything is working.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -65,8 +65,8 @@ run without needing to provide a special configuration file)
|
||||
# Create the MongoDB data directory
|
||||
RUN mkdir -p /data/db
|
||||
|
||||
Finally, we'll expose the standard port that MongoDB runs on (27107) as well as
|
||||
define an ENTRYPOINT for the container.
|
||||
Finally, we'll expose the standard port that MongoDB runs on, 27107, as well as
|
||||
define an ``ENTRYPOINT`` instruction for the container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -78,7 +78,7 @@ run all of the commands.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker build -t <yourname>/mongodb .
|
||||
sudo docker build -t <yourname>/mongodb .
|
||||
|
||||
Now you should be able to run ``mongod`` as a daemon and be able to connect on
|
||||
the local port!
|
||||
@@ -86,13 +86,13 @@ the local port!
|
||||
.. code-block:: bash
|
||||
|
||||
# Regular style
|
||||
MONGO_ID=$(docker run -d <yourname>/mongodb)
|
||||
MONGO_ID=$(sudo docker run -d <yourname>/mongodb)
|
||||
|
||||
# Lean and mean
|
||||
MONGO_ID=$(docker run -d <yourname>/mongodb --noprealloc --smallfiles)
|
||||
MONGO_ID=$(sudo docker run -d <yourname>/mongodb --noprealloc --smallfiles)
|
||||
|
||||
# Check the logs out
|
||||
docker logs $MONGO_ID
|
||||
sudo docker logs $MONGO_ID
|
||||
|
||||
# Connect and play around
|
||||
mongo --port <port you get from `docker ps`>
|
||||
|
||||
@@ -10,7 +10,7 @@ Node.js Web App
|
||||
.. include:: example_header.inc
|
||||
|
||||
The goal of this example is to show you how you can build your own
|
||||
docker images from a parent image using a ``Dockerfile`` . We will do
|
||||
Docker images from a parent image using a ``Dockerfile`` . We will do
|
||||
that by making a simple Node.js hello world web application running on
|
||||
CentOS. You can get the full source code at
|
||||
https://github.com/gasi/docker-node-hello.
|
||||
@@ -55,7 +55,7 @@ Then, create an ``index.js`` file that defines a web app using the
|
||||
|
||||
|
||||
In the next steps, we’ll look at how you can run this app inside a CentOS
|
||||
container using docker. First, you’ll need to build a docker image of your app.
|
||||
container using Docker. First, you’ll need to build a Docker image of your app.
|
||||
|
||||
Creating a ``Dockerfile``
|
||||
+++++++++++++++++++++++++
|
||||
@@ -67,8 +67,8 @@ Create an empty file called ``Dockerfile``:
|
||||
touch Dockerfile
|
||||
|
||||
Open the ``Dockerfile`` in your favorite text editor and add the following line
|
||||
that defines the version of docker the image requires to build
|
||||
(this example uses docker 0.3.4):
|
||||
that defines the version of Docker the image requires to build
|
||||
(this example uses Docker 0.3.4):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -76,7 +76,7 @@ that defines the version of docker the image requires to build
|
||||
|
||||
Next, define the parent image you want to use to build your own image on top of.
|
||||
Here, we’ll use `CentOS <https://index.docker.io/_/centos/>`_ (tag: ``6.4``)
|
||||
available on the `docker index`_:
|
||||
available on the `Docker index`_:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -95,23 +95,23 @@ To install the right package for CentOS, we’ll use the instructions from the
|
||||
# Install Node.js and npm
|
||||
RUN yum install -y npm
|
||||
|
||||
To bundle your app’s source code inside the docker image, use the ``ADD``
|
||||
command:
|
||||
To bundle your app’s source code inside the Docker image, use the ``ADD``
|
||||
instruction:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Bundle app source
|
||||
ADD . /src
|
||||
|
||||
Install your app dependencies using npm:
|
||||
Install your app dependencies using the ``npm`` binary:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Install app dependencies
|
||||
RUN cd /src; npm install
|
||||
|
||||
Your app binds to port ``8080`` so you’ll use the ``EXPOSE`` command
|
||||
to have it mapped by the docker daemon:
|
||||
Your app binds to port ``8080`` so you’ll use the ``EXPOSE`` instruction
|
||||
to have it mapped by the ``docker`` daemon:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -152,7 +152,7 @@ Building your image
|
||||
+++++++++++++++++++
|
||||
|
||||
Go to the directory that has your ``Dockerfile`` and run the following
|
||||
command to build a docker image. The ``-t`` flag let’s you tag your
|
||||
command to build a Docker image. The ``-t`` flag let’s you tag your
|
||||
image so it’s easier to find later using the ``docker images``
|
||||
command:
|
||||
|
||||
@@ -160,7 +160,7 @@ command:
|
||||
|
||||
sudo docker build -t <your username>/centos-node-hello .
|
||||
|
||||
Your image will now be listed by docker:
|
||||
Your image will now be listed by Docker:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -176,11 +176,11 @@ Run the image
|
||||
+++++++++++++
|
||||
|
||||
Running your image with ``-d`` runs the container in detached mode, leaving the
|
||||
container running in the background. Run the image you previously built:
|
||||
container running in the background. The ``-p`` flag redirects a public port to a private port in the container. Run the image you previously built:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker run -d <your username>/centos-node-hello
|
||||
sudo docker run -p 49160:8080 -d <your username>/centos-node-hello
|
||||
|
||||
Print the output of your app:
|
||||
|
||||
@@ -199,17 +199,17 @@ Print the output of your app:
|
||||
Test
|
||||
++++
|
||||
|
||||
To test your app, get the the port of your app that docker mapped:
|
||||
To test your app, get the the port of your app that Docker mapped:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps
|
||||
sudo docker ps
|
||||
|
||||
> # Example
|
||||
> ID IMAGE COMMAND ... PORTS
|
||||
> ecce33b30ebf gasi/centos-node-hello:latest node /src/index.js 49160->8080
|
||||
|
||||
In the example above, docker mapped the ``8080`` port of the container to
|
||||
In the example above, Docker mapped the ``8080`` port of the container to
|
||||
``49160``.
|
||||
|
||||
Now you can call your app using ``curl`` (install if needed via:
|
||||
@@ -229,7 +229,7 @@ Now you can call your app using ``curl`` (install if needed via:
|
||||
> Hello World
|
||||
|
||||
We hope this tutorial helped you get up and running with Node.js and
|
||||
CentOS on docker. You can get the full source code at
|
||||
CentOS on Docker. You can get the full source code at
|
||||
https://github.com/gasi/docker-node-hello.
|
||||
|
||||
Continue to :ref:`running_redis_service`.
|
||||
|
||||
@@ -13,7 +13,7 @@ PostgreSQL Service
|
||||
|
||||
.. note::
|
||||
|
||||
As of version 0.5.2, docker requires root privileges to run.
|
||||
As of version 0.5.2, Docker requires root privileges to run.
|
||||
You have to either manually adjust your system configuration (permissions on
|
||||
/var/run/docker.sock or sudo config), or prefix `docker` with `sudo`. Check
|
||||
`this thread`_ for details.
|
||||
@@ -24,8 +24,7 @@ PostgreSQL Service
|
||||
Installing PostgreSQL on Docker
|
||||
-------------------------------
|
||||
|
||||
For clarity I won't be showing commands output.
|
||||
|
||||
For clarity I won't be showing command output.
|
||||
|
||||
Run an interactive shell in Docker container.
|
||||
|
||||
@@ -62,7 +61,7 @@ Finally, install PostgreSQL 9.2
|
||||
|
||||
Now, create a PostgreSQL superuser role that can create databases and
|
||||
other roles. Following Vagrant's convention the role will be named
|
||||
`docker` with `docker` password assigned to it.
|
||||
``docker`` with ``docker`` password assigned to it.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -108,7 +107,7 @@ Bash prompt; you can also locate it using ``docker ps -a``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker commit <container_id> <your username>/postgresql
|
||||
sudo docker commit <container_id> <your username>/postgresql
|
||||
|
||||
Finally, run PostgreSQL server via ``docker``.
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ Python Web App
|
||||
.. include:: example_header.inc
|
||||
|
||||
The goal of this example is to show you how you can author your own
|
||||
docker images using a parent image, making changes to it, and then
|
||||
Docker images using a parent image, making changes to it, and then
|
||||
saving the results as a new image. We will do that by making a simple
|
||||
hello flask web application image.
|
||||
hello Flask web application image.
|
||||
|
||||
**Steps:**
|
||||
|
||||
@@ -20,36 +20,37 @@ hello flask web application image.
|
||||
|
||||
sudo docker pull shykes/pybuilder
|
||||
|
||||
We are downloading the "shykes/pybuilder" docker image
|
||||
We are downloading the ``shykes/pybuilder`` Docker image
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
URL=http://github.com/shykes/helloflask/archive/master.tar.gz
|
||||
|
||||
We set a URL variable that points to a tarball of a simple helloflask web app
|
||||
We set a ``URL`` variable that points to a tarball of a simple helloflask web app
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
BUILD_JOB=$(sudo docker run -d -t shykes/pybuilder:latest /usr/local/bin/buildapp $URL)
|
||||
|
||||
Inside of the "shykes/pybuilder" image there is a command called
|
||||
buildapp, we are running that command and passing the $URL variable
|
||||
Inside of the ``shykes/pybuilder`` image there is a command called
|
||||
``buildapp``, we are running that command and passing the ``$URL`` variable
|
||||
from step 2 to it, and running the whole thing inside of a new
|
||||
container. BUILD_JOB will be set with the new container_id.
|
||||
container. The ``BUILD_JOB`` environment variable will be set with the new container ID.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker attach $BUILD_JOB
|
||||
sudo docker attach -sig-proxy=false $BUILD_JOB
|
||||
[...]
|
||||
|
||||
While this container is running, we can attach to the new container to
|
||||
see what is going on. Ctrl-C to disconnect.
|
||||
see what is going on. The flag ``-sig-proxy`` set as ``false`` allows you to connect and
|
||||
disconnect (Ctrl-C) to it without stopping the container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker ps -a
|
||||
|
||||
List all docker containers. If this container has already finished
|
||||
|
||||
List all Docker containers. If this container has already finished
|
||||
running, it will still be listed here.
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -57,8 +58,8 @@ running, it will still be listed here.
|
||||
BUILD_IMG=$(sudo docker commit $BUILD_JOB _/builds/github.com/shykes/helloflask/master)
|
||||
|
||||
Save the changes we just made in the container to a new image called
|
||||
``_/builds/github.com/hykes/helloflask/master`` and save the image id in
|
||||
the BUILD_IMG variable name.
|
||||
``_/builds/github.com/hykes/helloflask/master`` and save the image ID in
|
||||
the ``BUILD_IMG`` variable name.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -72,24 +73,24 @@ the BUILD_IMG variable name.
|
||||
- **/usr/local/bin/runapp** is the command which starts the web app.
|
||||
|
||||
Use the new image we just created and create a new container with
|
||||
network port 5000, and return the container id and store in the
|
||||
WEB_WORKER variable.
|
||||
network port 5000, and return the container ID and store in the
|
||||
``WEB_WORKER`` variable.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker logs $WEB_WORKER
|
||||
* Running on http://0.0.0.0:5000/
|
||||
|
||||
View the logs for the new container using the WEB_WORKER variable, and
|
||||
if everything worked as planned you should see the line "Running on
|
||||
http://0.0.0.0:5000/" in the log output.
|
||||
View the logs for the new container using the ``WEB_WORKER`` variable, and
|
||||
if everything worked as planned you should see the line ``Running on
|
||||
http://0.0.0.0:5000/`` in the log output.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
WEB_PORT=$(sudo docker port $WEB_WORKER 5000)
|
||||
WEB_PORT=$(sudo docker port $WEB_WORKER 5000 | awk -F: '{ print $2 }')
|
||||
|
||||
Look up the public-facing port which is NAT-ed. Find the private port
|
||||
used by the container and store it inside of the WEB_PORT variable.
|
||||
used by the container and store it inside of the ``WEB_PORT`` variable.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -97,8 +98,8 @@ used by the container and store it inside of the WEB_PORT variable.
|
||||
curl http://127.0.0.1:$WEB_PORT
|
||||
Hello world!
|
||||
|
||||
Access the web app using curl. If everything worked as planned you
|
||||
should see the line "Hello world!" inside of your console.
|
||||
Access the web app using the ``curl`` binary. If everything worked as planned you
|
||||
should see the line ``Hello world!`` inside of your console.
|
||||
|
||||
**Video:**
|
||||
|
||||
|
||||
@@ -9,74 +9,93 @@ Redis Service
|
||||
|
||||
.. include:: example_header.inc
|
||||
|
||||
Very simple, no frills, redis service.
|
||||
Very simple, no frills, Redis service attached to a web application using a link.
|
||||
|
||||
Open a docker container
|
||||
-----------------------
|
||||
Create a docker container for Redis
|
||||
-----------------------------------
|
||||
|
||||
Firstly, we create a ``Dockerfile`` for our new Redis image.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker run -i -t ubuntu /bin/bash
|
||||
FROM ubuntu:12.10
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install redis-server
|
||||
EXPOSE 6379
|
||||
ENTRYPOINT ["/usr/bin/redis-server"]
|
||||
|
||||
Building your image
|
||||
-------------------
|
||||
|
||||
Update your Docker container, install the Redis server. Once
|
||||
installed, exit out of the Docker container.
|
||||
Next we build an image from our ``Dockerfile``. Replace ``<your username>``
|
||||
with your own user name.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
apt-get update
|
||||
apt-get install redis-server
|
||||
exit
|
||||
|
||||
Snapshot the installation
|
||||
-------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps -a # grab the container id (this will be the first one in the list)
|
||||
docker commit <container_id> <your username>/redis
|
||||
sudo docker build -t <your username>/redis .
|
||||
|
||||
Run the service
|
||||
---------------
|
||||
|
||||
Running the service with `-d` runs the container in detached mode, leaving the
|
||||
container running in the background. Use your snapshot.
|
||||
Use the image we've just created and name your container ``redis``.
|
||||
|
||||
Running the service with ``-d`` runs the container in detached mode, leaving the
|
||||
container running in the background.
|
||||
|
||||
Importantly, we're not exposing any ports on our container. Instead we're going to
|
||||
use a container link to provide access to our Redis database.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker run -d -p 6379 <your username>/redis /usr/bin/redis-server
|
||||
sudo docker run -name redis -d <your username>/redis
|
||||
|
||||
Test 1
|
||||
++++++
|
||||
Create your web application container
|
||||
-------------------------------------
|
||||
|
||||
Connect to the container with the redis-cli.
|
||||
Next we can create a container for our application. We're going to use the ``-link``
|
||||
flag to create a link to the ``redis`` container we've just created with an alias of
|
||||
``db``. This will create a secure tunnel to the ``redis`` container and expose the
|
||||
Redis instance running inside that container to only this container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker ps # grab the new container id
|
||||
sudo docker inspect <container_id> # grab the ipaddress of the container
|
||||
redis-cli -h <ipaddress> -p 6379
|
||||
redis 10.0.3.32:6379> set docker awesome
|
||||
sudo docker run -link redis:db -i -t ubuntu:12.10 /bin/bash
|
||||
|
||||
Once inside our freshly created container we need to install Redis to get the
|
||||
``redis-cli`` binary to test our connection.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
apt-get update
|
||||
apt-get -y install redis-server
|
||||
service redis-server stop
|
||||
|
||||
Now we can test the connection. Firstly, let's look at the available environmental
|
||||
variables in our web application container. We can use these to get the IP and port
|
||||
of our ``redis`` container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
env
|
||||
. . .
|
||||
DB_NAME=/violet_wolf/db
|
||||
DB_PORT_6379_TCP_PORT=6379
|
||||
DB_PORT=tcp://172.17.0.33:6379
|
||||
DB_PORT_6379_TCP=tcp://172.17.0.33:6379
|
||||
DB_PORT_6379_TCP_ADDR=172.17.0.33
|
||||
DB_PORT_6379_TCP_PROTO=tcp
|
||||
|
||||
We can see that we've got a small list of environment variables prefixed with ``DB``.
|
||||
The ``DB`` comes from the link alias specified when we launched the container. Let's use
|
||||
the ``DB_PORT_6379_TCP_ADDR`` variable to connect to our Redis container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
redis-cli -h $DB_PORT_6379_TCP_ADDR
|
||||
redis 172.17.0.33:6379>
|
||||
redis 172.17.0.33:6379> set docker awesome
|
||||
OK
|
||||
redis 10.0.3.32:6379> get docker
|
||||
redis 172.17.0.33:6379> get docker
|
||||
"awesome"
|
||||
redis 10.0.3.32:6379> exit
|
||||
redis 172.17.0.33:6379> exit
|
||||
|
||||
Test 2
|
||||
++++++
|
||||
We could easily use this or other environment variables in our web application to make a
|
||||
connection to our ``redis`` container.
|
||||
|
||||
Connect to the host os with the redis-cli.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker ps # grab the new container id
|
||||
sudo docker port <container_id> 6379 # grab the external port
|
||||
ip addr show # grab the host ip address
|
||||
redis-cli -h <host ipaddress> -p <external port>
|
||||
redis 192.168.0.1:49153> set docker awesome
|
||||
OK
|
||||
redis 192.168.0.1:49153> get docker
|
||||
"awesome"
|
||||
redis 192.168.0.1:49153> exit
|
||||
|
||||
@@ -107,7 +107,7 @@ Create a ``supervisord`` configuration file
|
||||
+++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
Create an empty file called ``supervisord.conf``. Make sure it's at the same
|
||||
level as your ``Dockerfile``:
|
||||
directory level as your ``Dockerfile``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ SSH Daemon Service
|
||||
|
||||
**Video:**
|
||||
|
||||
I've create a little screencast to show how to create a sshd service
|
||||
I've created a little screencast to show how to create an SSHd service
|
||||
and connect to it. It is something like 11 minutes and not entirely
|
||||
smooth, but gives you a good idea.
|
||||
smooth, but it gives you a good idea.
|
||||
|
||||
.. note::
|
||||
This screencast was created before ``docker`` version 0.5.2, so the
|
||||
This screencast was created before Docker version 0.5.2, so the
|
||||
daemon is unprotected and available via a TCP port. When you run
|
||||
through the same steps in a newer version of ``docker``, you will
|
||||
through the same steps in a newer version of Docker, you will
|
||||
need to add ``sudo`` in front of each ``docker`` command in order
|
||||
to reach the daemon over its protected Unix socket.
|
||||
|
||||
@@ -29,13 +29,14 @@ smooth, but gives you a good idea.
|
||||
<iframe width="800" height="400" src="http://ascii.io/a/2637/raw" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
You can also get this sshd container by using
|
||||
::
|
||||
You can also get this sshd container by using:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker pull dhrp/sshd
|
||||
|
||||
|
||||
The password is 'screencast'
|
||||
The password is ``screencast``.
|
||||
|
||||
**Video's Transcription:**
|
||||
|
||||
|
||||
@@ -22,12 +22,10 @@ Amazon QuickStart
|
||||
|
||||
1. **Choose an image:**
|
||||
|
||||
* Open http://cloud-images.ubuntu.com/locator/ec2/
|
||||
* Enter ``amd64 precise`` in the search field (it will search as you
|
||||
type)
|
||||
* Pick an image by clicking on the image name. *An EBS-enabled
|
||||
image will let you use a t1.micro instance.* Clicking on the image
|
||||
name will take you to your AWS Console.
|
||||
* Launch the `Create Instance Wizard` <https://console.aws.amazon.com/ec2/v2/home?#LaunchInstanceWizard:> menu on your AWS Console
|
||||
* Select "Community AMIs" option and serch for ``amd64 precise`` (click enter to search)
|
||||
* If you choose a EBS enabled AMI you will be able to launch a `t1.micro` instance (more info on `pricing` <http://aws.amazon.com/en/ec2/pricing/> )
|
||||
* When you click select you'll be taken to the instance setup, and you're one click away from having your Ubuntu VM up and running.
|
||||
|
||||
2. **Tell CloudInit to install Docker:**
|
||||
|
||||
@@ -102,26 +100,45 @@ Docker that way too. Vagrant 1.1 or higher is required.
|
||||
we need to set them there first. Make sure you have everything on
|
||||
amazon aws setup so you can (manually) deploy a new image to EC2.
|
||||
|
||||
Note that where possible these variables are the same as those honored by
|
||||
the ec2 api tools.
|
||||
::
|
||||
|
||||
export AWS_ACCESS_KEY_ID=xxx
|
||||
export AWS_SECRET_ACCESS_KEY=xxx
|
||||
export AWS_ACCESS_KEY=xxx
|
||||
export AWS_SECRET_KEY=xxx
|
||||
export AWS_KEYPAIR_NAME=xxx
|
||||
export AWS_SSH_PRIVKEY=xxx
|
||||
export SSH_PRIVKEY_PATH=xxx
|
||||
|
||||
The environment variables are:
|
||||
export BOX_NAME=xxx
|
||||
export AWS_REGION=xxx
|
||||
export AWS_AMI=xxx
|
||||
export AWS_INSTANCE_TYPE=xxx
|
||||
|
||||
* ``AWS_ACCESS_KEY_ID`` - The API key used to make requests to AWS
|
||||
* ``AWS_SECRET_ACCESS_KEY`` - The secret key to make AWS API requests
|
||||
The required environment variables are:
|
||||
|
||||
* ``AWS_ACCESS_KEY`` - The API key used to make requests to AWS
|
||||
* ``AWS_SECRET_KEY`` - The secret key to make AWS API requests
|
||||
* ``AWS_KEYPAIR_NAME`` - The name of the keypair used for this EC2 instance
|
||||
* ``AWS_SSH_PRIVKEY`` - The path to the private key for the named
|
||||
* ``SSH_PRIVKEY_PATH`` - The path to the private key for the named
|
||||
keypair, for example ``~/.ssh/docker.pem``
|
||||
|
||||
There are a number of optional environment variables:
|
||||
|
||||
* ``BOX_NAME`` - The name of the vagrant box to use. Defaults to
|
||||
``ubuntu``.
|
||||
* ``AWS_REGION`` - The aws region to spawn the vm in. Defaults to
|
||||
``us-east-1``.
|
||||
* ``AWS_AMI`` - The aws AMI to start with as a base. This must be
|
||||
be an ubuntu 12.04 precise image. You must change this value if
|
||||
``AWS_REGION`` is set to a value other than ``us-east-1``.
|
||||
This is because AMIs are region specific. Defaults to ``ami-69f5a900``.
|
||||
* ``AWS_INSTANCE_TYPE`` - The aws instance type. Defaults to ``t1.micro``.
|
||||
|
||||
You can check if they are set correctly by doing something like
|
||||
|
||||
::
|
||||
|
||||
echo $AWS_ACCESS_KEY_ID
|
||||
echo $AWS_ACCESS_KEY
|
||||
|
||||
6. Do the magic!
|
||||
|
||||
|
||||
@@ -19,11 +19,12 @@ Contents:
|
||||
|
||||
ubuntulinux
|
||||
binaries
|
||||
security
|
||||
upgrading
|
||||
kernel
|
||||
vagrant
|
||||
windows
|
||||
amazon
|
||||
rackspace
|
||||
archlinux
|
||||
gentoolinux
|
||||
upgrading
|
||||
kernel
|
||||
|
||||
@@ -25,6 +25,7 @@ If you cannot or do not want to use the "official" kernels,
|
||||
here is some technical background about the features (both optional and
|
||||
mandatory) that docker needs to run successfully.
|
||||
|
||||
|
||||
Linux version 3.8 or above
|
||||
--------------------------
|
||||
|
||||
@@ -39,6 +40,15 @@ The symptoms include:
|
||||
- kernel crash causing the machine to freeze for a few minutes, or even
|
||||
completely.
|
||||
|
||||
Additionally, kernels prior 3.4 did not implement ``reboot_pid_ns``,
|
||||
which means that the ``reboot()`` syscall could reboot the host machine,
|
||||
instead of terminating the container. To work around that problem,
|
||||
LXC userland tools (since version 0.8) automatically drop the ``SYS_BOOT``
|
||||
capability when necessary. Still, if you run a pre-3.4 kernel with pre-0.8
|
||||
LXC tools, be aware that containers can reboot the whole host! This is
|
||||
not something that Docker wants to address in the short term, since you
|
||||
shouldn't use kernels prior 3.8 with Docker anyway.
|
||||
|
||||
While it is still possible to use older kernels for development, it is
|
||||
really not advised to do so.
|
||||
|
||||
@@ -69,7 +79,7 @@ to run LXC containers. Note that 2.6.32 has some documented issues regarding
|
||||
network namespace setup and teardown; those issues are not a risk if you
|
||||
run containers in a private environment, but can lead to denial-of-service
|
||||
attacks if you want to run untrusted code in your containers. For more details,
|
||||
see `[LP#720095 <https://bugs.launchpad.net/ubuntu/+source/linux/+bug/720095>`_.
|
||||
see `LP#720095 <https://bugs.launchpad.net/ubuntu/+source/linux/+bug/720095>`_.
|
||||
|
||||
Kernels 2.6.38, and every version since 3.2, have been deployed successfully
|
||||
to run containerized production workloads. Feature-wise, there is no huge
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
:title: Docker Security
|
||||
:description: Review of the Docker Daemon attack surface
|
||||
:keywords: Docker, Docker documentation, security
|
||||
|
||||
.. _dockersecurity:
|
||||
|
||||
Docker Security
|
||||
===============
|
||||
|
||||
*Adapted from* `Containers & Docker: How Secure are They? <blogsecurity>`_
|
||||
|
||||
There are three major areas to consider when reviewing Docker security:
|
||||
|
||||
* the intrinsic security of containers, as implemented by kernel
|
||||
namespaces and cgroups;
|
||||
* the attack surface of the Docker daemon itself;
|
||||
* the "hardening" security features of the kernel and how they
|
||||
interact with containers.
|
||||
|
||||
Kernel Namespaces
|
||||
-----------------
|
||||
|
||||
Docker containers are essentially LXC containers, and they come with
|
||||
the same security features. When you start a container with ``docker
|
||||
run``, behind the scenes Docker uses ``lxc-start`` to execute the
|
||||
Docker container. This creates a set of namespaces and control groups
|
||||
for the container. Those namespaces and control groups are not created
|
||||
by Docker itself, but by ``lxc-start``. This means that as the LXC
|
||||
userland tools evolve (and provide additional namespaces and isolation
|
||||
features), Docker will automatically make use of them.
|
||||
|
||||
**Namespaces provide the first and most straightforward form of
|
||||
isolation**: processes running within a container cannot see, and even
|
||||
less affect, processes running in another container, or in the host
|
||||
system.
|
||||
|
||||
**Each container also gets its own network stack**, meaning that a
|
||||
container doesn’t get a privileged access to the sockets or interfaces
|
||||
of another container. Of course, if the host system is setup
|
||||
accordingly, containers can interact with each other through their
|
||||
respective network interfaces — just like they can interact with
|
||||
external hosts. When you specify public ports for your containers or
|
||||
use :ref:`links <working_with_links_names>` then IP traffic is allowed
|
||||
between containers. They can ping each other, send/receive UDP
|
||||
packets, and establish TCP connections, but that can be restricted if
|
||||
necessary. From a network architecture point of view, all containers
|
||||
on a given Docker host are sitting on bridge interfaces. This means
|
||||
that they are just like physical machines connected through a common
|
||||
Ethernet switch; no more, no less.
|
||||
|
||||
How mature is the code providing kernel namespaces and private
|
||||
networking? Kernel namespaces were introduced `between kernel version
|
||||
2.6.15 and 2.6.26
|
||||
<http://lxc.sourceforge.net/index.php/about/kernel-namespaces/>`_. This
|
||||
means that since July 2008 (date of the 2.6.26 release, now 5 years
|
||||
ago), namespace code has been exercised and scrutinized on a large
|
||||
number of production systems. And there is more: the design and
|
||||
inspiration for the namespaces code are even older. Namespaces are
|
||||
actually an effort to reimplement the features of `OpenVZ
|
||||
<http://en.wikipedia.org/wiki/OpenVZ>`_ in such a way that they could
|
||||
be merged within the mainstream kernel. And OpenVZ was initially
|
||||
released in 2005, so both the design and the implementation are
|
||||
pretty mature.
|
||||
|
||||
Control Groups
|
||||
--------------
|
||||
|
||||
Control Groups are the other key component of Linux Containers. They
|
||||
implement resource accounting and limiting. They provide a lot of very
|
||||
useful metrics, but they also help to ensure that each container gets
|
||||
its fair share of memory, CPU, disk I/O; and, more importantly, that a
|
||||
single container cannot bring the system down by exhausting one of
|
||||
those resources.
|
||||
|
||||
So while they do not play a role in preventing one container from
|
||||
accessing or affecting the data and processes of another container,
|
||||
they are essential to fend off some denial-of-service attacks. They
|
||||
are particularly important on multi-tenant platforms, like public and
|
||||
private PaaS, to guarantee a consistent uptime (and performance) even
|
||||
when some applications start to misbehave.
|
||||
|
||||
Control Groups have been around for a while as well: the code was
|
||||
started in 2006, and initially merged in kernel 2.6.24.
|
||||
|
||||
Docker Daemon Attack Surface
|
||||
----------------------------
|
||||
|
||||
Running containers (and applications) with Docker implies running the
|
||||
Docker daemon. This daemon currently requires root privileges, and you
|
||||
should therefore be aware of some important details.
|
||||
|
||||
First of all, **only trusted users should be allowed to control your
|
||||
Docker daemon**. This is a direct consequence of some powerful Docker
|
||||
features. Specifically, Docker allows you to share a directory between
|
||||
the Docker host and a guest container; and it allows you to do so
|
||||
without limiting the access rights of the container. This means that
|
||||
you can start a container where the ``/host`` directory will be the
|
||||
``/`` directory on your host; and the container will be able to alter
|
||||
your host filesystem without any restriction. This sounds crazy? Well,
|
||||
you have to know that **all virtualization systems allowing filesystem
|
||||
resource sharing behave the same way**. Nothing prevents you from
|
||||
sharing your root filesystem (or even your root block device) with a
|
||||
virtual machine.
|
||||
|
||||
This has a strong security implication: if you instrument Docker from
|
||||
e.g. a web server to provision containers through an API, you should
|
||||
be even more careful than usual with parameter checking, to make sure
|
||||
that a malicious user cannot pass crafted parameters causing Docker to
|
||||
create arbitrary containers.
|
||||
|
||||
For this reason, the REST API endpoint (used by the Docker CLI to
|
||||
communicate with the Docker daemon) changed in Docker 0.5.2, and now
|
||||
uses a UNIX socket instead of a TCP socket bound on 127.0.0.1 (the
|
||||
latter being prone to cross-site-scripting attacks if you happen to
|
||||
run Docker directly on your local machine, outside of a VM). You can
|
||||
then use traditional UNIX permission checks to limit access to the
|
||||
control socket.
|
||||
|
||||
You can also expose the REST API over HTTP if you explicitly decide
|
||||
so. However, if you do that, being aware of the abovementioned
|
||||
security implication, you should ensure that it will be reachable
|
||||
only from a trusted network or VPN; or protected with e.g. ``stunnel``
|
||||
and client SSL certificates.
|
||||
|
||||
Recent improvements in Linux namespaces will soon allow to run
|
||||
full-featured containers without root privileges, thanks to the new
|
||||
user namespace. This is covered in detail `here
|
||||
<http://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/>`_. Moreover,
|
||||
this will solve the problem caused by sharing filesystems between host
|
||||
and guest, since the user namespace allows users within containers
|
||||
(including the root user) to be mapped to other users in the host
|
||||
system.
|
||||
|
||||
The end goal for Docker is therefore to implement two additional
|
||||
security improvements:
|
||||
|
||||
* map the root user of a container to a non-root user of the Docker
|
||||
host, to mitigate the effects of a container-to-host privilege
|
||||
escalation;
|
||||
* allow the Docker daemon to run without root privileges, and delegate
|
||||
operations requiring those privileges to well-audited sub-processes,
|
||||
each with its own (very limited) scope: virtual network setup,
|
||||
filesystem management, etc.
|
||||
|
||||
Finally, if you run Docker on a server, it is recommended to run
|
||||
exclusively Docker in the server, and move all other services within
|
||||
containers controlled by Docker. Of course, it is fine to keep your
|
||||
favorite admin tools (probably at least an SSH server), as well as
|
||||
existing monitoring/supervision processes (e.g. NRPE, collectd, etc).
|
||||
|
||||
Linux Kernel Capabilities
|
||||
-------------------------
|
||||
|
||||
By default, Docker starts containers with a very restricted set of
|
||||
capabilities. What does that mean?
|
||||
|
||||
Capabilities turn the binary "root/non-root" dichotomy into a
|
||||
fine-grained access control system. Processes (like web servers) that
|
||||
just need to bind on a port below 1024 do not have to run as root:
|
||||
they can just be granted the ``net_bind_service`` capability
|
||||
instead. And there are many other capabilities, for almost all the
|
||||
specific areas where root privileges are usually needed.
|
||||
|
||||
This means a lot for container security; let’s see why!
|
||||
|
||||
Your average server (bare metal or virtual machine) needs to run a
|
||||
bunch of processes as root. Those typically include SSH, cron,
|
||||
syslogd; hardware management tools (to e.g. load modules), network
|
||||
configuration tools (to handle e.g. DHCP, WPA, or VPNs), and much
|
||||
more. A container is very different, because almost all of those tasks
|
||||
are handled by the infrastructure around the container:
|
||||
|
||||
* SSH access will typically be managed by a single server running in
|
||||
the Docker host;
|
||||
* ``cron``, when necessary, should run as a user process, dedicated
|
||||
and tailored for the app that needs its scheduling service, rather
|
||||
than as a platform-wide facility;
|
||||
* log management will also typically be handed to Docker, or by
|
||||
third-party services like Loggly or Splunk;
|
||||
* hardware management is irrelevant, meaning that you never need to
|
||||
run ``udevd`` or equivalent daemons within containers;
|
||||
* network management happens outside of the containers, enforcing
|
||||
separation of concerns as much as possible, meaning that a container
|
||||
should never need to perform ``ifconfig``, ``route``, or ip commands
|
||||
(except when a container is specifically engineered to behave like a
|
||||
router or firewall, of course).
|
||||
|
||||
This means that in most cases, containers will not need "real" root
|
||||
privileges *at all*. And therefore, containers can run with a reduced
|
||||
capability set; meaning that "root" within a container has much less
|
||||
privileges than the real "root". For instance, it is possible to:
|
||||
|
||||
* deny all "mount" operations;
|
||||
* deny access to raw sockets (to prevent packet spoofing);
|
||||
* deny access to some filesystem operations, like creating new device
|
||||
nodes, changing the owner of files, or altering attributes
|
||||
(including the immutable flag);
|
||||
* deny module loading;
|
||||
* and many others.
|
||||
|
||||
This means that even if an intruder manages to escalate to root within
|
||||
a container, it will be much harder to do serious damage, or to
|
||||
escalate to the host.
|
||||
|
||||
This won't affect regular web apps; but malicious users will find that
|
||||
the arsenal at their disposal has shrunk considerably! You can see
|
||||
`the list of dropped capabilities in the Docker code
|
||||
<https://github.com/dotcloud/docker/blob/v0.5.0/lxc_template.go#L97>`_,
|
||||
and a full list of available capabilities in `Linux manpages
|
||||
<http://man7.org/linux/man-pages/man7/capabilities.7.html>`_.
|
||||
|
||||
Of course, you can always enable extra capabilities if you really need
|
||||
them (for instance, if you want to use a FUSE-based filesystem), but
|
||||
by default, Docker containers will be locked down to ensure maximum
|
||||
safety.
|
||||
|
||||
Other Kernel Security Features
|
||||
------------------------------
|
||||
|
||||
Capabilities are just one of the many security features provided by
|
||||
modern Linux kernels. It is also possible to leverage existing,
|
||||
well-known systems like TOMOYO, AppArmor, SELinux, GRSEC, etc. with
|
||||
Docker.
|
||||
|
||||
While Docker currently only enables capabilities, it doesn't interfere
|
||||
with the other systems. This means that there are many different ways
|
||||
to harden a Docker host. Here are a few examples.
|
||||
|
||||
* You can run a kernel with GRSEC and PAX. This will add many safety
|
||||
checks, both at compile-time and run-time; it will also defeat many
|
||||
exploits, thanks to techniques like address randomization. It
|
||||
doesn’t require Docker-specific configuration, since those security
|
||||
features apply system-wide, independently of containers.
|
||||
* If your distribution comes with security model templates for LXC
|
||||
containers, you can use them out of the box. For instance, Ubuntu
|
||||
comes with AppArmor templates for LXC, and those templates provide
|
||||
an extra safety net (even though it overlaps greatly with
|
||||
capabilities).
|
||||
* You can define your own policies using your favorite access control
|
||||
mechanism. Since Docker containers are standard LXC containers,
|
||||
there is nothing “magic” or specific to Docker.
|
||||
|
||||
Just like there are many third-party tools to augment Docker
|
||||
containers with e.g. special network topologies or shared filesystems,
|
||||
you can expect to see tools to harden existing Docker containers
|
||||
without affecting Docker’s core.
|
||||
|
||||
Conclusions
|
||||
-----------
|
||||
|
||||
Docker containers are, by default, quite secure; especially if you
|
||||
take care of running your processes inside the containers as
|
||||
non-privileged users (i.e. non root).
|
||||
|
||||
You can add an extra layer of safety by enabling Apparmor, SELinux,
|
||||
GRSEC, or your favorite hardening solution.
|
||||
|
||||
Last but not least, if you see interesting security features in other
|
||||
containerization systems, you will be able to implement them as well
|
||||
with Docker, since everything is provided by the kernel anyway.
|
||||
|
||||
For more context and especially for comparisons with VMs and other
|
||||
container systems, please also see the `original blog post
|
||||
<blogsecurity>`_.
|
||||
|
||||
.. _blogsecurity: http://blog.docker.io/2013/08/containers-docker-how-secure-are-they/
|
||||
|
||||
@@ -78,7 +78,8 @@ Docker is available as a Debian package, which makes installation easy.
|
||||
sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -"
|
||||
|
||||
# Add the Docker repository to your apt sources list.
|
||||
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
|
||||
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\
|
||||
> /etc/apt/sources.list.d/docker.list"
|
||||
|
||||
# Update your sources
|
||||
sudo apt-get update
|
||||
@@ -132,7 +133,8 @@ to follow them again.*
|
||||
sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -"
|
||||
|
||||
# Add the Docker repository to your apt sources list.
|
||||
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
|
||||
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\
|
||||
> /etc/apt/sources.list.d/docker.list"
|
||||
|
||||
# update
|
||||
sudo apt-get update
|
||||
@@ -160,8 +162,8 @@ Verify it worked
|
||||
Docker and UFW
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Docker uses a bridge to manage containers networking, by default UFW
|
||||
drop all `forwarding`, a first step is to enable forwarding:
|
||||
Docker uses a bridge to manage container networking. By default, UFW
|
||||
drops all `forwarding`, thus a first step is to enable UFW forwarding:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Using Vagrant (Mac, Linux)
|
||||
|
||||
This guide will setup a new virtualbox virtual machine with docker
|
||||
installed on your computer. This works on most operating systems,
|
||||
including MacOX, Windows, Linux, FreeBSD and others. If you can
|
||||
including MacOSX, Windows, Linux, FreeBSD and others. If you can
|
||||
install these and have at least 400MB RAM to spare you should be good.
|
||||
|
||||
Install Vagrant and Virtualbox
|
||||
|
||||
@@ -208,6 +208,10 @@ configuration / Device configuration)
|
||||
|
||||
.. image:: images/win/hp_bios_vm.JPG
|
||||
|
||||
On some machines the BIOS menu can only be accessed before startup.
|
||||
To access BIOS in this scenario you should restart your computer and
|
||||
press ESC/Enter when prompted to access the boot and BIOS controls. Typically
|
||||
the option to allow virtualization is contained within the BIOS/Security menu.
|
||||
|
||||
Docker is not installed
|
||||
```````````````````````
|
||||
|
||||
@@ -38,3 +38,10 @@ was when the container was stopped.
|
||||
You can promote a container to an :ref:`image_def` with ``docker
|
||||
commit``. Once a container is an image, you can use it as a parent for
|
||||
new containers.
|
||||
|
||||
Container IDs
|
||||
.............
|
||||
All containers are identified by a 64 hexadecimal digit string (internally a 256bit
|
||||
value). To simplify their use, a short ID of the first 12 characters can be used
|
||||
on the commandline. There is a small possibility of short id collisions, so the
|
||||
docker server will always return the long ID.
|
||||
|
||||
@@ -36,3 +36,11 @@ Base Image
|
||||
..........
|
||||
|
||||
An image that has no parent is a **base image**.
|
||||
|
||||
Image IDs
|
||||
.........
|
||||
All images are identified by a 64 hexadecimal digit string (internally a 256bit
|
||||
value). To simplify their use, a short ID of the first 12 characters can be used
|
||||
on the command line. There is a small possibility of short id collisions, so the
|
||||
docker server will always return the long ID.
|
||||
|
||||
|
||||
@@ -40,4 +40,4 @@ Docker Github Repo:
|
||||
* `CentOS
|
||||
<https://github.com/dotcloud/docker/blob/master/contrib/mkimage-centos.sh>`_
|
||||
* `Debian/Ubuntu
|
||||
<https://github.com/dotcloud/docker/blob/master/contrib/mkimage-debian.sh>`_
|
||||
<https://github.com/dotcloud/docker/blob/master/contrib/mkimage-debootstrap.sh>`_
|
||||
|
||||
+42
-26
@@ -22,15 +22,29 @@ specify the path to it and manually start it.
|
||||
# Run docker in daemon mode
|
||||
sudo <path to>/docker -d &
|
||||
|
||||
|
||||
Running an interactive shell
|
||||
----------------------------
|
||||
Download a pre-built image
|
||||
--------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Download an ubuntu image
|
||||
sudo docker pull ubuntu
|
||||
|
||||
This will find the ``ubuntu`` image by name in the :ref:`Central Index
|
||||
<searching_central_index>` and download it from the top-level Central
|
||||
Repository to a local image cache.
|
||||
|
||||
.. NOTE:: When the image has successfully downloaded, you will see a
|
||||
12 character hash ``539c0211cd76: Download complete`` which is the
|
||||
short form of the image ID. These short image IDs are the first 12
|
||||
characters of the full image ID - which can be found using ``docker
|
||||
inspect`` or ``docker images -notrunc=true``
|
||||
|
||||
Running an interactive shell
|
||||
----------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Run an interactive shell in the ubuntu image,
|
||||
# allocate a tty, attach stdin and stdout
|
||||
# To detach the tty without exiting the shell,
|
||||
@@ -39,38 +53,44 @@ Running an interactive shell
|
||||
|
||||
.. _dockergroup:
|
||||
|
||||
Why ``sudo``?
|
||||
-------------
|
||||
sudo and the docker Group
|
||||
-------------------------
|
||||
|
||||
The ``docker`` daemon always runs as root, and since ``docker``
|
||||
version 0.5.2, ``docker`` binds to a Unix socket instead of a TCP
|
||||
port. By default that Unix socket is owned by the user *root*, and so,
|
||||
by default, you can access it with ``sudo``.
|
||||
|
||||
Starting in version 0.5.3, if you create a Unix group called *docker*
|
||||
and add users to it, then the ``docker`` daemon will make the
|
||||
ownership of the Unix socket read/writable by the *docker* group when
|
||||
the daemon starts. The ``docker`` daemon must always run as root, but
|
||||
if you run the ``docker`` client as a user in the *docker* group then
|
||||
you don't need to add ``sudo`` to all the client commands.
|
||||
Starting in version 0.5.3, if you (or your Docker installer) create a
|
||||
Unix group called *docker* and add users to it, then the ``docker``
|
||||
daemon will make the ownership of the Unix socket read/writable by the
|
||||
*docker* group when the daemon starts. The ``docker`` daemon must
|
||||
always run as root, but if you run the ``docker`` client as a user in
|
||||
the *docker* group then you don't need to add ``sudo`` to all the
|
||||
client commands.
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Add the docker group
|
||||
# Add the docker group if it doesn't already exist.
|
||||
sudo groupadd docker
|
||||
|
||||
# Add the ubuntu user to the docker group
|
||||
# Add the user "ubuntu" to the docker group.
|
||||
# Change the user name to match your preferred user.
|
||||
# You may have to logout and log back in again for
|
||||
# this to take effect
|
||||
# this to take effect.
|
||||
sudo gpasswd -a ubuntu docker
|
||||
|
||||
# Restart the docker daemon
|
||||
# Restart the docker daemon.
|
||||
sudo service docker restart
|
||||
|
||||
.. _bind_docker:
|
||||
|
||||
Bind Docker to another host/port or a Unix socket
|
||||
-------------------------------------------------
|
||||
|
||||
.. DANGER:: Changing the default ``docker`` daemon binding to a TCP
|
||||
.. warning:: Changing the default ``docker`` daemon binding to a TCP
|
||||
port or Unix *docker* user group will increase your security risks
|
||||
by allowing non-root users to potentially gain *root* access on the
|
||||
host (`e.g. #1369
|
||||
@@ -136,22 +156,19 @@ Listing all running containers
|
||||
|
||||
sudo docker ps
|
||||
|
||||
Expose a service on a TCP port
|
||||
Bind a service on a TCP port
|
||||
------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Expose port 4444 of this container, and tell netcat to listen on it
|
||||
JOB=$(sudo docker run -d -p 4444 ubuntu:12.10 /bin/nc -l -p 4444)
|
||||
# Bind port 4444 of this container, and tell netcat to listen on it
|
||||
JOB=$(sudo docker run -d -p 4444 ubuntu:12.10 /bin/nc -l 4444)
|
||||
|
||||
# Which public port is NATed to my container?
|
||||
PORT=$(sudo docker port $JOB 4444)
|
||||
PORT=$(sudo docker port $JOB 4444 | awk -F: '{ print $2 }')
|
||||
|
||||
# Connect to the public port via the host's public address
|
||||
# Please note that because of how routing works connecting to localhost or 127.0.0.1 $PORT will not work.
|
||||
# Replace *eth0* according to your local interface name.
|
||||
IP=$(ip -o -4 addr list eth0 | perl -n -e 'if (m{inet\s([\d\.]+)\/\d+\s}xms) { print $1 }')
|
||||
echo hello world | nc $IP $PORT
|
||||
# Connect to the public port
|
||||
echo hello world | nc 127.0.0.1 $PORT
|
||||
|
||||
# Verify that the network connection worked
|
||||
echo "Daemon received: $(sudo docker logs $JOB)"
|
||||
@@ -181,4 +198,3 @@ You now have a image state from which you can create new instances.
|
||||
|
||||
Read more about :ref:`working_with_the_repository` or continue to the
|
||||
complete :ref:`cli`
|
||||
|
||||
|
||||
@@ -15,27 +15,39 @@ commit them along the way, giving you a final image.
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
.. _dockerfile_usage:
|
||||
|
||||
1. Usage
|
||||
========
|
||||
|
||||
To build an image from a source repository, create a description file
|
||||
called ``Dockerfile`` at the root of your repository. This file will
|
||||
describe the steps to assemble the image.
|
||||
To :ref:`build <cli_build>` an image from a source repository, create
|
||||
a description file called ``Dockerfile`` at the root of your
|
||||
repository. This file will describe the steps to assemble the image.
|
||||
|
||||
Then call ``docker build`` with the path of your source repository as
|
||||
argument:
|
||||
argument (for example, ``.``):
|
||||
|
||||
``sudo docker build .``
|
||||
|
||||
The path to the source repository defines where to find the *context*
|
||||
of the build. The build is run by the Docker daemon, not by the CLI,
|
||||
so the whole context must be transferred to the daemon. The Docker CLI
|
||||
reports "Uploading context" when the context is sent to the daemon.
|
||||
|
||||
You can specify a repository and tag at which to save the new image if the
|
||||
build succeeds:
|
||||
|
||||
``sudo docker build -t shykes/myapp .``
|
||||
|
||||
Docker will run your steps one-by-one, committing the result if necessary,
|
||||
before finally outputting the ID of your new image.
|
||||
The Docker daemon will run your steps one-by-one, committing the
|
||||
result if necessary, before finally outputting the ID of your new
|
||||
image. The Docker daemon will automatically clean up the context you
|
||||
sent.
|
||||
|
||||
When you're done with your build, you're ready to look into :ref:`image_push`.
|
||||
When you're done with your build, you're ready to look into
|
||||
:ref:`image_push`.
|
||||
|
||||
.. _dockerfile_format:
|
||||
|
||||
2. Format
|
||||
=========
|
||||
@@ -63,12 +75,16 @@ allows statements like:
|
||||
# Comment
|
||||
RUN echo 'we are running some # of cool things'
|
||||
|
||||
.. _dockerfile_instructions:
|
||||
|
||||
3. Instructions
|
||||
===============
|
||||
|
||||
Here is the set of instructions you can use in a ``Dockerfile`` for
|
||||
building images.
|
||||
|
||||
.. _dockerfile_from:
|
||||
|
||||
3.1 FROM
|
||||
--------
|
||||
|
||||
@@ -94,6 +110,8 @@ output by the commit before each new ``FROM`` command.
|
||||
If no ``tag`` is given to the ``FROM`` instruction, ``latest`` is
|
||||
assumed. If the used tag does not exist, an error will be returned.
|
||||
|
||||
.. _dockerfile_maintainer:
|
||||
|
||||
3.2 MAINTAINER
|
||||
--------------
|
||||
|
||||
@@ -102,6 +120,8 @@ assumed. If the used tag does not exist, an error will be returned.
|
||||
The ``MAINTAINER`` instruction allows you to set the *Author* field of
|
||||
the generated images.
|
||||
|
||||
.. _dockerfile_run:
|
||||
|
||||
3.3 RUN
|
||||
-------
|
||||
|
||||
@@ -116,6 +136,16 @@ core concepts of Docker where commits are cheap and containers can be
|
||||
created from any point in an image's history, much like source
|
||||
control.
|
||||
|
||||
Known Issues (RUN)
|
||||
..................
|
||||
|
||||
* :issue:`783` is about file permissions problems that can occur when
|
||||
using the AUFS file system. You might notice it during an attempt to
|
||||
``rm`` a file, for example. The issue describes a workaround.
|
||||
* :issue:`2424` Locale will not be set automatically.
|
||||
|
||||
.. _dockerfile_cmd:
|
||||
|
||||
3.4 CMD
|
||||
-------
|
||||
|
||||
@@ -159,7 +189,7 @@ array:
|
||||
|
||||
If you would like your container to run the same executable every
|
||||
time, then you should consider using ``ENTRYPOINT`` in combination
|
||||
with ``CMD``. See :ref:`entrypoint_def`.
|
||||
with ``CMD``. See :ref:`dockerfile_entrypoint`.
|
||||
|
||||
If the user specifies arguments to ``docker run`` then they will
|
||||
override the default specified in CMD.
|
||||
@@ -169,15 +199,19 @@ override the default specified in CMD.
|
||||
command and commits the result; ``CMD`` does not execute anything at
|
||||
build time, but specifies the intended command for the image.
|
||||
|
||||
.. _dockerfile_expose:
|
||||
|
||||
3.5 EXPOSE
|
||||
----------
|
||||
|
||||
``EXPOSE <port> [<port>...]``
|
||||
|
||||
The ``EXPOSE`` instruction sets ports to be publicly exposed when
|
||||
running the image. This is functionally equivalent to running ``docker
|
||||
commit -run '{"PortSpecs": ["<port>", "<port2>"]}'`` outside the
|
||||
builder. Take a look at :ref:`port_redirection` for more information.
|
||||
The ``EXPOSE`` instruction exposes ports for use within links. This is
|
||||
functionally equivalent to running ``docker commit -run '{"PortSpecs":
|
||||
["<port>", "<port2>"]}'`` outside the builder. Refer to
|
||||
:ref:`port_redirection` for detailed information.
|
||||
|
||||
.. _dockerfile_env:
|
||||
|
||||
3.6 ENV
|
||||
-------
|
||||
@@ -193,6 +227,8 @@ with ``<key>=<value>``
|
||||
The environment variables will persist when a container is run
|
||||
from the resulting image.
|
||||
|
||||
.. _dockerfile_add:
|
||||
|
||||
3.7 ADD
|
||||
-------
|
||||
|
||||
@@ -208,8 +244,19 @@ a remote file URL.
|
||||
``<dest>`` is the path at which the source will be copied in the
|
||||
destination container.
|
||||
|
||||
All new files and directories are created with mode 0755, uid and gid
|
||||
0.
|
||||
|
||||
.. note::
|
||||
if you build using STDIN (``docker build - < somefile``), there is no build
|
||||
context, so the Dockerfile can only contain an URL based ADD statement.
|
||||
|
||||
The copy obeys the following rules:
|
||||
|
||||
* The ``<src>`` path must be inside the *context* of the build; you cannot
|
||||
``ADD ../something /something``, because the first step of a
|
||||
``docker build`` is to send the context directory (and subdirectories) to
|
||||
the docker daemon.
|
||||
* If ``<src>`` is a URL and ``<dest>`` does not end with a trailing slash,
|
||||
then a file is downloaded from the URL and copied to ``<dest>``.
|
||||
* If ``<src>`` is a URL and ``<dest>`` does end with a trailing slash,
|
||||
@@ -220,8 +267,9 @@ The copy obeys the following rules:
|
||||
(``http://example.com`` will not work).
|
||||
* If ``<src>`` is a directory, the entire directory is copied,
|
||||
including filesystem metadata.
|
||||
* If ``<src>``` is a tar archive in a recognized compression format
|
||||
(identity, gzip, bzip2 or xz), it is unpacked as a directory.
|
||||
* If ``<src>`` is a *local* tar archive in a recognized compression
|
||||
format (identity, gzip, bzip2 or xz) then it is unpacked as a
|
||||
directory. Resources from *remote* URLs are **not** decompressed.
|
||||
|
||||
When a directory is copied or unpacked, it has the same behavior as
|
||||
``tar -x``: the result is the union of
|
||||
@@ -229,7 +277,7 @@ The copy obeys the following rules:
|
||||
1. whatever existed at the destination path and
|
||||
2. the contents of the source tree,
|
||||
|
||||
with conflicts resolved in favor of 2) on a file-by-file basis.
|
||||
with conflicts resolved in favor of "2." on a file-by-file basis.
|
||||
|
||||
* If ``<src>`` is any other kind of file, it is copied individually
|
||||
along with its metadata. In this case, if ``<dest>`` ends with a
|
||||
@@ -237,12 +285,11 @@ The copy obeys the following rules:
|
||||
contents of ``<src>`` will be written at ``<dest>/base(<src>)``.
|
||||
* If ``<dest>`` does not end with a trailing slash, it will be
|
||||
considered a regular file and the contents of ``<src>`` will be
|
||||
written at ``<dst>``.
|
||||
written at ``<dest>``.
|
||||
* If ``<dest>`` doesn't exist, it is created along with all missing
|
||||
directories in its path. All new files and directories are created
|
||||
with mode 0755, uid and gid 0.
|
||||
directories in its path.
|
||||
|
||||
.. _entrypoint_def:
|
||||
.. _dockerfile_entrypoint:
|
||||
|
||||
3.8 ENTRYPOINT
|
||||
--------------
|
||||
@@ -291,14 +338,18 @@ this optional but default, you could use a CMD:
|
||||
CMD ["-l", "-"]
|
||||
ENTRYPOINT ["/usr/bin/wc"]
|
||||
|
||||
.. _dockerfile_volume:
|
||||
|
||||
3.9 VOLUME
|
||||
----------
|
||||
|
||||
``VOLUME ["/data"]``
|
||||
|
||||
The ``VOLUME`` instruction will add one or more new volumes to any
|
||||
container created from the image.
|
||||
The ``VOLUME`` instruction will create a mount point with the specified name and mark it
|
||||
as holding externally mounted volumes from native host or other containers. For more information/examples
|
||||
and mounting instructions via docker client, refer to :ref:`volume_def` documentation.
|
||||
|
||||
.. _dockerfile_user:
|
||||
|
||||
3.10 USER
|
||||
---------
|
||||
@@ -308,6 +359,8 @@ container created from the image.
|
||||
The ``USER`` instruction sets the username or UID to use when running
|
||||
the image.
|
||||
|
||||
.. _dockerfile_workdir:
|
||||
|
||||
3.11 WORKDIR
|
||||
------------
|
||||
|
||||
@@ -316,6 +369,7 @@ the image.
|
||||
The ``WORKDIR`` instruction sets the working directory in which
|
||||
the command given by ``CMD`` is executed.
|
||||
|
||||
.. _dockerfile_examples:
|
||||
|
||||
4. Dockerfile Examples
|
||||
======================
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
:title: Host Integration
|
||||
:description: How to generate scripts for upstart, systemd, etc.
|
||||
:keywords: systemd, upstart, supervisor, docker, documentation, host integration
|
||||
|
||||
|
||||
|
||||
Host Integration
|
||||
================
|
||||
|
||||
You can use your Docker containers with process managers like ``upstart``,
|
||||
``systemd`` and ``supervisor``.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
If you want a process manager to manage your containers you will need to run
|
||||
the docker daemon with the ``-r=false`` so that docker will not automatically
|
||||
restart your containers when the host is restarted.
|
||||
|
||||
When you have finished setting up your image and are happy with your
|
||||
running container, you may want to use a process manager to manage
|
||||
it. When your run ``docker start -a`` docker will automatically attach
|
||||
to the process and forward all signals so that the process manager can
|
||||
detect when a container stops and correctly restart it.
|
||||
|
||||
Here are a few sample scripts for systemd and upstart to integrate with docker.
|
||||
|
||||
|
||||
Sample Upstart Script
|
||||
---------------------
|
||||
|
||||
In this example we've already created a container to run Redis with an id of
|
||||
0a7e070b698b. To create an upstart script for our container, we create a file
|
||||
named ``/etc/init/redis.conf`` and place the following into it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
description "Redis container"
|
||||
author "Me"
|
||||
start on filesystem and started docker
|
||||
stop on runlevel [!2345]
|
||||
respawn
|
||||
script
|
||||
# Wait for docker to finish starting up first.
|
||||
FILE=/var/run/docker.sock
|
||||
while [ ! -e $FILE ] ; do
|
||||
inotifywait -t 2 -e create $(dirname $FILE)
|
||||
done
|
||||
/usr/bin/docker start -a 0a7e070b698b
|
||||
end script
|
||||
|
||||
Next, we have to configure docker so that it's run with the option ``-r=false``.
|
||||
Run the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo sh -c "echo 'DOCKER_OPTS=\"-r=false\"' > /etc/default/docker"
|
||||
|
||||
|
||||
Sample systemd Script
|
||||
---------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
[Unit]
|
||||
Description=Redis container
|
||||
Author=Me
|
||||
After=docker.service
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/docker start -a 0a7e070b698b
|
||||
ExecStop=/usr/bin/docker stop -t 2 0a7e070b698b
|
||||
|
||||
[Install]
|
||||
WantedBy=local.target
|
||||
|
||||
@@ -18,3 +18,6 @@ Contents:
|
||||
baseimages
|
||||
port_redirection
|
||||
puppet
|
||||
host_integration
|
||||
working_with_volumes
|
||||
working_with_links_names
|
||||
|
||||
@@ -8,29 +8,136 @@
|
||||
Port redirection
|
||||
================
|
||||
|
||||
Docker can redirect public TCP and UDP ports to your container, so it can be
|
||||
reached over the network. Port redirection is done on ``docker run``
|
||||
using the -p flag.
|
||||
|
||||
A port redirect is specified as *PUBLIC:PRIVATE*, where TCP port
|
||||
*PUBLIC* will be redirected to TCP port *PRIVATE*. As a special case,
|
||||
the public port can be omitted, in which case a random public port
|
||||
will be allocated.
|
||||
Interacting with a service is commonly done through a connection to a
|
||||
port. When this service runs inside a container, one can connect to
|
||||
the port after finding the IP address of the container as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# A random PUBLIC port is redirected to PRIVATE port 80 on the container
|
||||
sudo docker run -p 80 <image> <cmd>
|
||||
# Find IP address of container with ID <container_id>
|
||||
docker inspect <container_id> | grep IPAddress | cut -d '"' -f 4
|
||||
|
||||
# PUBLIC port 80 is redirected to PRIVATE port 80
|
||||
sudo docker run -p 80:80 <image> <cmd>
|
||||
However, this IP address is local to the host system and the container
|
||||
port is not reachable by the outside world. Furthermore, even if the
|
||||
port is used locally, e.g. by another container, this method is
|
||||
tedious as the IP address of the container changes every time it
|
||||
starts.
|
||||
|
||||
To redirect a UDP port the redirection must be expressed as *PUBLIC:PRIVATE/udp*:
|
||||
Docker addresses these two problems and give a simple and robust way
|
||||
to access services running inside containers.
|
||||
|
||||
To allow non-local clients to reach the service running inside the
|
||||
container, Docker provide ways to bind the container port to an
|
||||
interface of the host system. To simplify communication between
|
||||
containers, Docker provides the linking mechanism.
|
||||
|
||||
Binding a port to an host interface
|
||||
-----------------------------------
|
||||
|
||||
To bind a port of the container to a specific interface of the host
|
||||
system, use the ``-p`` parameter of the ``docker run`` command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# PUBLIC port 5300 is redirected to the PRIVATE port 53 using UDP
|
||||
sudo docker run -p 5300:53/udp <image> <cmd>
|
||||
# General syntax
|
||||
docker run -p [([<host_interface>:[host_port]])|(<host_port>):]<container_port>[/udp] <image> <cmd>
|
||||
|
||||
Default port redirects can be built into a container with the
|
||||
``EXPOSE`` build command.
|
||||
When no host interface is provided, the port is bound to all available
|
||||
interfaces of the host machine (aka INADDR_ANY, or 0.0.0.0).When no host port is
|
||||
provided, one is dynamically allocated. The possible combinations of options for
|
||||
TCP port are the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Bind TCP port 8080 of the container to TCP port 80 on 127.0.0.1 of the host machine.
|
||||
docker run -p 127.0.0.1:80:8080 <image> <cmd>
|
||||
|
||||
# Bind TCP port 8080 of the container to a dynamically allocated TCP port on 127.0.0.1 of the host machine.
|
||||
docker run -p 127.0.0.1::8080 <image> <cmd>
|
||||
|
||||
# Bind TCP port 8080 of the container to TCP port 80 on all available interfaces of the host machine.
|
||||
docker run -p 80:8080 <image> <cmd>
|
||||
|
||||
# Bind TCP port 8080 of the container to a dynamically allocated TCP port on all available interfaces of the host machine.
|
||||
docker run -p 8080 <image> <cmd>
|
||||
|
||||
UDP ports can also be bound by adding a trailing ``/udp``. All the
|
||||
combinations described for TCP work. Here is only one example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Bind UDP port 5353 of the container to UDP port 53 on 127.0.0.1 of the host machine.
|
||||
docker run -p 127.0.0.1:53:5353/udp <image> <cmd>
|
||||
|
||||
The command ``docker port`` lists the interface and port on the host
|
||||
machine bound to a given container port. It is useful when using
|
||||
dynamically allocated ports:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Bind to a dynamically allocated port
|
||||
docker run -p 127.0.0.1::8080 -name dyn-bound <image> <cmd>
|
||||
|
||||
# Lookup the actual port
|
||||
docker port dyn-bound 8080
|
||||
127.0.0.1:49160
|
||||
|
||||
|
||||
Linking a container
|
||||
-------------------
|
||||
|
||||
Communication between two containers can also be established in a
|
||||
docker-specific way called linking.
|
||||
|
||||
To briefly present the concept of linking, let us consider two
|
||||
containers: ``server``, containing the service, and ``client``,
|
||||
accessing the service. Once ``server`` is running, ``client`` is
|
||||
started and links to server. Linking sets environment variables in
|
||||
``client`` giving it some information about ``server``. In this sense,
|
||||
linking is a method of service discovery.
|
||||
|
||||
Let us now get back to our topic of interest; communication between
|
||||
the two containers. We mentioned that the tricky part about this
|
||||
communication was that the IP address of ``server`` was not
|
||||
fixed. Therefore, some of the environment variables are going to be
|
||||
used to inform ``client`` about this IP address. This process called
|
||||
exposure, is possible because ``client`` is started after ``server``
|
||||
has been started.
|
||||
|
||||
Here is a full example. On ``server``, the port of interest is
|
||||
exposed. The exposure is done either through the ``-expose`` parameter
|
||||
to the ``docker run`` command, or the ``EXPOSE`` build command in a
|
||||
Dockerfile:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Expose port 80
|
||||
docker run -expose 80 -name server <image> <cmd>
|
||||
|
||||
The ``client`` then links to the ``server``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Link
|
||||
docker run -name client -link server:linked-server <image> <cmd>
|
||||
|
||||
``client`` locally refers to ``server`` as ``linked-server``. The
|
||||
following environment variables, among others, are available on
|
||||
``client``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# The default protocol, ip, and port of the service running in the container
|
||||
LINKED-SERVER_PORT=tcp://172.17.0.8:80
|
||||
|
||||
# A specific protocol, ip, and port of various services
|
||||
LINKED-SERVER_PORT_80_TCP=tcp://172.17.0.8:80
|
||||
LINKED-SERVER_PORT_80_TCP_PROTO=tcp
|
||||
LINKED-SERVER_PORT_80_TCP_ADDR=172.17.0.8
|
||||
LINKED-SERVER_PORT_80_TCP_PORT=80
|
||||
|
||||
This tells ``client`` that a service is running on port 80 of
|
||||
``server`` and that ``server`` is accessible at the IP address
|
||||
172.17.0.8
|
||||
|
||||
Note: Using the ``-p`` parameter also exposes the port..
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
:title: Working with Links and Names
|
||||
:description: How to create and use links and names
|
||||
:keywords: Examples, Usage, links, docker, documentation, examples, names, name, container naming
|
||||
|
||||
.. _working_with_links_names:
|
||||
|
||||
Working with Links and Names
|
||||
============================
|
||||
|
||||
From version 0.6.5 you are now able to ``name`` a container and ``link`` it to another
|
||||
container by referring to its name. This will create a parent -> child relationship
|
||||
where the parent container can see selected information about its child.
|
||||
|
||||
.. _run_name:
|
||||
|
||||
Container Naming
|
||||
----------------
|
||||
|
||||
.. versionadded:: v0.6.5
|
||||
|
||||
You can now name your container by using the ``-name`` flag. If no name is provided, Docker
|
||||
will automatically generate a name. You can see this name using the ``docker ps`` command.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# format is "sudo docker run -name <container_name> <image_name> <command>"
|
||||
$ sudo docker run -name test ubuntu /bin/bash
|
||||
|
||||
# the flag "-a" Show all containers. Only running containers are shown by default.
|
||||
$ sudo docker ps -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
2522602a0d99 ubuntu:12.04 /bin/bash 14 seconds ago Exit 0 test
|
||||
|
||||
.. _run_link:
|
||||
|
||||
Links: service discovery for docker
|
||||
-----------------------------------
|
||||
|
||||
.. versionadded:: v0.6.5
|
||||
|
||||
Links allow containers to discover and securely communicate with each other by using the
|
||||
flag ``-link name:alias``. Inter-container communication can be disabled with the daemon
|
||||
flag ``-icc=false``. With this flag set to false, Container A cannot access Container B
|
||||
unless explicitly allowed via a link. This is a huge win for securing your containers.
|
||||
When two containers are linked together Docker creates a parent child relationship
|
||||
between the containers. The parent container will be able to access information via
|
||||
environment variables of the child such as name, exposed ports, IP and other selected
|
||||
environment variables.
|
||||
|
||||
When linking two containers Docker will use the exposed ports of the container to create
|
||||
a secure tunnel for the parent to access. If a database container only exposes port 8080
|
||||
then the linked container will only be allowed to access port 8080 and nothing else if
|
||||
inter-container communication is set to false.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Example: there is an image called redis-2.6 that exposes the port 6379 and starts redis-server.
|
||||
# Let's name the container as "redis" based on that image and run it as daemon.
|
||||
$ sudo docker run -d -name redis redis-2.6
|
||||
|
||||
We can issue all the commands that you would expect using the name "redis"; start, stop,
|
||||
attach, using the name for our container. The name also allows us to link other containers
|
||||
into this one.
|
||||
|
||||
Next, we can start a new web application that has a dependency on Redis and apply a link
|
||||
to connect both containers. If you noticed when running our Redis server we did not use
|
||||
the -p flag to publish the Redis port to the host system. Redis exposed port 6379 and
|
||||
this is all we need to establish a link.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Linking the redis container as a child
|
||||
$ sudo docker run -t -i -link redis:db -name webapp ubuntu bash
|
||||
|
||||
When you specified -link redis:db you are telling docker to link the container named redis
|
||||
into this new container with the alias db. Environment variables are prefixed with the alias
|
||||
so that the parent container can access network and environment information from the containers
|
||||
that are linked into it.
|
||||
|
||||
If we inspect the environment variables of the second container, we would see all the information
|
||||
about the child container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ root@4c01db0b339c:/# env
|
||||
|
||||
HOSTNAME=4c01db0b339c
|
||||
DB_NAME=/webapp/db
|
||||
TERM=xterm
|
||||
DB_PORT=tcp://172.17.0.8:6379
|
||||
DB_PORT_6379_TCP=tcp://172.17.0.8:6379
|
||||
DB_PORT_6379_TCP_PROTO=tcp
|
||||
DB_PORT_6379_TCP_ADDR=172.17.0.8
|
||||
DB_PORT_6379_TCP_PORT=6379
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
PWD=/
|
||||
SHLVL=1
|
||||
HOME=/
|
||||
container=lxc
|
||||
_=/usr/bin/env
|
||||
root@4c01db0b339c:/#
|
||||
|
||||
Accessing the network information along with the environment of the child container allows
|
||||
us to easily connect to the Redis service on the specific IP and port in the environment.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user