mirror of
https://github.com/moby/moby.git
synced 2026-01-12 19:21:41 +00:00
Compare commits
965 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e289308dff | ||
|
|
8fb8a08ff2 | ||
|
|
30f009150f | ||
|
|
0410397704 | ||
|
|
3cbf5670c5 | ||
|
|
55cf05835b | ||
|
|
c7a7983fcb | ||
|
|
44b33b44aa | ||
|
|
463658dc8f | ||
|
|
80f4b0df75 | ||
|
|
aaaf3f0726 | ||
|
|
eed64e6777 | ||
|
|
0f4469c2b1 | ||
|
|
06767fb99d | ||
|
|
5098c4fc00 | ||
|
|
c255976909 | ||
|
|
0e23b4e10e | ||
|
|
d6c24092eb | ||
|
|
6cafed45af | ||
|
|
3484781a6f | ||
|
|
c4ad6b077d | ||
|
|
45b5d3027e | ||
|
|
070b1cd541 | ||
|
|
8ff1765674 | ||
|
|
c4ebf870c8 | ||
|
|
7b1ec9ff30 | ||
|
|
244e6022ec | ||
|
|
f8dd04d567 | ||
|
|
42b1ea4889 | ||
|
|
d2eb2455a1 | ||
|
|
a2b5196061 | ||
|
|
f46ab22b7a | ||
|
|
074310063d | ||
|
|
01575e1f67 | ||
|
|
82513815f1 | ||
|
|
4df26b9ee7 | ||
|
|
fc2df7e634 | ||
|
|
c718eb282b | ||
|
|
0a13ce9bef | ||
|
|
0a197f9b4f | ||
|
|
3d25e09c3b | ||
|
|
d56c5406ac | ||
|
|
23c5c13014 | ||
|
|
6ac33eb649 | ||
|
|
a02ad8c896 | ||
|
|
4c7c177e4e | ||
|
|
e45aef0c82 | ||
|
|
8472a27e80 | ||
|
|
0d929d13d3 | ||
|
|
a0d80ed3e6 | ||
|
|
e8853ec3a4 | ||
|
|
8ea9811089 | ||
|
|
f3f2cba386 | ||
|
|
d581f0808c | ||
|
|
ce4e87196f | ||
|
|
7757be1f45 | ||
|
|
49b05eb24a | ||
|
|
dae2828957 | ||
|
|
3439cd9cea | ||
|
|
979db00d9a | ||
|
|
db4417b601 | ||
|
|
a64ebe5feb | ||
|
|
602786cd60 | ||
|
|
35c59f4e05 | ||
|
|
756df27e45 | ||
|
|
a46fc3a59e | ||
|
|
9959e2cd63 | ||
|
|
f911ccc27b | ||
|
|
96069de4e0 | ||
|
|
d92166cc79 | ||
|
|
ebb59c1125 | ||
|
|
e2880950c5 | ||
|
|
62a1850c16 | ||
|
|
2bc4ad9402 | ||
|
|
ae1e655fb1 | ||
|
|
92e98c66af | ||
|
|
6d6a03dfba | ||
|
|
924b61328c | ||
|
|
4ebec08add | ||
|
|
15ea5a479a | ||
|
|
6c168a8986 | ||
|
|
4386edff0b | ||
|
|
6bfb652f5b | ||
|
|
bbb634a980 | ||
|
|
034c7a7a5e | ||
|
|
4390a3182f | ||
|
|
e337949cb0 | ||
|
|
dade95844f | ||
|
|
74b9e851f6 | ||
|
|
ff95f2b0ec | ||
|
|
f7c5e92a2e | ||
|
|
6f2125386a | ||
|
|
0aebb25410 | ||
|
|
9db4972a70 | ||
|
|
9751483112 | ||
|
|
7bccdc0d33 | ||
|
|
97215ca384 | ||
|
|
b8f66c0d14 | ||
|
|
27319da0d2 | ||
|
|
f20b5e1323 | ||
|
|
15b85d9d76 | ||
|
|
b38fc9fcdc | ||
|
|
8646f7f11c | ||
|
|
87cc8b6058 | ||
|
|
0fabd390a9 | ||
|
|
2ac7298e4e | ||
|
|
840bde4393 | ||
|
|
bbad653b1a | ||
|
|
4f202cd07f | ||
|
|
da01dd3d56 | ||
|
|
09f1cbabb9 | ||
|
|
c9994ed0fb | ||
|
|
b0e076f374 | ||
|
|
00266df8ac | ||
|
|
3febeb93f5 | ||
|
|
bcdf03037b | ||
|
|
a372f982c1 | ||
|
|
d985050aeb | ||
|
|
0c5e76958b | ||
|
|
0f68042053 | ||
|
|
18796d55a6 | ||
|
|
594827d416 | ||
|
|
5690562fc8 | ||
|
|
be791a223b | ||
|
|
19045b530e | ||
|
|
b5873806d0 | ||
|
|
f10b0f75e0 | ||
|
|
6e2ddf6f60 | ||
|
|
e81a53eea9 | ||
|
|
1c76f91fc4 | ||
|
|
be75608906 | ||
|
|
3c85e9390e | ||
|
|
ea3374bcb0 | ||
|
|
6e936c8fd3 | ||
|
|
4cd9e4722c | ||
|
|
630d358384 | ||
|
|
84be35dce1 | ||
|
|
23953e7d67 | ||
|
|
6644a3c78a | ||
|
|
e179c66400 | ||
|
|
048fd671ef | ||
|
|
7c1a27e2ad | ||
|
|
1cf8a2c26c | ||
|
|
e639309a7a | ||
|
|
2f082510a7 | ||
|
|
2421838b0a | ||
|
|
58ca46af39 | ||
|
|
09d4b9452d | ||
|
|
d78b2d4ade | ||
|
|
424cc678eb | ||
|
|
1561232261 | ||
|
|
e392b7ee9b | ||
|
|
c3a5dd76cf | ||
|
|
359ecf88de | ||
|
|
3dba4022ad | ||
|
|
f4de9d919d | ||
|
|
04f41ebdbc | ||
|
|
c34989f1c4 | ||
|
|
a7c0e9a355 | ||
|
|
19df5a7965 | ||
|
|
589d7c68db | ||
|
|
8ef72cbc94 | ||
|
|
b9ec03c21b | ||
|
|
6cbe27b7a5 | ||
|
|
a82b60b30d | ||
|
|
c08d245539 | ||
|
|
64d7bc442d | ||
|
|
4bc8ef42d4 | ||
|
|
8378498951 | ||
|
|
1617a18258 | ||
|
|
6c1bb39c09 | ||
|
|
f6b5cd77eb | ||
|
|
5ffd63070f | ||
|
|
701132259d | ||
|
|
18b8eeb484 | ||
|
|
b6a5e604ab | ||
|
|
b682a8ea9e | ||
|
|
6e486b638b | ||
|
|
74cd7e822d | ||
|
|
21b9dcd518 | ||
|
|
897cc573f0 | ||
|
|
b0459adc27 | ||
|
|
3edd14b8c2 | ||
|
|
4099a31304 | ||
|
|
6fb495bf6f | ||
|
|
faf8daa7c6 | ||
|
|
8d9aaee60b | ||
|
|
35d704c8a0 | ||
|
|
1df5f4094b | ||
|
|
528da23d6a | ||
|
|
ff5e238de9 | ||
|
|
c63dce393e | ||
|
|
d6a63132ef | ||
|
|
e7271cdaae | ||
|
|
6ca3b151b1 | ||
|
|
0d9475346f | ||
|
|
71199f595d | ||
|
|
58b95878f1 | ||
|
|
e431dc26f1 | ||
|
|
09b1cd58c0 | ||
|
|
d42639e5c5 | ||
|
|
d0c2e31fb9 | ||
|
|
509a01bbe4 | ||
|
|
e7fb7f13d5 | ||
|
|
d172da58ce | ||
|
|
ad86dde10c | ||
|
|
c20e46587d | ||
|
|
eeb03164cf | ||
|
|
bb61678b57 | ||
|
|
a75a1b3859 | ||
|
|
08812096f5 | ||
|
|
5c30faf6f7 | ||
|
|
f7aaa06606 | ||
|
|
7ff65d40d5 | ||
|
|
904c2a0fc3 | ||
|
|
a3ce90b78b | ||
|
|
03b83b3210 | ||
|
|
40ccf1d300 | ||
|
|
038ca5ee39 | ||
|
|
957c500ac9 | ||
|
|
62a595da5c | ||
|
|
d97661aa71 | ||
|
|
c6119da339 | ||
|
|
5051c20833 | ||
|
|
cdc2657ee9 | ||
|
|
76a1a7cf5b | ||
|
|
20c2a4f80f | ||
|
|
ebe157ebb5 | ||
|
|
cb431f223f | ||
|
|
ab34115b42 | ||
|
|
4b3354af3f | ||
|
|
9042535f5a | ||
|
|
8f81e175af | ||
|
|
636c7835d3 | ||
|
|
6d1dd8b41a | ||
|
|
ae97477284 | ||
|
|
86ad98e72a | ||
|
|
03d82922aa | ||
|
|
30d327d37e | ||
|
|
724e2d6b0a | ||
|
|
51d6228261 | ||
|
|
4db680fda4 | ||
|
|
9c7293508d | ||
|
|
9d8743a7ae | ||
|
|
50144aeb42 | ||
|
|
ee298d1420 | ||
|
|
03855b0027 | ||
|
|
2726e3649a | ||
|
|
90668a8a99 | ||
|
|
c7fd84b8a0 | ||
|
|
874a40ed3a | ||
|
|
370fafacbf | ||
|
|
a0478f726d | ||
|
|
e5bc5a2e31 | ||
|
|
25fc3a7e76 | ||
|
|
b3ab0b561e | ||
|
|
8b8c8bf7cb | ||
|
|
a8651a23b2 | ||
|
|
f744cfd5a7 | ||
|
|
e03b241fb1 | ||
|
|
1ddca1948b | ||
|
|
2485bb2cd2 | ||
|
|
6ebb249131 | ||
|
|
c45beabcd5 | ||
|
|
a22c78523f | ||
|
|
5a02c9ba0a | ||
|
|
7577f48dc4 | ||
|
|
0512cf9c83 | ||
|
|
73da7a12e7 | ||
|
|
50f5723f1d | ||
|
|
cbc4eccd50 | ||
|
|
cff26b3a6c | ||
|
|
329c3e0ffd | ||
|
|
4f6cc5c733 | ||
|
|
e413340723 | ||
|
|
95e066d24f | ||
|
|
82b8f7a565 | ||
|
|
97badbd29e | ||
|
|
5a5e417d46 | ||
|
|
4031a01af1 | ||
|
|
0b0d958b88 | ||
|
|
03e4704ae5 | ||
|
|
7a8ac76299 | ||
|
|
c05c91ca3b | ||
|
|
b76d63cb0c | ||
|
|
f926ed182f | ||
|
|
d440782e17 | ||
|
|
82848d4158 | ||
|
|
97535e5a64 | ||
|
|
f079fbe3fa | ||
|
|
90d144b612 | ||
|
|
d3db94696d | ||
|
|
ffe16e3224 | ||
|
|
0b60829df7 | ||
|
|
690e118670 | ||
|
|
038e1d174b | ||
|
|
6c8dcd5cbb | ||
|
|
16aeb77d51 | ||
|
|
4ac3b803b9 | ||
|
|
3514e47edc | ||
|
|
acb546cd1b | ||
|
|
2ced94b414 | ||
|
|
71b5806614 | ||
|
|
1f65c6bf4c | ||
|
|
965e8a02d2 | ||
|
|
baacae8345 | ||
|
|
52cedb8a05 | ||
|
|
15c7e72e2a | ||
|
|
76b40ad6c9 | ||
|
|
6909f3911f | ||
|
|
3b6c540fe8 | ||
|
|
d49a273071 | ||
|
|
1201c418cd | ||
|
|
4a9c3a92e1 | ||
|
|
28831a412f | ||
|
|
70cf467fdf | ||
|
|
c40f01319f | ||
|
|
0731d1a582 | ||
|
|
8ecde8f9a5 | ||
|
|
911925b54a | ||
|
|
7f1a32b9ff | ||
|
|
930e9a7e43 | ||
|
|
61259ab4b4 | ||
|
|
931ca464a7 | ||
|
|
cc5a044a8c | ||
|
|
0eb425426f | ||
|
|
3bfb70db24 | ||
|
|
e49af5b6de | ||
|
|
d8416539b3 | ||
|
|
a76c3a9c95 | ||
|
|
e81ddb2dc7 | ||
|
|
4d728821e3 | ||
|
|
e92c4b1f39 | ||
|
|
152a9f77b4 | ||
|
|
bfb84b564c | ||
|
|
e8a67f632e | ||
|
|
3d2fd8a650 | ||
|
|
79a78d37e7 | ||
|
|
3ae5c45d9a | ||
|
|
f3e89fae28 | ||
|
|
c42a4179fc | ||
|
|
2d32ac8cff | ||
|
|
f68d107a13 | ||
|
|
640efc2ed2 | ||
|
|
003622c8b6 | ||
|
|
6de5ca1e64 | ||
|
|
deb55e416e | ||
|
|
7eda9c64b8 | ||
|
|
84c13a3dcf | ||
|
|
90602ab62a | ||
|
|
8e6ba343bf | ||
|
|
523cd8e29c | ||
|
|
fd39af7f85 | ||
|
|
ee82870ff7 | ||
|
|
227a8142a3 | ||
|
|
4ef2d5c1e6 | ||
|
|
e34e44e8e6 | ||
|
|
13d9e26edd | ||
|
|
0a3131554c | ||
|
|
521ce07859 | ||
|
|
f02950965e | ||
|
|
16f6daa5be | ||
|
|
ca6cd5b557 | ||
|
|
1615bb08c7 | ||
|
|
c4cd224d90 | ||
|
|
7b0e96f1f4 | ||
|
|
fc72a809c1 | ||
|
|
2a47df0202 | ||
|
|
468fb90117 | ||
|
|
ac49a797b4 | ||
|
|
1ec6c223c9 | ||
|
|
db08705e3c | ||
|
|
fdf3308260 | ||
|
|
c2c72bcfd7 | ||
|
|
cdf90bb04b | ||
|
|
45809e9a05 | ||
|
|
1967c8342a | ||
|
|
7673afc843 | ||
|
|
b1fbebb4a3 | ||
|
|
3527291b47 | ||
|
|
57d31c9777 | ||
|
|
a2f5a56143 | ||
|
|
343ed6b53f | ||
|
|
22893429ed | ||
|
|
c1703c2b68 | ||
|
|
a8c15477d9 | ||
|
|
9d03b2bb62 | ||
|
|
8987bd5832 | ||
|
|
f226842aa1 | ||
|
|
b14164879b | ||
|
|
bb22cd492e | ||
|
|
27be5aec74 | ||
|
|
048f9f4974 | ||
|
|
fb0b375be7 | ||
|
|
79d934bfb0 | ||
|
|
54dfedc516 | ||
|
|
0eb7157b6f | ||
|
|
2de953490d | ||
|
|
3ba44d2d5f | ||
|
|
313d13ea01 | ||
|
|
e68c04b722 | ||
|
|
c902c43766 | ||
|
|
c105049f7e | ||
|
|
17136d58f2 | ||
|
|
8ea1e9126f | ||
|
|
6dc4c74b5a | ||
|
|
9d1fd2317d | ||
|
|
1f9f5eed5d | ||
|
|
5e1a975b48 | ||
|
|
97f48e59fc | ||
|
|
e41fd24542 | ||
|
|
8bd192fb16 | ||
|
|
d2c1850fb5 | ||
|
|
8c3331dc97 | ||
|
|
f507188ddc | ||
|
|
76b7b2adf7 | ||
|
|
cb68662b9b | ||
|
|
b7cda3288e | ||
|
|
a1f54cad6c | ||
|
|
9f83b9df22 | ||
|
|
4ab241c930 | ||
|
|
f731835e45 | ||
|
|
bbaa975ec8 | ||
|
|
418ef43fbb | ||
|
|
40ebe78bb1 | ||
|
|
1b7115a337 | ||
|
|
2e6a5bc7ee | ||
|
|
72cef46e5e | ||
|
|
626bfd87a7 | ||
|
|
8f41f1fa60 | ||
|
|
faa8843650 | ||
|
|
0d9e54367f | ||
|
|
1f70b1e15d | ||
|
|
3f63b87807 | ||
|
|
9c3d2b6a4e | ||
|
|
1716fccbcc | ||
|
|
9043e4c757 | ||
|
|
2e9a73c5d8 | ||
|
|
1eaaa6b744 | ||
|
|
cb54e9c659 | ||
|
|
7c2b085d1a | ||
|
|
d063d52cce | ||
|
|
64c1b6d9cd | ||
|
|
8f15c423e6 | ||
|
|
329f4449dc | ||
|
|
0767916ade | ||
|
|
10923c7890 | ||
|
|
2832ea0cfe | ||
|
|
a7299a3f26 | ||
|
|
1601366cb6 | ||
|
|
e9a68801ba | ||
|
|
f73401fb9a | ||
|
|
dcf4572a69 | ||
|
|
d530d581f7 | ||
|
|
bdf05d8368 | ||
|
|
b71b226cc1 | ||
|
|
80f6b4587b | ||
|
|
e6e9c1cd62 | ||
|
|
246eed52de | ||
|
|
b306a60738 | ||
|
|
7d0ab3858e | ||
|
|
4e5001b46a | ||
|
|
b8f9803459 | ||
|
|
0c018d3697 | ||
|
|
72fdb41069 | ||
|
|
6eb8a74ff9 | ||
|
|
81ebf4fcf6 | ||
|
|
9875a9b1f1 | ||
|
|
27feba4594 | ||
|
|
c83393a541 | ||
|
|
7e1e7d14fa | ||
|
|
99b5bec069 | ||
|
|
7d8895545e | ||
|
|
33a5fe3bd4 | ||
|
|
847a8f45a4 | ||
|
|
8cf30395a1 | ||
|
|
22adb52c0a | ||
|
|
793c1ad990 | ||
|
|
febaeebfb8 | ||
|
|
d32f184696 | ||
|
|
20085794f0 | ||
|
|
a4fc52305a | ||
|
|
2aad4a3478 | ||
|
|
a5fb1d6c01 | ||
|
|
b76b329ef0 | ||
|
|
bae6f95830 | ||
|
|
cda9cf1539 | ||
|
|
f344212b93 | ||
|
|
0424998f38 | ||
|
|
8bfbdd7afa | ||
|
|
3de51b7bfe | ||
|
|
a58cd8c616 | ||
|
|
586a79cca0 | ||
|
|
349edf1bea | ||
|
|
677908910c | ||
|
|
6b5fe8c2ec | ||
|
|
26088a72b3 | ||
|
|
ebc837957f | ||
|
|
c4d3da5871 | ||
|
|
32f5811476 | ||
|
|
a7f191d51d | ||
|
|
1b370f9d8d | ||
|
|
92186d7cf7 | ||
|
|
5d3c0767da | ||
|
|
aa4bf4284b | ||
|
|
d9a9bfc9c7 | ||
|
|
90a6e310fe | ||
|
|
f39af7e05d | ||
|
|
dce5a06aba | ||
|
|
3b65be9127 | ||
|
|
ad0183e419 | ||
|
|
4f36039e7b | ||
|
|
b74d1c9247 | ||
|
|
cf8b8c1969 | ||
|
|
d1767bbf67 | ||
|
|
7b74b9cab5 | ||
|
|
14d3880daf | ||
|
|
22f1cc955d | ||
|
|
cab31fd512 | ||
|
|
1fc55c2bb9 | ||
|
|
5ecd940a59 | ||
|
|
3b8c2417fb | ||
|
|
15c3096e89 | ||
|
|
22d1622926 | ||
|
|
35c68944c7 | ||
|
|
b1fa26bb76 | ||
|
|
d6fb2a0836 | ||
|
|
65aa3dda85 | ||
|
|
a05af3ebf3 | ||
|
|
0e1781af26 | ||
|
|
14d9f51bbe | ||
|
|
c04af2a330 | ||
|
|
c77063afcd | ||
|
|
a19a9e3ca8 | ||
|
|
ad2bbe23be | ||
|
|
6882c78ce4 | ||
|
|
2db358146f | ||
|
|
1cc1cb099e | ||
|
|
aea2675f7b | ||
|
|
8f9e454241 | ||
|
|
7666307931 | ||
|
|
791ca6fde4 | ||
|
|
43484e8b50 | ||
|
|
5471f5b2ee | ||
|
|
02c211a0dc | ||
|
|
c780ff5ae7 | ||
|
|
8edf0ca7f3 | ||
|
|
927308cfd9 | ||
|
|
8fed600077 | ||
|
|
a83d87abd4 | ||
|
|
c808940c04 | ||
|
|
81874ad442 | ||
|
|
3478d6f706 | ||
|
|
13b6309138 | ||
|
|
90db9e7517 | ||
|
|
f15889461d | ||
|
|
dea4194f8b | ||
|
|
e331f1ee0e | ||
|
|
0ddc6867fb | ||
|
|
3c5d2e4661 | ||
|
|
ff5cb8e864 | ||
|
|
7ad2e022fb | ||
|
|
f65fc1e766 | ||
|
|
dcc9dfb27d | ||
|
|
650dff73bd | ||
|
|
6d00145076 | ||
|
|
cc2558bf10 | ||
|
|
e566b89a5f | ||
|
|
47c4c2abd4 | ||
|
|
fa5bb5acf1 | ||
|
|
50500cfcb6 | ||
|
|
9e81ab65cb | ||
|
|
ff26493fd5 | ||
|
|
9b13d21fc9 | ||
|
|
887f509d1d | ||
|
|
13d2b08638 | ||
|
|
c298a91f95 | ||
|
|
37a78902db | ||
|
|
15b3088157 | ||
|
|
7830cf9166 | ||
|
|
321d94b17e | ||
|
|
6b59cc8a10 | ||
|
|
91b1f9eee9 | ||
|
|
c9a13147fe | ||
|
|
1632566ecb | ||
|
|
a52a28b609 | ||
|
|
54443c092c | ||
|
|
ad1e8a9b0f | ||
|
|
29b7ecb017 | ||
|
|
6f9a67a7c7 | ||
|
|
cfeed391d7 | ||
|
|
8c36e6920a | ||
|
|
3dcaf20d6b | ||
|
|
d949e2804a | ||
|
|
1fc9405537 | ||
|
|
b64dfdd8cd | ||
|
|
a6779bcae2 | ||
|
|
8293a0d533 | ||
|
|
0b9a3c86a2 | ||
|
|
5a2a044e24 | ||
|
|
99f9b69716 | ||
|
|
b336d928fe | ||
|
|
4760749402 | ||
|
|
7efde5eb83 | ||
|
|
5252ab697c | ||
|
|
41555f67e0 | ||
|
|
75ba07cb3a | ||
|
|
0bdfcfaa33 | ||
|
|
8cceafc834 | ||
|
|
2d4c5ddbdd | ||
|
|
d1ed28cb94 | ||
|
|
7dbb1eacc1 | ||
|
|
e9d17b1f91 | ||
|
|
6437648176 | ||
|
|
e99541e637 | ||
|
|
68278b66c5 | ||
|
|
f483b214bb | ||
|
|
f5b458b1dc | ||
|
|
f7b4f0c193 | ||
|
|
6ede6bc8f2 | ||
|
|
fdae64d8d7 | ||
|
|
f85e6548c7 | ||
|
|
c937e237ad | ||
|
|
0ebdca5e61 | ||
|
|
81eac415ad | ||
|
|
0b2eee8b33 | ||
|
|
d0d5d5ff09 | ||
|
|
57dfca052b | ||
|
|
99b36c2c32 | ||
|
|
b013d93786 | ||
|
|
b1fa21aa0e | ||
|
|
9740102990 | ||
|
|
0f7a4534c1 | ||
|
|
7a565a0479 | ||
|
|
69c2250ec2 | ||
|
|
d17f78c373 | ||
|
|
ccac5b1382 | ||
|
|
9442d6b349 | ||
|
|
232dbb1864 | ||
|
|
58befe3081 | ||
|
|
bd3c6793a1 | ||
|
|
d52451bcf8 | ||
|
|
6d72758f12 | ||
|
|
1d6929c8bc | ||
|
|
48a208baf1 | ||
|
|
61cf09b2e7 | ||
|
|
b51fe837a4 | ||
|
|
4e11e42546 | ||
|
|
ba33d67a1a | ||
|
|
70853785b6 | ||
|
|
12a65dc4a8 | ||
|
|
b67fe1ecb9 | ||
|
|
6bcc55f7d0 | ||
|
|
a6da7f138c | ||
|
|
d66de319bd | ||
|
|
760736b3f3 | ||
|
|
0636c11f0b | ||
|
|
5dc1e66366 | ||
|
|
a5054184a1 | ||
|
|
09910785c8 | ||
|
|
523803d633 | ||
|
|
4bd21e0d7f | ||
|
|
c66d2b6a53 | ||
|
|
da69df5f42 | ||
|
|
32b58159cd | ||
|
|
dfc3904f77 | ||
|
|
4825d3a537 | ||
|
|
5c639118d3 | ||
|
|
9bc7e71f16 | ||
|
|
19316955dd | ||
|
|
172f746e4d | ||
|
|
47e5d2f5e1 | ||
|
|
70594bdd16 | ||
|
|
09e69e45a6 | ||
|
|
9528b8685f | ||
|
|
b3cbe87b62 | ||
|
|
6a236184af | ||
|
|
108acc0511 | ||
|
|
e37ce11cfa | ||
|
|
fa89076673 | ||
|
|
5aba56e0e0 | ||
|
|
daa7e4a203 | ||
|
|
a3ab89df2b | ||
|
|
90fb5dc962 | ||
|
|
3b71336edc | ||
|
|
baea0a98f8 | ||
|
|
d8dc6d4583 | ||
|
|
95d87f1ac0 | ||
|
|
7e9975d00a | ||
|
|
212a044a55 | ||
|
|
165a7f3670 | ||
|
|
0d75c68e5e | ||
|
|
ff04ce3ddf | ||
|
|
43213dfc4a | ||
|
|
4a086dfc08 | ||
|
|
6b54a439b2 | ||
|
|
00b81936aa | ||
|
|
b2e16f941d | ||
|
|
72563925a1 | ||
|
|
f951f7876b | ||
|
|
7e4ac6c689 | ||
|
|
9e5a25c100 | ||
|
|
8461196a79 | ||
|
|
5bec4b8f04 | ||
|
|
502f772839 | ||
|
|
8cfaf658cc | ||
|
|
2b7284db4f | ||
|
|
2b090320be | ||
|
|
378dacdf1c | ||
|
|
8513c179f3 | ||
|
|
a710475726 | ||
|
|
a8ae0aafe3 | ||
|
|
9518503ebe | ||
|
|
141b5fc7d7 | ||
|
|
709849e717 | ||
|
|
2ee3db6cd2 | ||
|
|
84d1929973 | ||
|
|
195208593d | ||
|
|
846a9e8963 | ||
|
|
5cec37de53 | ||
|
|
261003ceb0 | ||
|
|
e260e80814 | ||
|
|
2d71e2a44c | ||
|
|
84df72222d | ||
|
|
08f1e3af48 | ||
|
|
afdf29e57f | ||
|
|
262be79041 | ||
|
|
8da1810975 | ||
|
|
9df7023497 | ||
|
|
54fa59c8ec | ||
|
|
2664139da4 | ||
|
|
6bf4a10ed4 | ||
|
|
7f79fabaee | ||
|
|
3813fa8a16 | ||
|
|
75a116bdaa | ||
|
|
f87aa7e336 | ||
|
|
1904003511 | ||
|
|
84cca8afc8 | ||
|
|
1a96ce552f | ||
|
|
7db1890c99 | ||
|
|
5cebc226cc | ||
|
|
1c5162c5a9 | ||
|
|
53641e8b8d | ||
|
|
038fb523f1 | ||
|
|
b70858ccae | ||
|
|
f7d69601c5 | ||
|
|
2333be46aa | ||
|
|
f961ec55e7 | ||
|
|
21f55419b7 | ||
|
|
a26c58e27e | ||
|
|
5a0010abe9 | ||
|
|
a57b37ed0e | ||
|
|
6b4bc971fd | ||
|
|
7009d6c6dd | ||
|
|
b2b6d519c5 | ||
|
|
3cce89d8ed | ||
|
|
cca59081de | ||
|
|
e53f45f621 | ||
|
|
004a5310d9 | ||
|
|
6ccd473127 | ||
|
|
161526d99d | ||
|
|
069918e1fd | ||
|
|
91d78a10c3 | ||
|
|
6f80674d66 | ||
|
|
3150a789c1 | ||
|
|
f37a693825 | ||
|
|
7e540a083f | ||
|
|
522b8bf2c1 | ||
|
|
243eea36ca | ||
|
|
69b09ccfc8 | ||
|
|
41a2954e4e | ||
|
|
c85db1003b | ||
|
|
7943a02cb6 | ||
|
|
f70bc2c98c | ||
|
|
022a1f9957 | ||
|
|
211ed0a766 | ||
|
|
50bee2f811 | ||
|
|
922a8648fc | ||
|
|
c9d93cd333 | ||
|
|
a9a439183d | ||
|
|
e4a69b1044 | ||
|
|
b31211cbe9 | ||
|
|
d01b5894c4 | ||
|
|
504663a6ee | ||
|
|
bd63ae72e6 | ||
|
|
4c19c9341c | ||
|
|
222c04a7e7 | ||
|
|
fcdfd696ec | ||
|
|
c8ca50b483 | ||
|
|
a61e68275a | ||
|
|
6576b19a28 | ||
|
|
ceb66fd035 | ||
|
|
22598ee572 | ||
|
|
52969416bc | ||
|
|
c61172f9c2 | ||
|
|
0786d9ec22 | ||
|
|
938bf4c901 | ||
|
|
87d4e16568 | ||
|
|
55c8908756 | ||
|
|
51455b1ee0 | ||
|
|
906626b8f8 | ||
|
|
94b9ca988d | ||
|
|
bea7894166 | ||
|
|
b32436cd2e | ||
|
|
190e2fa50f | ||
|
|
0d46ddf7b4 | ||
|
|
f7eaaa3adb | ||
|
|
57e2126a02 | ||
|
|
5130d3d6ec | ||
|
|
587debf92e | ||
|
|
d301c7b98c | ||
|
|
f43fbda2a4 | ||
|
|
e09383bccf | ||
|
|
301a8afff5 | ||
|
|
371225520f | ||
|
|
eb95e49150 | ||
|
|
96010e3ca1 | ||
|
|
e55b8b2fd9 | ||
|
|
ffe5370e35 | ||
|
|
df19863b23 | ||
|
|
cb3c4af404 | ||
|
|
bd2a55cd26 | ||
|
|
b370acd679 | ||
|
|
5c04d3488a | ||
|
|
690cae0ef4 | ||
|
|
936bd87a52 | ||
|
|
dc2d930520 | ||
|
|
966cddf26b | ||
|
|
6e35f28352 | ||
|
|
0146c80c40 | ||
|
|
b809dc4271 | ||
|
|
f37c432bd5 | ||
|
|
d9471bee3d | ||
|
|
6ce64e8458 | ||
|
|
031f91df1a | ||
|
|
89763bc8af | ||
|
|
6e507b9460 | ||
|
|
c57727fd65 | ||
|
|
a2e5333a93 | ||
|
|
5e6355d182 | ||
|
|
e4886a9e33 | ||
|
|
95ad9e4573 | ||
|
|
3c6b8bb888 | ||
|
|
cff01ec5ec | ||
|
|
0c4b639083 | ||
|
|
d1c8eabc63 | ||
|
|
c000a5ed75 | ||
|
|
9542876d2f | ||
|
|
899613f788 | ||
|
|
829eeb07f8 | ||
|
|
841c7ac0f9 | ||
|
|
34fbaa5f6d | ||
|
|
9b5f0fac81 | ||
|
|
1ed78ee160 | ||
|
|
e726bdcce2 | ||
|
|
ab3a57d01b | ||
|
|
bc51d961cd | ||
|
|
12049f956a | ||
|
|
7952e6befe | ||
|
|
72e16f6d96 | ||
|
|
bf7602bc09 | ||
|
|
520af226c0 | ||
|
|
542c66997f | ||
|
|
f8ebeaae10 | ||
|
|
56752158af | ||
|
|
09b27f9e8d | ||
|
|
77549ad4f6 | ||
|
|
fc0eac37e4 | ||
|
|
db8f2a1a9d | ||
|
|
08cb430281 | ||
|
|
9fa3d891c6 | ||
|
|
b00ff47963 | ||
|
|
e02f7912bc | ||
|
|
e4f9a0dca0 | ||
|
|
3870ebee6d | ||
|
|
062ebff098 | ||
|
|
0eed4b4386 | ||
|
|
4307b7dd8e | ||
|
|
c72ff318d3 | ||
|
|
5e561a9d52 | ||
|
|
640026ec59 | ||
|
|
11c4294846 | ||
|
|
1850e8d49c | ||
|
|
afb4a36ffa | ||
|
|
45df6f7801 | ||
|
|
6295a02275 | ||
|
|
13e597a5ad | ||
|
|
d515e2b06c | ||
|
|
41c664cacf | ||
|
|
7566006d0d | ||
|
|
d8fa52b7b5 | ||
|
|
f246cc9cdd | ||
|
|
da266e6c7b | ||
|
|
f50dcbe404 | ||
|
|
cdd62522b6 | ||
|
|
1ad69ad415 | ||
|
|
05ae69a6eb | ||
|
|
8396798eba | ||
|
|
49a78929c6 | ||
|
|
379d449c44 | ||
|
|
d0c776528b | ||
|
|
4af8b711c0 | ||
|
|
ef711962d5 | ||
|
|
44faa07b6c | ||
|
|
680f40c37e | ||
|
|
3aefed2dc2 | ||
|
|
8ff60ddef4 | ||
|
|
eef9659c95 | ||
|
|
42cf74d56b | ||
|
|
04ba4348de | ||
|
|
864a8d9aca | ||
|
|
edcfd687ef | ||
|
|
3e8d1dfb69 | ||
|
|
b6b5e5cec1 | ||
|
|
f783759928 | ||
|
|
c37d7aad36 | ||
|
|
d65983f386 | ||
|
|
1ed13f65fe | ||
|
|
377cebe36f | ||
|
|
2f781f2128 | ||
|
|
e627a0da1e | ||
|
|
623e91e2e3 | ||
|
|
deb603aaf4 | ||
|
|
0208b6accd | ||
|
|
d7c5d060c4 | ||
|
|
299d0b2720 | ||
|
|
b8547f31e4 | ||
|
|
7c57a4cfc0 | ||
|
|
84e8c4aa1d | ||
|
|
89a140fb75 | ||
|
|
3e9877a30f | ||
|
|
3bb176d8ae | ||
|
|
34023558f5 | ||
|
|
9d82bab041 | ||
|
|
3eff62394b | ||
|
|
4d9c324495 | ||
|
|
75c866d6a3 | ||
|
|
6f6eaca861 | ||
|
|
ea258c4492 | ||
|
|
240333277a | ||
|
|
9e8278134d | ||
|
|
c8db980add | ||
|
|
3f63e3426e | ||
|
|
31296cc3f7 | ||
|
|
33d2905cde | ||
|
|
2048354c8b | ||
|
|
98542d4497 | ||
|
|
6d580247c2 | ||
|
|
ab99e9252d | ||
|
|
fac32cda5a | ||
|
|
a3174fd874 | ||
|
|
ddf4c79977 | ||
|
|
acd51ecea8 | ||
|
|
4389574aff | ||
|
|
ff2ae90764 | ||
|
|
2508b5cef9 | ||
|
|
b1acd0a7b0 | ||
|
|
8be58d3a7f | ||
|
|
c5051ea0ea | ||
|
|
3c1db4ca43 | ||
|
|
33f6a0aaf5 | ||
|
|
6316b99556 | ||
|
|
bb9ce6b287 | ||
|
|
a3ca3e9218 | ||
|
|
71c997dc83 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.vagrant
|
||||
.vagrant*
|
||||
bin
|
||||
docker/docker
|
||||
.*.swp
|
||||
a.out
|
||||
@@ -6,3 +7,11 @@ a.out
|
||||
build_src
|
||||
command-line-arguments.test
|
||||
.flymake*
|
||||
docker.test
|
||||
auth/auth.test
|
||||
.idea
|
||||
.DS_Store
|
||||
docs/_build
|
||||
docs/_static
|
||||
docs/_templates
|
||||
.gopath/
|
||||
|
||||
19
.mailmap
Normal file
19
.mailmap
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generate AUTHORS: git log --all --format='%aN <%aE>' | sort -uf | grep -v vagrant-ubuntu-12
|
||||
<charles.hooper@dotcloud.com> <chooper@plumata.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
||||
Guillaume J. Charmes <guillaume.charmes@dotcloud.com> creack <charmes.guillaume@gmail.com>
|
||||
<guillaume.charmes@dotcloud.com> <guillaume@dotcloud.com>
|
||||
<kencochrane@gmail.com> <KenCochrane@gmail.com>
|
||||
<sridharr@activestate.com> <github@srid.name>
|
||||
Thatcher Peskens <thatcher@dotcloud.com> dhrp <thatcher@dotcloud.com>
|
||||
Thatcher Peskens <thatcher@dotcloud.com> dhrp <thatcher@gmx.net>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> jpetazzo <jerome.petazzoni@dotcloud.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> <jp@enix.org>
|
||||
Joffrey F <joffrey@dotcloud.com>
|
||||
<joffrey@dotcloud.com> <f.joffrey@gmail.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
<kalessin@kalessin.fr> <louis@dotcloud.com>
|
||||
<victor.vieux@dotcloud.com> <victor@dotcloud.com>
|
||||
<dominik@honnef.co> <dominikh@fork-bomb.org>
|
||||
58
AUTHORS
58
AUTHORS
@@ -1,13 +1,45 @@
|
||||
Solomon Hykes
|
||||
Sam Alba
|
||||
Jérôme Petazzoni
|
||||
Andrea Luzzardi
|
||||
Joffrey Fuhrer
|
||||
Louis Opter
|
||||
Niall O'Higgins
|
||||
Brian McCallister
|
||||
Jeff Lindsay
|
||||
Ken Cochrane
|
||||
Charles Hooper
|
||||
Guillaume Charmes
|
||||
Daniel Mizyrycki
|
||||
Andrea Luzzardi <aluzzardi@gmail.com>
|
||||
Andy Rothfusz <github@metaliveblog.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
Antony Messerli <amesserl@rackspace.com>
|
||||
Brian McCallister <brianm@skife.org>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Charles Hooper <charles.hooper@dotcloud.com>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com>
|
||||
Daniel Robinson <gottagetmac@gmail.com>
|
||||
Dominik Honnef <dominik@honnef.co>
|
||||
Don Spaulding <donspauldingii@gmail.com>
|
||||
ezbercih <cem.ezberci@gmail.com>
|
||||
Flavio Castelli <fcastelli@suse.com>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
|
||||
Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
|
||||
Hunter Blanks <hunter@twilio.com>
|
||||
Jeff Lindsay <progrium@gmail.com>
|
||||
Jeremy Grosser <jeremy@synack.me>
|
||||
Joffrey F <joffrey@dotcloud.com>
|
||||
John Costa <john.costa@gmail.com>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Julien Barbier <write0@gmail.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
|
||||
Ken Cochrane <kencochrane@gmail.com>
|
||||
Kevin J. Lynagh <kevin@keminglabs.com>
|
||||
Louis Opter <kalessin@kalessin.fr>
|
||||
Maxim Treskin <zerthurd@gmail.com>
|
||||
Mikhail Sobolev <mss@mawhrin.net>
|
||||
Nelson Chen <crazysim@gmail.com>
|
||||
Niall O'Higgins <niallo@unworkable.org>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Piotr Bogdan <ppbogdan@gmail.com>
|
||||
Robert Obryk <robryk@gmail.com>
|
||||
Sam Alba <sam.alba@gmail.com>
|
||||
Shawn Siefkas <shawn.siefkas@meredith.com>
|
||||
Silas Sewell <silas@sewell.org>
|
||||
Solomon Hykes <solomon@dotcloud.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Thatcher Peskens <thatcher@dotcloud.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Troy Howard <thoward37@gmail.com>
|
||||
unclejack <unclejacksons@gmail.com>
|
||||
Victor Vieux <victor.vieux@dotcloud.com>
|
||||
Vivek Agarwal <me@vivek.im>
|
||||
|
||||
143
CHANGELOG.md
Normal file
143
CHANGELOG.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Changelog
|
||||
|
||||
## 0.3.2 (2013-05-09)
|
||||
* Runtime: Store the actual archive on commit
|
||||
* Registry: Improve the checksum process
|
||||
* Registry: Use the size to have a good progress bar while pushing
|
||||
* Registry: Use the actual archive if it exists in order to speed up the push
|
||||
- Registry: Fix error 400 on push
|
||||
|
||||
## 0.3.1 (2013-05-08)
|
||||
+ Builder: Implement the autorun capability within docker builder
|
||||
+ Builder: Add caching to docker builder
|
||||
+ Builder: Add support for docker builder with native API as top level command
|
||||
+ Runtime: Add go version to debug infos
|
||||
+ Builder: Implement ENV within docker builder
|
||||
+ Registry: Add docker search top level command in order to search a repository
|
||||
+ Images: output graph of images to dot (graphviz)
|
||||
+ Documentation: new introduction and high-level overview
|
||||
+ Documentation: Add the documentation for docker builder
|
||||
+ Website: new high-level overview
|
||||
- Makefile: Swap "go get" for "go get -d", especially to compile on go1.1rc
|
||||
- Images: fix ByParent function
|
||||
- Builder: Check the command existance prior create and add Unit tests for the case
|
||||
- Registry: Fix pull for official images with specific tag
|
||||
- Registry: Fix issue when login in with a different user and trying to push
|
||||
- Documentation: CSS fix for docker documentation to make REST API docs look better.
|
||||
- Documentation: Fixed CouchDB example page header mistake
|
||||
- Documentation: fixed README formatting
|
||||
* Registry: Improve checksum - async calculation
|
||||
* Runtime: kernel version - don't show the dash if flavor is empty
|
||||
* Documentation: updated www.docker.io website.
|
||||
* Builder: use any whitespaces instead of tabs
|
||||
* Packaging: packaging ubuntu; issue #510: Use goland-stable PPA package to build docker
|
||||
|
||||
## 0.3.0 (2013-05-06)
|
||||
+ Registry: Implement the new registry
|
||||
+ Documentation: new example: sharing data between 2 couchdb databases
|
||||
- Runtime: Fix the command existance check
|
||||
- Runtime: strings.Split may return an empty string on no match
|
||||
- Runtime: Fix an index out of range crash if cgroup memory is not
|
||||
* Documentation: Various improvments
|
||||
* Vagrant: Use only one deb line in /etc/apt
|
||||
|
||||
## 0.2.2 (2013-05-03)
|
||||
+ Support for data volumes ('docker run -v=PATH')
|
||||
+ Share data volumes between containers ('docker run -volumes-from')
|
||||
+ Improved documentation
|
||||
* Upgrade to Go 1.0.3
|
||||
* Various upgrades to the dev environment for contributors
|
||||
|
||||
## 0.2.1 (2013-05-01)
|
||||
+ 'docker commit -run' bundles a layer with default runtime options: command, ports etc.
|
||||
* Improve install process on Vagrant
|
||||
+ New Dockerfile operation: "maintainer"
|
||||
+ New Dockerfile operation: "expose"
|
||||
+ New Dockerfile operation: "cmd"
|
||||
+ Contrib script to build a Debian base layer
|
||||
+ 'docker -d -r': restart crashed containers at daemon startup
|
||||
* Runtime: improve test coverage
|
||||
|
||||
## 0.2.0 (2013-04-23)
|
||||
- Runtime: ghost containers can be killed and waited for
|
||||
* Documentation: update install intructions
|
||||
- Packaging: fix Vagrantfile
|
||||
- Development: automate releasing binaries and ubuntu packages
|
||||
+ Add a changelog
|
||||
- Various bugfixes
|
||||
|
||||
## 0.1.8 (2013-04-22)
|
||||
- Dynamically detect cgroup capabilities
|
||||
- Issue stability warning on kernels <3.8
|
||||
- 'docker push' buffers on disk instead of memory
|
||||
- Fix 'docker diff' for removed files
|
||||
- Fix 'docker stop' for ghost containers
|
||||
- Fix handling of pidfile
|
||||
- Various bugfixes and stability improvements
|
||||
|
||||
## 0.1.7 (2013-04-18)
|
||||
- Container ports are available on localhost
|
||||
- 'docker ps' shows allocated TCP ports
|
||||
- Contributors can run 'make hack' to start a continuous integration VM
|
||||
- Streamline ubuntu packaging & uploading
|
||||
- Various bugfixes and stability improvements
|
||||
|
||||
## 0.1.6 (2013-04-17)
|
||||
- Record the author an image with 'docker commit -author'
|
||||
|
||||
## 0.1.5 (2013-04-17)
|
||||
- Disable standalone mode
|
||||
- Use a custom DNS resolver with 'docker -d -dns'
|
||||
- Detect ghost containers
|
||||
- Improve diagnosis of missing system capabilities
|
||||
- Allow disabling memory limits at compile time
|
||||
- Add debian packaging
|
||||
- Documentation: installing on Arch Linux
|
||||
- Documentation: running Redis on docker
|
||||
- Fixed lxc 0.9 compatibility
|
||||
- Automatically load aufs module
|
||||
- Various bugfixes and stability improvements
|
||||
|
||||
## 0.1.4 (2013-04-09)
|
||||
- Full support for TTY emulation
|
||||
- Detach from a TTY session with the escape sequence `C-p C-q`
|
||||
- Various bugfixes and stability improvements
|
||||
- Minor UI improvements
|
||||
- Automatically create our own bridge interface 'docker0'
|
||||
|
||||
## 0.1.3 (2013-04-04)
|
||||
- Choose TCP frontend port with '-p :PORT'
|
||||
- Layer format is versioned
|
||||
- Major reliability improvements to the process manager
|
||||
- Various bugfixes and stability improvements
|
||||
|
||||
## 0.1.2 (2013-04-03)
|
||||
- Set container hostname with 'docker run -h'
|
||||
- Selective attach at run with 'docker run -a [stdin[,stdout[,stderr]]]'
|
||||
- Various bugfixes and stability improvements
|
||||
- UI polish
|
||||
- Progress bar on push/pull
|
||||
- Use XZ compression by default
|
||||
- Make IP allocator lazy
|
||||
|
||||
## 0.1.1 (2013-03-31)
|
||||
- Display shorthand IDs for convenience
|
||||
- Stabilize process management
|
||||
- Layers can include a commit message
|
||||
- Simplified 'docker attach'
|
||||
- Fixed support for re-attaching
|
||||
- Various bugfixes and stability improvements
|
||||
- Auto-download at run
|
||||
- Auto-login on push
|
||||
- Beefed up documentation
|
||||
|
||||
## 0.1.0 (2013-03-23)
|
||||
- First release
|
||||
- Implement registry in order to push/pull images
|
||||
- TCP port allocation
|
||||
- Fix termcaps on Linux
|
||||
- Add documentation
|
||||
- Add Vagrant support with Vagrantfile
|
||||
- Add unit tests
|
||||
- Add repository/tags to ease image management
|
||||
- Improve the layer implementation
|
||||
93
CONTRIBUTING.md
Normal file
93
CONTRIBUTING.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Contributing to Docker
|
||||
|
||||
Want to hack on Docker? Awesome! There are instructions to get you
|
||||
started on the website: http://docker.io/gettingstarted.html
|
||||
|
||||
They are probably not perfect, please let us know if anything feels
|
||||
wrong or incomplete.
|
||||
|
||||
## Contribution guidelines
|
||||
|
||||
### Pull requests are always welcome
|
||||
|
||||
We are always thrilled to receive pull requests, and do our best to
|
||||
process them as fast as possible. Not sure if that typo is worth a pull
|
||||
request? Do it! We will appreciate it.
|
||||
|
||||
If your pull request is not accepted on the first try, don't be
|
||||
discouraged! If there's a problem with the implementation, hopefully you
|
||||
received feedback on what to improve.
|
||||
|
||||
We're trying very hard to keep Docker lean and focused. We don't want it
|
||||
to do everything for everybody. This means that we might decide against
|
||||
incorporating a new feature. However, there might be a way to implement
|
||||
that feature *on top of* docker.
|
||||
|
||||
### Discuss your design on the mailing list
|
||||
|
||||
We recommend discussing your plans [on the mailing
|
||||
list](https://groups.google.com/forum/?fromgroups#!forum/docker-club)
|
||||
before starting to code - especially for more ambitious contributions.
|
||||
This gives other contributors a chance to point you in the right
|
||||
direction, give feedback on your design, and maybe point out if someone
|
||||
else is working on the same thing.
|
||||
|
||||
### Create issues...
|
||||
|
||||
Any significant improvement should be documented as [a github
|
||||
issue](https://github.com/dotcloud/docker/issues) before anybody
|
||||
starts working on it.
|
||||
|
||||
### ...but check for existing issues first!
|
||||
|
||||
Please take a moment to check that an issue doesn't already exist
|
||||
documenting your bug report or improvement proposal. If it does, it
|
||||
never hurts to add a quick "+1" or "I have this problem too". This will
|
||||
help prioritize the most common problems and requests.
|
||||
|
||||
### Conventions
|
||||
|
||||
Fork the repo and make changes on your fork in a feature branch:
|
||||
|
||||
- If it's a bugfix branch, name it XXX-something where XXX is the number of the
|
||||
issue
|
||||
- If it's a feature branch, create an enhancement issue to announce your
|
||||
intentions, and name it XXX-something where XXX is the number of the issue.
|
||||
|
||||
Submit unit tests for your changes. Go has a great test framework built in; use
|
||||
it! Take a look at existing tests for inspiration. Run the full test suite on
|
||||
your branch before submitting a pull request.
|
||||
|
||||
Make sure you include relevant updates or additions to documentation when
|
||||
creating or modifying features.
|
||||
|
||||
Write clean code. Universally formatted code promotes ease of writing, reading,
|
||||
and maintenance. Always run `go fmt` before committing your changes. Most
|
||||
editors have plugins that do this automatically, and there's also a git
|
||||
pre-commit hook:
|
||||
|
||||
```
|
||||
curl -o .git/hooks/pre-commit https://raw.github.com/edsrzf/gofmt-git-hook/master/fmt-check && chmod +x .git/hooks/pre-commit
|
||||
```
|
||||
|
||||
Pull requests descriptions should be as clear as possible and include a
|
||||
reference to all the issues that they address.
|
||||
|
||||
Code review comments may be added to your pull request. Discuss, then make the
|
||||
suggested modifications and push additional commits to your feature branch. Be
|
||||
sure to post a comment after pushing. The new commits will show up in the pull
|
||||
request automatically, but the reviewers will not be notified unless you
|
||||
comment.
|
||||
|
||||
Before the pull request is merged, make sure that you squash your commits into
|
||||
logical units of work using `git rebase -i` and `git push -f`. After every
|
||||
commit the test suite should be passing. Include documentation changes in the
|
||||
same commit so that a revert would remove all traces of the feature or fix.
|
||||
|
||||
Commits that fix or close an issue should include a reference like `Closes #XXX`
|
||||
or `Fixes #XXX`, which will automatically close the issue when merged.
|
||||
|
||||
Add your name to the AUTHORS file, but make sure the list is sorted and your
|
||||
name and email address match your git configuration. The AUTHORS file is
|
||||
regenerated occasionally from the git commit history, so a mismatch may result
|
||||
in your changes being overwritten.
|
||||
136
Makefile
136
Makefile
@@ -1,84 +1,82 @@
|
||||
PKG_NAME=dotcloud-docker
|
||||
PKG_ARCH=amd64
|
||||
PKG_VERSION=1
|
||||
ROOT_PATH:=$(PWD)
|
||||
BUILD_PATH=build # Do not change, decided by dpkg-buildpackage
|
||||
BUILD_SRC=build_src
|
||||
GITHUB_PATH=src/github.com/dotcloud/docker
|
||||
INSDIR=usr/bin
|
||||
SOURCE_PACKAGE=$(PKG_NAME)_$(PKG_VERSION).orig.tar.gz
|
||||
DEB_PACKAGE=$(PKG_NAME)_$(PKG_VERSION)_$(PKG_ARCH).deb
|
||||
EXTRA_GO_PKG=fs auth
|
||||
DOCKER_PACKAGE := github.com/dotcloud/docker
|
||||
RELEASE_VERSION := $(shell git tag | grep -E "v[0-9\.]+$$" | sort -nr | head -n 1)
|
||||
SRCRELEASE := docker-$(RELEASE_VERSION)
|
||||
BINRELEASE := docker-$(RELEASE_VERSION).tgz
|
||||
|
||||
TMPDIR=$(shell mktemp -d -t XXXXXX)
|
||||
GIT_ROOT := $(shell git rev-parse --show-toplevel)
|
||||
BUILD_DIR := $(CURDIR)/.gopath
|
||||
|
||||
GOPATH ?= $(BUILD_DIR)
|
||||
export GOPATH
|
||||
|
||||
# Build a debian source package
|
||||
all: build_in_deb
|
||||
GO_OPTIONS ?=
|
||||
ifeq ($(VERBOSE), 1)
|
||||
GO_OPTIONS += -v
|
||||
endif
|
||||
|
||||
build_in_deb:
|
||||
echo "GOPATH = " $(ROOT_PATH)
|
||||
mkdir bin
|
||||
cd $(GITHUB_PATH)/docker; GOPATH=$(ROOT_PATH) go build -o $(ROOT_PATH)/bin/docker
|
||||
GIT_COMMIT = $(shell git rev-parse --short HEAD)
|
||||
GIT_STATUS = $(shell test -n "`git status --porcelain`" && echo "+CHANGES")
|
||||
|
||||
# DESTDIR provided by Debian packaging
|
||||
install:
|
||||
# Call this from a go environment (as packaged for deb source package)
|
||||
mkdir -p $(DESTDIR)/$(INSDIR)
|
||||
mkdir -p $(DESTDIR)/etc/init
|
||||
install -m 0755 bin/docker $(DESTDIR)/$(INSDIR)
|
||||
install -o root -m 0755 etc/docker.upstart $(DESTDIR)/etc/init/docker.conf
|
||||
BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS)"
|
||||
|
||||
$(BUILD_SRC): cleanup
|
||||
# Copy ourselves into $BUILD_SRC to comply with unusual golang constraints
|
||||
tar --exclude=*.tar.gz --exclude=checkout.tgz -f checkout.tgz -cz *
|
||||
mkdir -p $(BUILD_SRC)/$(GITHUB_PATH)
|
||||
tar -f checkout.tgz -C $(BUILD_SRC)/$(GITHUB_PATH) -xz
|
||||
cd $(BUILD_SRC)/$(GITHUB_PATH)/docker; GOPATH=$(ROOT_PATH)/$(BUILD_SRC) go get -d
|
||||
for d in `find $(BUILD_SRC) -name '.git*'`; do rm -rf $$d; done
|
||||
# Populate source build with debian stuff
|
||||
cp -R -L ./deb/* $(BUILD_SRC)
|
||||
SRC_DIR := $(GOPATH)/src
|
||||
|
||||
$(SOURCE_PACKAGE): $(BUILD_SRC)
|
||||
rm -f $(SOURCE_PACKAGE)
|
||||
# Create the debian source package
|
||||
tar -f $(SOURCE_PACKAGE) -C ${ROOT_PATH}/${BUILD_SRC} -cz .
|
||||
DOCKER_DIR := $(SRC_DIR)/$(DOCKER_PACKAGE)
|
||||
DOCKER_MAIN := $(DOCKER_DIR)/docker
|
||||
|
||||
# Build deb package fetching go dependencies and cleaning up git repositories
|
||||
deb: $(DEB_PACKAGE)
|
||||
DOCKER_BIN_RELATIVE := bin/docker
|
||||
DOCKER_BIN := $(CURDIR)/$(DOCKER_BIN_RELATIVE)
|
||||
|
||||
$(DEB_PACKAGE): $(SOURCE_PACKAGE)
|
||||
# dpkg-buildpackage looks for source package tarball in ../
|
||||
cd $(BUILD_SRC); dpkg-buildpackage
|
||||
rm -rf $(BUILD_PATH) debian/$(PKG_NAME)* debian/files
|
||||
.PHONY: all clean test hack release srcrelease $(BINRELEASE) $(SRCRELEASE) $(DOCKER_BIN) $(DOCKER_DIR)
|
||||
|
||||
debsrc: $(SOURCE_PACKAGE)
|
||||
all: $(DOCKER_BIN)
|
||||
|
||||
# Build local sources
|
||||
#$(PKG_NAME): build_local
|
||||
$(DOCKER_BIN): $(DOCKER_DIR)
|
||||
@mkdir -p $(dir $@)
|
||||
@(cd $(DOCKER_MAIN); go build $(GO_OPTIONS) $(BUILD_OPTIONS) -o $@)
|
||||
@echo $(DOCKER_BIN_RELATIVE) is created.
|
||||
|
||||
build_local:
|
||||
-@mkdir -p bin
|
||||
cd docker && go build -o ../bin/docker
|
||||
$(DOCKER_DIR):
|
||||
@mkdir -p $(dir $@)
|
||||
@if [ -h $@ ]; then rm -f $@; fi; ln -sf $(CURDIR)/ $@
|
||||
@(cd $(DOCKER_MAIN); go get -d $(GO_OPTIONS))
|
||||
|
||||
gotest:
|
||||
@echo "\033[36m[Testing]\033[00m docker..."
|
||||
@sudo -E GOPATH=$(ROOT_PATH)/$(BUILD_SRC) go test -v && \
|
||||
echo -n "\033[32m[OK]\033[00m" || \
|
||||
echo -n "\033[31m[FAIL]\033[00m"; \
|
||||
echo " docker"
|
||||
@echo "Testing extra repos {$(EXTRA_GO_PKG)}"
|
||||
@for package in $(EXTRA_GO_PKG); do \
|
||||
echo "\033[36m[Testing]\033[00m docker/$$package..." && \
|
||||
cd $$package ; \
|
||||
sudo -E GOPATH=$(ROOT_PATH)/$(BUILD_SRC) go test -v && \
|
||||
echo -n "\033[32m[OK]\033[00m" || \
|
||||
echo -n "\033[31m[FAIL]\033[00m" ; \
|
||||
echo " docker/$$package" ; \
|
||||
cd .. ;\
|
||||
done
|
||||
@sudo rm -rf /tmp/docker-*
|
||||
whichrelease:
|
||||
echo $(RELEASE_VERSION)
|
||||
|
||||
cleanup:
|
||||
release: $(BINRELEASE)
|
||||
s3cmd -P put $(BINRELEASE) s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-$(RELEASE_VERSION).tgz
|
||||
|
||||
rm -rf $(BUILD_PATH) debian/$(PKG_NAME)* debian/files $(BUILD_SRC) checkout.tgz
|
||||
srcrelease: $(SRCRELEASE)
|
||||
deps: $(DOCKER_DIR)
|
||||
|
||||
# A clean checkout of $RELEASE_VERSION, with vendored dependencies
|
||||
$(SRCRELEASE):
|
||||
rm -fr $(SRCRELEASE)
|
||||
git clone $(GIT_ROOT) $(SRCRELEASE)
|
||||
cd $(SRCRELEASE); git checkout -q $(RELEASE_VERSION)
|
||||
|
||||
# A binary release ready to be uploaded to a mirror
|
||||
$(BINRELEASE): $(SRCRELEASE)
|
||||
rm -f $(BINRELEASE)
|
||||
cd $(SRCRELEASE); make; cp -R bin docker-$(RELEASE_VERSION); tar -f ../$(BINRELEASE) -zv -c docker-$(RELEASE_VERSION)
|
||||
|
||||
clean:
|
||||
@rm -rf $(dir $(DOCKER_BIN))
|
||||
ifeq ($(GOPATH), $(BUILD_DIR))
|
||||
@rm -rf $(BUILD_DIR)
|
||||
else ifneq ($(DOCKER_DIR), $(realpath $(DOCKER_DIR)))
|
||||
@rm -f $(DOCKER_DIR)
|
||||
endif
|
||||
|
||||
test: all
|
||||
@(cd $(DOCKER_DIR); sudo -E go test $(GO_OPTIONS))
|
||||
|
||||
fmt:
|
||||
@gofmt -s -l -w .
|
||||
|
||||
hack:
|
||||
cd $(CURDIR)/hack && vagrant up
|
||||
|
||||
ssh-dev:
|
||||
cd $(CURDIR)/hack && vagrant ssh
|
||||
|
||||
421
README.md
421
README.md
@@ -1,39 +1,227 @@
|
||||
Docker: the Linux container runtime
|
||||
===================================
|
||||
Docker: the Linux container engine
|
||||
==================================
|
||||
|
||||
Docker complements LXC with a high-level API with operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers.
|
||||
Docker is an open-source engine which automates the deployment of applications as highly portable, self-sufficient containers.
|
||||
|
||||
Is is a great building block for automating distributed systems: large-scale web deployments, database clusters, continuous deployment systems, private PaaS, service-oriented architectures, etc.
|
||||
Docker containers are both *hardware-agnostic* and *platform-agnostic*. This means that they can run anywhere, from your
|
||||
laptop to the largest EC2 compute instance and everything in between - and they don't require that you use a particular
|
||||
language, framework or packaging system. That makes them great building blocks for deploying and scaling web apps, databases
|
||||
and backend services without depending on a particular stack or provider.
|
||||
|
||||
<img src="http://bricks.argz.com/bricksfiles/lego/07000/7823/012.jpg"/>
|
||||
Docker is an open-source implementation of the deployment engine which powers [dotCloud](http://dotcloud.com), a popular Platform-as-a-Service.
|
||||
It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands
|
||||
of applications and databases.
|
||||
|
||||
* *Heterogeneous payloads*: any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all.
|
||||

|
||||
|
||||
* *Any server*: docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments.
|
||||
## Better than VMs
|
||||
|
||||
* *Isolation*: docker isolates processes from each other and from the underlying host, using lightweight containers.
|
||||
A common method for distributing applications and sandbox their execution is to use virtual machines, or VMs. Typical VM formats
|
||||
are VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory these formats should allow every developer to
|
||||
automatically package their application into a "machine" for easy distribution and deployment. In practice, that almost never
|
||||
happens, for a few reasons:
|
||||
|
||||
* *Repeatability*: because containers are isolated in their own filesystem, they behave the same regardless of where, when, and alongside what they run.
|
||||
* *Size*: VMs are very large which makes them impractical to store and transfer.
|
||||
* *Performance*: running VMs consumes significant CPU and memory, which makes them impractical in many scenarios, for example local development of multi-tier applications, and
|
||||
large-scale deployment of cpu and memory-intensive applications on large numbers of machines.
|
||||
* *Portability*: competing VM environments don't play well with each other. Although conversion tools do exist, they are limited and add even more overhead.
|
||||
* *Hardware-centric*: VMs were designed with machine operators in mind, not software developers. As a result, they offer very limited tooling for what developers need most:
|
||||
building, testing and running their software. For example, VMs offer no facilities for application versioning, monitoring, configuration, logging or service discovery.
|
||||
|
||||
By contrast, Docker relies on a different sandboxing method known as *containerization*. Unlike traditional virtualization,
|
||||
containerization takes place at the kernel level. Most modern operating system kernels now support the primitives necessary
|
||||
for containerization, including Linux with [openvz](http://openvz.org), [vserver](http://linux-vserver.org) and more recently [lxc](http://lxc.sourceforge.net),
|
||||
Solaris with [zones](http://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc) and FreeBSD with [Jails](http://www.freebsd.org/doc/handbook/jails.html).
|
||||
|
||||
Docker builds on top of these low-level primitives to offer developers a portable format and runtime environment that solves
|
||||
all 4 problems. Docker containers are small (and their transfer can be optimized with layers), they have basically zero memory and cpu overhead,
|
||||
the are completely portable and are designed from the ground up with an application-centric design.
|
||||
|
||||
The best part: because docker operates at the OS level, it can still be run inside a VM!
|
||||
|
||||
## Plays well with others
|
||||
|
||||
Docker does not require that you buy into a particular programming language, framework, packaging system or configuration language.
|
||||
|
||||
Is your application a unix process? Does it use files, tcp connections, environment variables, standard unix streams and command-line
|
||||
arguments as inputs and outputs? Then docker can run it.
|
||||
|
||||
Can your application's build be expressed a sequence of such commands? Then docker can build it.
|
||||
|
||||
|
||||
Notable features
|
||||
-----------------
|
||||
## Escape dependency hell
|
||||
|
||||
* Filesystem isolation: each process container runs in a completely separate root filesystem.
|
||||
A common problem for developers is the difficulty of managing all their application's dependencies in a simple and automated way.
|
||||
|
||||
* Resource isolation: system resources like cpu and memory can be allocated differently to each process container, using cgroups.
|
||||
This is usually difficult for several reasons:
|
||||
|
||||
* Network isolation: each process container runs in its own network namespace, with a virtual interface and IP address of its own.
|
||||
* *Cross-platform dependencies*. Modern applications often depend on a combination of system libraries and binaries, language-specific packages, framework-specific modules,
|
||||
internal components developed for another project, etc. These dependencies live in different "worlds" and require different tools - these tools typically don't work
|
||||
well with each other, requiring awkward custom integrations.
|
||||
|
||||
* Copy-on-write: root filesystems are created using copy-on-write, which makes deployment extremeley fast, memory-cheap and disk-cheap.
|
||||
|
||||
* Logging: the standard streams (stdout/stderr/stdin) of each process container is collected and logged for real-time or batch retrieval.
|
||||
|
||||
* Change management: changes to a container's filesystem can be committed into a new image and re-used to create more containers. No templating or manual configuration required.
|
||||
|
||||
* Interactive shell: docker can allocate a pseudo-tty and attach to the standard input of any container, for example to run a throwaway interactive shell.
|
||||
* Conflicting dependencies. Different applications may depend on different versions of the same dependency. Packaging tools handle these situations with various degrees of ease -
|
||||
but they all handle them in different and incompatible ways, which again forces the developer to do extra work.
|
||||
|
||||
* Custom dependencies. A developer may need to prepare a custom version of his application's dependency. Some packaging systems can handle custom versions of a dependency,
|
||||
others can't - and all of them handle it differently.
|
||||
|
||||
|
||||
Docker solves dependency hell by giving the developer a simple way to express *all* his application's dependencies in one place,
|
||||
and streamline the process of assembling them. If this makes you think of [XKCD 927](http://xkcd.com/927/), don't worry. Docker doesn't
|
||||
*replace* your favorite packaging systems. It simply orchestrates their use in a simple and repeatable way. How does it do that? With layers.
|
||||
|
||||
Docker defines a build as running a sequence unix commands, one after the other, in the same container. Build commands modify the contents of the container
|
||||
(usually by installing new files on the filesystem), the next command modifies it some more, etc. Since each build command inherits the result of the previous
|
||||
commands, the *order* in which the commands are executed expresses *dependencies*.
|
||||
|
||||
Here's a typical docker build process:
|
||||
|
||||
```bash
|
||||
from ubuntu:12.10
|
||||
run apt-get update
|
||||
run apt-get install python
|
||||
run apt-get install python-pip
|
||||
run pip install django
|
||||
run apt-get install curl
|
||||
run curl http://github.com/shykes/helloflask/helloflask/master.tar.gz | tar -zxv
|
||||
run cd master && pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Note that Docker doesn't care *how* dependencies are built - as long as they can be built by running a unix command in a container.
|
||||
|
||||
|
||||
Install instructions
|
||||
==================
|
||||
|
||||
Quick install on Ubuntu 12.04 and 12.10
|
||||
---------------------------------------
|
||||
|
||||
```bash
|
||||
curl get.docker.io | sh -x
|
||||
```
|
||||
|
||||
Binary installs
|
||||
----------------
|
||||
|
||||
Docker supports the following binary installation methods.
|
||||
Note that some methods are community contributions and not yet officially supported.
|
||||
|
||||
* [Ubuntu 12.04 and 12.10 (officially supported)](http://docs.docker.io/en/latest/installation/ubuntulinux/)
|
||||
* [Arch Linux](http://docs.docker.io/en/latest/installation/archlinux/)
|
||||
* [MacOS X (with Vagrant)](http://docs.docker.io/en/latest/installation/macos/)
|
||||
* [Windows (with Vagrant)](http://docs.docker.io/en/latest/installation/windows/)
|
||||
* [Amazon EC2 (with Vagrant)](http://docs.docker.io/en/latest/installation/amazon/)
|
||||
|
||||
Installing from source
|
||||
----------------------
|
||||
|
||||
1. Make sure you have a [Go language](http://golang.org/doc/install) compiler and [git](http://git-scm.com) installed.
|
||||
|
||||
2. Checkout the source code
|
||||
|
||||
```bash
|
||||
git clone http://github.com/dotcloud/docker
|
||||
```
|
||||
|
||||
3. Build the docker binary
|
||||
|
||||
```bash
|
||||
cd docker
|
||||
make VERBOSE=1
|
||||
sudo cp ./bin/docker /usr/local/bin/docker
|
||||
```
|
||||
|
||||
Usage examples
|
||||
==============
|
||||
|
||||
First run the docker daemon
|
||||
---------------------------
|
||||
|
||||
All the examples assume your machine is running the docker daemon. To run the docker daemon in the background, simply type:
|
||||
|
||||
```bash
|
||||
# On a production system you want this running in an init script
|
||||
sudo docker -d &
|
||||
```
|
||||
|
||||
Now you can run docker in client mode: all commands will be forwarded to the docker daemon, so the client can run from any account.
|
||||
|
||||
```bash
|
||||
# Now you can run docker commands from any account.
|
||||
docker help
|
||||
```
|
||||
|
||||
|
||||
Throwaway shell in a base ubuntu image
|
||||
--------------------------------------
|
||||
|
||||
```bash
|
||||
docker pull ubuntu:12.10
|
||||
|
||||
# Run an interactive shell, allocate a tty, attach stdin and stdout
|
||||
# To detach the tty without exiting the shell, use the escape sequence Ctrl-p + Ctrl-q
|
||||
docker run -i -t ubuntu:12.10 /bin/bash
|
||||
```
|
||||
|
||||
Starting a long-running worker process
|
||||
--------------------------------------
|
||||
|
||||
```bash
|
||||
# Start a very useful long-running process
|
||||
JOB=$(docker run -d ubuntu /bin/sh -c "while true; do echo Hello world; sleep 1; done")
|
||||
|
||||
# Collect the output of the job so far
|
||||
docker logs $JOB
|
||||
|
||||
# Kill the job
|
||||
docker kill $JOB
|
||||
```
|
||||
|
||||
Running an irc bouncer
|
||||
----------------------
|
||||
|
||||
```bash
|
||||
BOUNCER_ID=$(docker run -d -p 6667 -u irc shykes/znc $USER $PASSWORD)
|
||||
echo "Configure your irc client to connect to port $(docker port $BOUNCER_ID 6667) of this machine"
|
||||
```
|
||||
|
||||
Running Redis
|
||||
-------------
|
||||
|
||||
```bash
|
||||
REDIS_ID=$(docker run -d -p 6379 shykes/redis redis-server)
|
||||
echo "Configure your redis client to connect to port $(docker port $REDIS_ID 6379) of this machine"
|
||||
```
|
||||
|
||||
Share your own image!
|
||||
---------------------
|
||||
|
||||
```bash
|
||||
CONTAINER=$(docker run -d ubuntu:12.10 apt-get install -y curl)
|
||||
docker commit -m "Installed curl" $CONTAINER $USER/betterbase
|
||||
docker push $USER/betterbase
|
||||
```
|
||||
|
||||
A list of publicly available images is [available here](https://github.com/dotcloud/docker/wiki/Public-docker-images).
|
||||
|
||||
Expose a service on a TCP port
|
||||
------------------------------
|
||||
|
||||
```bash
|
||||
# Expose port 4444 of this container, and tell netcat to listen on it
|
||||
JOB=$(docker run -d -p 4444 base /bin/nc -l -p 4444)
|
||||
|
||||
# Which public port is NATed to my container?
|
||||
PORT=$(docker port $JOB 4444)
|
||||
|
||||
# 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.
|
||||
IP=$(ifconfig eth0 | perl -n -e 'if (m/inet addr:([\d\.]+)/g) { print $1 }')
|
||||
echo hello world | nc $IP $PORT
|
||||
|
||||
# Verify that the network connection worked
|
||||
echo "Daemon received: $(docker logs $JOB)"
|
||||
```
|
||||
|
||||
Under the hood
|
||||
--------------
|
||||
@@ -50,189 +238,60 @@ Under the hood, Docker is built on the following components:
|
||||
* [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to simplify the creation of linux containers.
|
||||
|
||||
|
||||
Install instructions
|
||||
==================
|
||||
|
||||
Installing on Ubuntu 12.04 and 12.10
|
||||
------------------------------------
|
||||
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
sudo apt-get install lxc wget bsdtar curl
|
||||
```
|
||||
|
||||
2. Install the latest docker binary:
|
||||
|
||||
```bash
|
||||
wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz
|
||||
tar -xf docker-master.tgz
|
||||
```
|
||||
|
||||
3. Run your first container!
|
||||
|
||||
```bash
|
||||
cd docker-master
|
||||
sudo ./docker run -a -i -t base /bin/bash
|
||||
```
|
||||
|
||||
Consider adding docker to your `PATH` for simplicity.
|
||||
|
||||
Installing on other Linux distributions
|
||||
---------------------------------------
|
||||
|
||||
Right now, the officially supported distributions are:
|
||||
|
||||
* Ubuntu 12.04 (precise LTS)
|
||||
* Ubuntu 12.10 (quantal)
|
||||
|
||||
Docker probably works on other distributions featuring a recent kernel, the AUFS patch, and up-to-date lxc. However this has not been tested.
|
||||
|
||||
Installing with Vagrant
|
||||
-----------------------
|
||||
|
||||
Currently, Docker can be installed with Vagrant both on your localhost
|
||||
with VirtualBox as well as on Amazon EC2. Vagrant 1.1 is required for
|
||||
EC2, but deploying is as simple as:
|
||||
|
||||
```bash
|
||||
$ export AWS_ACCESS_KEY_ID=xxx \
|
||||
AWS_SECRET_ACCESS_KEY=xxx \
|
||||
AWS_KEYPAIR_NAME=xxx \
|
||||
AWS_SSH_PRIVKEY=xxx
|
||||
$ vagrant plugin install vagrant-aws
|
||||
$ vagrant up --provider=aws
|
||||
```
|
||||
|
||||
The environment variables are:
|
||||
|
||||
* `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
|
||||
* `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 keypair
|
||||
|
||||
For VirtualBox, you can simply ignore setting any of the environment
|
||||
variables and omit the ``provider`` flag. VirtualBox is still supported with
|
||||
Vagrant <= 1.1:
|
||||
|
||||
```bash
|
||||
$ vagrant up
|
||||
```
|
||||
|
||||
|
||||
|
||||
Usage examples
|
||||
==============
|
||||
|
||||
Running an interactive shell
|
||||
----------------------------
|
||||
|
||||
```bash
|
||||
# Download a base image
|
||||
docker import base
|
||||
|
||||
# Run an interactive shell in the base image,
|
||||
# allocate a tty, attach stdin and stdout
|
||||
docker run -a -i -t base /bin/bash
|
||||
```
|
||||
|
||||
|
||||
Starting a long-running worker process
|
||||
--------------------------------------
|
||||
|
||||
```bash
|
||||
# Run docker in daemon mode
|
||||
(docker -d || echo "Docker daemon already running") &
|
||||
|
||||
# Start a very useful long-running process
|
||||
JOB=$(docker run base /bin/sh -c "while true; do echo Hello world!; sleep 1; done")
|
||||
|
||||
# Collect the output of the job so far
|
||||
docker logs $JOB
|
||||
|
||||
# Kill the job
|
||||
docker kill $JOB
|
||||
```
|
||||
|
||||
|
||||
Listing all running containers
|
||||
------------------------------
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
```
|
||||
|
||||
|
||||
Expose a service on a TCP port
|
||||
------------------------------
|
||||
|
||||
```bash
|
||||
# Expose port 4444 of this container, and tell netcat to listen on it
|
||||
JOB=$(docker run -p 4444 base /bin/nc -l -p 4444)
|
||||
|
||||
# Which public port is NATed to my container?
|
||||
PORT=$(docker port $JOB 4444)
|
||||
|
||||
# Connect to the public port via the host's public address
|
||||
echo hello world | nc $(hostname) $PORT
|
||||
|
||||
# Verify that the network connection worked
|
||||
echo "Daemon received: $(docker logs $JOB)"
|
||||
```
|
||||
|
||||
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! There are instructions to get you started on the website: http://docs.docker.io/en/latest/contributing/contributing/
|
||||
|
||||
Contribution guidelines
|
||||
-----------------------
|
||||
|
||||
### Pull requests are always welcome
|
||||
|
||||
We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it.
|
||||
|
||||
If your pull request is not accepted on the first try, don't be discouraged! If there's a problen with the implementation, hopefully you received feedback on what to improve.
|
||||
|
||||
We're trying very hard to keep Docker lean and focused. We don't want it to do everything for everybody. This means that we might decide against incorporating a new feature.
|
||||
However there might be a way to implement that feature *on top of* docker.
|
||||
|
||||
### Discuss your design on the mailing list
|
||||
|
||||
We recommend discussing your plans [on the mailing list](https://groups.google.com/forum/?fromgroups#!forum/docker-club) before starting to code - especially for more ambitious contributions. This gives other contributors a chance to point
|
||||
you in the right direction, give feedback on your design, and maybe point out if someone else is working on the same thing.
|
||||
|
||||
### Create issues...
|
||||
|
||||
Any significant improvement should be documented as a github issue before anybody start working on it.
|
||||
|
||||
### ...but check for existing issues first!
|
||||
|
||||
Please take a moment to check that an issue doesn't already exist documenting your bug report or improvement proposal.
|
||||
If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests.
|
||||
They are probably not perfect, please let us know if anything feels wrong or incomplete.
|
||||
|
||||
|
||||
### Write tests
|
||||
Note
|
||||
----
|
||||
|
||||
Golang has a great testing suite built in: use it! Take a look at existing tests for inspiration.
|
||||
We also keep the documentation in this repository. The website documentation is generated using sphinx using these sources.
|
||||
Please find it under docs/sources/ and read more about it https://github.com/dotcloud/docker/master/docs/README.md
|
||||
|
||||
Please feel free to fix / update the documentation and send us pull requests. More tutorials are also welcome.
|
||||
|
||||
|
||||
Setting up a dev environment
|
||||
----------------------------
|
||||
|
||||
Coming soon!
|
||||
Instructions that have been verified to work on Ubuntu 12.10,
|
||||
|
||||
```bash
|
||||
sudo apt-get -y install lxc wget bsdtar curl golang git
|
||||
|
||||
export GOPATH=~/go/
|
||||
export PATH=$GOPATH/bin:$PATH
|
||||
|
||||
mkdir -p $GOPATH/src/github.com/dotcloud
|
||||
cd $GOPATH/src/github.com/dotcloud
|
||||
git clone git@github.com:dotcloud/docker.git
|
||||
cd docker
|
||||
|
||||
go get -v github.com/dotcloud/docker/...
|
||||
go install -v github.com/dotcloud/docker/...
|
||||
```
|
||||
|
||||
Then run the docker daemon,
|
||||
|
||||
```bash
|
||||
sudo $GOPATH/bin/docker -d
|
||||
```
|
||||
|
||||
Run the `go install` command (above) to recompile docker.
|
||||
|
||||
|
||||
What is a Standard Container?
|
||||
=============================
|
||||
|
||||
Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in
|
||||
a format that is self-describing and portable, so that any compliant runtime can run it without extra dependency, regardless of the underlying machine and the contents of the container.
|
||||
a format that is self-describing and portable, so that any compliant runtime can run it without extra dependencies, regardless of the underlying machine and the contents of the container.
|
||||
|
||||
The spec for Standard Containers is currently work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
|
||||
The spec for Standard Containers is currently a work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
|
||||
|
||||
A great analogy for this is the shipping container. Just like Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery.
|
||||
|
||||
|
||||
71
SPECS/data-volumes.md
Normal file
71
SPECS/data-volumes.md
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
## Spec for data volumes
|
||||
|
||||
Spec owner: Solomon Hykes <solomon@dotcloud.com>
|
||||
|
||||
Data volumes (issue #111) are a much-requested feature which trigger much discussion and debate. Below is the current authoritative spec for implementing data volumes.
|
||||
This spec will be deprecated once the feature is fully implemented.
|
||||
|
||||
Discussion, requests, trolls, demands, offerings, threats and other forms of supplications concerning this spec should be addressed to Solomon here: https://github.com/dotcloud/docker/issues/111
|
||||
|
||||
|
||||
### 1. Creating data volumes
|
||||
|
||||
At container creation, parts of a container's filesystem can be mounted as separate data volumes. Volumes are defined with the -v flag.
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
$ docker run -v /var/lib/postgres -v /var/log postgres /usr/bin/postgres
|
||||
```
|
||||
|
||||
In this example, a new container is created from the 'postgres' image. At the same time, docker creates 2 new data volumes: one will be mapped to the container at /var/lib/postgres, the other at /var/log.
|
||||
|
||||
2 important notes:
|
||||
|
||||
1) Volumes don't have top-level names. At no point does the user provide a name, or is a name given to him. Volumes are identified by the path at which they are mounted inside their container.
|
||||
|
||||
2) The user doesn't choose the source of the volume. Docker only mounts volumes it created itself, in the same way that it only runs containers that it created itself. That is by design.
|
||||
|
||||
|
||||
### 2. Sharing data volumes
|
||||
|
||||
Instead of creating its own volumes, a container can share another container's volumes. For example:
|
||||
|
||||
```bash
|
||||
$ docker run --volumes-from $OTHER_CONTAINER_ID postgres /usr/local/bin/postgres-backup
|
||||
```
|
||||
|
||||
In this example, a new container is created from the 'postgres' example. At the same time, docker will *re-use* the 2 data volumes created in the previous example. One volume will be mounted on the /var/lib/postgres of *both* containers, and the other will be mounted on the /var/log of both containers.
|
||||
|
||||
### 3. Under the hood
|
||||
|
||||
Docker stores volumes in /var/lib/docker/volumes. Each volume receives a globally unique ID at creation, and is stored at /var/lib/docker/volumes/ID.
|
||||
|
||||
At creation, volumes are attached to a single container - the source of truth for this mapping will be the container's configuration.
|
||||
|
||||
Mounting a volume consists of calling "mount --bind" from the volume's directory to the appropriate sub-directory of the container mountpoint. This may be done by Docker itself, or farmed out to lxc (which supports mount-binding) if possible.
|
||||
|
||||
|
||||
### 4. Backups, transfers and other volume operations
|
||||
|
||||
Volumes sometimes need to be backed up, transfered between hosts, synchronized, etc. These operations typically are application-specific or site-specific, eg. rsync vs. S3 upload vs. replication vs...
|
||||
|
||||
Rather than attempting to implement all these scenarios directly, Docker will allow for custom implementations using an extension mechanism.
|
||||
|
||||
### 5. Custom volume handlers
|
||||
|
||||
Docker allows for arbitrary code to be executed against a container's volumes, to implement any custom action: backup, transfer, synchronization across hosts, etc.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```bash
|
||||
$ DB=$(docker run -d -v /var/lib/postgres -v /var/log postgres /usr/bin/postgres)
|
||||
|
||||
$ BACKUP_JOB=$(docker run -d --volumes-from $DB shykes/backuper /usr/local/bin/backup-postgres --s3creds=$S3CREDS)
|
||||
|
||||
$ docker wait $BACKUP_JOB
|
||||
```
|
||||
|
||||
Congratulations, you just implemented a custom volume handler, using Docker's built-in ability to 1) execute arbitrary code and 2) share volumes between containers.
|
||||
|
||||
150
Vagrantfile
vendored
150
Vagrantfile
vendored
@@ -1,119 +1,53 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure("1") do |config|
|
||||
# All Vagrant configuration is done here. The most common configuration
|
||||
# options are documented and commented below. For a complete reference,
|
||||
# please see the online documentation at vagrantup.com.
|
||||
BOX_NAME = ENV['BOX_NAME'] || "ubuntu"
|
||||
BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64.box"
|
||||
PPA_KEY = "E61D797F63561DC6"
|
||||
|
||||
# Every Vagrant virtual environment requires a box to build off of.
|
||||
config.vm.box = "quantal64_3.5.0-25"
|
||||
|
||||
# The url from where the 'config.vm.box' box will be fetched if it
|
||||
# doesn't already exist on the user's system.
|
||||
config.vm.box_url = "http://get.docker.io/vbox/ubuntu/12.10/quantal64_3.5.0-25.box"
|
||||
|
||||
# Boot with a GUI so you can see the screen. (Default is headless)
|
||||
# config.vm.boot_mode = :gui
|
||||
|
||||
# Assign this VM to a host-only network IP, allowing you to access it
|
||||
# via the IP. Host-only networks can talk to the host machine as well as
|
||||
# any other machines on the same network, but cannot be accessed (through this
|
||||
# network interface) by any external networks.
|
||||
# config.vm.network :hostonly, "192.168.33.10"
|
||||
|
||||
# Assign this VM to a bridged network, allowing you to connect directly to a
|
||||
# network using the host's network device. This makes the VM appear as another
|
||||
# physical device on your network.
|
||||
# config.vm.network :bridged
|
||||
|
||||
# Forward a port from the guest to the host, which allows for outside
|
||||
# computers to access the VM, whereas host only networking does not.
|
||||
# config.vm.forward_port 80, 8080
|
||||
|
||||
# Share an additional folder to the guest VM. The first argument is
|
||||
# an identifier, the second is the path on the guest to mount the
|
||||
# folder, and the third is the path on the host to the actual folder.
|
||||
config.vm.share_folder "v-data", "~/docker", "~/docker"
|
||||
|
||||
# Enable provisioning with Puppet stand alone. Puppet manifests
|
||||
# are contained in a directory path relative to this Vagrantfile.
|
||||
# You will need to create the manifests directory and a manifest in
|
||||
# the file quantal64.pp in the manifests_path directory.
|
||||
#
|
||||
# An example Puppet manifest to provision the message of the day:
|
||||
#
|
||||
# # group { "puppet":
|
||||
# # ensure => "present",
|
||||
# # }
|
||||
# #
|
||||
# # File { owner => 0, group => 0, mode => 0644 }
|
||||
# #
|
||||
# # file { '/etc/motd':
|
||||
# # content => "Welcome to your Vagrant-built virtual machine!
|
||||
# # Managed by Puppet.\n"
|
||||
# # }
|
||||
#
|
||||
config.vm.provision :puppet do |puppet|
|
||||
puppet.manifests_path = "puppet/manifests"
|
||||
puppet.manifest_file = "quantal64.pp"
|
||||
puppet.module_path = "puppet/modules"
|
||||
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
|
||||
# Add docker PPA key to the local repository and install docker
|
||||
pkg_cmd = "apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys #{PPA_KEY}; "
|
||||
pkg_cmd << "echo 'deb http://ppa.launchpad.net/dotcloud/lxc-docker/ubuntu precise main' >/etc/apt/sources.list.d/lxc-docker.list; "
|
||||
pkg_cmd << "apt-get update -qq; apt-get install -q -y lxc-docker"
|
||||
if ARGV.include?("--provider=aws".downcase)
|
||||
# Add AUFS dependency to amazon's VM
|
||||
pkg_cmd << "; apt-get install linux-image-extra-3.2.0-40-virtual"
|
||||
end
|
||||
|
||||
# Enable provisioning with chef solo, specifying a cookbooks path, roles
|
||||
# path, and data_bags path (all relative to this Vagrantfile), and adding
|
||||
# some recipes and/or roles.
|
||||
#
|
||||
# config.vm.provision :chef_solo do |chef|
|
||||
# chef.cookbooks_path = "../my-recipes/cookbooks"
|
||||
# chef.roles_path = "../my-recipes/roles"
|
||||
# chef.data_bags_path = "../my-recipes/data_bags"
|
||||
# chef.add_recipe "mysql"
|
||||
# chef.add_role "web"
|
||||
#
|
||||
# # You may also specify custom JSON attributes:
|
||||
# chef.json = { :mysql_password => "foo" }
|
||||
# end
|
||||
|
||||
# Enable provisioning with chef server, specifying the chef server URL,
|
||||
# and the path to the validation key (relative to this Vagrantfile).
|
||||
#
|
||||
# The Opscode Platform uses HTTPS. Substitute your organization for
|
||||
# ORGNAME in the URL and validation key.
|
||||
#
|
||||
# If you have your own Chef Server, use the appropriate URL, which may be
|
||||
# HTTP instead of HTTPS depending on your configuration. Also change the
|
||||
# validation key to validation.pem.
|
||||
#
|
||||
# config.vm.provision :chef_client do |chef|
|
||||
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
|
||||
# chef.validation_key_path = "ORGNAME-validator.pem"
|
||||
# end
|
||||
#
|
||||
# If you're using the Opscode platform, your validator client is
|
||||
# ORGNAME-validator, replacing ORGNAME with your organization name.
|
||||
#
|
||||
# IF you have your own Chef Server, the default validation client name is
|
||||
# chef-validator, unless you changed the configuration.
|
||||
#
|
||||
# chef.validation_client_name = "ORGNAME-validator"
|
||||
config.vm.provision :shell, :inline => pkg_cmd
|
||||
end
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :aws do |aws|
|
||||
config.vm.box = "dummy"
|
||||
config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
|
||||
# Providers were added on Vagrant >= 1.1.0
|
||||
Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
|
||||
config.vm.provider :aws do |aws, override|
|
||||
config.vm.box = "dummy"
|
||||
config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
|
||||
aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"]
|
||||
aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
|
||||
aws.keypair_name = ENV["AWS_KEYPAIR_NAME"]
|
||||
aws.ssh_private_key_path = ENV["AWS_SSH_PRIVKEY"]
|
||||
aws.region = "us-east-1"
|
||||
aws.ami = "ami-1c1e8075"
|
||||
aws.ssh_username = "vagrant"
|
||||
aws.instance_type = "t1.micro"
|
||||
aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
|
||||
aws.keypair_name = ENV["AWS_KEYPAIR_NAME"]
|
||||
override.ssh.private_key_path = ENV["AWS_SSH_PRIVKEY"]
|
||||
override.ssh.username = "ubuntu"
|
||||
aws.region = "us-east-1"
|
||||
aws.ami = "ami-d0f89fb9"
|
||||
aws.instance_type = "t1.micro"
|
||||
end
|
||||
|
||||
config.vm.provider :rackspace do |rs|
|
||||
config.vm.box = "dummy"
|
||||
config.vm.box_url = "https://github.com/mitchellh/vagrant-rackspace/raw/master/dummy.box"
|
||||
config.ssh.private_key_path = ENV["RS_PRIVATE_KEY"]
|
||||
rs.username = ENV["RS_USERNAME"]
|
||||
rs.api_key = ENV["RS_API_KEY"]
|
||||
rs.public_key_path = ENV["RS_PUBLIC_KEY"]
|
||||
rs.flavor = /512MB/
|
||||
rs.image = /Ubuntu/
|
||||
end
|
||||
|
||||
config.vm.provider :virtualbox do |vb|
|
||||
config.vm.box = "quantal64_3.5.0-25"
|
||||
config.vm.box_url = "http://get.docker.io/vbox/ubuntu/12.10/quantal64_3.5.0-25.box"
|
||||
end
|
||||
config.vm.box = BOX_NAME
|
||||
config.vm.box_url = BOX_URI
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package fs
|
||||
package docker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type Archive io.Reader
|
||||
|
||||
type Compression uint32
|
||||
|
||||
const (
|
||||
Uncompressed Compression = iota
|
||||
Bzip2
|
||||
Gzip
|
||||
Xz
|
||||
)
|
||||
|
||||
func (compression *Compression) Flag() string {
|
||||
@@ -21,6 +25,8 @@ func (compression *Compression) Flag() string {
|
||||
return "j"
|
||||
case Gzip:
|
||||
return "z"
|
||||
case Xz:
|
||||
return "J"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -40,6 +46,9 @@ func Untar(archive io.Reader, path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdStream executes a command, and returns its stdout as a stream.
|
||||
// If the command fails to run or doesn't complete successfully, an error
|
||||
// will be returned, including anything written on stderr.
|
||||
func CmdStream(cmd *exec.Cmd) (io.Reader, error) {
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
@@ -50,24 +59,66 @@ func CmdStream(cmd *exec.Cmd) (io.Reader, error) {
|
||||
return nil, err
|
||||
}
|
||||
pipeR, pipeW := io.Pipe()
|
||||
errChan := make(chan []byte)
|
||||
// Collect stderr, we will use it in case of an error
|
||||
go func() {
|
||||
errText, e := ioutil.ReadAll(stderr)
|
||||
if e != nil {
|
||||
errText = []byte("(...couldn't fetch stderr: " + e.Error() + ")")
|
||||
}
|
||||
errChan <- errText
|
||||
}()
|
||||
// Copy stdout to the returned pipe
|
||||
go func() {
|
||||
_, err := io.Copy(pipeW, stdout)
|
||||
if err != nil {
|
||||
pipeW.CloseWithError(err)
|
||||
}
|
||||
errText, e := ioutil.ReadAll(stderr)
|
||||
if e != nil {
|
||||
errText = []byte("(...couldn't fetch stderr: " + e.Error() + ")")
|
||||
}
|
||||
errText := <-errChan
|
||||
if err := cmd.Wait(); err != nil {
|
||||
// FIXME: can this block if stderr outputs more than the size of StderrPipe()'s buffer?
|
||||
pipeW.CloseWithError(errors.New(err.Error() + ": " + string(errText)))
|
||||
} else {
|
||||
pipeW.Close()
|
||||
}
|
||||
}()
|
||||
// Run the command and return the pipe
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pipeR, nil
|
||||
}
|
||||
|
||||
// NewTempArchive reads the content of src into a temporary file, and returns the contents
|
||||
// of that file as an archive. The archive can only be read once - as soon as reading completes,
|
||||
// the file will be deleted.
|
||||
func NewTempArchive(src Archive, dir string) (*TempArchive, error) {
|
||||
f, err := ioutil.TempFile(dir, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.Copy(f, src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
size := st.Size()
|
||||
return &TempArchive{f, size}, nil
|
||||
}
|
||||
|
||||
type TempArchive struct {
|
||||
*os.File
|
||||
Size int64 // Pre-computed from Stat().Size() as a convenience
|
||||
}
|
||||
|
||||
func (archive *TempArchive) Read(data []byte) (int, error) {
|
||||
n, err := archive.File.Read(data)
|
||||
if err != nil {
|
||||
os.Remove(archive.File.Name())
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
@@ -1,12 +1,35 @@
|
||||
package fs
|
||||
package docker
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCmdStreamLargeStderr(t *testing.T) {
|
||||
cmd := exec.Command("/bin/sh", "-c", "dd if=/dev/zero bs=1k count=1000 of=/dev/stderr; echo hello")
|
||||
out, err := CmdStream(cmd)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start command: " + err.Error())
|
||||
}
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
_, err := io.Copy(ioutil.Discard, out)
|
||||
errCh <- err
|
||||
}()
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
t.Fatalf("Command should not have failed (err=%s...)", err.Error()[:100])
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("Command did not complete in 5 seconds; probable deadlock")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmdStreamBad(t *testing.T) {
|
||||
badCmd := exec.Command("/bin/sh", "-c", "echo hello; echo >&2 error couldn\\'t reverse the phase pulser; exit 1")
|
||||
out, err := CmdStream(badCmd)
|
||||
121
auth/auth.go
121
auth/auth.go
@@ -3,28 +3,38 @@ package auth
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Where we store the config file
|
||||
const CONFIGFILE = "/var/lib/docker/.dockercfg"
|
||||
const CONFIGFILE = ".dockercfg"
|
||||
|
||||
// the registry server we want to login against
|
||||
const REGISTRY_SERVER = "http://registry.docker.io"
|
||||
const INDEX_SERVER = "https://index.docker.io"
|
||||
|
||||
type AuthConfig struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Email string `json:"email"`
|
||||
rootPath string `json:-`
|
||||
}
|
||||
|
||||
func NewAuthConfig(username, password, email, rootPath string) *AuthConfig {
|
||||
return &AuthConfig{
|
||||
Username: username,
|
||||
Password: password,
|
||||
Email: email,
|
||||
rootPath: rootPath,
|
||||
}
|
||||
}
|
||||
|
||||
// create a base64 encoded auth string to store in config
|
||||
func EncodeAuth(authConfig AuthConfig) string {
|
||||
func EncodeAuth(authConfig *AuthConfig) string {
|
||||
authStr := authConfig.Username + ":" + authConfig.Password
|
||||
msg := []byte(authStr)
|
||||
encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
|
||||
@@ -33,50 +43,62 @@ func EncodeAuth(authConfig AuthConfig) string {
|
||||
}
|
||||
|
||||
// decode the auth string
|
||||
func DecodeAuth(authStr string) (AuthConfig, error) {
|
||||
func DecodeAuth(authStr string) (*AuthConfig, error) {
|
||||
decLen := base64.StdEncoding.DecodedLen(len(authStr))
|
||||
decoded := make([]byte, decLen)
|
||||
authByte := []byte(authStr)
|
||||
n, err := base64.StdEncoding.Decode(decoded, authByte)
|
||||
if err != nil {
|
||||
return AuthConfig{}, err
|
||||
return nil, err
|
||||
}
|
||||
if n > decLen {
|
||||
return AuthConfig{}, errors.New("something went wrong decoding auth config")
|
||||
return nil, fmt.Errorf("Something went wrong decoding auth config")
|
||||
}
|
||||
arr := strings.Split(string(decoded), ":")
|
||||
if len(arr) != 2 {
|
||||
return nil, fmt.Errorf("Invalid auth configuration file")
|
||||
}
|
||||
password := strings.Trim(arr[1], "\x00")
|
||||
return AuthConfig{Username: arr[0], Password: password}, nil
|
||||
return &AuthConfig{Username: arr[0], Password: password}, nil
|
||||
|
||||
}
|
||||
|
||||
// load up the auth config information and return values
|
||||
func LoadConfig() (AuthConfig, error) {
|
||||
if _, err := os.Stat(CONFIGFILE); err == nil {
|
||||
b, err := ioutil.ReadFile(CONFIGFILE)
|
||||
if err != nil {
|
||||
return AuthConfig{}, err
|
||||
}
|
||||
arr := strings.Split(string(b), "\n")
|
||||
orig_auth := strings.Split(arr[0], " = ")
|
||||
orig_email := strings.Split(arr[1], " = ")
|
||||
authConfig, err := DecodeAuth(orig_auth[1])
|
||||
if err != nil {
|
||||
return AuthConfig{}, err
|
||||
}
|
||||
authConfig.Email = orig_email[1]
|
||||
return authConfig, nil
|
||||
} else {
|
||||
return AuthConfig{}, nil
|
||||
// FIXME: use the internal golang config parser
|
||||
func LoadConfig(rootPath string) (*AuthConfig, error) {
|
||||
confFile := path.Join(rootPath, CONFIGFILE)
|
||||
if _, err := os.Stat(confFile); err != nil {
|
||||
return &AuthConfig{}, fmt.Errorf("The Auth config file is missing")
|
||||
}
|
||||
return AuthConfig{}, nil
|
||||
b, err := ioutil.ReadFile(confFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arr := strings.Split(string(b), "\n")
|
||||
if len(arr) < 2 {
|
||||
return nil, fmt.Errorf("The Auth config file is empty")
|
||||
}
|
||||
origAuth := strings.Split(arr[0], " = ")
|
||||
origEmail := strings.Split(arr[1], " = ")
|
||||
authConfig, err := DecodeAuth(origAuth[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authConfig.Email = origEmail[1]
|
||||
authConfig.rootPath = rootPath
|
||||
return authConfig, nil
|
||||
}
|
||||
|
||||
// save the auth config
|
||||
func saveConfig(authStr string, email string) error {
|
||||
func saveConfig(rootPath, authStr string, email string) error {
|
||||
confFile := path.Join(rootPath, CONFIGFILE)
|
||||
if len(email) == 0 {
|
||||
os.Remove(confFile)
|
||||
return nil
|
||||
}
|
||||
lines := "auth = " + authStr + "\n" + "email = " + email + "\n"
|
||||
b := []byte(lines)
|
||||
err := ioutil.WriteFile(CONFIGFILE, b, 0600)
|
||||
err := ioutil.WriteFile(confFile, b, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -84,40 +106,40 @@ func saveConfig(authStr string, email string) error {
|
||||
}
|
||||
|
||||
// try to register/login to the registry server
|
||||
func Login(authConfig AuthConfig) (string, error) {
|
||||
func Login(authConfig *AuthConfig) (string, error) {
|
||||
storeConfig := false
|
||||
client := &http.Client{}
|
||||
reqStatusCode := 0
|
||||
var status string
|
||||
var errMsg string
|
||||
var reqBody []byte
|
||||
jsonBody, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
errMsg = fmt.Sprintf("Config Error: %s", err)
|
||||
return "", errors.New(errMsg)
|
||||
return "", fmt.Errorf("Config Error: %s", err)
|
||||
}
|
||||
|
||||
// using `bytes.NewReader(jsonBody)` here causes the server to respond with a 411 status.
|
||||
b := strings.NewReader(string(jsonBody))
|
||||
req1, err := http.Post(REGISTRY_SERVER+"/v1/users", "application/json; charset=utf-8", b)
|
||||
req1, err := http.Post(INDEX_SERVER+"/v1/users/", "application/json; charset=utf-8", b)
|
||||
if err != nil {
|
||||
errMsg = fmt.Sprintf("Server Error: %s", err)
|
||||
return "", errors.New(errMsg)
|
||||
return "", fmt.Errorf("Server Error: %s", err)
|
||||
}
|
||||
|
||||
reqStatusCode = req1.StatusCode
|
||||
defer req1.Body.Close()
|
||||
reqBody, err = ioutil.ReadAll(req1.Body)
|
||||
if err != nil {
|
||||
errMsg = fmt.Sprintf("Server Error: [%#v] %s", reqStatusCode, err)
|
||||
return "", errors.New(errMsg)
|
||||
return "", fmt.Errorf("Server Error: [%#v] %s", reqStatusCode, err)
|
||||
}
|
||||
|
||||
if reqStatusCode == 201 {
|
||||
status = "Account Created\n"
|
||||
status = "Account created. Please use the confirmation link we sent" +
|
||||
" to your e-mail to activate it.\n"
|
||||
storeConfig = true
|
||||
} else if reqStatusCode == 403 {
|
||||
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
|
||||
"Please check your e-mail for a confirmation link.")
|
||||
} else if reqStatusCode == 400 {
|
||||
if string(reqBody) == "Username or email already exist" {
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", REGISTRY_SERVER+"/v1/users", nil)
|
||||
if string(reqBody) == "\"Username or email already exists\"" {
|
||||
req, err := http.NewRequest("GET", INDEX_SERVER+"/v1/users/", nil)
|
||||
req.SetBasicAuth(authConfig.Username, authConfig.Password)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
@@ -131,21 +153,22 @@ func Login(authConfig AuthConfig) (string, error) {
|
||||
if resp.StatusCode == 200 {
|
||||
status = "Login Succeeded\n"
|
||||
storeConfig = true
|
||||
} else if resp.StatusCode == 401 {
|
||||
saveConfig(authConfig.rootPath, "", "")
|
||||
return "", fmt.Errorf("Wrong login/password, please try again")
|
||||
} else {
|
||||
status = fmt.Sprintf("Login: %s", body)
|
||||
return "", errors.New(status)
|
||||
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
|
||||
resp.StatusCode, resp.Header)
|
||||
}
|
||||
} else {
|
||||
status = fmt.Sprintf("Registration: %s", string(reqBody))
|
||||
return "", errors.New(status)
|
||||
return "", fmt.Errorf("Registration: %s", reqBody)
|
||||
}
|
||||
} else {
|
||||
status = fmt.Sprintf("[%s] : %s", reqStatusCode, string(reqBody))
|
||||
return "", errors.New(status)
|
||||
return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody)
|
||||
}
|
||||
if storeConfig {
|
||||
authStr := EncodeAuth(authConfig)
|
||||
saveConfig(authStr, authConfig.Email)
|
||||
saveConfig(authConfig.rootPath, authStr, authConfig.Email)
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
func TestEncodeAuth(t *testing.T) {
|
||||
newAuthConfig := AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
|
||||
newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
|
||||
authStr := EncodeAuth(newAuthConfig)
|
||||
decAuthConfig, err := DecodeAuth(authStr)
|
||||
if err != nil {
|
||||
|
||||
20
buildbot/README.rst
Normal file
20
buildbot/README.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
Buildbot
|
||||
========
|
||||
|
||||
Buildbot is a continuous integration system designed to automate the
|
||||
build/test cycle. By automatically rebuilding and testing the tree each time
|
||||
something has changed, build problems are pinpointed quickly, before other
|
||||
developers are inconvenienced by the failure.
|
||||
|
||||
When running 'make hack' at the docker root directory, it spawns a virtual
|
||||
machine in the background running a buildbot instance and adds a git
|
||||
post-commit hook that automatically run docker tests for you.
|
||||
|
||||
You can check your buildbot instance at http://192.168.33.21:8010/waterfall
|
||||
|
||||
|
||||
Buildbot dependencies
|
||||
---------------------
|
||||
|
||||
vagrant, virtualbox packages and python package requests
|
||||
|
||||
28
buildbot/Vagrantfile
vendored
Normal file
28
buildbot/Vagrantfile
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
$BUILDBOT_IP = '192.168.33.21'
|
||||
|
||||
def v10(config)
|
||||
config.vm.box = "quantal64_3.5.0-25"
|
||||
config.vm.box_url = "http://get.docker.io/vbox/ubuntu/12.10/quantal64_3.5.0-25.box"
|
||||
config.vm.share_folder 'v-data', '/data/docker', File.dirname(__FILE__) + '/..'
|
||||
config.vm.network :hostonly, $BUILDBOT_IP
|
||||
|
||||
# Ensure puppet is installed on the instance
|
||||
config.vm.provision :shell, :inline => 'apt-get -qq update; apt-get install -y puppet'
|
||||
|
||||
config.vm.provision :puppet do |puppet|
|
||||
puppet.manifests_path = '.'
|
||||
puppet.manifest_file = 'buildbot.pp'
|
||||
puppet.options = ['--templatedir','.']
|
||||
end
|
||||
end
|
||||
|
||||
Vagrant::VERSION < '1.1.0' and Vagrant::Config.run do |config|
|
||||
v10(config)
|
||||
end
|
||||
|
||||
Vagrant::VERSION >= '1.1.0' and Vagrant.configure('1') do |config|
|
||||
v10(config)
|
||||
end
|
||||
43
buildbot/buildbot-cfg/buildbot-cfg.sh
Executable file
43
buildbot/buildbot-cfg/buildbot-cfg.sh
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Auto setup of buildbot configuration. Package installation is being done
|
||||
# on buildbot.pp
|
||||
# Dependencies: buildbot, buildbot-slave, supervisor
|
||||
|
||||
SLAVE_NAME='buildworker'
|
||||
SLAVE_SOCKET='localhost:9989'
|
||||
BUILDBOT_PWD='pass-docker'
|
||||
USER='vagrant'
|
||||
ROOT_PATH='/data/buildbot'
|
||||
DOCKER_PATH='/data/docker'
|
||||
BUILDBOT_CFG="$DOCKER_PATH/buildbot/buildbot-cfg"
|
||||
IP=$(grep BUILDBOT_IP /data/docker/buildbot/Vagrantfile | awk -F "'" '{ print $2; }')
|
||||
|
||||
function run { su $USER -c "$1"; }
|
||||
|
||||
export PATH=/bin:sbin:/usr/bin:/usr/sbin:/usr/local/bin
|
||||
|
||||
# Exit if buildbot has already been installed
|
||||
[ -d "$ROOT_PATH" ] && exit 0
|
||||
|
||||
# Setup buildbot
|
||||
run "mkdir -p ${ROOT_PATH}"
|
||||
cd ${ROOT_PATH}
|
||||
run "buildbot create-master master"
|
||||
run "cp $BUILDBOT_CFG/master.cfg master"
|
||||
run "sed -i 's/localhost/$IP/' master/master.cfg"
|
||||
run "buildslave create-slave slave $SLAVE_SOCKET $SLAVE_NAME $BUILDBOT_PWD"
|
||||
|
||||
# Allow buildbot subprocesses (docker tests) to properly run in containers,
|
||||
# in particular with docker -u
|
||||
run "sed -i 's/^umask = None/umask = 000/' ${ROOT_PATH}/slave/buildbot.tac"
|
||||
|
||||
# Setup supervisor
|
||||
cp $BUILDBOT_CFG/buildbot.conf /etc/supervisor/conf.d/buildbot.conf
|
||||
sed -i "s/^chmod=0700.*0700./chmod=0770\nchown=root:$USER/" /etc/supervisor/supervisord.conf
|
||||
kill -HUP `pgrep -f "/usr/bin/python /usr/bin/supervisord"`
|
||||
|
||||
# Add git hook
|
||||
cp $BUILDBOT_CFG/post-commit $DOCKER_PATH/.git/hooks
|
||||
sed -i "s/localhost/$IP/" $DOCKER_PATH/.git/hooks/post-commit
|
||||
|
||||
32
buildbot/buildbot.pp
Normal file
32
buildbot/buildbot.pp
Normal file
@@ -0,0 +1,32 @@
|
||||
node default {
|
||||
$USER = 'vagrant'
|
||||
$ROOT_PATH = '/data/buildbot'
|
||||
$DOCKER_PATH = '/data/docker'
|
||||
|
||||
exec {'apt_update': command => '/usr/bin/apt-get update' }
|
||||
Package { require => Exec['apt_update'] }
|
||||
group {'puppet': ensure => 'present'}
|
||||
|
||||
# Install dependencies
|
||||
Package { ensure => 'installed' }
|
||||
package { ['python-dev','python-pip','supervisor','lxc','bsdtar','git','golang']: }
|
||||
|
||||
file{[ '/data' ]:
|
||||
owner => $USER, group => $USER, ensure => 'directory' }
|
||||
|
||||
file {'/var/tmp/requirements.txt':
|
||||
content => template('requirements.txt') }
|
||||
|
||||
exec {'requirements':
|
||||
require => [ Package['python-dev'], Package['python-pip'],
|
||||
File['/var/tmp/requirements.txt'] ],
|
||||
cwd => '/var/tmp',
|
||||
command => "/bin/sh -c '(/usr/bin/pip install -r requirements.txt;
|
||||
rm /var/tmp/requirements.txt)'" }
|
||||
|
||||
exec {'buildbot-cfg-sh':
|
||||
require => [ Package['supervisor'], Exec['requirements']],
|
||||
path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin',
|
||||
cwd => '/data',
|
||||
command => "$DOCKER_PATH/buildbot/buildbot-cfg/buildbot-cfg.sh" }
|
||||
}
|
||||
6
buildbot/requirements.txt
Normal file
6
buildbot/requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
sqlalchemy<=0.7.9
|
||||
sqlalchemy-migrate>=0.7.2
|
||||
buildbot==0.8.7p1
|
||||
buildbot_slave==0.8.7p1
|
||||
nose==1.2.1
|
||||
requests==1.1.0
|
||||
463
builder.go
Normal file
463
builder.go
Normal file
@@ -0,0 +1,463 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
runtime *Runtime
|
||||
repositories *TagStore
|
||||
graph *Graph
|
||||
}
|
||||
|
||||
func NewBuilder(runtime *Runtime) *Builder {
|
||||
return &Builder{
|
||||
runtime: runtime,
|
||||
graph: runtime.graph,
|
||||
repositories: runtime.repositories,
|
||||
}
|
||||
}
|
||||
|
||||
func (builder *Builder) mergeConfig(userConf, imageConf *Config) {
|
||||
if userConf.Hostname != "" {
|
||||
userConf.Hostname = imageConf.Hostname
|
||||
}
|
||||
if userConf.User != "" {
|
||||
userConf.User = imageConf.User
|
||||
}
|
||||
if userConf.Memory == 0 {
|
||||
userConf.Memory = imageConf.Memory
|
||||
}
|
||||
if userConf.MemorySwap == 0 {
|
||||
userConf.MemorySwap = imageConf.MemorySwap
|
||||
}
|
||||
if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
|
||||
userConf.PortSpecs = imageConf.PortSpecs
|
||||
}
|
||||
if !userConf.Tty {
|
||||
userConf.Tty = userConf.Tty
|
||||
}
|
||||
if !userConf.OpenStdin {
|
||||
userConf.OpenStdin = imageConf.OpenStdin
|
||||
}
|
||||
if !userConf.StdinOnce {
|
||||
userConf.StdinOnce = imageConf.StdinOnce
|
||||
}
|
||||
if userConf.Env == nil || len(userConf.Env) == 0 {
|
||||
userConf.Env = imageConf.Env
|
||||
}
|
||||
if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
|
||||
userConf.Cmd = imageConf.Cmd
|
||||
}
|
||||
if userConf.Dns == nil || len(userConf.Dns) == 0 {
|
||||
userConf.Dns = imageConf.Dns
|
||||
}
|
||||
}
|
||||
|
||||
func (builder *Builder) Create(config *Config) (*Container, error) {
|
||||
// Lookup image
|
||||
img, err := builder.repositories.LookupImage(config.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if img.Config != nil {
|
||||
builder.mergeConfig(config, img.Config)
|
||||
}
|
||||
|
||||
if config.Cmd == nil || len(config.Cmd) == 0 {
|
||||
return nil, fmt.Errorf("No command specified")
|
||||
}
|
||||
|
||||
// Generate id
|
||||
id := GenerateId()
|
||||
// Generate default hostname
|
||||
// FIXME: the lxc template no longer needs to set a default hostname
|
||||
if config.Hostname == "" {
|
||||
config.Hostname = id[:12]
|
||||
}
|
||||
|
||||
container := &Container{
|
||||
// FIXME: we should generate the ID here instead of receiving it as an argument
|
||||
Id: id,
|
||||
Created: time.Now(),
|
||||
Path: config.Cmd[0],
|
||||
Args: config.Cmd[1:], //FIXME: de-duplicate from config
|
||||
Config: config,
|
||||
Image: img.Id, // Always use the resolved image id
|
||||
NetworkSettings: &NetworkSettings{},
|
||||
// FIXME: do we need to store this in the container?
|
||||
SysInitPath: sysInitPath,
|
||||
}
|
||||
container.root = builder.runtime.containerRoot(container.Id)
|
||||
// Step 1: create the container directory.
|
||||
// This doubles as a barrier to avoid race conditions.
|
||||
if err := os.Mkdir(container.root, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If custom dns exists, then create a resolv.conf for the container
|
||||
if len(config.Dns) > 0 {
|
||||
container.ResolvConfPath = path.Join(container.root, "resolv.conf")
|
||||
f, err := os.Create(container.ResolvConfPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
for _, dns := range config.Dns {
|
||||
if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
container.ResolvConfPath = "/etc/resolv.conf"
|
||||
}
|
||||
|
||||
// Step 2: save the container json
|
||||
if err := container.ToDisk(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Step 3: register the container
|
||||
if err := builder.runtime.Register(container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return container, nil
|
||||
}
|
||||
|
||||
// Commit creates a new filesystem image from the current state of a container.
|
||||
// The image can optionally be tagged into a repository
|
||||
func (builder *Builder) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
|
||||
// FIXME: freeze the container before copying it to avoid data corruption?
|
||||
// FIXME: this shouldn't be in commands.
|
||||
rwTar, err := container.ExportRw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create a new image from the container's base layers + a new layer from container changes
|
||||
img, err := builder.graph.Create(rwTar, container, comment, author, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Register the image if needed
|
||||
if repository != "" {
|
||||
if err := builder.repositories.Set(repository, tag, img.Id, true); err != nil {
|
||||
return img, err
|
||||
}
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func (builder *Builder) clearTmp(containers, images map[string]struct{}) {
|
||||
for c := range containers {
|
||||
tmp := builder.runtime.Get(c)
|
||||
builder.runtime.Destroy(tmp)
|
||||
Debugf("Removing container %s", c)
|
||||
}
|
||||
for i := range images {
|
||||
builder.runtime.graph.Delete(i)
|
||||
Debugf("Removing image %s", i)
|
||||
}
|
||||
}
|
||||
|
||||
func (builder *Builder) getCachedImage(image *Image, config *Config) (*Image, error) {
|
||||
// Retrieve all images
|
||||
images, err := builder.graph.All()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Store the tree in a map of map (map[parentId][childId])
|
||||
imageMap := make(map[string]map[string]struct{})
|
||||
for _, img := range images {
|
||||
if _, exists := imageMap[img.Parent]; !exists {
|
||||
imageMap[img.Parent] = make(map[string]struct{})
|
||||
}
|
||||
imageMap[img.Parent][img.Id] = struct{}{}
|
||||
}
|
||||
|
||||
// Loop on the children of the given image and check the config
|
||||
for elem := range imageMap[image.Id] {
|
||||
img, err := builder.graph.Get(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if CompareConfig(&img.ContainerConfig, config) {
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (builder *Builder) Build(dockerfile io.Reader, stdout io.Writer) (*Image, error) {
|
||||
var (
|
||||
image, base *Image
|
||||
config *Config
|
||||
maintainer string
|
||||
env map[string]string = make(map[string]string)
|
||||
tmpContainers map[string]struct{} = make(map[string]struct{})
|
||||
tmpImages map[string]struct{} = make(map[string]struct{})
|
||||
)
|
||||
defer builder.clearTmp(tmpContainers, tmpImages)
|
||||
|
||||
file := bufio.NewReader(dockerfile)
|
||||
for {
|
||||
line, err := file.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
line = strings.Replace(strings.TrimSpace(line), " ", " ", 1)
|
||||
// Skip comments and empty line
|
||||
if len(line) == 0 || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
tmp := strings.SplitN(line, " ", 2)
|
||||
if len(tmp) != 2 {
|
||||
return nil, fmt.Errorf("Invalid Dockerfile format")
|
||||
}
|
||||
instruction := strings.Trim(tmp[0], " ")
|
||||
arguments := strings.Trim(tmp[1], " ")
|
||||
switch strings.ToLower(instruction) {
|
||||
case "from":
|
||||
fmt.Fprintf(stdout, "FROM %s\n", arguments)
|
||||
image, err = builder.runtime.repositories.LookupImage(arguments)
|
||||
if err != nil {
|
||||
if builder.runtime.graph.IsNotExist(err) {
|
||||
|
||||
var tag, remote string
|
||||
if strings.Contains(arguments, ":") {
|
||||
remoteParts := strings.Split(arguments, ":")
|
||||
tag = remoteParts[1]
|
||||
remote = remoteParts[0]
|
||||
} else {
|
||||
remote = arguments
|
||||
}
|
||||
|
||||
if err := builder.runtime.graph.PullRepository(stdout, remote, tag, builder.runtime.repositories, builder.runtime.authConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
image, err = builder.runtime.repositories.LookupImage(arguments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
config = &Config{}
|
||||
|
||||
break
|
||||
case "maintainer":
|
||||
fmt.Fprintf(stdout, "MAINTAINER %s\n", arguments)
|
||||
maintainer = arguments
|
||||
break
|
||||
case "run":
|
||||
fmt.Fprintf(stdout, "RUN %s\n", arguments)
|
||||
if image == nil {
|
||||
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
||||
}
|
||||
config, err := ParseRun([]string{image.Id, "/bin/sh", "-c", arguments}, nil, builder.runtime.capabilities)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for key, value := range env {
|
||||
config.Env = append(config.Env, fmt.Sprintf("%s=%s", key, value))
|
||||
}
|
||||
|
||||
if cache, err := builder.getCachedImage(image, config); err != nil {
|
||||
return nil, err
|
||||
} else if cache != nil {
|
||||
image = cache
|
||||
fmt.Fprintf(stdout, "===> %s\n", image.ShortId())
|
||||
break
|
||||
}
|
||||
|
||||
Debugf("Env -----> %v ------ %v\n", config.Env, env)
|
||||
|
||||
// Create the container and start it
|
||||
c, err := builder.Create(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
out, _ := c.StdoutPipe()
|
||||
err2, _ := c.StderrPipe()
|
||||
go io.Copy(os.Stdout, out)
|
||||
go io.Copy(os.Stdout, err2)
|
||||
}
|
||||
|
||||
if err := c.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpContainers[c.Id] = struct{}{}
|
||||
|
||||
// Wait for it to finish
|
||||
if result := c.Wait(); result != 0 {
|
||||
return nil, fmt.Errorf("!!! '%s' return non-zero exit code '%d'. Aborting.", arguments, result)
|
||||
}
|
||||
|
||||
// Commit the container
|
||||
base, err = builder.Commit(c, "", "", "", maintainer, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpImages[base.Id] = struct{}{}
|
||||
|
||||
fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
|
||||
|
||||
// use the base as the new image
|
||||
image = base
|
||||
|
||||
break
|
||||
case "env":
|
||||
tmp := strings.SplitN(arguments, " ", 2)
|
||||
if len(tmp) != 2 {
|
||||
return nil, fmt.Errorf("Invalid ENV format")
|
||||
}
|
||||
key := strings.Trim(tmp[0], " ")
|
||||
value := strings.Trim(tmp[1], " ")
|
||||
fmt.Fprintf(stdout, "ENV %s %s\n", key, value)
|
||||
env[key] = value
|
||||
if image != nil {
|
||||
fmt.Fprintf(stdout, "===> %s\n", image.ShortId())
|
||||
} else {
|
||||
fmt.Fprintf(stdout, "===> <nil>\n")
|
||||
}
|
||||
break
|
||||
case "cmd":
|
||||
fmt.Fprintf(stdout, "CMD %s\n", arguments)
|
||||
|
||||
// Create the container and start it
|
||||
c, err := builder.Create(&Config{Image: image.Id, Cmd: []string{"", ""}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpContainers[c.Id] = struct{}{}
|
||||
|
||||
cmd := []string{}
|
||||
if err := json.Unmarshal([]byte(arguments), &cmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Cmd = cmd
|
||||
|
||||
// Commit the container
|
||||
base, err = builder.Commit(c, "", "", "", maintainer, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpImages[base.Id] = struct{}{}
|
||||
|
||||
fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
|
||||
image = base
|
||||
break
|
||||
case "expose":
|
||||
ports := strings.Split(arguments, " ")
|
||||
|
||||
fmt.Fprintf(stdout, "EXPOSE %v\n", ports)
|
||||
if image == nil {
|
||||
return nil, fmt.Errorf("Please provide a source image with `from` prior to copy")
|
||||
}
|
||||
|
||||
// Create the container and start it
|
||||
c, err := builder.Create(&Config{Image: image.Id, Cmd: []string{"", ""}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpContainers[c.Id] = struct{}{}
|
||||
|
||||
config.PortSpecs = append(ports, config.PortSpecs...)
|
||||
|
||||
// Commit the container
|
||||
base, err = builder.Commit(c, "", "", "", maintainer, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpImages[base.Id] = struct{}{}
|
||||
|
||||
fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
|
||||
image = base
|
||||
break
|
||||
case "insert":
|
||||
if image == nil {
|
||||
return nil, fmt.Errorf("Please provide a source image with `from` prior to copy")
|
||||
}
|
||||
tmp = strings.SplitN(arguments, " ", 2)
|
||||
if len(tmp) != 2 {
|
||||
return nil, fmt.Errorf("Invalid INSERT format")
|
||||
}
|
||||
sourceUrl := strings.Trim(tmp[0], " ")
|
||||
destPath := strings.Trim(tmp[1], " ")
|
||||
fmt.Fprintf(stdout, "COPY %s to %s in %s\n", sourceUrl, destPath, base.ShortId())
|
||||
|
||||
file, err := Download(sourceUrl, stdout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Body.Close()
|
||||
|
||||
config, err := ParseRun([]string{base.Id, "echo", "insert", sourceUrl, destPath}, nil, builder.runtime.capabilities)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := builder.Create(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Wait for echo to finish
|
||||
if result := c.Wait(); result != 0 {
|
||||
return nil, fmt.Errorf("!!! '%s' return non-zero exit code '%d'. Aborting.", arguments, result)
|
||||
}
|
||||
|
||||
if err := c.Inject(file.Body, destPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base, err = builder.Commit(c, "", "", "", maintainer, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
|
||||
|
||||
image = base
|
||||
|
||||
break
|
||||
default:
|
||||
fmt.Fprintf(stdout, "Skipping unknown instruction %s\n", strings.ToUpper(instruction))
|
||||
}
|
||||
}
|
||||
if image != nil {
|
||||
// The build is successful, keep the temporary containers and images
|
||||
for i := range tmpImages {
|
||||
delete(tmpImages, i)
|
||||
}
|
||||
for i := range tmpContainers {
|
||||
delete(tmpContainers, i)
|
||||
}
|
||||
fmt.Fprintf(stdout, "Build finished. image id: %s\n", image.ShortId())
|
||||
return image, nil
|
||||
}
|
||||
return nil, fmt.Errorf("An error occured during the build\n")
|
||||
}
|
||||
88
builder_test.go
Normal file
88
builder_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const Dockerfile = `
|
||||
# VERSION 0.1
|
||||
# DOCKER-VERSION 0.2
|
||||
|
||||
from ` + unitTestImageName + `
|
||||
run sh -c 'echo root:testpass > /tmp/passwd'
|
||||
run mkdir -p /var/run/sshd
|
||||
insert https://raw.github.com/dotcloud/docker/master/CHANGELOG.md /tmp/CHANGELOG.md
|
||||
`
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
builder := NewBuilder(runtime)
|
||||
|
||||
img, err := builder.Build(strings.NewReader(Dockerfile), &nopWriter{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
container, err := builder.Create(
|
||||
&Config{
|
||||
Image: img.Id,
|
||||
Cmd: []string{"cat", "/tmp/passwd"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
output, err := container.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(output) != "root:testpass\n" {
|
||||
t.Fatalf("Unexpected output. Read '%s', expected '%s'", output, "root:testpass\n")
|
||||
}
|
||||
|
||||
container2, err := builder.Create(
|
||||
&Config{
|
||||
Image: img.Id,
|
||||
Cmd: []string{"ls", "-d", "/var/run/sshd"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container2)
|
||||
|
||||
output, err = container2.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(output) != "/var/run/sshd\n" {
|
||||
t.Fatal("/var/run/sshd has not been created")
|
||||
}
|
||||
|
||||
container3, err := builder.Create(
|
||||
&Config{
|
||||
Image: img.Id,
|
||||
Cmd: []string{"cat", "/tmp/CHANGELOG.md"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container3)
|
||||
|
||||
output, err = container3.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(output) == 0 {
|
||||
t.Fatal("/tmp/CHANGELOG.md has not been copied")
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package fs
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -33,24 +33,15 @@ func (change *Change) String() string {
|
||||
return fmt.Sprintf("%s %s", kind, change.Path)
|
||||
}
|
||||
|
||||
func (store *Store) Changes(mp *Mountpoint) ([]Change, error) {
|
||||
func Changes(layers []string, rw string) ([]Change, error) {
|
||||
var changes []Change
|
||||
image, err := store.Get(mp.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
layers, err := image.layers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = filepath.Walk(mp.Rw, func(path string, f os.FileInfo, err error) error {
|
||||
err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Rebase path
|
||||
path, err = filepath.Rel(mp.Rw, path)
|
||||
path, err = filepath.Rel(rw, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -113,15 +104,3 @@ func (store *Store) Changes(mp *Mountpoint) ([]Change, error) {
|
||||
}
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
// Reset removes all changes to the filesystem, reverting it to its initial state.
|
||||
func (mp *Mountpoint) Reset() error {
|
||||
if err := os.RemoveAll(mp.Rw); err != nil {
|
||||
return err
|
||||
}
|
||||
// We removed the RW directory itself along with its content: let's re-create an empty one.
|
||||
if err := mp.createFolders(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
1318
commands.go
1318
commands.go
File diff suppressed because it is too large
Load Diff
469
commands_test.go
Normal file
469
commands_test.go
Normal file
@@ -0,0 +1,469 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/rcli"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func closeWrap(args ...io.Closer) error {
|
||||
e := false
|
||||
ret := fmt.Errorf("Error closing elements")
|
||||
for _, c := range args {
|
||||
if err := c.Close(); err != nil {
|
||||
e = true
|
||||
ret = fmt.Errorf("%s\n%s", ret, err)
|
||||
}
|
||||
}
|
||||
if e {
|
||||
return ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
|
||||
c := make(chan bool)
|
||||
|
||||
// Make sure we are not too long
|
||||
go func() {
|
||||
time.Sleep(d)
|
||||
c <- true
|
||||
}()
|
||||
go func() {
|
||||
f()
|
||||
c <- false
|
||||
}()
|
||||
if <-c {
|
||||
t.Fatal(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
|
||||
for i := 0; i < count; i++ {
|
||||
if _, err := w.Write([]byte(input)); err != nil {
|
||||
return err
|
||||
}
|
||||
o, err := bufio.NewReader(r).ReadString('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Trim(o, " \r\n") != output {
|
||||
return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", output, o)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cmdWait(srv *Server, container *Container) error {
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
go func() {
|
||||
srv.CmdWait(nil, stdoutPipe, container.Id)
|
||||
}()
|
||||
|
||||
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
// Cleanup pipes
|
||||
return closeWrap(stdout, stdoutPipe)
|
||||
}
|
||||
|
||||
func cmdImages(srv *Server, args ...string) (string, error) {
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
go func() {
|
||||
if err := srv.CmdImages(nil, stdoutPipe, args...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// force the pipe closed, so that the code below gets an EOF
|
||||
stdoutPipe.Close()
|
||||
}()
|
||||
|
||||
output, err := ioutil.ReadAll(stdout)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Cleanup pipes
|
||||
return string(output), closeWrap(stdout, stdoutPipe)
|
||||
}
|
||||
|
||||
// TestImages checks that 'docker images' displays information correctly
|
||||
func TestImages(t *testing.T) {
|
||||
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
output, err := cmdImages(srv)
|
||||
|
||||
if !strings.Contains(output, "REPOSITORY") {
|
||||
t.Fatal("'images' should have a header")
|
||||
}
|
||||
if !strings.Contains(output, "docker-ut") {
|
||||
t.Fatal("'images' should show the docker-ut image")
|
||||
}
|
||||
if !strings.Contains(output, "e9aa60c60128") {
|
||||
t.Fatal("'images' should show the docker-ut image id")
|
||||
}
|
||||
|
||||
output, err = cmdImages(srv, "-q")
|
||||
|
||||
if strings.Contains(output, "REPOSITORY") {
|
||||
t.Fatal("'images -q' should not have a header")
|
||||
}
|
||||
if strings.Contains(output, "docker-ut") {
|
||||
t.Fatal("'images' should not show the docker-ut image name")
|
||||
}
|
||||
if !strings.Contains(output, "e9aa60c60128") {
|
||||
t.Fatal("'images' should show the docker-ut image id")
|
||||
}
|
||||
|
||||
output, err = cmdImages(srv, "-viz")
|
||||
|
||||
if !strings.HasPrefix(output, "digraph docker {") {
|
||||
t.Fatal("'images -v' should start with the dot header")
|
||||
}
|
||||
if !strings.HasSuffix(output, "}\n") {
|
||||
t.Fatal("'images -v' should end with a '}'")
|
||||
}
|
||||
if !strings.Contains(output, "base -> \"e9aa60c60128\" [style=invis]") {
|
||||
t.Fatal("'images -v' should have the docker-ut image id node")
|
||||
}
|
||||
|
||||
// todo: add checks for -a
|
||||
}
|
||||
|
||||
// TestRunHostname checks that 'docker run -h' correctly sets a custom hostname
|
||||
func TestRunHostname(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, _ := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
c := make(chan struct{})
|
||||
go func() {
|
||||
if err := srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-h", "foobar", GetTestImage(runtime).Id, "hostname"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
close(c)
|
||||
}()
|
||||
cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cmdOutput != "foobar\n" {
|
||||
t.Fatalf("'hostname' should display '%s', not '%s'", "foobar\n", cmdOutput)
|
||||
}
|
||||
|
||||
setTimeout(t, "CmdRun timed out", 2*time.Second, func() {
|
||||
<-c
|
||||
cmdWait(srv, srv.runtime.List()[0])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRunExit(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
|
||||
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
container := runtime.List()[0]
|
||||
|
||||
// Closing /bin/cat stdin, expect it to exit
|
||||
p, err := container.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := p.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// as the process exited, CmdRun must finish and unblock. Wait for it
|
||||
setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
|
||||
<-c1
|
||||
cmdWait(srv, container)
|
||||
})
|
||||
|
||||
// Make sure that the client has been disconnected
|
||||
setTimeout(t, "The client should have been disconnected once the remote process exited.", 2*time.Second, func() {
|
||||
// Expecting pipe i/o error, just check that read does not block
|
||||
stdin.Read([]byte{})
|
||||
})
|
||||
|
||||
// Cleanup pipes
|
||||
if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Expected behaviour: the process dies when the client disconnects
|
||||
func TestRunDisconnect(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
// We're simulating a disconnect so the return value doesn't matter. What matters is the
|
||||
// fact that CmdRun returns.
|
||||
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
|
||||
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
// Close pipes (simulate disconnect)
|
||||
if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// as the pipes are close, we expect the process to die,
|
||||
// therefore CmdRun to unblock. Wait for CmdRun
|
||||
setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
|
||||
<-c1
|
||||
})
|
||||
|
||||
// Client disconnect after run -i should cause stdin to be closed, which should
|
||||
// cause /bin/cat to exit.
|
||||
setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() {
|
||||
container := runtime.List()[0]
|
||||
container.Wait()
|
||||
if container.State.Running {
|
||||
t.Fatalf("/bin/cat is still running after closing stdin")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Expected behaviour: the process dies when the client disconnects
|
||||
func TestRunDisconnectTty(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
// We're simulating a disconnect so the return value doesn't matter. What matters is the
|
||||
// fact that CmdRun returns.
|
||||
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", "-t", GetTestImage(runtime).Id, "/bin/cat")
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
|
||||
for {
|
||||
// Client disconnect after run -i should keep stdin out in TTY mode
|
||||
l := runtime.List()
|
||||
if len(l) == 1 && l[0].State.Running {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
})
|
||||
|
||||
// Client disconnect after run -i should keep stdin out in TTY mode
|
||||
container := runtime.List()[0]
|
||||
|
||||
setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
|
||||
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
// Close pipes (simulate disconnect)
|
||||
if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// In tty mode, we expect the process to stay alive even after client's stdin closes.
|
||||
// Do not wait for run to finish
|
||||
|
||||
// Give some time to monitor to do his thing
|
||||
container.WaitTimeout(500 * time.Millisecond)
|
||||
if !container.State.Running {
|
||||
t.Fatalf("/bin/cat should still be running after closing stdin (tty mode)")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAttachStdin checks attaching to stdin without stdout and stderr.
|
||||
// 'docker run -i -a stdin' should sends the client's stdin to the command,
|
||||
// then detach from it and print the container id.
|
||||
func TestRunAttachStdin(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", "-a", "stdin", GetTestImage(runtime).Id, "sh", "-c", "echo hello; cat")
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
// Send input to the command, close stdin
|
||||
setTimeout(t, "Write timed out", 2*time.Second, func() {
|
||||
if _, err := stdinPipe.Write([]byte("hi there\n")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := stdinPipe.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
container := runtime.List()[0]
|
||||
|
||||
// Check output
|
||||
cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cmdOutput != container.ShortId()+"\n" {
|
||||
t.Fatalf("Wrong output: should be '%s', not '%s'\n", container.ShortId()+"\n", cmdOutput)
|
||||
}
|
||||
|
||||
// wait for CmdRun to return
|
||||
setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
|
||||
<-ch
|
||||
})
|
||||
|
||||
setTimeout(t, "Waiting for command to exit timed out", 2*time.Second, func() {
|
||||
container.Wait()
|
||||
})
|
||||
|
||||
// Check logs
|
||||
if cmdLogs, err := container.ReadLog("stdout"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if output, err := ioutil.ReadAll(cmdLogs); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
expectedLog := "hello\nhi there\n"
|
||||
if string(output) != expectedLog {
|
||||
t.Fatalf("Unexpected logs: should be '%s', not '%s'\n", expectedLog, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expected behaviour, the process stays alive when the client disconnects
|
||||
func TestAttachDisconnect(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
container, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).Id,
|
||||
Memory: 33554432,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
// Start the process
|
||||
if err := container.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
// Attach to it
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
// We're simulating a disconnect so the return value doesn't matter. What matters is the
|
||||
// fact that CmdAttach returns.
|
||||
srv.CmdAttach(stdin, rcli.NewDockerLocalConn(stdoutPipe), container.Id)
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
|
||||
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
// Close pipes (client disconnects)
|
||||
if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
|
||||
setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
|
||||
<-c1
|
||||
})
|
||||
|
||||
// We closed stdin, expect /bin/cat to still be running
|
||||
// Wait a little bit to make sure container.monitor() did his thing
|
||||
err = container.WaitTimeout(500 * time.Millisecond)
|
||||
if err == nil || !container.State.Running {
|
||||
t.Fatalf("/bin/cat is not running after closing stdin")
|
||||
}
|
||||
|
||||
// Try to avoid the timeoout in destroy. Best effort, don't check error
|
||||
cStdin, _ := container.StdinPipe()
|
||||
cStdin.Close()
|
||||
container.Wait()
|
||||
}
|
||||
831
container.go
831
container.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
126
contrib/crashTest.go
Normal file
126
contrib/crashTest.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
var DOCKER_PATH string = path.Join(os.Getenv("DOCKERPATH"), "docker")
|
||||
|
||||
// WARNING: this crashTest will 1) crash your host, 2) remove all containers
|
||||
func runDaemon() (*exec.Cmd, error) {
|
||||
os.Remove("/var/run/docker.pid")
|
||||
exec.Command("rm", "-rf", "/var/lib/docker/containers").Run()
|
||||
cmd := exec.Command(DOCKER_PATH, "-d")
|
||||
outPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
errPipe, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
io.Copy(os.Stdout, outPipe)
|
||||
}()
|
||||
go func() {
|
||||
io.Copy(os.Stderr, errPipe)
|
||||
}()
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func crashTest() error {
|
||||
if err := exec.Command("/bin/bash", "-c", "while true; do true; done").Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var endpoint string
|
||||
if ep := os.Getenv("TEST_ENDPOINT"); ep == "" {
|
||||
endpoint = "192.168.56.1:7979"
|
||||
} else {
|
||||
endpoint = ep
|
||||
}
|
||||
|
||||
c := make(chan bool)
|
||||
var conn io.Writer
|
||||
|
||||
go func() {
|
||||
conn, _ = net.Dial("tcp", endpoint)
|
||||
c <- false
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
c <- true
|
||||
}()
|
||||
<-c
|
||||
|
||||
restartCount := 0
|
||||
totalTestCount := 1
|
||||
for {
|
||||
daemon, err := runDaemon()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
restartCount++
|
||||
// time.Sleep(5000 * time.Millisecond)
|
||||
var stop bool
|
||||
go func() error {
|
||||
stop = false
|
||||
for i := 0; i < 100 && !stop; {
|
||||
func() error {
|
||||
cmd := exec.Command(DOCKER_PATH, "run", "base", "echo", fmt.Sprintf("%d", totalTestCount))
|
||||
i++
|
||||
totalTestCount++
|
||||
outPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
inPipe, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
if conn != nil {
|
||||
go io.Copy(conn, outPipe)
|
||||
}
|
||||
|
||||
// Expecting error, do not check
|
||||
inPipe.Write([]byte("hello world!!!!!\n"))
|
||||
go inPipe.Write([]byte("hello world!!!!!\n"))
|
||||
go inPipe.Write([]byte("hello world!!!!!\n"))
|
||||
inPipe.Close()
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
outPipe.Close()
|
||||
return nil
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
time.Sleep(20 * time.Second)
|
||||
stop = true
|
||||
if err := daemon.Process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := crashTest(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
68
contrib/docker-build/README
Normal file
68
contrib/docker-build/README
Normal file
@@ -0,0 +1,68 @@
|
||||
# docker-build: build your software with docker
|
||||
|
||||
## Description
|
||||
|
||||
docker-build is a script to build docker images from source. It will be deprecated once the 'build' feature is incorporated into docker itself (See https://github.com/dotcloud/docker/issues/278)
|
||||
|
||||
Author: Solomon Hykes <solomon@dotcloud.com>
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
docker-builder requires:
|
||||
|
||||
1) A reasonably recent Python setup (tested on 2.7.2).
|
||||
|
||||
2) A running docker daemon at version 0.1.4 or more recent (http://www.docker.io/gettingstarted)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
First create a valid Changefile, which defines a sequence of changes to apply to a base image.
|
||||
|
||||
$ cat Changefile
|
||||
# Start build from a know base image
|
||||
from base:ubuntu-12.10
|
||||
# Update ubuntu sources
|
||||
run echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
# Install system packages
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
# Insert files from the host (./myscript must be present in the current directory)
|
||||
copy myscript /usr/local/bin/myscript
|
||||
|
||||
|
||||
Run docker-build, and pass the contents of your Changefile as standard input.
|
||||
|
||||
$ IMG=$(./docker-build < Changefile)
|
||||
|
||||
This will take a while: for each line of the changefile, docker-build will:
|
||||
|
||||
1. Create a new container to execute the given command or insert the given file
|
||||
2. Wait for the container to complete execution
|
||||
3. Commit the resulting changes as a new image
|
||||
4. Use the resulting image as the input of the next step
|
||||
|
||||
|
||||
If all the steps succeed, the result will be an image containing the combined results of each build step.
|
||||
You can trace back those build steps by inspecting the image's history:
|
||||
|
||||
$ docker history $IMG
|
||||
ID CREATED CREATED BY
|
||||
1e9e2045de86 A few seconds ago /bin/sh -c cat > /usr/local/bin/myscript; chmod +x /usr/local/bin/git
|
||||
77db140aa62a A few seconds ago /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
77db140aa62a A few seconds ago /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
77db140aa62a A few seconds ago /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
83e85d155451 A few seconds ago /bin/sh -c apt-get update
|
||||
bfd53b36d9d3 A few seconds ago /bin/sh -c echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
base 2 weeks ago /bin/bash
|
||||
27cf78414709 2 weeks ago
|
||||
|
||||
|
||||
Note that your build started from 'base', as instructed by your Changefile. But that base image itself seems to have been built in 2 steps - hence the extra step in the history.
|
||||
|
||||
|
||||
You can use this build technique to create any image you want: a database, a web application, or anything else that can be build by a sequence of unix commands - in other words, anything else.
|
||||
|
||||
142
contrib/docker-build/docker-build
Executable file
142
contrib/docker-build/docker-build
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# docker-build is a script to build docker images from source.
|
||||
# It will be deprecated once the 'build' feature is incorporated into docker itself.
|
||||
# (See https://github.com/dotcloud/docker/issues/278)
|
||||
#
|
||||
# Author: Solomon Hykes <solomon@dotcloud.com>
|
||||
|
||||
|
||||
|
||||
# First create a valid Changefile, which defines a sequence of changes to apply to a base image.
|
||||
#
|
||||
# $ cat Changefile
|
||||
# # Start build from a know base image
|
||||
# from base:ubuntu-12.10
|
||||
# # Update ubuntu sources
|
||||
# run echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
# run apt-get update
|
||||
# # Install system packages
|
||||
# run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
# run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
# run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
# # Insert files from the host (./myscript must be present in the current directory)
|
||||
# copy myscript /usr/local/bin/myscript
|
||||
#
|
||||
#
|
||||
# Run docker-build, and pass the contents of your Changefile as standard input.
|
||||
#
|
||||
# $ IMG=$(./docker-build < Changefile)
|
||||
#
|
||||
# This will take a while: for each line of the changefile, docker-build will:
|
||||
#
|
||||
# 1. Create a new container to execute the given command or insert the given file
|
||||
# 2. Wait for the container to complete execution
|
||||
# 3. Commit the resulting changes as a new image
|
||||
# 4. Use the resulting image as the input of the next step
|
||||
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import json
|
||||
import hashlib
|
||||
|
||||
def docker(args, stdin=None):
|
||||
print "# docker " + " ".join(args)
|
||||
p = subprocess.Popen(["docker"] + list(args), stdin=stdin, stdout=subprocess.PIPE)
|
||||
return p.stdout
|
||||
|
||||
def image_exists(img):
|
||||
return docker(["inspect", img]).read().strip() != ""
|
||||
|
||||
def image_config(img):
|
||||
return json.loads(docker(["inspect", img]).read()).get("config", {})
|
||||
|
||||
def run_and_commit(img_in, cmd, stdin=None, author=None, run=None):
|
||||
run_id = docker(["run"] + (["-i", "-a", "stdin"] if stdin else ["-d"]) + [img_in, "/bin/sh", "-c", cmd], stdin=stdin).read().rstrip()
|
||||
print "---> Waiting for " + run_id
|
||||
result=int(docker(["wait", run_id]).read().rstrip())
|
||||
if result != 0:
|
||||
print "!!! '{}' return non-zero exit code '{}'. Aborting.".format(cmd, result)
|
||||
sys.exit(1)
|
||||
return docker(["commit"] + (["-author", author] if author else []) + (["-run", json.dumps(run)] if run is not None else []) + [run_id]).read().rstrip()
|
||||
|
||||
def insert(base, src, dst, author=None):
|
||||
print "COPY {} to {} in {}".format(src, dst, base)
|
||||
if dst == "":
|
||||
raise Exception("Missing destination path")
|
||||
stdin = file(src)
|
||||
stdin.seek(0)
|
||||
return run_and_commit(base, "cat > {0}; chmod +x {0}".format(dst), stdin=stdin, author=author)
|
||||
|
||||
def add(base, src, dst, author=None):
|
||||
print "PUSH to {} in {}".format(dst, base)
|
||||
if src == ".":
|
||||
tar = subprocess.Popen(["tar", "-c", "."], stdout=subprocess.PIPE).stdout
|
||||
else:
|
||||
tar = subprocess.Popen(["curl", src], stdout=subprocess.PIPE).stdout
|
||||
if dst == "":
|
||||
raise Exception("Missing argument to push")
|
||||
return run_and_commit(base, "mkdir -p '{0}' && tar -C '{0}' -x".format(dst), stdin=tar, author=author)
|
||||
|
||||
def main():
|
||||
base=""
|
||||
maintainer=""
|
||||
steps = []
|
||||
try:
|
||||
for line in sys.stdin.readlines():
|
||||
line = line.strip()
|
||||
# Skip comments and empty lines
|
||||
if line == "" or line[0] == "#":
|
||||
continue
|
||||
op, param = line.split(None, 1)
|
||||
print op.upper() + " " + param
|
||||
if op == "from":
|
||||
base = param
|
||||
steps.append(base)
|
||||
elif op == "maintainer":
|
||||
maintainer = param
|
||||
elif op == "run":
|
||||
result = run_and_commit(base, param, author=maintainer)
|
||||
steps.append(result)
|
||||
base = result
|
||||
print "===> " + base
|
||||
elif op == "copy":
|
||||
src, dst = param.split(" ", 1)
|
||||
result = insert(base, src, dst, author=maintainer)
|
||||
steps.append(result)
|
||||
base = result
|
||||
print "===> " + base
|
||||
elif op == "add":
|
||||
src, dst = param.split(" ", 1)
|
||||
result = add(base, src, dst, author=maintainer)
|
||||
steps.append(result)
|
||||
base=result
|
||||
print "===> " + base
|
||||
elif op == "expose":
|
||||
config = image_config(base)
|
||||
if config.get("PortSpecs") is None:
|
||||
config["PortSpecs"] = []
|
||||
portspec = param.strip()
|
||||
config["PortSpecs"].append(portspec)
|
||||
result = run_and_commit(base, "# (nop) expose port {}".format(portspec), author=maintainer, run=config)
|
||||
steps.append(result)
|
||||
base=result
|
||||
print "===> " + base
|
||||
elif op == "cmd":
|
||||
config = image_config(base)
|
||||
cmd = list(json.loads(param))
|
||||
config["Cmd"] = cmd
|
||||
result = run_and_commit(base, "# (nop) set default command to '{}'".format(" ".join(cmd)), author=maintainer, run=config)
|
||||
steps.append(result)
|
||||
base=result
|
||||
print "===> " + base
|
||||
else:
|
||||
print "Skipping uknown op " + op
|
||||
except:
|
||||
docker(["rmi"] + steps[1:])
|
||||
raise
|
||||
print base
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
13
contrib/docker-build/example.changefile
Normal file
13
contrib/docker-build/example.changefile
Normal file
@@ -0,0 +1,13 @@
|
||||
# Start build from a know base image
|
||||
maintainer Solomon Hykes <solomon@dotcloud.com>
|
||||
from base:ubuntu-12.10
|
||||
# Update ubuntu sources
|
||||
run echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
# Install system packages
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
# Insert files from the host (./myscript must be present in the current directory)
|
||||
copy myscript /usr/local/bin/myscript
|
||||
push /src
|
||||
3
contrib/docker-build/myscript
Normal file
3
contrib/docker-build/myscript
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo hello, world!
|
||||
@@ -36,16 +36,16 @@ else
|
||||
fi
|
||||
|
||||
echo "Downloading docker binary and uncompressing into /usr/local/bin..."
|
||||
curl -s http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz |
|
||||
curl -s http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-latest.tgz |
|
||||
tar -C /usr/local/bin --strip-components=1 -zxf- \
|
||||
docker-master/docker
|
||||
docker-latest/docker
|
||||
|
||||
if [ -f /etc/init/dockerd.conf ]
|
||||
then
|
||||
echo "Upstart script already exists."
|
||||
else
|
||||
echo "Creating /etc/init/dockerd.conf..."
|
||||
echo "exec /usr/local/bin/docker -d" > /etc/init/dockerd.conf
|
||||
echo "exec env LANG=\"en_US.UTF-8\" /usr/local/bin/docker -d" > /etc/init/dockerd.conf
|
||||
fi
|
||||
|
||||
echo "Starting dockerd..."
|
||||
|
||||
@@ -35,6 +35,5 @@ do
|
||||
cp -a /dev/$X dev
|
||||
done
|
||||
|
||||
tar -cf- . | docker put busybox
|
||||
docker run -i -a -u root busybox /bin/echo Success.
|
||||
|
||||
tar -cf- . | docker import - busybox
|
||||
docker run -i -u root busybox /bin/echo Success.
|
||||
|
||||
61
contrib/mkimage-debian.sh
Executable file
61
contrib/mkimage-debian.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# these should match the names found at http://www.debian.org/releases/
|
||||
stableSuite='squeeze'
|
||||
testingSuite='wheezy'
|
||||
unstableSuite='sid'
|
||||
|
||||
# if suite is equal to this, it gets the "latest" tag
|
||||
latestSuite="$testingSuite"
|
||||
|
||||
variant='minbase'
|
||||
include='iproute,iputils-ping'
|
||||
|
||||
repo="$1"
|
||||
suite="${2:-$latestSuite}"
|
||||
mirror="${3:-}" # stick to the default debootstrap mirror if one is not provided
|
||||
|
||||
if [ ! "$repo" ]; then
|
||||
echo >&2 "usage: $0 repo [suite [mirror]]"
|
||||
echo >&2 " ie: $0 tianon/debian squeeze"
|
||||
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"
|
||||
|
||||
# create the image
|
||||
img=$(sudo tar -c . | docker import -)
|
||||
|
||||
# tag suite
|
||||
docker tag $img $repo $suite
|
||||
|
||||
if [ "$suite" = "$latestSuite" ]; then
|
||||
# tag latest
|
||||
docker tag $img $repo latest
|
||||
fi
|
||||
|
||||
# test the image
|
||||
docker run -i -t $repo:$suite echo success
|
||||
|
||||
# unstable's version numbers match testing (since it's mostly just a sandbox for testing), so it doesn't get a version number tag
|
||||
if [ "$suite" != "$unstableSuite" -a "$suite" != 'unstable' ]; then
|
||||
# tag the specific version
|
||||
ver=$(docker run $repo:$suite cat /etc/debian_version)
|
||||
docker tag $img $repo $ver
|
||||
fi
|
||||
|
||||
# cleanup
|
||||
cd "$returnTo"
|
||||
sudo rm -rf "$target"
|
||||
3
contrib/vagrant-docker/README.md
Normal file
3
contrib/vagrant-docker/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Vagrant-docker
|
||||
|
||||
This is a placeholder for the official vagrant-docker, a plugin for Vagrant (http://vagrantup.com) which exposes Docker as a provider.
|
||||
@@ -1 +0,0 @@
|
||||
../Makefile
|
||||
@@ -1 +0,0 @@
|
||||
../README.md
|
||||
@@ -1,5 +0,0 @@
|
||||
dotcloud-docker (1) precise; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- dotCloud <ops@dotcloud.com> Mon, 14 Mar 2013 04:43:21 -0700
|
||||
@@ -1,20 +0,0 @@
|
||||
Source: dotcloud-docker
|
||||
Section: misc
|
||||
Priority: extra
|
||||
Homepage: https://github.com/dotcloud/docker
|
||||
Maintainer: Daniel Mizyrycki <daniel@dotcloud.com>
|
||||
Build-Depends: debhelper (>= 8.0.0), pkg-config, git, golang, libsqlite3-dev
|
||||
Vcs-Git: https://github.com/dotcloud/docker.git
|
||||
Standards-Version: 3.9.2
|
||||
|
||||
Package: dotcloud-docker
|
||||
Architecture: amd64
|
||||
Provides: dotcloud-docker
|
||||
Depends: lxc, wget, bsdtar, curl, sqlite3
|
||||
Conflicts: docker
|
||||
Description: A process manager with superpowers
|
||||
It encapsulates heterogeneous payloads in Standard Containers, and runs
|
||||
them on any server with strong guarantees of isolation and repeatability.
|
||||
Is is a great building block for automating distributed systems:
|
||||
large-scale web deployments, database clusters, continuous deployment
|
||||
systems, private PaaS, service-oriented architectures, etc.
|
||||
@@ -1,209 +0,0 @@
|
||||
Format: http://dep.debian.net/deps/dep5
|
||||
Upstream-Name: dotcloud-docker
|
||||
Source: https://github.com/dotcloud/docker
|
||||
|
||||
Files: *
|
||||
Copyright: 2012 DotCloud Inc (opensource@dotcloud.com)
|
||||
License: Apache License Version 2.0
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2012 DotCloud Inc (opensource@dotcloud.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,10 +0,0 @@
|
||||
description "Run docker"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on starting rc RUNLEVEL=[016]
|
||||
respawn
|
||||
|
||||
script
|
||||
test -f /etc/default/locale && . /etc/default/locale || true
|
||||
LANG=$LANG LC_ALL=$LANG /usr/bin/docker -d
|
||||
end script
|
||||
161
docker.go
161
docker.go
@@ -1,161 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type Docker struct {
|
||||
root string
|
||||
repository string
|
||||
containers *list.List
|
||||
networkManager *NetworkManager
|
||||
Store *fs.Store
|
||||
}
|
||||
|
||||
func (docker *Docker) List() []*Container {
|
||||
containers := new(History)
|
||||
for e := docker.containers.Front(); e != nil; e = e.Next() {
|
||||
containers.Add(e.Value.(*Container))
|
||||
}
|
||||
return *containers
|
||||
}
|
||||
|
||||
func (docker *Docker) getContainerElement(id string) *list.Element {
|
||||
for e := docker.containers.Front(); e != nil; e = e.Next() {
|
||||
container := e.Value.(*Container)
|
||||
if container.Id == id {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (docker *Docker) Get(id string) *Container {
|
||||
e := docker.getContainerElement(id)
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Value.(*Container)
|
||||
}
|
||||
|
||||
func (docker *Docker) Exists(id string) bool {
|
||||
return docker.Get(id) != nil
|
||||
}
|
||||
|
||||
func (docker *Docker) Create(id string, command string, args []string, image *fs.Image, config *Config) (*Container, error) {
|
||||
if docker.Exists(id) {
|
||||
return nil, fmt.Errorf("Container %v already exists", id)
|
||||
}
|
||||
root := path.Join(docker.repository, id)
|
||||
|
||||
container, err := createContainer(id, root, command, args, image, config, docker.networkManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
docker.containers.PushBack(container)
|
||||
return container, nil
|
||||
}
|
||||
|
||||
func (docker *Docker) Destroy(container *Container) error {
|
||||
element := docker.getContainerElement(container.Id)
|
||||
if element == nil {
|
||||
return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.Id)
|
||||
}
|
||||
|
||||
if err := container.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
if container.Mountpoint.Mounted() {
|
||||
if err := container.Mountpoint.Umount(); err != nil {
|
||||
return fmt.Errorf("Unable to umount container %v: %v", container.Id, err)
|
||||
}
|
||||
}
|
||||
if err := container.Mountpoint.Deregister(); err != nil {
|
||||
return fmt.Errorf("Unable to deregiser -- ? mountpoint %v: %v", container.Mountpoint.Root, err)
|
||||
}
|
||||
if err := os.RemoveAll(container.Root); err != nil {
|
||||
return fmt.Errorf("Unable to remove filesystem for %v: %v", container.Id, err)
|
||||
}
|
||||
docker.containers.Remove(element)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (docker *Docker) restore() error {
|
||||
dir, err := ioutil.ReadDir(docker.repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range dir {
|
||||
container, err := loadContainer(docker.Store, path.Join(docker.repository, v.Name()), docker.networkManager)
|
||||
if err != nil {
|
||||
log.Printf("Failed to load container %v: %v", v.Name(), err)
|
||||
continue
|
||||
}
|
||||
docker.containers.PushBack(container)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func New() (*Docker, error) {
|
||||
return NewFromDirectory("/var/lib/docker")
|
||||
}
|
||||
|
||||
func NewFromDirectory(root string) (*Docker, error) {
|
||||
docker_repo := path.Join(root, "containers")
|
||||
|
||||
if err := os.MkdirAll(docker_repo, 0700); err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store, err := fs.New(path.Join(root, "images"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netManager, err := newNetworkManager(networkBridgeIface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
docker := &Docker{
|
||||
root: root,
|
||||
repository: docker_repo,
|
||||
containers: list.New(),
|
||||
Store: store,
|
||||
networkManager: netManager,
|
||||
}
|
||||
|
||||
if err := docker.restore(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return docker, nil
|
||||
}
|
||||
|
||||
type History []*Container
|
||||
|
||||
func (history *History) Len() int {
|
||||
return len(*history)
|
||||
}
|
||||
|
||||
func (history *History) Less(i, j int) bool {
|
||||
containers := *history
|
||||
return containers[j].When().Before(containers[i].When())
|
||||
}
|
||||
|
||||
func (history *History) Swap(i, j int) {
|
||||
containers := *history
|
||||
tmp := containers[i]
|
||||
containers[i] = containers[j]
|
||||
containers[j] = tmp
|
||||
}
|
||||
|
||||
func (history *History) Add(container *Container) {
|
||||
*history = append(*history, container)
|
||||
sort.Sort(history)
|
||||
}
|
||||
115
docker/docker.go
115
docker/docker.go
@@ -2,13 +2,21 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/future"
|
||||
"github.com/dotcloud/docker/rcli"
|
||||
"github.com/dotcloud/docker/term"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
GIT_COMMIT string
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -17,14 +25,28 @@ func main() {
|
||||
docker.SysInit()
|
||||
return
|
||||
}
|
||||
fl_daemon := flag.Bool("d", false, "Daemon mode")
|
||||
// FIXME: Switch d and D ? (to be more sshd like)
|
||||
flDaemon := flag.Bool("d", false, "Daemon mode")
|
||||
flDebug := flag.Bool("D", false, "Debug mode")
|
||||
flAutoRestart := flag.Bool("r", false, "Restart previously running containers")
|
||||
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
|
||||
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
|
||||
flag.Parse()
|
||||
if *fl_daemon {
|
||||
if *bridgeName != "" {
|
||||
docker.NetworkBridgeIface = *bridgeName
|
||||
} else {
|
||||
docker.NetworkBridgeIface = docker.DefaultNetworkBridge
|
||||
}
|
||||
if *flDebug {
|
||||
os.Setenv("DEBUG", "1")
|
||||
}
|
||||
docker.GIT_COMMIT = GIT_COMMIT
|
||||
if *flDaemon {
|
||||
if flag.NArg() != 0 {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
if err := daemon(); err != nil {
|
||||
if err := daemon(*pidfile, *flAutoRestart); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
@@ -34,8 +56,49 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func daemon() error {
|
||||
service, err := docker.NewServer()
|
||||
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, autoRestart bool) 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)
|
||||
}()
|
||||
|
||||
service, err := docker.NewServer(autoRestart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -43,50 +106,42 @@ func daemon() error {
|
||||
}
|
||||
|
||||
func runCommand(args []string) error {
|
||||
var oldState *term.State
|
||||
var err error
|
||||
if term.IsTerminal(0) && os.Getenv("NORAW") == "" {
|
||||
oldState, err = term.MakeRaw(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer term.Restore(0, oldState)
|
||||
}
|
||||
// FIXME: we want to use unix sockets here, but net.UnixConn doesn't expose
|
||||
// CloseWrite(), which we need to cleanly signal that stdin is closed without
|
||||
// closing the connection.
|
||||
// See http://code.google.com/p/go/issues/detail?id=3345
|
||||
if conn, err := rcli.Call("tcp", "127.0.0.1:4242", args...); err == nil {
|
||||
receive_stdout := future.Go(func() error {
|
||||
options := conn.GetOptions()
|
||||
if options.RawTerminal &&
|
||||
term.IsTerminal(int(os.Stdin.Fd())) &&
|
||||
os.Getenv("NORAW") == "" {
|
||||
if oldState, err := rcli.SetRawTerminal(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer rcli.RestoreTerminal(oldState)
|
||||
}
|
||||
}
|
||||
receiveStdout := docker.Go(func() error {
|
||||
_, err := io.Copy(os.Stdout, conn)
|
||||
return err
|
||||
})
|
||||
send_stdin := future.Go(func() error {
|
||||
sendStdin := docker.Go(func() error {
|
||||
_, err := io.Copy(conn, os.Stdin)
|
||||
if err := conn.CloseWrite(); err != nil {
|
||||
log.Printf("Couldn't send EOF: " + err.Error())
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err := <-receive_stdout; err != nil {
|
||||
if err := <-receiveStdout; err != nil {
|
||||
return err
|
||||
}
|
||||
if !term.IsTerminal(0) {
|
||||
if err := <-send_stdin; err != nil {
|
||||
if !term.IsTerminal(int(os.Stdin.Fd())) {
|
||||
if err := <-sendStdin; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
service, err := docker.NewServer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rcli.LocalCall(service, os.Stdin, os.Stdout, args...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if oldState != nil {
|
||||
term.Restore(0, oldState)
|
||||
return fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
319
docker_test.go
319
docker_test.go
@@ -1,319 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/fs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testLayerPath string = "/var/lib/docker/docker-ut.tar"
|
||||
const unitTestImageName string = "busybox"
|
||||
|
||||
var unitTestStoreBase string
|
||||
var srv *Server
|
||||
|
||||
func nuke(docker *Docker) error {
|
||||
return os.RemoveAll(docker.root)
|
||||
}
|
||||
|
||||
func CopyDirectory(source, dest string) error {
|
||||
if _, err := exec.Command("cp", "-ra", source, dest).Output(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func layerArchive(tarfile string) (io.Reader, error) {
|
||||
// FIXME: need to close f somewhere
|
||||
f, err := os.Open(tarfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Hack to run sys init during unit testing
|
||||
if SelfPath() == "/sbin/init" {
|
||||
SysInit()
|
||||
return
|
||||
}
|
||||
|
||||
if usr, err := user.Current(); err != nil {
|
||||
panic(err)
|
||||
} else if usr.Uid != "0" {
|
||||
panic("docker tests needs to be run as root")
|
||||
}
|
||||
|
||||
// Create a temp directory
|
||||
root, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
unitTestStoreBase = root
|
||||
|
||||
// Make it our Store root
|
||||
docker, err := NewFromDirectory(root)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Create the "Server"
|
||||
srv := &Server{
|
||||
images: docker.Store,
|
||||
containers: docker,
|
||||
}
|
||||
// Retrieve the Image
|
||||
if err := srv.CmdImport(os.Stdin, os.Stdout, unitTestImageName); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newTestDocker() (*Docker, error) {
|
||||
root, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Remove(root); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := CopyDirectory(unitTestStoreBase, root); err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
docker, err := NewFromDirectory(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return docker, nil
|
||||
}
|
||||
|
||||
func GetTestImage(docker *Docker) *fs.Image {
|
||||
imgs, err := docker.Store.Images()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else if len(imgs) < 1 {
|
||||
panic("GASP")
|
||||
}
|
||||
return imgs[0]
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
docker, err := newTestDocker()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(docker)
|
||||
|
||||
// Make sure we start we 0 containers
|
||||
if len(docker.List()) != 0 {
|
||||
t.Errorf("Expected 0 containers, %v found", len(docker.List()))
|
||||
}
|
||||
container, err := docker.Create(
|
||||
"test_create",
|
||||
"ls",
|
||||
[]string{"-al"},
|
||||
GetTestImage(docker),
|
||||
&Config{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := docker.Destroy(container); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Make sure we can find the newly created container with List()
|
||||
if len(docker.List()) != 1 {
|
||||
t.Errorf("Expected 1 container, %v found", len(docker.List()))
|
||||
}
|
||||
|
||||
// Make sure the container List() returns is the right one
|
||||
if docker.List()[0].Id != "test_create" {
|
||||
t.Errorf("Unexpected container %v returned by List", docker.List()[0])
|
||||
}
|
||||
|
||||
// Make sure we can get the container with Get()
|
||||
if docker.Get("test_create") == nil {
|
||||
t.Errorf("Unable to get newly created container")
|
||||
}
|
||||
|
||||
// Make sure it is the right container
|
||||
if docker.Get("test_create") != container {
|
||||
t.Errorf("Get() returned the wrong container")
|
||||
}
|
||||
|
||||
// Make sure Exists returns it as existing
|
||||
if !docker.Exists("test_create") {
|
||||
t.Errorf("Exists() returned false for a newly created container")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestroy(t *testing.T) {
|
||||
docker, err := newTestDocker()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(docker)
|
||||
container, err := docker.Create(
|
||||
"test_destroy",
|
||||
"ls",
|
||||
[]string{"-al"},
|
||||
GetTestImage(docker),
|
||||
&Config{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Destroy
|
||||
if err := docker.Destroy(container); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Make sure docker.Exists() behaves correctly
|
||||
if docker.Exists("test_destroy") {
|
||||
t.Errorf("Exists() returned true")
|
||||
}
|
||||
|
||||
// Make sure docker.List() doesn't list the destroyed container
|
||||
if len(docker.List()) != 0 {
|
||||
t.Errorf("Expected 0 container, %v found", len(docker.List()))
|
||||
}
|
||||
|
||||
// Make sure docker.Get() refuses to return the unexisting container
|
||||
if docker.Get("test_destroy") != nil {
|
||||
t.Errorf("Unable to get newly created container")
|
||||
}
|
||||
|
||||
// Make sure the container root directory does not exist anymore
|
||||
_, err = os.Stat(container.Root)
|
||||
if err == nil || !os.IsNotExist(err) {
|
||||
t.Errorf("Container root directory still exists after destroy")
|
||||
}
|
||||
|
||||
// Test double destroy
|
||||
if err := docker.Destroy(container); err == nil {
|
||||
// It should have failed
|
||||
t.Errorf("Double destroy did not fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
docker, err := newTestDocker()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(docker)
|
||||
container1, err := docker.Create(
|
||||
"test1",
|
||||
"ls",
|
||||
[]string{"-al"},
|
||||
GetTestImage(docker),
|
||||
&Config{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer docker.Destroy(container1)
|
||||
|
||||
container2, err := docker.Create(
|
||||
"test2",
|
||||
"ls",
|
||||
[]string{"-al"},
|
||||
GetTestImage(docker),
|
||||
&Config{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer docker.Destroy(container2)
|
||||
|
||||
container3, err := docker.Create(
|
||||
"test3",
|
||||
"ls",
|
||||
[]string{"-al"},
|
||||
GetTestImage(docker),
|
||||
&Config{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer docker.Destroy(container3)
|
||||
|
||||
if docker.Get("test1") != container1 {
|
||||
t.Errorf("Get(test1) returned %v while expecting %v", docker.Get("test1"), container1)
|
||||
}
|
||||
|
||||
if docker.Get("test2") != container2 {
|
||||
t.Errorf("Get(test2) returned %v while expecting %v", docker.Get("test2"), container2)
|
||||
}
|
||||
|
||||
if docker.Get("test3") != container3 {
|
||||
t.Errorf("Get(test3) returned %v while expecting %v", docker.Get("test3"), container3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRestore(t *testing.T) {
|
||||
|
||||
root, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Remove(root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := CopyDirectory(unitTestStoreBase, root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
docker1, err := NewFromDirectory(root)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a container with one instance of docker
|
||||
container1, err := docker1.Create(
|
||||
"restore_test",
|
||||
"ls",
|
||||
[]string{"-al"},
|
||||
GetTestImage(docker1),
|
||||
&Config{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer docker1.Destroy(container1)
|
||||
if len(docker1.List()) != 1 {
|
||||
t.Errorf("Expected 1 container, %v found", len(docker1.List()))
|
||||
}
|
||||
if err := container1.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Here are are simulating a docker restart - that is, reloading all containers
|
||||
// from scratch
|
||||
docker2, err := NewFromDirectory(root)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(docker2)
|
||||
if len(docker2.List()) != 1 {
|
||||
t.Errorf("Expected 1 container, %v found", len(docker2.List()))
|
||||
}
|
||||
container2 := docker2.Get("restore_test")
|
||||
if container2 == nil {
|
||||
t.Fatal("Unable to Get container")
|
||||
}
|
||||
if err := container2.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
186
docs/Makefile
Normal file
186
docs/Makefile
Normal file
@@ -0,0 +1,186 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) sources
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
# @echo " html to make standalone HTML files"
|
||||
# @echo " dirhtml to make HTML files named index.html in directories"
|
||||
# @echo " singlehtml to make a single large HTML file"
|
||||
# @echo " pickle to make pickle files"
|
||||
# @echo " json to make JSON files"
|
||||
# @echo " htmlhelp to make HTML files and a HTML help project"
|
||||
# @echo " qthelp to make HTML files and a qthelp project"
|
||||
# @echo " devhelp to make HTML files and a Devhelp project"
|
||||
# @echo " epub to make an epub"
|
||||
# @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 " texinfo to make Texinfo files"
|
||||
# @echo " info to make Texinfo files and run them through makeinfo"
|
||||
# @echo " gettext to make PO message catalogs"
|
||||
# @echo " changes to make an overview of all changed/added/deprecated items"
|
||||
# @echo " linkcheck to check all external links for integrity"
|
||||
# @echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " docs to build the docs and copy the static files to the outputdir"
|
||||
@echo " publish to publish the app to dotcloud"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
docs:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The documentation pages are now in $(BUILDDIR)/html."
|
||||
|
||||
|
||||
site:
|
||||
cp -r website $(BUILDDIR)/
|
||||
cp -r theme/docker/static/ $(BUILDDIR)/website/
|
||||
@echo
|
||||
@echo "The Website pages are in $(BUILDDIR)/site."
|
||||
|
||||
connect:
|
||||
@echo connecting dotcloud to www.docker.io website, make sure to use user 1
|
||||
@cd _build/website/ ; \
|
||||
dotcloud list ; \
|
||||
dotcloud connect dockerwebsite
|
||||
|
||||
push:
|
||||
@cd _build/website/ ; \
|
||||
dotcloud push
|
||||
|
||||
github-deploy: docs
|
||||
rm -fr github-deploy
|
||||
git clone ssh://git@github.com/dotcloud/docker github-deploy
|
||||
cd github-deploy && git checkout -f gh-pages && git rm -r * && rsync -avH ../_build/html/ ./ && touch .nojekyll && echo "docker.io" > CNAME && git add * && git commit -m "Updating docs"
|
||||
|
||||
$(VERSIONS):
|
||||
@echo "Hello world"
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Docker.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Docker.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Docker"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Docker"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
75
docs/README.md
Normal file
75
docs/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
Docker documentation and website
|
||||
================================
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
This is your definite place to contribute to the docker documentation. The documentation is generated from the
|
||||
.rst files under sources.
|
||||
|
||||
The folder also contains the other files to create the http://docker.io website, but you can generally ignore
|
||||
most of those.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
* Work in your own fork of the code, we accept pull requests.
|
||||
* Install sphinx: ``pip install sphinx``
|
||||
* Install sphinx httpdomain contrib package ``sphinxcontrib-httpdomain``
|
||||
* If pip is not available you can probably install it using your favorite package manager as **python-pip**
|
||||
|
||||
Usage
|
||||
-----
|
||||
* change the .rst files with your favorite editor to your liking
|
||||
* run *make docs* to clean up old files and generate new ones
|
||||
* your static website can now be found in the _build dir
|
||||
* to preview what you have generated, cd into _build/html and then run 'python -m SimpleHTTPServer 8000'
|
||||
|
||||
Working using github's file editor
|
||||
----------------------------------
|
||||
Alternatively, for small changes and typo's you might want to use github's built in file editor. It allows
|
||||
you to preview your changes right online. Just be carefull not to create many commits.
|
||||
|
||||
Images
|
||||
------
|
||||
When you need to add images, try to make them as small as possible (e.g. as gif).
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
* The index.html and gettingstarted.html files are copied from the source dir to the output dir without modification.
|
||||
So changes to those pages should be made directly in html
|
||||
* For the template the css is compiled from less. When changes are needed they can be compiled using
|
||||
lessc ``lessc main.less`` or watched using watch-lessc ``watch-lessc -i main.less -o main.css``
|
||||
|
||||
|
||||
Guides on using sphinx
|
||||
----------------------
|
||||
* To make links to certain pages create a link target like so:
|
||||
|
||||
```
|
||||
.. _hello_world:
|
||||
|
||||
Hello world
|
||||
===========
|
||||
|
||||
This is.. (etc.)
|
||||
```
|
||||
|
||||
The ``_hello_world:`` will make it possible to link to this position (page and marker) from all other pages.
|
||||
|
||||
* Notes, warnings and alarms
|
||||
|
||||
```
|
||||
# a note (use when something is important)
|
||||
.. note::
|
||||
|
||||
# a warning (orange)
|
||||
.. warning::
|
||||
|
||||
# danger (red, use sparsely)
|
||||
.. danger::
|
||||
|
||||
* Code examples
|
||||
|
||||
Start without $, so it's easy to copy and paste.
|
||||
2
docs/requirements.txt
Normal file
2
docs/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Sphinx==1.1.3
|
||||
sphinxcontrib-httpdomain==1.1.8
|
||||
130
docs/sources/builder/basics.rst
Normal file
130
docs/sources/builder/basics.rst
Normal file
@@ -0,0 +1,130 @@
|
||||
==============
|
||||
Docker Builder
|
||||
==============
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
1. Format
|
||||
=========
|
||||
|
||||
The Docker builder format is quite simple:
|
||||
|
||||
``instruction arguments``
|
||||
|
||||
The first instruction must be `FROM`
|
||||
|
||||
All instruction are to be placed in a file named `Dockerfile`
|
||||
|
||||
In order to place comments within a Dockerfile, simply prefix the line with "`#`"
|
||||
|
||||
2. Instructions
|
||||
===============
|
||||
|
||||
Docker builder comes with a set of instructions:
|
||||
|
||||
1. FROM: Set from what image to build
|
||||
2. RUN: Execute a command
|
||||
3. INSERT: Insert a remote file (http) into the image
|
||||
|
||||
2.1 FROM
|
||||
--------
|
||||
``FROM <image>``
|
||||
|
||||
The `FROM` instruction must be the first one in order for Builder to know from where to run commands.
|
||||
|
||||
`FROM` can also be used in order to build multiple images within a single Dockerfile
|
||||
|
||||
2.2 MAINTAINER
|
||||
--------------
|
||||
``MAINTAINER <name>``
|
||||
|
||||
The `MAINTAINER` instruction allow you to set the Author field of the generated images.
|
||||
This instruction is never automatically reset.
|
||||
|
||||
2.3 RUN
|
||||
-------
|
||||
``RUN <command>``
|
||||
|
||||
The `RUN` instruction is the main one, it allows you to execute any commands on the `FROM` image and to save the results.
|
||||
You can use as many `RUN` as you want within a Dockerfile, the commands will be executed on the result of the previous command.
|
||||
|
||||
|
||||
2.4 CMD
|
||||
-------
|
||||
``CMD <command>``
|
||||
|
||||
The `CMD` instruction sets the command to be executed when running the image.
|
||||
It is equivalent to do `docker commit -run '{"Cmd": <command>}'` outside the builder.
|
||||
|
||||
.. note::
|
||||
Do not confuse `RUN` with `CMD`. `RUN` actually run a command and save the result, `CMD` does not execute anything.
|
||||
|
||||
2.5 EXPOSE
|
||||
----------
|
||||
``EXPOSE <port> [<port>...]``
|
||||
|
||||
The `EXPOSE` instruction sets ports to be publicly exposed when running the image.
|
||||
This is equivalent to do `docker commit -run '{"PortSpecs": ["<port>", "<port2>"]}'` outside the builder.
|
||||
|
||||
2.6 ENV
|
||||
-------
|
||||
``ENV <key> <value>``
|
||||
|
||||
The `ENV` instruction set as environment variable `<key>` with the value `<value>`. This value will be passed to all future ``RUN`` instructions.
|
||||
|
||||
.. note::
|
||||
The environment variables are local to the Dockerfile, they will not be set as autorun.
|
||||
|
||||
2.7 INSERT
|
||||
----------
|
||||
|
||||
``INSERT <file url> <path>``
|
||||
|
||||
The `INSERT` instruction will download the file at the given url and place it within the image at the given path.
|
||||
|
||||
.. note::
|
||||
The path must include the file name.
|
||||
|
||||
|
||||
3. Dockerfile Examples
|
||||
======================
|
||||
|
||||
::
|
||||
|
||||
# Nginx
|
||||
#
|
||||
# VERSION 0.0.1
|
||||
# DOCKER-VERSION 0.2
|
||||
|
||||
from ubuntu
|
||||
maintainer Guillaume J. Charmes "guillaume@dotcloud.com"
|
||||
|
||||
# make sure the package repository is up to date
|
||||
run echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
|
||||
run apt-get install -y inotify-tools nginx apache2 openssh-server
|
||||
insert https://raw.github.com/creack/docker-vps/master/nginx-wrapper.sh /usr/sbin/nginx-wrapper
|
||||
|
||||
::
|
||||
|
||||
# Firefox over VNC
|
||||
#
|
||||
# VERSION 0.3
|
||||
# DOCKER-VERSION 0.2
|
||||
|
||||
from ubuntu
|
||||
# make sure the package repository is up to date
|
||||
run echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
|
||||
# Install vnc, xvfb in order to create a 'fake' display and firefox
|
||||
run apt-get install -y x11vnc xvfb firefox
|
||||
run mkdir /.vnc
|
||||
# Setup a password
|
||||
run x11vnc -storepasswd 1234 ~/.vnc/passwd
|
||||
# Autostart firefox (might not be the best way to do it, but it does the trick)
|
||||
run bash -c 'echo "firefox" >> /.bashrc'
|
||||
|
||||
expose 5900
|
||||
cmd ["x11vnc", "-forever", "-usepw", "-create"]
|
||||
14
docs/sources/builder/index.rst
Normal file
14
docs/sources/builder/index.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
:title: docker documentation
|
||||
:description: Documentation for docker builder
|
||||
:keywords: docker, builder, dockerfile
|
||||
|
||||
|
||||
Builder
|
||||
=======
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
basics
|
||||
101
docs/sources/commandline/basics.rst
Normal file
101
docs/sources/commandline/basics.rst
Normal file
@@ -0,0 +1,101 @@
|
||||
:title: Base commands
|
||||
:description: Common usage and commands
|
||||
:keywords: Examples, Usage
|
||||
|
||||
|
||||
The basics
|
||||
=============
|
||||
|
||||
Starting Docker
|
||||
---------------
|
||||
|
||||
If you have used one of the quick install paths', Docker may have been installed with upstart, Ubuntu's
|
||||
system for starting processes at boot time. You should be able to run ``docker help`` and get output.
|
||||
|
||||
If you get ``docker: command not found`` or something like ``/var/lib/docker/repositories: permission denied``
|
||||
you will need to specify the path to it and manually start it.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Run docker in daemon mode
|
||||
sudo <path to>/docker -d &
|
||||
|
||||
|
||||
Running an interactive shell
|
||||
----------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Download a base image
|
||||
docker pull base
|
||||
|
||||
# Run an interactive shell in the base image,
|
||||
# allocate a tty, attach stdin and stdout
|
||||
docker run -i -t base /bin/bash
|
||||
|
||||
|
||||
Starting a long-running worker process
|
||||
--------------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Start a very useful long-running process
|
||||
JOB=$(docker run -d base /bin/sh -c "while true; do echo Hello world; sleep 1; done")
|
||||
|
||||
# Collect the output of the job so far
|
||||
docker logs $JOB
|
||||
|
||||
# Kill the job
|
||||
docker kill $JOB
|
||||
|
||||
|
||||
Listing all running containers
|
||||
------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps
|
||||
|
||||
Expose a service on a TCP port
|
||||
------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Expose port 4444 of this container, and tell netcat to listen on it
|
||||
JOB=$(docker run -d -p 4444 base /bin/nc -l -p 4444)
|
||||
|
||||
# Which public port is NATed to my container?
|
||||
PORT=$(docker port $JOB 4444)
|
||||
|
||||
# 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.
|
||||
IP=$(ifconfig eth0 | perl -n -e 'if (m/inet addr:([\d\.]+)/g) { print $1 }')
|
||||
echo hello world | nc $IP $PORT
|
||||
|
||||
# Verify that the network connection worked
|
||||
echo "Daemon received: $(docker logs $JOB)"
|
||||
|
||||
|
||||
Committing (saving) an image
|
||||
-----------------------------
|
||||
|
||||
Save your containers state to a container image, so the state can be re-used.
|
||||
|
||||
When you commit your container only the differences between the image the container was created from
|
||||
and the current state of the container will be stored (as a diff). See which images you already have
|
||||
using ``docker images``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Commit your container to a new named image
|
||||
docker commit <container_id> <some_name>
|
||||
|
||||
# List your containers
|
||||
docker images
|
||||
|
||||
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`
|
||||
|
||||
55
docs/sources/commandline/cli.rst
Normal file
55
docs/sources/commandline/cli.rst
Normal file
@@ -0,0 +1,55 @@
|
||||
:title: Command Line Interface
|
||||
:description: Docker's CLI command description and usage
|
||||
:keywords: Docker, Docker documentation, CLI, command line
|
||||
|
||||
.. _cli:
|
||||
|
||||
Command Line Interface
|
||||
======================
|
||||
|
||||
Docker Usage
|
||||
~~~~~~~~~~~~
|
||||
|
||||
To list available commands, either run ``docker`` with no parameters or execute
|
||||
``docker help``::
|
||||
|
||||
$ docker
|
||||
Usage: docker COMMAND [arg...]
|
||||
|
||||
A self-sufficient runtime for linux containers.
|
||||
|
||||
...
|
||||
|
||||
Available Commands
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
command/attach
|
||||
command/build
|
||||
command/commit
|
||||
command/diff
|
||||
command/export
|
||||
command/history
|
||||
command/images
|
||||
command/import
|
||||
command/info
|
||||
command/inspect
|
||||
command/kill
|
||||
command/login
|
||||
command/logs
|
||||
command/port
|
||||
command/ps
|
||||
command/pull
|
||||
command/push
|
||||
command/restart
|
||||
command/rm
|
||||
command/rmi
|
||||
command/run
|
||||
command/search
|
||||
command/start
|
||||
command/stop
|
||||
command/tag
|
||||
command/version
|
||||
command/wait
|
||||
9
docs/sources/commandline/command/attach.rst
Normal file
9
docs/sources/commandline/command/attach.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
===========================================
|
||||
``attach`` -- Attach to a running container
|
||||
===========================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker attach CONTAINER
|
||||
|
||||
Attach to a running container
|
||||
9
docs/sources/commandline/command/build.rst
Normal file
9
docs/sources/commandline/command/build.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
========================================================
|
||||
``build`` -- Build a container from Dockerfile via stdin
|
||||
========================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker build -
|
||||
Example: cat Dockerfile | docker build -
|
||||
Build a new image from the Dockerfile passed via stdin
|
||||
27
docs/sources/commandline/command/commit.rst
Normal file
27
docs/sources/commandline/command/commit.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
===========================================================
|
||||
``commit`` -- Create a new image from a container's changes
|
||||
===========================================================
|
||||
|
||||
::
|
||||
|
||||
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="": Config automatically applied when the image is run. "+`(ex: {"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
|
||||
|
||||
Full -run example::
|
||||
|
||||
{"Hostname": "",
|
||||
"User": "",
|
||||
"Memory": 0,
|
||||
"MemorySwap": 0,
|
||||
"PortSpecs": ["22", "80", "443"],
|
||||
"Tty": true,
|
||||
"OpenStdin": true,
|
||||
"StdinOnce": true,
|
||||
"Env": ["FOO=BAR", "FOO2=BAR2"],
|
||||
"Cmd": ["cat", "-e", "/etc/resolv.conf"],
|
||||
"Dns": ["8.8.8.8", "8.8.4.4"]}
|
||||
9
docs/sources/commandline/command/diff.rst
Normal file
9
docs/sources/commandline/command/diff.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
=======================================================
|
||||
``diff`` -- Inspect changes on a container's filesystem
|
||||
=======================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker diff CONTAINER [OPTIONS]
|
||||
|
||||
Inspect changes on a container's filesystem
|
||||
9
docs/sources/commandline/command/export.rst
Normal file
9
docs/sources/commandline/command/export.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
=================================================================
|
||||
``export`` -- Stream the contents of a container as a tar archive
|
||||
=================================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker export CONTAINER
|
||||
|
||||
Export the contents of a filesystem as a tar archive
|
||||
9
docs/sources/commandline/command/history.rst
Normal file
9
docs/sources/commandline/command/history.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
===========================================
|
||||
``history`` -- Show the history of an image
|
||||
===========================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker history [OPTIONS] IMAGE
|
||||
|
||||
Show the history of an image
|
||||
22
docs/sources/commandline/command/images.rst
Normal file
22
docs/sources/commandline/command/images.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
=========================
|
||||
``images`` -- List images
|
||||
=========================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker images [OPTIONS] [NAME]
|
||||
|
||||
List images
|
||||
|
||||
-a=false: show all images
|
||||
-q=false: only show numeric IDs
|
||||
-viz=false: output in graphviz format
|
||||
|
||||
Displaying images visually
|
||||
--------------------------
|
||||
|
||||
::
|
||||
|
||||
docker images -viz | dot -Tpng -o docker.png
|
||||
|
||||
.. image:: images/docker_images.gif
|
||||
BIN
docs/sources/commandline/command/images/docker_images.gif
Normal file
BIN
docs/sources/commandline/command/images/docker_images.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
9
docs/sources/commandline/command/import.rst
Normal file
9
docs/sources/commandline/command/import.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
==========================================================================
|
||||
``import`` -- Create a new filesystem image from the contents of a tarball
|
||||
==========================================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker import [OPTIONS] URL|- [REPOSITORY [TAG]]
|
||||
|
||||
Create a new filesystem image from the contents of a tarball
|
||||
9
docs/sources/commandline/command/info.rst
Normal file
9
docs/sources/commandline/command/info.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
===========================================
|
||||
``info`` -- Display system-wide information
|
||||
===========================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker info
|
||||
|
||||
Display system-wide information.
|
||||
9
docs/sources/commandline/command/inspect.rst
Normal file
9
docs/sources/commandline/command/inspect.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
==========================================================
|
||||
``inspect`` -- Return low-level information on a container
|
||||
==========================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker inspect [OPTIONS] CONTAINER
|
||||
|
||||
Return low-level information on a container
|
||||
9
docs/sources/commandline/command/kill.rst
Normal file
9
docs/sources/commandline/command/kill.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
====================================
|
||||
``kill`` -- Kill a running container
|
||||
====================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
|
||||
|
||||
Kill a running container
|
||||
9
docs/sources/commandline/command/login.rst
Normal file
9
docs/sources/commandline/command/login.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
============================================================
|
||||
``login`` -- Register or Login to the docker registry server
|
||||
============================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker login
|
||||
|
||||
Register or Login to the docker registry server
|
||||
9
docs/sources/commandline/command/logs.rst
Normal file
9
docs/sources/commandline/command/logs.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
=========================================
|
||||
``logs`` -- Fetch the logs of a container
|
||||
=========================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker logs [OPTIONS] CONTAINER
|
||||
|
||||
Fetch the logs of a container
|
||||
9
docs/sources/commandline/command/port.rst
Normal file
9
docs/sources/commandline/command/port.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
=========================================================================
|
||||
``port`` -- Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
|
||||
=========================================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker port [OPTIONS] CONTAINER PRIVATE_PORT
|
||||
|
||||
Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
|
||||
13
docs/sources/commandline/command/ps.rst
Normal file
13
docs/sources/commandline/command/ps.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
=========================
|
||||
``ps`` -- List containers
|
||||
=========================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker ps [OPTIONS]
|
||||
|
||||
List containers
|
||||
|
||||
-a=false: Show all containers. Only running containers are shown by default.
|
||||
-notrunc=false: Don't truncate output
|
||||
-q=false: Only display numeric IDs
|
||||
9
docs/sources/commandline/command/pull.rst
Normal file
9
docs/sources/commandline/command/pull.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
=========================================================================
|
||||
``pull`` -- Pull an image or a repository from the docker registry server
|
||||
=========================================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker pull NAME
|
||||
|
||||
Pull an image or a repository from the registry
|
||||
9
docs/sources/commandline/command/push.rst
Normal file
9
docs/sources/commandline/command/push.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
=======================================================================
|
||||
``push`` -- Push an image or a repository to the docker registry server
|
||||
=======================================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker push NAME
|
||||
|
||||
Push an image or a repository to the registry
|
||||
9
docs/sources/commandline/command/restart.rst
Normal file
9
docs/sources/commandline/command/restart.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
==========================================
|
||||
``restart`` -- Restart a running container
|
||||
==========================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker restart [OPTIONS] NAME
|
||||
|
||||
Restart a running container
|
||||
9
docs/sources/commandline/command/rm.rst
Normal file
9
docs/sources/commandline/command/rm.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
============================
|
||||
``rm`` -- Remove a container
|
||||
============================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker rm [OPTIONS] CONTAINER
|
||||
|
||||
Remove a container
|
||||
9
docs/sources/commandline/command/rmi.rst
Normal file
9
docs/sources/commandline/command/rmi.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
==========================
|
||||
``rmi`` -- Remove an image
|
||||
==========================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker rmimage [OPTIONS] IMAGE
|
||||
|
||||
Remove an image
|
||||
22
docs/sources/commandline/command/run.rst
Normal file
22
docs/sources/commandline/command/run.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
===========================================
|
||||
``run`` -- Run a command in a new container
|
||||
===========================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker run [OPTIONS] IMAGE COMMAND [ARG...]
|
||||
|
||||
Run a command in a new container
|
||||
|
||||
-a=map[]: Attach to stdin, stdout or stderr.
|
||||
-d=false: Detached mode: leave the container running in the background
|
||||
-e=[]: Set environment variables
|
||||
-h="": Container host name
|
||||
-i=false: Keep stdin open even if not attached
|
||||
-m=0: Memory limit (in bytes)
|
||||
-p=[]: Map a network port to the container
|
||||
-t=false: Allocate a pseudo-tty
|
||||
-u="": Username or UID
|
||||
-d=[]: Set custom dns servers for the container
|
||||
-v=[]: Creates a new volumes and mount it at the specified path.
|
||||
-volumes-from="": Mount all volumes from the given container.
|
||||
10
docs/sources/commandline/command/search.rst
Normal file
10
docs/sources/commandline/command/search.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
===================================================================
|
||||
``search`` -- Search for an image in the docker index
|
||||
===================================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker search TERM
|
||||
|
||||
Searches for the TERM parameter on the Docker index and prints out a list of repositories
|
||||
that match.
|
||||
9
docs/sources/commandline/command/start.rst
Normal file
9
docs/sources/commandline/command/start.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
======================================
|
||||
``start`` -- Start a stopped container
|
||||
======================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker start [OPTIONS] NAME
|
||||
|
||||
Start a stopped container
|
||||
9
docs/sources/commandline/command/stop.rst
Normal file
9
docs/sources/commandline/command/stop.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
====================================
|
||||
``stop`` -- Stop a running container
|
||||
====================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker stop [OPTIONS] NAME
|
||||
|
||||
Stop a running container
|
||||
11
docs/sources/commandline/command/tag.rst
Normal file
11
docs/sources/commandline/command/tag.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
=========================================
|
||||
``tag`` -- Tag an image into a repository
|
||||
=========================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker tag [OPTIONS] IMAGE REPOSITORY [TAG]
|
||||
|
||||
Tag an image into a repository
|
||||
|
||||
-f=false: Force
|
||||
3
docs/sources/commandline/command/version.rst
Normal file
3
docs/sources/commandline/command/version.rst
Normal file
@@ -0,0 +1,3 @@
|
||||
==================================================
|
||||
``version`` -- Show the docker version information
|
||||
==================================================
|
||||
9
docs/sources/commandline/command/wait.rst
Normal file
9
docs/sources/commandline/command/wait.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
===================================================================
|
||||
``wait`` -- Block until a container stops, then print its exit code
|
||||
===================================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker wait [OPTIONS] NAME
|
||||
|
||||
Block until a container stops, then print its exit code.
|
||||
16
docs/sources/commandline/index.rst
Normal file
16
docs/sources/commandline/index.rst
Normal file
@@ -0,0 +1,16 @@
|
||||
:title: docker documentation
|
||||
:description: -- todo: change me
|
||||
:keywords: todo: change me
|
||||
|
||||
|
||||
Commands
|
||||
========
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
basics
|
||||
workingwithrepository
|
||||
cli
|
||||
42
docs/sources/commandline/workingwithrepository.rst
Normal file
42
docs/sources/commandline/workingwithrepository.rst
Normal file
@@ -0,0 +1,42 @@
|
||||
.. _working_with_the_repository:
|
||||
|
||||
Working with the repository
|
||||
============================
|
||||
|
||||
Connecting to the repository
|
||||
----------------------------
|
||||
|
||||
You create a user on the central docker repository by running
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker login
|
||||
|
||||
|
||||
If your username does not exist it will prompt you to also enter a password and your e-mail address. It will then
|
||||
automatically log you in.
|
||||
|
||||
|
||||
Committing a container to a named image
|
||||
---------------------------------------
|
||||
|
||||
In order to commit to the repository it is required to have committed your container to an image with your namespace.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# for example docker commit $CONTAINER_ID dhrp/kickassapp
|
||||
docker commit <container_id> <your username>/<some_name>
|
||||
|
||||
|
||||
Pushing a container to the repository
|
||||
-----------------------------------------
|
||||
|
||||
In order to push an image to the repository you need to have committed your container to a named image (see above)
|
||||
|
||||
Now you can commit this image to the repository
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# for example docker push dhrp/kickassapp
|
||||
docker push <image-name>
|
||||
|
||||
25
docs/sources/concepts/buildingblocks.rst
Normal file
25
docs/sources/concepts/buildingblocks.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
:title: Building blocks
|
||||
:description: An introduction to docker and standard containers?
|
||||
:keywords: containers, lxc, concepts, explanation
|
||||
|
||||
|
||||
Building blocks
|
||||
===============
|
||||
|
||||
.. _images:
|
||||
|
||||
Images
|
||||
------
|
||||
An original container image. These are stored on disk and are comparable with what you normally expect from a stopped virtual machine image. Images are stored (and retrieved from) repository
|
||||
|
||||
Images are stored on your local file system under /var/lib/docker/graph
|
||||
|
||||
|
||||
.. _containers:
|
||||
|
||||
Containers
|
||||
----------
|
||||
A container is a local version of an image. It can be running or stopped, The equivalent would be a virtual machine instance.
|
||||
|
||||
Containers are stored on your local file system under /var/lib/docker/containers
|
||||
|
||||
8
docs/sources/concepts/containers.rst
Normal file
8
docs/sources/concepts/containers.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
:title: Introduction
|
||||
:description: An introduction to docker and standard containers?
|
||||
:keywords: containers, lxc, concepts, explanation
|
||||
|
||||
|
||||
:note: This version of the introduction is temporary, just to make sure we don't break the links from the website when the documentation is updated
|
||||
|
||||
This document has been moved to :ref:`introduction`, please update your bookmarks.
|
||||
17
docs/sources/concepts/index.rst
Normal file
17
docs/sources/concepts/index.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
:title: docker documentation
|
||||
:description: -- todo: change me
|
||||
:keywords: todo: change me
|
||||
|
||||
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
introduction
|
||||
buildingblocks
|
||||
|
||||
127
docs/sources/concepts/introduction.rst
Normal file
127
docs/sources/concepts/introduction.rst
Normal file
@@ -0,0 +1,127 @@
|
||||
:title: Introduction
|
||||
:description: An introduction to docker and standard containers?
|
||||
:keywords: containers, lxc, concepts, explanation
|
||||
|
||||
.. _introduction:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Docker - The Linux container runtime
|
||||
------------------------------------
|
||||
|
||||
Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers.
|
||||
|
||||
Docker is a great building block for automating distributed systems: large-scale web deployments, database clusters, continuous deployment systems, private PaaS, service-oriented architectures, etc.
|
||||
|
||||
|
||||
- **Heterogeneous payloads** Any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all.
|
||||
- **Any server** Docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments.
|
||||
- **Isolation** docker isolates processes from each other and from the underlying host, using lightweight containers.
|
||||
- **Repeatability** Because containers are isolated in their own filesystem, they behave the same regardless of where, when, and alongside what they run.
|
||||
|
||||
.. image:: http://www.docker.io/_static/lego_docker.jpg
|
||||
|
||||
|
||||
What is a Standard Container?
|
||||
-----------------------------
|
||||
|
||||
Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in
|
||||
a format that is self-describing and portable, so that any compliant runtime can run it without extra dependency, regardless of the underlying machine and the contents of the container.
|
||||
|
||||
The spec for Standard Containers is currently work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
|
||||
|
||||
A great analogy for this is the shipping container. Just like Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery.
|
||||
|
||||
Standard operations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, standard containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged.
|
||||
|
||||
|
||||
Content-agnostic
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts.
|
||||
|
||||
|
||||
Infrastructure-agnostic
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions.
|
||||
|
||||
|
||||
Designed for automation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterpart, are extremely well-suited for automation. In fact, you could say automation is their secret weapon.
|
||||
|
||||
Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods.
|
||||
|
||||
Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider.
|
||||
|
||||
|
||||
Industrial-grade delivery
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded on the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away.
|
||||
|
||||
With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality.
|
||||
|
||||
|
||||
Standard Container Specification
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(TODO)
|
||||
|
||||
Image format
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Standard operations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Copy
|
||||
- Run
|
||||
- Stop
|
||||
- Wait
|
||||
- Commit
|
||||
- Attach standard streams
|
||||
- List filesystem changes
|
||||
- ...
|
||||
|
||||
Execution environment
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Root filesystem
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Environment variables
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Process arguments
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Networking
|
||||
^^^^^^^^^^
|
||||
|
||||
Process namespacing
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Resource limits
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Process monitoring
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Logging
|
||||
^^^^^^^
|
||||
|
||||
Signals
|
||||
^^^^^^^
|
||||
|
||||
Pseudo-terminal allocation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Security
|
||||
^^^^^^^^
|
||||
|
||||
247
docs/sources/conf.py
Normal file
247
docs/sources/conf.py
Normal file
@@ -0,0 +1,247 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Docker documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Mar 19 12:34:07 2013.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# 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']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
#disable the parmalinks on headers, I find them really annoying
|
||||
html_add_permalinks = None
|
||||
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Docker'
|
||||
copyright = u'2013, Team Docker'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'docker'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
html_theme_path = ['../theme']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['static_files']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_show_sourcelink = False
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Dockerdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Docker.tex', u'Docker Documentation',
|
||||
u'Team Docker', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'docker', u'Docker Documentation',
|
||||
[u'Team Docker'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'Docker', u'Docker Documentation',
|
||||
u'Team Docker', 'Docker', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
101
docs/sources/contributing/contributing.rst
Normal file
101
docs/sources/contributing/contributing.rst
Normal file
@@ -0,0 +1,101 @@
|
||||
Contributing to Docker
|
||||
======================
|
||||
|
||||
Want to hack on Docker? Awesome! There are instructions to get you
|
||||
started on the website: http://docker.io/gettingstarted.html
|
||||
|
||||
They are probably not perfect, please let us know if anything feels
|
||||
wrong or incomplete.
|
||||
|
||||
Contribution guidelines
|
||||
-----------------------
|
||||
|
||||
Pull requests are always welcome
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We are always thrilled to receive pull requests, and do our best to
|
||||
process them as fast as possible. Not sure if that typo is worth a pull
|
||||
request? Do it! We will appreciate it.
|
||||
|
||||
If your pull request is not accepted on the first try, don't be
|
||||
discouraged! If there's a problem with the implementation, hopefully you
|
||||
received feedback on what to improve.
|
||||
|
||||
We're trying very hard to keep Docker lean and focused. We don't want it
|
||||
to do everything for everybody. This means that we might decide against
|
||||
incorporating a new feature. However, there might be a way to implement
|
||||
that feature *on top of* docker.
|
||||
|
||||
Discuss your design on the mailing list
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We recommend discussing your plans `on the mailing
|
||||
list <https://groups.google.com/forum/?fromgroups#!forum/docker-club>`__
|
||||
before starting to code - especially for more ambitious contributions.
|
||||
This gives other contributors a chance to point you in the right
|
||||
direction, give feedback on your design, and maybe point out if someone
|
||||
else is working on the same thing.
|
||||
|
||||
Create issues...
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Any significant improvement should be documented as `a github
|
||||
issue <https://github.com/dotcloud/docker/issues>`__ before anybody
|
||||
starts working on it.
|
||||
|
||||
...but check for existing issues first!
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Please take a moment to check that an issue doesn't already exist
|
||||
documenting your bug report or improvement proposal. If it does, it
|
||||
never hurts to add a quick "+1" or "I have this problem too". This will
|
||||
help prioritize the most common problems and requests.
|
||||
|
||||
Conventions
|
||||
~~~~~~~~~~~
|
||||
|
||||
Fork the repo and make changes on your fork in a feature branch:
|
||||
|
||||
- If it's a bugfix branch, name it XXX-something where XXX is the number of the
|
||||
issue
|
||||
- If it's a feature branch, create an enhancement issue to announce your
|
||||
intentions, and name it XXX-something where XXX is the number of the issue.
|
||||
|
||||
Submit unit tests for your changes. Go has a great test framework built in; use
|
||||
it! Take a look at existing tests for inspiration. Run the full test suite on
|
||||
your branch before submitting a pull request.
|
||||
|
||||
Make sure you include relevant updates or additions to documentation when
|
||||
creating or modifying features.
|
||||
|
||||
Write clean code. Universally formatted code promotes ease of writing, reading,
|
||||
and maintenance. Always run ``go fmt`` before committing your changes. Most
|
||||
editors have plugins that do this automatically, and there's also a git
|
||||
pre-commit hook:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -o .git/hooks/pre-commit https://raw.github.com/edsrzf/gofmt-git-hook/master/fmt-check && chmod +x .git/hooks/pre-commit
|
||||
|
||||
|
||||
Pull requests descriptions should be as clear as possible and include a
|
||||
reference to all the issues that they address.
|
||||
|
||||
Code review comments may be added to your pull request. Discuss, then make the
|
||||
suggested modifications and push additional commits to your feature branch. Be
|
||||
sure to post a comment after pushing. The new commits will show up in the pull
|
||||
request automatically, but the reviewers will not be notified unless you
|
||||
comment.
|
||||
|
||||
Before the pull request is merged, make sure that you squash your commits into
|
||||
logical units of work using ``git rebase -i`` and ``git push -f``. After every
|
||||
commit the test suite should be passing. Include documentation changes in the
|
||||
same commit so that a revert would remove all traces of the feature or fix.
|
||||
|
||||
Commits that fix or close an issue should include a reference like ``Closes #XXX``
|
||||
or ``Fixes #XXX``, which will automatically close the issue when merged.
|
||||
|
||||
Add your name to the AUTHORS file, but make sure the list is sorted and your
|
||||
name and email address match your git configuration. The AUTHORS file is
|
||||
regenerated occasionally from the git commit history, so a mismatch may result
|
||||
in your changes being overwritten.
|
||||
33
docs/sources/contributing/devenvironment.rst
Normal file
33
docs/sources/contributing/devenvironment.rst
Normal file
@@ -0,0 +1,33 @@
|
||||
:title: Setting up a dev environment
|
||||
:description: Guides on how to contribute to docker
|
||||
:keywords: Docker, documentation, developers, contributing, dev environment
|
||||
|
||||
Setting up a dev environment
|
||||
============================
|
||||
|
||||
Instructions that have been verified to work on Ubuntu 12.10,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt-get -y install lxc wget bsdtar curl golang git
|
||||
|
||||
export GOPATH=~/go/
|
||||
export PATH=$GOPATH/bin:$PATH
|
||||
|
||||
mkdir -p $GOPATH/src/github.com/dotcloud
|
||||
cd $GOPATH/src/github.com/dotcloud
|
||||
git clone git@github.com:dotcloud/docker.git
|
||||
cd docker
|
||||
|
||||
go get -v github.com/dotcloud/docker/...
|
||||
go install -v github.com/dotcloud/docker/...
|
||||
|
||||
|
||||
Then run the docker daemon,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo $GOPATH/bin/docker -d
|
||||
|
||||
|
||||
Run the ``go install`` command (above) to recompile docker.
|
||||
14
docs/sources/contributing/index.rst
Normal file
14
docs/sources/contributing/index.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
:title: Contributing to Docker
|
||||
:description: Guides on how to contribute to docker
|
||||
:keywords: Docker, documentation, developers, contributing, dev environment
|
||||
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
contributing
|
||||
devenvironment
|
||||
53
docs/sources/examples/couchdb_data_volumes.rst
Normal file
53
docs/sources/examples/couchdb_data_volumes.rst
Normal file
@@ -0,0 +1,53 @@
|
||||
:title: Sharing data between 2 couchdb databases
|
||||
:description: Sharing data between 2 couchdb databases
|
||||
:keywords: docker, example, package installation, networking, couchdb, data volumes
|
||||
|
||||
.. _running_couchdb_service:
|
||||
|
||||
Create a 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 different versions of couchdb on the same data, etc.
|
||||
|
||||
Create first database
|
||||
---------------------
|
||||
|
||||
Note that we're marking /var/lib/couchdb as a data volume.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
COUCH1=$(docker run -d -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.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
HOST=localhost
|
||||
URL="http://$HOST:$(docker port $COUCH1 5984)/_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.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
COUCH2=$(docker run -d -volumes-from $COUCH1) shykes/couchdb:2013-05-03)
|
||||
|
||||
Browse data on the second database
|
||||
----------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
HOST=localhost
|
||||
URL="http://$HOST:$(docker port $COUCH2 5984)/_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 isolated from each other *except* for their data.
|
||||
4
docs/sources/examples/example_header.inc
Normal file
4
docs/sources/examples/example_header.inc
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
.. note::
|
||||
|
||||
This example assumes you have Docker running in daemon mode. For more information please see :ref:`running_examples`
|
||||
50
docs/sources/examples/hello_world.rst
Normal file
50
docs/sources/examples/hello_world.rst
Normal file
@@ -0,0 +1,50 @@
|
||||
:title: Hello world example
|
||||
:description: A simple hello world example with Docker
|
||||
:keywords: docker, example, hello world
|
||||
|
||||
.. _hello_world:
|
||||
|
||||
Hello World
|
||||
===========
|
||||
|
||||
.. include:: example_header.inc
|
||||
|
||||
This is the most basic example available for using Docker.
|
||||
|
||||
Download the base container
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Download a base image
|
||||
docker pull base
|
||||
|
||||
The *base* image is a minimal *ubuntu* based container, alternatively 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.
|
||||
docker run base /bin/echo hello world
|
||||
|
||||
**Explanation:**
|
||||
|
||||
- **"docker run"** run a command in a new container
|
||||
- **"base"** is the image we want to run the command inside of.
|
||||
- **"/bin/echo"** is the command we want to run in the container
|
||||
- **"hello world"** is the input for the echo command
|
||||
|
||||
|
||||
|
||||
**Video:**
|
||||
|
||||
See the example in action
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div style="margin-top:10px;">
|
||||
<iframe width="560" height="350" src="http://ascii.io/a/2603/raw" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
|
||||
Continue to the :ref:`hello_world_daemon` example.
|
||||
84
docs/sources/examples/hello_world_daemon.rst
Normal file
84
docs/sources/examples/hello_world_daemon.rst
Normal file
@@ -0,0 +1,84 @@
|
||||
:title: Hello world daemon example
|
||||
:description: A simple hello world daemon example with Docker
|
||||
:keywords: docker, example, hello world, daemon
|
||||
|
||||
.. _hello_world_daemon:
|
||||
|
||||
Hello World Daemon
|
||||
==================
|
||||
|
||||
.. include:: example_header.inc
|
||||
|
||||
The most boring daemon ever written.
|
||||
|
||||
This example assumes you have Docker installed and with the base image already imported ``docker pull base``.
|
||||
We will use the base image to run a simple hello world daemon that will just print hello world to standard
|
||||
out every second. It will continue to do this until we stop it.
|
||||
|
||||
**Steps:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
CONTAINER_ID=$(docker run -d base /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 base image.
|
||||
|
||||
- **"docker run -d "** run a command in a new container. We pass "-d" so it runs as a daemon.
|
||||
- **"base"** is the image we want to run the command inside of.
|
||||
- **"/bin/sh -c"** is the command we want to run in the container
|
||||
- **"while true; do echo hello world; sleep 1; done"** is the mini script we want to run, that will just print hello world once a second until we stop it.
|
||||
- **$CONTAINER_ID** the output of the run command will return a container id, we can use in future commands to see what is going on with this process.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker logs $CONTAINER_ID
|
||||
|
||||
Check the logs make sure it is working correctly.
|
||||
|
||||
- **"docker logs**" This will return the logs for a container
|
||||
- **$CONTAINER_ID** The Id of the container we want the logs for.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker attach $CONTAINER_ID
|
||||
|
||||
Attach to the container to see the results in realtime.
|
||||
|
||||
- **"docker attach**" This will allow us to attach to a background process to see what is going on.
|
||||
- **$CONTAINER_ID** The Id of the container we want to attach too.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps
|
||||
|
||||
Check the process list to make sure it is running.
|
||||
|
||||
- **"docker ps"** this shows all running process managed by docker
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker stop $CONTAINER_ID
|
||||
|
||||
Stop the container, since we don't need it anymore.
|
||||
|
||||
- **"docker stop"** This stops a container
|
||||
- **$CONTAINER_ID** The Id of the container we want to stop.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps
|
||||
|
||||
Make sure it is really stopped.
|
||||
|
||||
|
||||
**Video:**
|
||||
|
||||
See the example in action
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div style="margin-top:10px;">
|
||||
<iframe width="560" height="350" src="http://ascii.io/a/2562/raw" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
Continue to the :ref:`python_web_app` example.
|
||||
21
docs/sources/examples/index.rst
Normal file
21
docs/sources/examples/index.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
:title: Docker Examples
|
||||
:description: Examples on how to use Docker
|
||||
:keywords: docker, hello world, examples
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
============
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
running_examples
|
||||
hello_world
|
||||
hello_world_daemon
|
||||
python_web_app
|
||||
running_redis_service
|
||||
running_ssh_service
|
||||
couchdb_data_volumes
|
||||
88
docs/sources/examples/python_web_app.rst
Normal file
88
docs/sources/examples/python_web_app.rst
Normal file
@@ -0,0 +1,88 @@
|
||||
:title: Python Web app example
|
||||
:description: Building your own python web app using docker
|
||||
:keywords: docker, example, python, web app
|
||||
|
||||
.. _python_web_app:
|
||||
|
||||
Building a 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 saving the results as a new image. We will do that by making a simple hello flask web application image.
|
||||
|
||||
**Steps:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker pull shykes/pybuilder
|
||||
|
||||
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
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
BUILD_JOB=$(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 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.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker attach $BUILD_JOB
|
||||
[...]
|
||||
|
||||
We attach to the new container to see what is going on. Ctrl-C to disconnect
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
BUILD_IMG=$(docker commit $BUILD_JOB _/builds/github.com/hykes/helloflask/master)
|
||||
|
||||
Save the changed 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.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
WEB_WORKER=$(docker run -d -p 5000 $BUILD_IMG /usr/local/bin/runapp)
|
||||
|
||||
- **"docker run -d "** run a command in a new container. We pass "-d" so it runs as a daemon.
|
||||
- **"-p 5000"** the web app is going to listen on this port, so it must be mapped from the container to the host system.
|
||||
- **"$BUILD_IMG"** is the image we want to run the command inside of.
|
||||
- **/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.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
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.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
WEB_PORT=$(docker port $WEB_WORKER 5000)
|
||||
|
||||
lookup the public-facing port which is NAT-ed store the private port used by the container and store it inside of the WEB_PORT variable.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl http://`hostname`:$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.
|
||||
|
||||
**Video:**
|
||||
|
||||
See the example in action
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div style="margin-top:10px;">
|
||||
<iframe width="720" height="350" src="http://ascii.io/a/2573/raw" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
Continue to :ref:`running_ssh_service`.
|
||||
22
docs/sources/examples/running_examples.rst
Normal file
22
docs/sources/examples/running_examples.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
:title: Running the Examples
|
||||
:description: An overview on how to run the docker examples
|
||||
:keywords: docker, examples, how to
|
||||
|
||||
.. _running_examples:
|
||||
|
||||
Running The Examples
|
||||
--------------------
|
||||
|
||||
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: all commands will be forwarded to the docker daemon, so the client
|
||||
can run from any account.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# now you can run docker commands from any account.
|
||||
docker help
|
||||
81
docs/sources/examples/running_redis_service.rst
Normal file
81
docs/sources/examples/running_redis_service.rst
Normal file
@@ -0,0 +1,81 @@
|
||||
:title: Running a Redis service
|
||||
:description: Installing and running an redis service
|
||||
:keywords: docker, example, package installation, networking, redis
|
||||
|
||||
.. _running_redis_service:
|
||||
|
||||
Create a redis service
|
||||
======================
|
||||
|
||||
.. include:: example_header.inc
|
||||
|
||||
Very simple, no frills, redis service.
|
||||
|
||||
Open a docker container
|
||||
-----------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -i -t base /bin/bash
|
||||
|
||||
Building your image
|
||||
-------------------
|
||||
|
||||
Update your docker container, install the redis server. Once installed, exit out of docker.
|
||||
|
||||
.. 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 last one in the list)
|
||||
docker commit <container_id> <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.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -d -p 6379 <your username>/redis /usr/bin/redis-server
|
||||
|
||||
Test 1
|
||||
++++++
|
||||
|
||||
Connect to the container with the redis-cli.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps # grab the new container id
|
||||
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
|
||||
OK
|
||||
redis 10.0.3.32:6379> get docker
|
||||
"awesome"
|
||||
redis 10.0.3.32:6379> exit
|
||||
|
||||
Test 2
|
||||
++++++
|
||||
|
||||
Connect to the host os with the redis-cli.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps # grab the new container id
|
||||
docker port <container_id> 6379 # grab the external port
|
||||
ifconfig # 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
|
||||
32
docs/sources/examples/running_ssh_service.rst
Normal file
32
docs/sources/examples/running_ssh_service.rst
Normal file
@@ -0,0 +1,32 @@
|
||||
:title: Running an SSH service
|
||||
:description: A screencast of installing and running an sshd service
|
||||
:keywords: docker, example, package installation, networking
|
||||
|
||||
.. _running_ssh_service:
|
||||
|
||||
Create an ssh daemon service
|
||||
============================
|
||||
|
||||
.. include:: example_header.inc
|
||||
|
||||
|
||||
**Video:**
|
||||
|
||||
I've create a little screencast to show how to create a sshd service and connect to it. It is something like 11
|
||||
minutes and not entirely smooth, but gives you a good idea.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div style="margin-top:10px;">
|
||||
<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
|
||||
::
|
||||
|
||||
docker pull dhrp/sshd
|
||||
|
||||
|
||||
The password is 'screencast'
|
||||
|
||||
47
docs/sources/faq.rst
Normal file
47
docs/sources/faq.rst
Normal file
@@ -0,0 +1,47 @@
|
||||
FAQ
|
||||
===
|
||||
|
||||
|
||||
Most frequently asked questions.
|
||||
--------------------------------
|
||||
|
||||
1. **How much does Docker cost?**
|
||||
|
||||
Docker is 100% free, it is open source, so you can use it without paying.
|
||||
|
||||
2. **What open source license are you using?**
|
||||
|
||||
We are using the Apache License Version 2.0, see it here: https://github.com/dotcloud/docker/blob/master/LICENSE
|
||||
|
||||
3. **Does Docker run on Mac OS X or Windows?**
|
||||
|
||||
Not at this time, Docker currently only runs on Linux, but you can use VirtualBox to run Docker in a virtual machine on your box, and get the best of both worlds. Check out the MacOSX_ and Windows_ intallation guides.
|
||||
|
||||
4. **How do containers compare to virtual machines?**
|
||||
|
||||
They are complementary. VMs are best used to allocate chunks of hardware resources. Containers operate at the process level, which makes them very lightweight and perfect as a unit of software delivery.
|
||||
|
||||
5. **Can I help by adding some questions and answers?**
|
||||
|
||||
Definitely! You can fork `the repo`_ and edit the documentation sources.
|
||||
|
||||
|
||||
42. **Where can I find more answers?**
|
||||
|
||||
You can find more answers on:
|
||||
|
||||
* `IRC: docker on freenode`_
|
||||
* `Github`_
|
||||
* `Ask questions on Stackoverflow`_
|
||||
* `Join the conversation on Twitter`_
|
||||
|
||||
.. _Windows: ../documentation/installation/windows.html
|
||||
.. _MacOSX: ../documentation/installation/macos.html
|
||||
.. _the repo: http://www.github.com/dotcloud/docker
|
||||
.. _IRC\: docker on freenode: irc://chat.freenode.net#docker
|
||||
.. _Github: http://www.github.com/dotcloud/docker
|
||||
.. _Ask questions on Stackoverflow: http://stackoverflow.com/search?q=docker
|
||||
.. _Join the conversation on Twitter: http://twitter.com/getdocker
|
||||
|
||||
|
||||
Looking for something else to read? Checkout the :ref:`hello_world` example.
|
||||
24
docs/sources/index.rst
Normal file
24
docs/sources/index.rst
Normal file
@@ -0,0 +1,24 @@
|
||||
:title: docker documentation
|
||||
:description: docker documentation
|
||||
:keywords:
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
This documentation has the following resources:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
concepts/index
|
||||
installation/index
|
||||
examples/index
|
||||
contributing/index
|
||||
commandline/index
|
||||
registry/index
|
||||
index/index
|
||||
builder/index
|
||||
faq
|
||||
|
||||
|
||||
.. image:: http://www.docker.io/_static/lego_docker.jpg
|
||||
15
docs/sources/index/index.rst
Normal file
15
docs/sources/index/index.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
:title: Docker Index documentation
|
||||
:description: Documentation for docker Index
|
||||
:keywords: docker, index, api
|
||||
|
||||
|
||||
|
||||
Index
|
||||
=====
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
search
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user