diff --git a/.drone.yml b/.drone.yml index 53e00e0fd..0b8625d2a 100755 --- a/.drone.yml +++ b/.drone.yml @@ -10,5 +10,5 @@ script: - rm integration-cli/docker_cli_daemon_test.go - rm integration-cli/docker_cli_exec_test.go # Validate and test. - - hack/make.sh validate-dco validate-gofmt - - hack/make.sh binary cross test-unit test-integration-cli test-integration + - hack/make.sh validate-dco validate-gofmt validate-toml + - hack/make.sh binary cross test-unit test-integration-cli test-integration test-docker-py diff --git a/.gitignore b/.gitignore index 68d2da95b..49fa58a94 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ docs/AWS_S3_BUCKET docs/GIT_BRANCH docs/VERSION docs/GITCOMMIT +docs/changed-files diff --git a/.mailmap b/.mailmap index 826fae0ea..00b698bba 100644 --- a/.mailmap +++ b/.mailmap @@ -6,6 +6,24 @@ # # For explanation on this file format: man git-shortlog +Patrick Stapleton +Shishir Mahajan +Erwin van der Koogh +Ahmed Kamal +Tejesh Mehta +Cristian Staretu +Cristian Staretu +Cristian Staretu +Marcus Linke +Aleksandrs Fadins +Christopher Latham +Hu Keping +Wayne Chang +Chen Chao +Daehyeok Mun + + + @@ -58,7 +76,7 @@ Jean-Baptiste Dalido - + @@ -74,7 +92,6 @@ Sven Dowideit Sven Dowideit <¨SvenDowideit@home.org.au¨> Sven Dowideit Sven Dowideit -unclejack Alexandr Morozov diff --git a/AUTHORS b/AUTHORS index 3d3fe3c7b..e6ec5d00f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,41 +12,46 @@ Adam Singer Aditya Adrian Mouat Adrien Folie +Ahmed Kamal Ahmet Alp Balkan +Aidan Hobson Sayers AJ Bowen +Al Tobey alambike Alan Thompson Albert Callarisa Albert Zhang Aleksa Sarai +Aleksandrs Fadins +Alex Gaynor +Alex Warhawk +Alexander Boyd Alexander Larsson +Alexander Morozov Alexander Shopov Alexandr Morozov Alexey Kotlyarov Alexey Shamrin -Alex Gaynor Alexis THOMAS -Alex Warhawk almoehi -Al Tobey -Álvaro Lázaro amangoel Amit Bakshi -AnandkumarPatel Anand Patil +AnandkumarPatel +Andre Dublin <81dublin@gmail.com> Andrea Luzzardi +Andrea Turli Andreas Köhler Andreas Savvides Andreas Tiefenthaler -Andrea Turli -Andre Dublin <81dublin@gmail.com> +Andrew C. Bodine Andrew Duckworth Andrew France Andrew Macgregor Andrew Munsell -Andrews Medina Andrew Weiss Andrew Williams +Andrews Medina Andrey Petrov Andrey Stolbovsky Andy Chambers @@ -56,6 +61,8 @@ Andy Kipp Andy Rothfusz Andy Smith Andy Wilson +Ankush Agarwal +Anthony Baire Anthony Bishopric Anton Löfgren Anton Nikitin @@ -72,11 +79,11 @@ Barry Allard Bartłomiej Piotrowski bdevloed Ben Firshman -Benjamin Atkin -Benoit Chesneau Ben Sargent Ben Toews Ben Wiklund +Benjamin Atkin +Benoit Chesneau Bernerd Schaefer Bert Goethals Bhiraj Butala @@ -113,18 +120,22 @@ Charles Hooper Charles Lindsay Charles Merriam Charlie Lewis +Chen Chao Chewey Chia-liang Kao Chris Alfonso Chris Armstrong -chrismckinnel Chris Snow Chris St. Pierre +chrismckinnel Christian Berendt +Christian Stefanescu ChristoperBiscardi -Christopher Currie -Christopher Rigor Christophe Troestler +Christopher Currie +Christopher Latham +Christopher Rigor +Chun Chen Ciro S. Costa Clayton Coleman Colin Dunklau @@ -132,15 +143,20 @@ Colin Rice Colin Walters Cory Forsyth cressie176 +Cristian Staretu Cruceru Calin-Cristian Daan van Berkel -Daehyeok.Mun +Daehyeok Mun Dafydd Crosby Dan Buch Dan Cotora Dan Griffin Dan Hirsch -Daniel, Dao Quang Minh +Dan Keder +Dan McPherson +Dan Stine +Dan Walsh +Dan Williams Daniel Exner Daniel Farrell Daniel Garcia @@ -152,29 +168,27 @@ Daniel Nordberg Daniel Robinson Daniel Von Fange Daniel YC Lin -Dan Keder -Dan McPherson +Daniel, Dao Quang Minh Danny Berger Danny Yates -Dan Stine -Dan Walsh -Dan Williams Darren Coxall Darren Shepherd David Anderson David Calavera David Corking -Davide Ceretti David Gageot David Gebler +David Mat David Mcanulty David Pelaez David Röthlisberger David Sissitka +Davide Ceretti Dawn Chen decadent Deni Bertovic Derek +Derek Derek McGowan Deric Crago Deshi Xiao @@ -182,14 +196,16 @@ Dinesh Subhraveti Djibril Koné dkumor Dmitry Demeshchuk +Dmitry V. Krivenok Dolph Mathews Dominik Honnef +Don Kjer Don Spaulding Doug Davis doug tangren +Dr Nic Williams dragon788 Dražen Lučanin -Dr Nic Williams Dustin Sallings Edmund Wagner Eiichi Tsukata @@ -197,19 +213,22 @@ Eike Herzbach Eivind Uggedal Elias Probst Emil Hernvall +Emily Maier Emily Rose Eric Hanchrow Eric Lee Eric Myhre Eric Paris Eric Windisch +Erik Dubbelboer Erik Hollensbe Erik Inge Bolsø Erik Kristensen Erno Hopearuoho +Erwin van der Koogh Eugene Yakubovich eugenkrizo -evanderkoogh +Evan Carmi Evan Hazlett Evan Krall Evan Phoenix @@ -230,9 +249,9 @@ Francisco Carriedo Francisco Souza Frank Macreery Frank Rosquin +Fred Lifton Frederick F. Kautz IV Frederik Loeffert -Fred Lifton Freek Kalter Gabe Rosenhouse Gabor Nagy @@ -266,13 +285,15 @@ Hector Castro Henning Sprang Hobofan Hollie Teal +Hu Keping +Hu Tao Huayi Zhang Hugo Duncan Hunter Blanks -Hu Tao Huu Nguyen hyeongkyu.lee Ian Babrou +Ian Bishop Ian Bull Ian Main Ian Truslove @@ -284,8 +305,10 @@ Isabel Jimenez Isao Jonas Ivan Fraixedes Jack Danger Canty -jakedt +Jacob Atzen +Jacob Edelman Jake Moshenko +jakedt James Allen James Carr James DeFelice @@ -306,49 +329,52 @@ Jason Plum Jean-Baptiste Barth Jean-Baptiste Dalido Jean-Paul Calderone +Jean-Tiare Le Bigot +Jeff Anderson Jeff Lindsay -Jeffrey Bolle Jeff Welch +Jeffrey Bolle Jeremy Grosser -Jérôme Petazzoni Jesse Dubay Jessica Frazelle Jezeniel Zapanta Jilles Oldenbeuving Jim Alateras -Jimmy Cuadra Jim Perrin +Jimmy Cuadra Jiří Župka Joe Beda Joe Ferguson -Joel Handwell Joe Shaw Joe Van Dyk +Joel Friedly +Joel Handwell Joffrey F Johan Euphrosine -Johannes 'fish' Ziemke Johan Rydberg +Johannes 'fish' Ziemke John Costa John Feminella John Gardiner Myers John Gossman John OBrien III John Warwick +Jon Wedaman Jonas Pfenniger +Jonathan A. Sternberg Jonathan Boulle Jonathan Camp Jonathan McCrohan Jonathan Mueller Jonathan Pares Jonathan Rudenberg -Jon Wedaman Joost Cassee Jordan Arentsen Jordan Sissel Joseph Anthony Pasquale Holsten Joseph Hager -Josh Hawn Josh +Josh Hawn Josh Poimboeuf Josiah Kiehl JP @@ -360,6 +386,9 @@ Justin Force Justin Plock Justin Simonelis Jyrki Puttonen +Jérôme Petazzoni +Jörg Thalheim +Kamil Domanski Karan Lyons Karl Grzeszczak Kato Kazuyoshi @@ -367,14 +396,13 @@ Kawsar Saiyeed Keli Hu Ken Cochrane Ken ICHIKAWA +Kevin "qwazerty" Houdebert Kevin Clark Kevin J. Lynagh Kevin Menard -Kevin "qwazerty" Houdebert Kevin Wallace Keyvan Fatehi kies -kim0 Kim BKC Carlbacker Kimbro Staken Kiran Gangadharan @@ -382,6 +410,7 @@ knappe Kohei Tsuruta Konrad Kleine Konstantin Pelykh +Krasimir Georgiev krrg Kyle Conroy kyu @@ -397,13 +426,16 @@ Lei Jitang Len Weincier Leszek Kowalski Levi Gross +Lewis Marshall Lewis Peckover Liang-Chi Hsieh limsy Lokesh Mandvekar +Lorenz Leutgeb Louis Opter lukaspustina lukemarsden +Lénaïc Huard Madhu Venugopal Mahesh Tiyyagura Malte Janduda @@ -412,12 +444,13 @@ Manuel Meurer Manuel Woelker Marc Abramowitz Marc Kuo -Marco Hennings Marc Tamsky +Marco Hennings Marcus Farkas -marcuslinke +Marcus Linke Marcus Ramberg Marek Goldmann +Marianna Marius Voila Mark Allen Mark McGranaghan @@ -425,7 +458,9 @@ Marko Mikulicic Marko Tibold Markus Fix Martijn van Oosterhout +Martin Honermeyer Martin Redmond +Mary Anthony Mason Malone Mateusz Sulima Mathias Monnerville @@ -435,14 +470,14 @@ Matt Bachmann Matt Haggard Matthew Heon Matthew Mueller +Matthew Riley Matthias Klumpp Matthias Kühnle mattymo mattyw -Maxime Petazzoni -Maxim Treskin Max Shytikov -Médi-Rémi Hashim +Maxim Treskin +Maxime Petazzoni meejah Mengdi Gao Mert Yazıcıoğlu @@ -451,12 +486,14 @@ Michael Crosby Michael Gorsuch Michael Hudson-Doyle Michael Neale -Michaël Pailloncy Michael Prokop Michael Scharf Michael Stapelberg +Michael Steinert Michael Thies Michal Jemala +Michal Minar +Michaël Pailloncy Michiel@unhosted Miguel Angel Fernández Mike Chelen @@ -471,12 +508,15 @@ Morten Siebuhr Mrunal Patel mschurenko Mustafa Akın +Médi-Rémi Hashim Nan Monnand Deng Naoki Orii +Nate Eagleson Nate Jones Nathan Hsieh Nathan Kleyn Nathan LeClaire +Neal McBurnett Nelson Chen Niall O'Higgins Nicholas E. Rabenau @@ -491,18 +531,21 @@ NikolaMandic noducks Nolan Darilek nzwsch +O.S. Tezer OddBloke odk- Oguz Bilgic Oh Jinkyun Ole Reifschneider Olivier Gambier -O.S. Tezer pandrew +panticz Pascal Borreli Pascal Hartig Patrick Hemmer +Patrick Stapleton pattichen +Paul Paul Annesley Paul Bowsher Paul Hammond @@ -510,7 +553,6 @@ Paul Jimenez Paul Lietar Paul Morie Paul Nasrat -Paul Paul Weaver Pavlos Ratis Peter Bourgon @@ -518,16 +560,18 @@ Peter Braden Peter Ericson Peter Salvatore Peter Waller +Phil Phil Estes +Phil Spitler Philipp Weissensteiner Phillip Alexander -Phil Spitler -Phil Piergiuliano Bossi -Pierre-Alain RIVIERE Pierre +Pierre Wacrenier +Pierre-Alain RIVIERE Piotr Bogdan pixelistik +Porjo Prasanna Gautam Przemek Hejman pysqz @@ -547,6 +591,7 @@ Renato Riccieri Santos Zannon rgstephens Rhys Hiltner Richard Harvey +Richard Metzler Richo Healey Rick Bradley Rick van de Loo @@ -572,25 +617,26 @@ Ryan Fowler Ryan O'Donnell Ryan Seto Ryan Thomas +Rémy Greinhofer Sam Alba Sam Bailey Sam J Sharpe Sam Reis Sam Rijs +Sami Wagiaalla Samuel Andaya Samuel PHAN +Satnam Singh satoru Satoshi Amemiya Scott Bessler Scott Collier Scott Johnston +Scott Stamp Scott Walls Sean Cronin Sean P. Kane Sebastiaan van Stijn -Sébastien Luttringer -Sébastien -Sébastien Stormacq Senthil Kumar Selvaraj SeongJae Park Shane Canon @@ -598,12 +644,12 @@ shaunol Shawn Landden Shawn Siefkas Shih-Yuan Lee +Shishir Mahajan shuai-z Silas Sewell Simon Taranto Sindhu S Sjoerd Langkemper -s-ko Solomon Hykes Song Gao Soulou @@ -611,18 +657,23 @@ soulshake Sridatta Thatipamala Sridhar Ratnakumar Srini Brahmaroutu +Srini Brahmaroutu Steeve Morin Stefan Praszalowicz Stephen Crosby Steven Burgess Steven Merrill -sudosurootdev Sven Dowideit Sylvain Bellemare +Sébastien +Sébastien Luttringer +Sébastien Stormacq tang0th Tatsuki Sugiura +Tatsushi Inagaki Ted M. Young Tehmasp Chaudhri +Tejesh Mehta Thatcher Peskens Thermionix Thijs Terlouw @@ -636,11 +687,10 @@ Tianon Gravi Tibor Vass Tim Bosse Tim Hockin -Timothy Hobbs Tim Ruffles Tim Smith Tim Terhorst -tjmehta +Timothy Hobbs tjwebb123 tobe Tobias Bieniek @@ -648,10 +698,12 @@ Tobias Gesellchen Tobias Schmidt Tobias Schwab Todd Lunter -Tomasz Lipinski Tom Fotherby Tom Hulihan Tom Maaswinkel +Tomas Tomecek +Tomasz Lipinski +Tomasz Nurkiewicz Tommaso Visconti Tonis Tiigi Tony Daws @@ -662,7 +714,8 @@ Trent Ogren Tyler Brock Tzu-Jung Lee Ulysse Carion -unclejack +unknown +Vaidas Jablonskis vgeta Victor Coisne Victor Lyuboslavsky @@ -691,15 +744,15 @@ Walter Leibbrandt Walter Stanish Ward Vandewege WarheadsSE +Wayne Chang Wes Morgan Will Dietz +Will Rouesnel +Will Weaver William Delanoue William Henry William Riancho William Thurston -Will Rouesnel -Will Weaver -wyc Xiuming Chen xuzhaokui Yang Bai @@ -715,4 +768,6 @@ Zilin Du zimbatm Zoltan Tombol zqh +Álex González +Álvaro Lázaro 尹吉峰 diff --git a/CHANGELOG.md b/CHANGELOG.md index e5dfab823..8e845e459 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Changelog +## 1.5.0 (2015-02-10) + +#### Builder ++ Dockerfile to use for a given `docker build` can be specified with the `-f` flag +* Dockerfile and .dockerignore files can be themselves excluded as part of the .dockerignore file, thus preventing modifications to these files invalidating ADD or COPY instructions cache +* ADD and COPY instructions accept relative paths +* Dockerfile `FROM scratch` instruction is now interpreted as a no-base specifier +* Improve performance when exposing a large number of ports + +#### Hack ++ Allow client-side only integration tests for Windows +* Include docker-py integration tests against Docker daemon as part of our test suites + +#### Packaging ++ Support for the new version of the registry HTTP API +* Speed up `docker push` for images with a majority of already existing layers +- Fixed contacting a private registry through a proxy + +#### Remote API ++ A new endpoint will stream live container resource metrics and can be accessed with the `docker stats` command ++ Containers can be renamed using the new `rename` endpoint and the associated `docker rename` command +* Container `inspect` endpoint show the ID of `exec` commands running in this container +* Container `inspect` endpoint show the number of times Docker auto-restarted the container +* New types of event can be streamed by the `events` endpoint: ‘OOM’ (container died with out of memory), ‘exec_create’, and ‘exec_start' +- Fixed returned string fields which hold numeric characters incorrectly omitting surrounding double quotes + +#### Runtime ++ Docker daemon has full IPv6 support ++ The `docker run` command can take the `--pid=host` flag to use the host PID namespace, which makes it possible for example to debug host processes using containerized debugging tools ++ The `docker run` command can take the `--read-only` flag to make the container’s root filesystem mounted as readonly, which can be used in combination with volumes to force a container’s processes to only write to locations that will be persisted ++ Container total memory usage can be limited for `docker run` using the `—memory-swap` flag +* Major stability improvements for devicemapper storage driver +* Better integration with host system: containers will reflect changes to the host's `/etc/resolv.conf` file when restarted +* Better integration with host system: per-container iptable rules are moved to the DOCKER chain +- Fixed container exiting on out of memory to return an invalid exit code + +#### Other +* The HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables are properly taken into account by the client when connecting to the Docker daemon + ## 1.4.1 (2014-12-15) #### Runtime diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 77af00e40..038dcefcd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,6 +64,45 @@ Please also include the steps required to reproduce the problem if possible and applicable. This information will help us review and fix your issue faster. +### Template + +``` +Description of problem: + + +`docker version`: + + +`docker info`: + + +`uname -a`: + + +Environment details (AWS, VirtualBox, physical, etc.): + + +How reproducible: + + +Steps to Reproduce: +1. +2. +3. + + +Actual Results: + + +Expected Results: + + +Additional info: + + + +``` + ## Build Environment For instructions on setting up your development environment, please @@ -172,7 +211,7 @@ component affected. For example, if a change affects `docs/` and `registry/`, it needs an absolute majority from the maintainers of `docs/` AND, separately, an absolute majority of the maintainers of `registry/`. -For more details see [MAINTAINERS.md](project/MAINTAINERS.md) +For more details see [MAINTAINERS](MAINTAINERS) ### Sign your work @@ -233,18 +272,6 @@ Note that the old-style `Docker-DCO-1.1-Signed-off-by: ...` format is still accepted, so there is no need to update outstanding pull requests to the new format right away, but please do adjust your processes for future contributions. -#### Small patch exception - -There are several exceptions to the signing requirement. Currently these are: - -* Your patch fixes spelling or grammar errors. -* Your patch is a single line change to documentation contained in the - `docs` directory. -* Your patch fixes Markdown formatting or syntax errors in the - documentation contained in the `docs` directory. - -If you have any questions, please refer to the FAQ in the [docs](http://docs.docker.com) - ### How can I become a maintainer? * Step 1: Learn the component inside out diff --git a/Dockerfile b/Dockerfile index af559759b..fdf35227f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,11 +23,12 @@ # the case. Therefore, you don't have to disable it anymore. # -FROM ubuntu:14.04 -MAINTAINER Tianon Gravi (@tianon) +FROM ubuntu:14.04 +MAINTAINER Tianon Gravi (@tianon) # Packaged dependencies -RUN apt-get update && apt-get install -y \ +RUN apt-get update && apt-get install -y \ + apparmor \ aufs-tools \ automake \ btrfs-tools \ @@ -39,9 +40,11 @@ RUN apt-get update && apt-get install -y \ libapparmor-dev \ libcap-dev \ libsqlite3-dev \ - lxc=1.0* \ mercurial \ parallel \ + python-mock \ + python-pip \ + python-websocket \ reprepro \ ruby1.9.1 \ ruby1.9.1-dev \ @@ -49,67 +52,115 @@ RUN apt-get update && apt-get install -y \ --no-install-recommends # Get lvm2 source for compiling statically -RUN git clone --no-checkout https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2 && cd /usr/local/lvm2 && git checkout -q v2_02_103 +RUN git clone -b v2_02_103 https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2 # see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags -# note: we don't use "git clone -b" above because it then spews big nasty warnings about 'detached HEAD' state that we can't silence as easily as we can silence them using "git checkout" directly # Compile and install lvm2 -RUN cd /usr/local/lvm2 && ./configure --enable-static_link && make device-mapper && make install_device-mapper +RUN cd /usr/local/lvm2 \ + && ./configure --enable-static_link \ + && make device-mapper \ + && make install_device-mapper # see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL +# Install lxc +ENV LXC_VERSION 1.0.7 +RUN mkdir -p /usr/src/lxc \ + && curl -sSL https://linuxcontainers.org/downloads/lxc/lxc-${LXC_VERSION}.tar.gz | tar -v -C /usr/src/lxc/ -xz --strip-components=1 +RUN cd /usr/src/lxc \ + && ./configure \ + && make \ + && make install \ + && ldconfig + # Install Go -RUN curl -sSL https://golang.org/dl/go1.3.3.src.tar.gz | tar -v -C /usr/local -xz -ENV PATH /usr/local/go/bin:$PATH -ENV GOPATH /go:/go/src/github.com/docker/docker/vendor -ENV PATH /go/bin:$PATH -RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1 +ENV GO_VERSION 1.4.1 +RUN curl -sSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/local -xz \ + && mkdir -p /go/bin +ENV PATH /go/bin:/usr/local/go/bin:$PATH +ENV GOPATH /go:/go/src/github.com/docker/docker/vendor +RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1 # Compile Go for cross compilation -ENV DOCKER_CROSSPLATFORMS \ +ENV DOCKER_CROSSPLATFORMS \ linux/386 linux/arm \ darwin/amd64 darwin/386 \ - freebsd/amd64 freebsd/386 freebsd/arm -# windows is experimental for now + freebsd/amd64 freebsd/386 freebsd/arm + +# TODO when https://jenkins.dockerproject.com/job/Windows/ is green, add windows back to the list above # windows/amd64 windows/386 # (set an explicit GOARM of 5 for maximum compatibility) -ENV GOARM 5 -RUN cd /usr/local/go/src && bash -xc 'for platform in $DOCKER_CROSSPLATFORMS; do GOOS=${platform%/*} GOARCH=${platform##*/} ./make.bash --no-clean 2>&1; done' +ENV GOARM 5 +RUN cd /usr/local/go/src \ + && set -x \ + && for platform in $DOCKER_CROSSPLATFORMS; do \ + GOOS=${platform%/*} \ + GOARCH=${platform##*/} \ + ./make.bash --no-clean 2>&1; \ + done + +# We still support compiling with older Go, so need to grab older "gofmt" +ENV GOFMT_VERSION 1.3.3 +RUN curl -sSL https://storage.googleapis.com/golang/go${GOFMT_VERSION}.$(go env GOOS)-$(go env GOARCH).tar.gz | tar -C /go/bin -xz --strip-components=2 go/bin/gofmt # Grab Go's cover tool for dead-simple code coverage testing -RUN go get golang.org/x/tools/cmd/cover +RUN go get golang.org/x/tools/cmd/cover # TODO replace FPM with some very minimal debhelper stuff -RUN gem install --no-rdoc --no-ri fpm --version 1.3.2 - -# Install man page generator -RUN mkdir -p /go/src/github.com/cpuguy83 \ - && git clone -b v1 https://github.com/cpuguy83/go-md2man.git /go/src/github.com/cpuguy83/go-md2man \ - && cd /go/src/github.com/cpuguy83/go-md2man \ - && go get -v ./... +RUN gem install --no-rdoc --no-ri fpm --version 1.3.2 # Get the "busybox" image source so we can build locally instead of pulling -RUN git clone -b buildroot-2014.02 https://github.com/jpetazzo/docker-busybox.git /docker-busybox +RUN git clone -b buildroot-2014.02 https://github.com/jpetazzo/docker-busybox.git /docker-busybox # Get the "cirros" image source so we can import it instead of fetching it during tests -RUN curl -sSL -o /cirros.tar.gz https://github.com/ewindisch/docker-cirros/raw/1cded459668e8b9dbf4ef976c94c05add9bbd8e9/cirros-0.3.0-x86_64-lxc.tar.gz +RUN curl -sSL -o /cirros.tar.gz https://github.com/ewindisch/docker-cirros/raw/1cded459668e8b9dbf4ef976c94c05add9bbd8e9/cirros-0.3.0-x86_64-lxc.tar.gz + +# Install registry +ENV REGISTRY_COMMIT c448e0416925a9876d5576e412703c9b8b865e19 +RUN set -x \ + && git clone https://github.com/docker/distribution.git /go/src/github.com/docker/distribution \ + && (cd /go/src/github.com/docker/distribution && git checkout -q $REGISTRY_COMMIT) \ + && GOPATH=/go/src/github.com/docker/distribution/Godeps/_workspace:/go \ + go build -o /go/bin/registry-v2 github.com/docker/distribution/cmd/registry + +# Get the "docker-py" source so we can run their integration tests +ENV DOCKER_PY_COMMIT aa19d7b6609c6676e8258f6b900dea2eda1dbe95 +RUN git clone https://github.com/docker/docker-py.git /docker-py \ + && cd /docker-py \ + && git checkout -q $DOCKER_PY_COMMIT # Setup s3cmd config -RUN /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEY' > $HOME/.s3cfg +RUN { \ + echo '[default]'; \ + echo 'access_key=$AWS_ACCESS_KEY'; \ + echo 'secret_key=$AWS_SECRET_KEY'; \ + } > ~/.s3cfg # Set user.email so crosbymichael's in-container merge commits go smoothly -RUN git config --global user.email 'docker-dummy@example.com' +RUN git config --global user.email 'docker-dummy@example.com' # Add an unprivileged user to be used for tests which need it RUN groupadd -r docker RUN useradd --create-home --gid docker unprivilegeduser -VOLUME /var/lib/docker -WORKDIR /go/src/github.com/docker/docker -ENV DOCKER_BUILDTAGS apparmor selinux btrfs_noversion +VOLUME /var/lib/docker +WORKDIR /go/src/github.com/docker/docker +ENV DOCKER_BUILDTAGS apparmor selinux btrfs_noversion + +# Install man page generator +COPY vendor /go/src/github.com/docker/docker/vendor +# (copy vendor/ because go-md2man needs golang.org/x/net) +RUN set -x \ + && git clone -b v1.0.1 https://github.com/cpuguy83/go-md2man.git /go/src/github.com/cpuguy83/go-md2man \ + && git clone -b v1.2 https://github.com/russross/blackfriday.git /go/src/github.com/russross/blackfriday \ + && go install -v github.com/cpuguy83/go-md2man + +# install toml validator +RUN git clone -b v0.1.0 https://github.com/BurntSushi/toml.git /go/src/github.com/BurntSushi/toml \ + && go install -v github.com/BurntSushi/toml/cmd/tomlv # Wrap all commands in the "docker-in-docker" script to allow nested containers -ENTRYPOINT ["hack/dind"] +ENTRYPOINT ["hack/dind"] # Upload docker source -COPY . /go/src/github.com/docker/docker +COPY . /go/src/github.com/docker/docker diff --git a/LICENSE b/LICENSE index 27448585a..508036ef4 100644 --- a/LICENSE +++ b/LICENSE @@ -176,7 +176,7 @@ END OF TERMS AND CONDITIONS - Copyright 2014 Docker, Inc. + Copyright 2013-2015 Docker, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MAINTAINERS b/MAINTAINERS index 2947eb355..ecad16030 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,9 +1,590 @@ -Solomon Hykes (@shykes) -Victor Vieux (@vieux) -Michael Crosby (@crosbymichael) -.mailmap: Tianon Gravi (@tianon) -.travis.yml: Tianon Gravi (@tianon) -AUTHORS: Tianon Gravi (@tianon) -Dockerfile: Tianon Gravi (@tianon) -Makefile: Tianon Gravi (@tianon) -.dockerignore: Tianon Gravi (@tianon) +# Docker maintainers file +# +# This file describes who runs the Docker project and how. +# This is a living document - if you see something out of date or missing, +# speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant +# parser. + +[Rules] + + [Rules.maintainers] + + title = "What is a maintainer?" + + text = """ +There are different types of maintainers, with different responsibilities, but +all maintainers have 3 things in common: + +1) They share responsibility in the project's success. +2) They have made a long-term, recurring time investment to improve the project. +3) They spend that time doing whatever needs to be done, not necessarily what +is the most interesting or fun. + +Maintainers are often under-appreciated, because their work is harder to appreciate. +It's easy to appreciate a really cool and technically advanced feature. It's harder +to appreciate the absence of bugs, the slow but steady improvement in stability, +or the reliability of a release process. But those things distinguish a good +project from a great one. +""" + + [Rules.bdfl] + + title = "The Benevolent dictator for life (BDFL)" + + text = """ +Docker follows the timeless, highly efficient and totally unfair system +known as [Benevolent dictator for +life](http://en.wikipedia.org/wiki/Benevolent_Dictator_for_Life), with +yours truly, Solomon Hykes, in the role of BDFL. This means that all +decisions are made, by default, by Solomon. Since making every decision +myself would be highly un-scalable, in practice decisions are spread +across multiple maintainers. + +Ideally, the BDFL role is like the Queen of England: awesome crown, but not +an actual operational role day-to-day. The real job of a BDFL is to NEVER GO AWAY. +Every other rule can change, perhaps drastically so, but the BDFL will always +be there, preserving the philosophy and principles of the project, and keeping +ultimate authority over its fate. This gives us great flexibility in experimenting +with various governance models, knowing that we can always press the "reset" button +without fear of fragmentation or deadlock. See the US congress for a counter-example. + +BDFL daily routine: + +* Is the project governance stuck in a deadlock or irreversibly fragmented? + * If yes: refactor the project governance +* Are there issues or conflicts escalated by core? + * If yes: resolve them +* Go back to polishing that crown. +""" + + [Rules.decisions] + + title = "How are decisions made?" + + text = """ +Short answer: EVERYTHING IS A PULL REQUEST. + +Docker is an open-source project with an open design philosophy. This +means that the repository is the source of truth for EVERY aspect of the +project, including its philosophy, design, road map, and APIs. *If it's +part of the project, it's in the repo. If it's in the repo, it's part of +the project.* + +As a result, all decisions can be expressed as changes to the +repository. An implementation change is a change to the source code. An +API change is a change to the API specification. A philosophy change is +a change to the philosophy manifesto, and so on. + +All decisions affecting Docker, big and small, follow the same 3 steps: + +* Step 1: Open a pull request. Anyone can do this. + +* Step 2: Discuss the pull request. Anyone can do this. + +* Step 3: Merge or refuse the pull request. Who does this depends on the nature +of the pull request and which areas of the project it affects. See *review flow* +for details. + +Because Docker is such a large and active project, it's important for everyone to know +who is responsible for deciding what. That is determined by a precise set of rules. + +* For every *decision* in the project, the rules should designate, in a deterministic way, +who should *decide*. + +* For every *problem* in the project, the rules should designate, in a deterministic way, +who should be responsible for *fixing* it. + +* For every *question* in the project, the rules should designate, in a deterministic way, +who should be expected to have the *answer*. +""" + + [Rules.review] + + title = "Review flow" + + text = """ +Pull requests should be processed according to the following flow: + +* For each subsystem affected by the change, the maintainers of the subsystem must approve or refuse it. +It is the responsibility of the subsystem maintainers to process patches affecting them in a timely +manner. + +* If the change affects areas of the code which are not part of a subsystem, +or if subsystem maintainers are unable to reach a timely decision, it must be approved by +the core maintainers. + +* If the change affects the UI or public APIs, or if it represents a major change in architecture, +the architects must approve or refuse it. + +* If the change affects the operations of the project, it must be approved or rejected by +the relevant operators. + +* If the change affects the governance, philosophy, goals or principles of the project, +it must be approved by BDFL. + +* A pull request can be in 1 of 5 distinct states, for each of which there is a corresponding label +that needs to be applied. `Rules.review.states` contains the list of states with possible targets +for each. +""" + + # Triage + [Rules.review.states.0-triage] + + # Maintainers are expected to triage new incoming pull requests by removing + # the `0-triage` label and adding the correct labels (e.g. `1-design-review`) + # potentially skipping some steps depending on the kind of pull request. + # Use common sense for judging. + # + # Checking for DCO should be done at this stage. + # + # If an owner, responsible for closing or merging, can be assigned to the PR, + # the better. + + close = "e.g. unresponsive contributor without DCO" + 3-docs-review = "non-proposal documentation-only change" + 2-code-review = "e.g. trivial bugfix" + 1-design-review = "general case" + + # Design review + [Rules.review.states.1-design-review] + + # Maintainers are expected to comment on the design of the pull request. + # Review of documentation is expected only in the context of design validation, + # not for stylistic changes. + # + # Ideally, documentation should reflect the expected behavior of the code. + # No code review should take place in this step. + # + # Once design is approved, a maintainer should make sure to remove this label + # and add the next one. + + close = "design rejected" + 3-docs-review = "proposals with only documentation changes" + 2-code-review = "general case" + + # Code review + [Rules.review.states.2-code-review] + + # Maintainers are expected to review the code and ensure that it is good + # quality and in accordance with the documentation in the PR. + # + # If documentation is absent but expected, maintainers should ask for documentation. + # + # All tests should pass. + # + # Once code is approved according to the rules of the subsystem, a maintainer + # should make sure to remove this label and add the next one. + + close = "" + 1-design-review = "raises design concerns" + 4-merge = "trivial change not impacting documentation" + 3-docs-review = "general case" + + # Docs review + [Rules.review.states.3-docs-review] + + # Maintainers are expected to review the documentation in its bigger context, + # ensuring consistency, completeness, validity, and breadth of coverage across + # all extent and new documentation. + # + # They should ask for any editorial change that makes the documentation more + # consistent and easier to understand. + # + # Once documentation is approved, a maintainer should make sure to remove this + # label and add the next one. + + close = "" + 2-code-review = "requires more code changes" + 1-design-review = "raises design concerns" + 4-merge = "general case" + + # Merge + [Rules.review.states.4-merge] + + # Maintainers are expected to merge this pull request as soon as possible. + # They can ask for a rebase, or carry the pull request themselves. + # These should be the easy PRs to merge. + + close = "carry PR" + merge = "" + + [Rules.DCO] + + title = "Helping contributors with the DCO" + + text = """ +The [DCO or `Sign your work`]( +https://github.com/docker/docker/blob/master/CONTRIBUTING.md#sign-your-work) +requirement is not intended as a roadblock or speed bump. + +Some Docker contributors are not as familiar with `git`, or have used a web based +editor, and thus asking them to `git commit --amend -s` is not the best way forward. + +In this case, maintainers can update the commits based on clause (c) of the DCO. The +most trivial way for a contributor to allow the maintainer to do this, is to add +a DCO signature in a Pull Requests's comment, or a maintainer can simply note that +the change is sufficiently trivial that it does not substantivly change the existing +contribution - i.e., a spelling change. + +When you add someone's DCO, please also add your own to keep a log. +""" + + [Rules.holiday] + + title = "I'm a maintainer, and I'm going on holiday" + + text = """ +Please let your co-maintainers and other contributors know by raising a pull +request that comments out your `MAINTAINERS` file entry using a `#`. +""" + + [Rules."no direct push"] + + title = "I'm a maintainer. Should I make pull requests too?" + + text = """ +Yes. Nobody should ever push to master directly. All changes should be +made through a pull request. +""" + + [Rules.meta] + + title = "How is this process changed?" + + text = "Just like everything else: by making a pull request :)" + +# Current project organization +[Org] + + bdfl = "shykes" + + # The chief architect is responsible for the overall integrity of the technical architecture + # across all subsystems, and the consistency of APIs and UI. + # + # Changes to UI, public APIs and overall architecture (for example a plugin system) must + # be approved by the chief architect. + "Chief Architect" = "shykes" + + # The Chief Operator is responsible for the day-to-day operations of the project including: + # - facilitating communications amongst all the contributors; + # - tracking release schedules; + # - managing the relationship with downstream distributions and upstream dependencies; + # - helping new contributors to get involved and become successful contributors and maintainers + # + # The role is also responsible for managing and measuring the success of the overall project + # and ensuring it is governed properly working in concert with the Docker Governance Advisory Board (DGAB). + "Chief Operator" = "spf13" + + [Org.Operators] + + # The operators make sure the trains run on time. They are responsible for overall operations + # of the project. This includes facilitating communication between all the participants; helping + # newcomers get involved and become successful contributors and maintainers; tracking the schedule + # of releases; managing the relationship with downstream distributions and upstream dependencies; + # define measures of success for the project and measure progress; Devise and implement tools and + # processes which make contributors and maintainers happier and more efficient. + + + [Org.Operators.security] + + people = [ + "erw" + ] + + [Org.Operators."monthly meetings"] + + people = [ + "sven", + "tianon" + ] + + [Org.Operators.infrastructure] + + people = [ + "jfrazelle", + "crosbymichael" + ] + + # The chief maintainer is responsible for all aspects of quality for the project including + # code reviews, usability, stability, security, performance, etc. + # The most important function of the chief maintainer is to lead by example. On the first + # day of a new maintainer, the best advice should be "follow the C.M.'s example and you'll + # be fine". + "Chief Maintainer" = "crosbymichael" + + [Org."Core maintainers"] + + # The Core maintainers are the ghostbusters of the project: when there's a problem others + # can't solve, they show up and fix it with bizarre devices and weaponry. + # They have final say on technical implementation and coding style. + # They are ultimately responsible for quality in all its forms: usability polish, + # bugfixes, performance, stability, etc. When ownership can cleanly be passed to + # a subsystem, they are responsible for doing so and holding the + # subsystem maintainers accountable. If ownership is unclear, they are the de facto owners. + + # For each release (including minor releases), a "release captain" is assigned from the + # pool of core maintainers. Rotation is encouraged across all maintainers, to ensure + # the release process is clear and up-to-date. + # + # It is common for core maintainers to "branch out" to join or start a subsystem. + + + + people = [ + "unclejack", + "crosbymichael", + "erikh", + "icecrime", + "jfrazelle", + "lk4d4", + "tibor", + "vbatts", + "vieux", + "vish" + ] + + + [Org.Subsystems] + + # As the project grows, it gets separated into well-defined subsystems. Each subsystem + # has a dedicated group of maintainers, which are dedicated to that subsytem and responsible + # for its quality. + # This "cellular division" is the primary mechanism for scaling maintenance of the project as it grows. + # + # The maintainers of each subsytem are responsible for: + # + # 1. Exposing a clear road map for improving their subsystem. + # 2. Deliver prompt feedback and decisions on pull requests affecting their subsystem. + # 3. Be available to anyone with questions, bug reports, criticism etc. + # on their component. This includes IRC, GitHub requests and the mailing + # list. + # 4. Make sure their subsystem respects the philosophy, design and + # road map of the project. + # + # #### How to review patches to your subsystem + # + # Accepting pull requests: + # + # - If the pull request appears to be ready to merge, give it a `LGTM`, which + # stands for "Looks Good To Me". + # - If the pull request has some small problems that need to be changed, make + # a comment adressing the issues. + # - If the changes needed to a PR are small, you can add a "LGTM once the + # following comments are adressed..." this will reduce needless back and + # forth. + # - If the PR only needs a few changes before being merged, any MAINTAINER can + # make a replacement PR that incorporates the existing commits and fixes the + # problems before a fast track merge. + # + # Closing pull requests: + # + # - If a PR appears to be abandoned, after having attempted to contact the + # original contributor, then a replacement PR may be made. Once the + # replacement PR is made, any contributor may close the original one. + # - If you are not sure if the pull request implements a good feature or you + # do not understand the purpose of the PR, ask the contributor to provide + # more documentation. If the contributor is not able to adequately explain + # the purpose of the PR, the PR may be closed by any MAINTAINER. + # - If a MAINTAINER feels that the pull request is sufficiently architecturally + # flawed, or if the pull request needs significantly more design discussion + # before being considered, the MAINTAINER should close the pull request with + # a short explanation of what discussion still needs to be had. It is + # important not to leave such pull requests open, as this will waste both the + # MAINTAINER's time and the contributor's time. It is not good to string a + # contributor on for weeks or months, having them make many changes to a PR + # that will eventually be rejected. + + [Org.Subsystems.Documentation] + + people = [ + "fredlf", + "james", + "sven", + ] + + [Org.Subsystems.libcontainer] + + people = [ + "crosbymichael", + "vmarmol", + "mpatel", + "jnagal", + "lk4d4" + ] + + [Org.Subsystems.registry] + + people = [ + "dmp42", + "vbatts", + "joffrey", + "samalba" + ] + + [Org.Subsystems."build tools"] + + people = [ + "shykes", + "tianon" + ] + + [Org.Subsystem."remote api"] + + people = [ + "vieux" + ] + + [Org.Subsystem.swarm] + + people = [ + "aluzzardi", + "vieux" + ] + + [Org.Subsystem.machine] + + people = [ + "bfirsh", + "ehazlett" + ] + + [Org.Subsystem.compose] + + people = [ + "aanand" + ] + + [Org.Subsystem.builder] + + people = [ + "erikh", + "tibor", + "duglin" + ] + + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.aanand] + Name = "Aanand Prasad" + Email = "aanand@docker.com" + GitHub = "aanand" + + [people.aluzzardi] + Name = "Andrea Luzzardi" + Email = "aluzzardi@docker.com" + GitHub = "aluzzardi" + + [people.bfirsh] + Name = "Ben Firshman" + Email = "ben@firshman.co.uk" + GitHub = "bfirsh" + + [people.crosbymichael] + Name = "Michael Crosby" + Email = "crosbymichael@gmail.com" + GitHub = "crosbymichael" + + [people.duglin] + Name = "Doug Davis" + Email = "dug@us.ibm.com" + GitHub = "duglin" + + [people.ehazlett] + Name = "Evan Hazlett" + Email = "ejhazlett@gmail.com" + GitHub = "ehazlett" + + [people.erikh] + Name = "Erik Hollensbe" + Email = "erik@docker.com" + GitHub = "erikh" + + [people.erw] + Name = "Eric Windisch" + Email = "eric@windisch.us" + GitHub = "ewindisch" + + [people.icecrime] + Name = "Arnaud Porterie" + Email = "arnaud@docker.com" + GitHub = "icecrime" + + [people.jfrazelle] + Name = "Jessie Frazelle" + Email = "jess@docker.com" + GitHub = "jfrazelle" + + [people.lk4d4] + Name = "Alexander Morozov" + Email = "lk4d4@docker.com" + GitHub = "lk4d4" + + [people.shykes] + Name = "Solomon Hykes" + Email = "solomon@docker.com" + GitHub = "shykes" + + [people.spf13] + Name = "Steve Francia" + Email = "steve.francia@gmail.com" + GitHub = "spf13" + + [people.sven] + Name = "Sven Dowideit" + Email = "SvenDowideit@home.org.au" + GitHub = "SvenDowideit" + + [people.tianon] + Name = "Tianon Gravi" + Email = "admwiggin@gmail.com" + GitHub = "tianon" + + [people.tibor] + Name = "Tibor Vass" + Email = "tibor@docker.com" + GitHub = "tiborvass" + + [people.vbatts] + Name = "Vincent Batts" + Email = "vbatts@redhat.com" + GitHub = "vbatts" + + [people.vieux] + Name = "Victor Vieux" + Email = "vieux@docker.com" + GitHub = "vieux" + + [people.vmarmol] + Name = "Victor Marmol" + Email = "vmarmol@google.com" + GitHub = "vmarmol" + + [people.jnagal] + Name = "Rohit Jnagal" + Email = "jnagal@google.com" + GitHub = "rjnagal" + + [people.mpatel] + Name = "Mrunal Patel" + Email = "mpatel@redhat.com" + GitHub = "mrunalp" + + [people.unclejack] + Name = "Cristian Staretu" + Email = "cristian.staretu@gmail.com" + GitHub = "unclejack" + + [people.vish] + Name = "Vishnu Kannan" + Email = "vishnuk@google.com" + GitHub = "vishh" diff --git a/Makefile b/Makefile index 6f76fa4d2..266fa2a9a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli validate +.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli test-docker-py validate # env vars passed through directly to Docker's build scripts # to allow things like `make DOCKER_CLIENTONLY=1 binary` easily @@ -30,7 +30,7 @@ DOCKER_DOCS_IMAGE := docker-docs$(if $(GIT_BRANCH),:$(GIT_BRANCH)) DOCKER_RUN_DOCKER := docker run --rm -it --privileged $(DOCKER_ENVS) $(DOCKER_MOUNT) "$(DOCKER_IMAGE)" -DOCKER_RUN_DOCS := docker run --rm -it $(DOCS_MOUNT) -e AWS_S3_BUCKET +DOCKER_RUN_DOCS := docker run --rm -it $(DOCS_MOUNT) -e AWS_S3_BUCKET -e NOCACHE # for some docs workarounds (see below in "docs-build" target) GITCOMMIT := $(shell git rev-parse --short HEAD 2>/dev/null) @@ -53,10 +53,13 @@ docs-shell: docs-build $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash docs-release: docs-build - $(DOCKER_RUN_DOCS) -e OPTIONS -e BUILD_ROOT "$(DOCKER_DOCS_IMAGE)" ./release.sh + $(DOCKER_RUN_DOCS) -e OPTIONS -e BUILD_ROOT -e DISTRIBUTION_ID "$(DOCKER_DOCS_IMAGE)" ./release.sh + +docs-test: docs-build + $(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./test.sh test: build - $(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration test-integration-cli + $(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration test-integration-cli test-docker-py test-unit: build $(DOCKER_RUN_DOCKER) hack/make.sh test-unit @@ -67,8 +70,11 @@ test-integration: build test-integration-cli: build $(DOCKER_RUN_DOCKER) hack/make.sh binary test-integration-cli +test-docker-py: build + $(DOCKER_RUN_DOCKER) hack/make.sh binary test-docker-py + validate: build - $(DOCKER_RUN_DOCKER) hack/make.sh validate-gofmt validate-dco + $(DOCKER_RUN_DOCKER) hack/make.sh validate-gofmt validate-dco validate-toml shell: build $(DOCKER_RUN_DOCKER) bash @@ -77,6 +83,7 @@ build: bundles docker build -t "$(DOCKER_IMAGE)" . docs-build: + ( git remote | grep -v upstream ) || git diff --name-status upstream/release..upstream/docs docs/ > docs/changed-files cp ./VERSION docs/VERSION echo "$(GIT_BRANCH)" > docs/GIT_BRANCH echo "$(AWS_S3_BUCKET)" > docs/AWS_S3_BUCKET diff --git a/README.md b/README.md index c2273eb65..2ef78b78c 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ Docker is an open source project to pack, ship and run any application as a lightweight container Docker containers are both *hardware-agnostic* and *platform-agnostic*. -This means that they can run anywhere, from your laptop to the largest +This means 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 +you to 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 +databases, and backend services without depending on a particular stack or provider. -Docker is an open-source implementation of the deployment engine which +Docker began as 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 @@ -22,7 +22,7 @@ applications and databases. ## Security Disclosure -Security is very important to us. If you have any issue regarding security, +Security is very important to us. If you have any issue regarding security, please disclose the information responsibly by sending an email to security@docker.com and not by creating a github issue. @@ -59,24 +59,24 @@ 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) +[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. +portable format and runtime environment that solves all four problems. Docker containers are small (and their transfer can be optimized with layers), they have basically zero memory and cpu overhead, they are -completely portable and are designed from the ground up with an +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 +Perhaps best of all, 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. +Docker does not require you to 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 @@ -100,21 +100,21 @@ This is usually difficult for several reasons: typically don't work well with each other, requiring awkward custom integrations. - * Conflicting dependencies. Different applications may depend on + * *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 + * *Custom dependencies*. A developer may need to prepare a custom version of their 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* their application's dependencies in one place, and -streamline the process of assembling them. If this makes you think of +Docker solves the problem of dependency hell by giving the developer a simple +way to express *all* their application's dependencies in one place, while +streamlining 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 @@ -178,19 +178,35 @@ Contributing to Docker ====================== [![GoDoc](https://godoc.org/github.com/docker/docker?status.png)](https://godoc.org/github.com/docker/docker) -[![Build Status](https://ci.dockerproject.com/github.com/docker/docker/status.svg?branch=master)](https://ci.dockerproject.com/github.com/docker/docker) +[![Jenkins Build Status](https://jenkins.dockerproject.com/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.com/job/Docker%20Master/) -Want to hack on Docker? Awesome! There are instructions to get you -started [here](CONTRIBUTING.md). If you'd like to contribute to the +Want to hack on Docker? Awesome! We have [instructions to help you get +started](CONTRIBUTING.md). If you'd like to contribute to the documentation, please take a look at this [README.md](https://github.com/docker/docker/blob/master/docs/README.md). These instructions are probably not perfect, please let us know if anything -feels wrong or incomplete. +feels wrong or incomplete. Better yet, submit a PR and improve them yourself. + +Want to run Docker from a master build? You can download +master builds at [master.dockerproject.com](https://master.dockerproject.com). +They are updated with each commit merged into the master branch. + +Don't know how to use that super cool new feature in the master build? Check +out the master docs at +[docs.master.dockerproject.com](http://docs.master.dockerproject.com). + +How the project is run +====================== + +Docker is a very, very active project. If you want to learn more about how it is run, +or want to get more involved, the best place to start is [the project directory](https://github.com/docker/docker/tree/master/project). + +We are always open to suggestions on process improvements, and are always looking for more maintainers. ### Legal *Brought to you courtesy of our legal counsel. For more context, -please see the Notice document.* +please see the "NOTICE" document in this repo.* Use and transfer of Docker may be subject to certain restrictions by the United States and other governments. @@ -206,3 +222,21 @@ Docker is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/docker/docker/blob/master/LICENSE) for the full license text. +Other Docker Related Projects +============================= +There are a number of projects under development that are based on Docker's +core technology. These projects expand the tooling built around the +Docker platform to broaden its application and utility. + +If you know of another project underway that should be listed here, please help +us keep this list up-to-date by submitting a PR. + +* [Docker Registry](https://github.com/docker/docker-registry): Registry +server for Docker (hosting/delivering of repositories and images) +* [Docker Machine](https://github.com/docker/machine): Machine management +for a container-centric world +* [Docker Swarm](https://github.com/docker/swarm): A Docker-native clustering +system +* [Docker Compose, aka Fig](https://github.com/docker/fig): +Multi-container application management + diff --git a/VERSION b/VERSION index 347f5833e..bc80560fa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.1 +1.5.0 diff --git a/api/client/cli.go b/api/client/cli.go index e54eb8056..5e1ccb329 100644 --- a/api/client/cli.go +++ b/api/client/cli.go @@ -17,7 +17,6 @@ import ( flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/term" "github.com/docker/docker/registry" - "github.com/docker/libtrust" ) type DockerCli struct { @@ -27,7 +26,7 @@ type DockerCli struct { in io.ReadCloser out io.Writer err io.Writer - key libtrust.PrivateKey + keyFile string tlsConfig *tls.Config scheme string // inFd holds file descriptor of the client's STDIN, if it's a valid file @@ -75,24 +74,31 @@ func (cli *DockerCli) Cmd(args ...string) error { if len(args) > 0 { method, exists := cli.getMethod(args[0]) if !exists { - fmt.Println("Error: Command not found:", args[0]) - return cli.CmdHelp() + fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0]) + os.Exit(1) } return method(args[1:]...) } return cli.CmdHelp() } -func (cli *DockerCli) Subcmd(name, signature, description string) *flag.FlagSet { - flags := flag.NewFlagSet(name, flag.ContinueOnError) +func (cli *DockerCli) Subcmd(name, signature, description string, exitOnError bool) *flag.FlagSet { + var errorHandling flag.ErrorHandling + if exitOnError { + errorHandling = flag.ExitOnError + } else { + errorHandling = flag.ContinueOnError + } + flags := flag.NewFlagSet(name, errorHandling) flags.Usage = func() { options := "" if flags.FlagCountUndeprecated() > 0 { options = "[OPTIONS] " } - fmt.Fprintf(cli.err, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description) + fmt.Fprintf(cli.out, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description) + flags.SetOutput(cli.out) flags.PrintDefaults() - os.Exit(2) + os.Exit(0) } return flags } @@ -115,7 +121,7 @@ func (cli *DockerCli) CheckTtyInput(attachStdin, ttyMode bool) error { return nil } -func NewDockerCli(in io.ReadCloser, out, err io.Writer, key libtrust.PrivateKey, proto, addr string, tlsConfig *tls.Config) *DockerCli { +func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli { var ( inFd uintptr outFd uintptr @@ -148,6 +154,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, key libtrust.PrivateKey, // The transport is created here for reuse during the client session tr := &http.Transport{ + Proxy: http.ProxyFromEnvironment, TLSClientConfig: tlsConfig, } @@ -169,7 +176,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, key libtrust.PrivateKey, in: in, out: out, err: err, - key: key, + keyFile: keyFile, inFd: inFd, outFd: outFd, isTerminalIn: isTerminalIn, diff --git a/api/client/commands.go b/api/client/commands.go index 89e5796bb..c4ce5e01f 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -16,25 +16,30 @@ import ( "path" "path/filepath" "runtime" + "sort" "strconv" "strings" + "sync" "text/tabwriter" "text/template" "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/api" + "github.com/docker/docker/api/stats" "github.com/docker/docker/dockerversion" "github.com/docker/docker/engine" "github.com/docker/docker/graph" "github.com/docker/docker/nat" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/archive" + "github.com/docker/docker/pkg/fileutils" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers/filters" "github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/signal" + "github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/timeutils" "github.com/docker/docker/pkg/units" @@ -48,10 +53,6 @@ const ( tarHeaderSize = 512 ) -var ( - acceptedImageFilterTags = map[string]struct{}{"dangling": {}} -) - func (cli *DockerCli) CmdHelp(args ...string) error { if len(args) > 1 { method, exists := cli.getMethod(args[:2]...) @@ -63,7 +64,8 @@ func (cli *DockerCli) CmdHelp(args ...string) error { if len(args) > 0 { method, exists := cli.getMethod(args[0]) if !exists { - fmt.Fprintf(cli.err, "Error: Command not found: %s\n", args[0]) + fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0]) + os.Exit(1) } else { method("--help") return nil @@ -76,20 +78,18 @@ func (cli *DockerCli) CmdHelp(args ...string) error { } func (cli *DockerCli) CmdBuild(args ...string) error { - cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH") + cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true) tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success") suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers") noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image") rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build") forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds") pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile(Default is 'Dockerfile' at context root)") + + cmd.Require(flag.Exact, 1) + + utils.ParseFlags(cmd, args, true) var ( context archive.Archive @@ -112,7 +112,10 @@ func (cli *DockerCli) CmdBuild(args ...string) error { if err != nil { return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err) } - context, err = archive.Generate("Dockerfile", string(dockerfile)) + if *dockerfileName == "" { + *dockerfileName = api.DefaultDockerfileName + } + context, err = archive.Generate(*dockerfileName, string(dockerfile)) } else { context = ioutil.NopCloser(buf) } @@ -139,36 +142,67 @@ func (cli *DockerCli) CmdBuild(args ...string) error { if _, err := os.Stat(root); err != nil { return err } - filename := path.Join(root, "Dockerfile") - if _, err = os.Stat(filename); os.IsNotExist(err) { - return fmt.Errorf("no Dockerfile found in %s", cmd.Arg(0)) + + absRoot, err := filepath.Abs(root) + if err != nil { + return err } - var excludes []string - ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore")) - if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("Error reading .dockerignore: '%s'", err) + + filename := *dockerfileName // path to Dockerfile + + if *dockerfileName == "" { + // No -f/--file was specified so use the default + *dockerfileName = api.DefaultDockerfileName + filename = path.Join(absRoot, *dockerfileName) } - for _, pattern := range strings.Split(string(ignore), "\n") { - pattern = strings.TrimSpace(pattern) - if pattern == "" { - continue - } - pattern = filepath.Clean(pattern) - ok, err := filepath.Match(pattern, "Dockerfile") - if err != nil { - return fmt.Errorf("Bad .dockerignore pattern: '%s', error: %s", pattern, err) - } - if ok { - return fmt.Errorf("Dockerfile was excluded by .dockerignore pattern '%s'", pattern) - } - excludes = append(excludes, pattern) + + origDockerfile := *dockerfileName // used for error msg + + if filename, err = filepath.Abs(filename); err != nil { + return err } + + // Verify that 'filename' is within the build context + filename, err = symlink.FollowSymlinkInScope(filename, absRoot) + if err != nil { + return fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", origDockerfile, root) + } + + // Now reset the dockerfileName to be relative to the build context + *dockerfileName, err = filepath.Rel(absRoot, filename) + if err != nil { + return err + } + + if _, err = os.Lstat(filename); os.IsNotExist(err) { + return fmt.Errorf("Cannot locate Dockerfile: %s", origDockerfile) + } + var includes = []string{"."} + + excludes, err := utils.ReadDockerIgnore(path.Join(root, ".dockerignore")) + if err != nil { + return err + } + + // If .dockerignore mentions .dockerignore or the Dockerfile + // then make sure we send both files over to the daemon + // because Dockerfile is, obviously, needed no matter what, and + // .dockerignore is needed to know if either one needs to be + // removed. The deamon will remove them for us, if needed, after it + // parses the Dockerfile. + keepThem1, _ := fileutils.Matches(".dockerignore", excludes) + keepThem2, _ := fileutils.Matches(*dockerfileName, excludes) + if keepThem1 || keepThem2 { + includes = append(includes, ".dockerignore", *dockerfileName) + } + if err = utils.ValidateContextDirectory(root, excludes); err != nil { return fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err) } options := &archive.TarOptions{ - Compression: archive.Uncompressed, - Excludes: excludes, + Compression: archive.Uncompressed, + ExcludePatterns: excludes, + IncludeFiles: includes, } context, err = archive.TarWithOptions(root, options) if err != nil { @@ -188,7 +222,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { //Check if the given image name can be resolved if *tag != "" { repository, tag := parsers.ParseRepositoryTag(*tag) - if _, _, err := registry.ResolveRepositoryName(repository); err != nil { + if err := registry.ValidateRepositoryName(repository); err != nil { return err } if len(tag) > 0 { @@ -222,6 +256,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error { if *pull { v.Set("pull", "1") } + + v.Set("dockerfile", *dockerfileName) + cli.LoadConfigFile() headers := http.Header(make(map[string][]string)) @@ -247,17 +284,17 @@ func (cli *DockerCli) CmdBuild(args ...string) error { // 'docker login': login / register a user to registry service. func (cli *DockerCli) CmdLogin(args ...string) error { - cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.") + cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true) + cmd.Require(flag.Max, 1) var username, password, email string cmd.StringVar(&username, []string{"u", "-username"}, "", "Username") cmd.StringVar(&password, []string{"p", "-password"}, "", "Password") cmd.StringVar(&email, []string{"e", "-email"}, "", "Email") - err := cmd.Parse(args) - if err != nil { - return nil - } + + utils.ParseFlags(cmd, args, true) + serverAddress := registry.IndexServerAddress() if len(cmd.Args()) > 0 { serverAddress = cmd.Arg(0) @@ -363,11 +400,10 @@ func (cli *DockerCli) CmdLogin(args ...string) error { // log out from a Docker registry func (cli *DockerCli) CmdLogout(args ...string) error { - cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.") + cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true) + cmd.Require(flag.Max, 1) - if err := cmd.Parse(args); err != nil { - return nil - } + utils.ParseFlags(cmd, args, false) serverAddress := registry.IndexServerAddress() if len(cmd.Args()) > 0 { serverAddress = cmd.Arg(0) @@ -389,14 +425,11 @@ func (cli *DockerCli) CmdLogout(args ...string) error { // 'docker wait': block until a container stops func (cli *DockerCli) CmdWait(args ...string) error { - cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true) + cmd.Require(flag.Min, 1) + + utils.ParseFlags(cmd, args, true) + var encounteredError error for _, name := range cmd.Args() { status, err := waitForExit(cli, name) @@ -412,15 +445,11 @@ func (cli *DockerCli) CmdWait(args ...string) error { // 'docker version': show version information func (cli *DockerCli) CmdVersion(args ...string) error { - cmd := cli.Subcmd("version", "", "Show the Docker version information.") - if err := cmd.Parse(args); err != nil { - return nil - } + cmd := cli.Subcmd("version", "", "Show the Docker version information.", true) + cmd.Require(flag.Exact, 0) + + utils.ParseFlags(cmd, args, false) - if cmd.NArg() > 0 { - cmd.Usage() - return nil - } if dockerversion.VERSION != "" { fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION) } @@ -458,14 +487,9 @@ func (cli *DockerCli) CmdVersion(args ...string) error { // 'docker info': display system-wide information. func (cli *DockerCli) CmdInfo(args ...string) error { - cmd := cli.Subcmd("info", "", "Display system-wide information") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() > 0 { - cmd.Usage() - return nil - } + cmd := cli.Subcmd("info", "", "Display system-wide information", true) + cmd.Require(flag.Exact, 0) + utils.ParseFlags(cmd, args, false) body, _, err := readBody(cli.call("GET", "/info", nil, false)) if err != nil { @@ -577,15 +601,11 @@ func (cli *DockerCli) CmdInfo(args ...string) error { } func (cli *DockerCli) CmdStop(args ...string) error { - cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period") + cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period", true) nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + cmd.Require(flag.Min, 1) + + utils.ParseFlags(cmd, args, true) v := url.Values{} v.Set("t", strconv.Itoa(*nSeconds)) @@ -604,15 +624,11 @@ func (cli *DockerCli) CmdStop(args ...string) error { } func (cli *DockerCli) CmdRestart(args ...string) error { - cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container") + cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true) nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + cmd.Require(flag.Min, 1) + + utils.ParseFlags(cmd, args, true) v := url.Values{} v.Set("t", strconv.Itoa(*nSeconds)) @@ -661,18 +677,13 @@ func (cli *DockerCli) CmdStart(args ...string) error { cErr chan error tty bool - cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container") + cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container", true) attach = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process") openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN") ) - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + cmd.Require(flag.Min, 1) + utils.ParseFlags(cmd, args, true) hijacked := make(chan io.Closer) @@ -736,12 +747,12 @@ func (cli *DockerCli) CmdStart(args ...string) error { for _, name := range cmd.Args() { _, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false)) if err != nil { - if !*attach || !*openStdin { + if !*attach && !*openStdin { fmt.Fprintf(cli.err, "%s\n", err) } encounteredError = fmt.Errorf("Error: failed to start one or more containers") } else { - if !*attach || !*openStdin { + if !*attach && !*openStdin { fmt.Fprintf(cli.out, "%s\n", name) } } @@ -774,15 +785,9 @@ func (cli *DockerCli) CmdStart(args ...string) error { } func (cli *DockerCli) CmdUnpause(args ...string) error { - cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container") - if err := cmd.Parse(args); err != nil { - return nil - } - - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container", true) + cmd.Require(flag.Exact, 1) + utils.ParseFlags(cmd, args, false) var encounteredError error for _, name := range cmd.Args() { @@ -797,15 +802,9 @@ func (cli *DockerCli) CmdUnpause(args ...string) error { } func (cli *DockerCli) CmdPause(args ...string) error { - cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container") - if err := cmd.Parse(args); err != nil { - return nil - } - - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container", true) + cmd.Require(flag.Exact, 1) + utils.ParseFlags(cmd, args, false) var encounteredError error for _, name := range cmd.Args() { @@ -819,16 +818,32 @@ func (cli *DockerCli) CmdPause(args ...string) error { return encounteredError } -func (cli *DockerCli) CmdInspect(args ...string) error { - cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image") - tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.") +func (cli *DockerCli) CmdRename(args ...string) error { + cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true) if err := cmd.Parse(args); err != nil { return nil } - if cmd.NArg() < 1 { + + if cmd.NArg() != 2 { cmd.Usage() return nil } + old_name := cmd.Arg(0) + new_name := cmd.Arg(1) + + if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, false)); err != nil { + fmt.Fprintf(cli.err, "%s\n", err) + return fmt.Errorf("Error: failed to rename container named %s", old_name) + } + return nil +} + +func (cli *DockerCli) CmdInspect(args ...string) error { + cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true) + tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.") + cmd.Require(flag.Min, 1) + + utils.ParseFlags(cmd, args, true) var tmpl *template.Template if *tmplStr != "" { @@ -900,14 +915,11 @@ func (cli *DockerCli) CmdInspect(args ...string) error { } func (cli *DockerCli) CmdTop(args ...string) error { - cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() == 0 { - cmd.Usage() - return nil - } + cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true) + cmd.Require(flag.Min, 1) + + utils.ParseFlags(cmd, args, true) + val := url.Values{} if cmd.NArg() > 1 { val.Set("ps_args", strings.Join(cmd.Args()[1:], " ")) @@ -935,14 +947,9 @@ func (cli *DockerCli) CmdTop(args ...string) error { } func (cli *DockerCli) CmdPort(args ...string) error { - cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT", true) + cmd.Require(flag.Min, 1) + utils.ParseFlags(cmd, args, true) stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false) if err != nil { @@ -991,17 +998,13 @@ func (cli *DockerCli) CmdPort(args ...string) error { // 'docker rmi IMAGE' removes all images with the name IMAGE func (cli *DockerCli) CmdRmi(args ...string) error { var ( - cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images") + cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true) force = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image") noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents") ) - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + cmd.Require(flag.Min, 1) + + utils.ParseFlags(cmd, args, true) v := url.Values{} if *force { @@ -1037,17 +1040,12 @@ func (cli *DockerCli) CmdRmi(args ...string) error { } func (cli *DockerCli) CmdHistory(args ...string) error { - cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image") + cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true) quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs") noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") + cmd.Require(flag.Exact, 1) - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false)) if err != nil { @@ -1080,7 +1078,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error { } else { fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45)) } - fmt.Fprintf(w, "%s\n", units.HumanSize(out.GetInt64("Size"))) + fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("Size")))) } else { if *noTrunc { fmt.Fprintln(w, outID) @@ -1094,18 +1092,13 @@ func (cli *DockerCli) CmdHistory(args ...string) error { } func (cli *DockerCli) CmdRm(args ...string) error { - cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers") + cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true) v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container") link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container") force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)") + cmd.Require(flag.Min, 1) - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) val := url.Values{} if *v { @@ -1134,16 +1127,11 @@ func (cli *DockerCli) CmdRm(args ...string) error { // 'docker kill NAME' kills a running container func (cli *DockerCli) CmdKill(args ...string) error { - cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal") + cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true) signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container") + cmd.Require(flag.Min, 1) - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) var encounteredError error for _, name := range cmd.Args() { @@ -1158,15 +1146,10 @@ func (cli *DockerCli) CmdKill(args ...string) error { } func (cli *DockerCli) CmdImport(args ...string) error { - cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.") + cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.", true) + cmd.Require(flag.Min, 1) - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) var ( v = url.Values{} @@ -1178,14 +1161,14 @@ func (cli *DockerCli) CmdImport(args ...string) error { v.Set("repo", repository) if cmd.NArg() == 3 { - fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' as been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n") + fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' has been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n") v.Set("tag", cmd.Arg(2)) } if repository != "" { //Check if the given image name can be resolved repo, _ := parsers.ParseRepositoryTag(repository) - if _, _, err := registry.ResolveRepositoryName(repo); err != nil { + if err := registry.ValidateRepositoryName(repo); err != nil { return err } } @@ -1200,42 +1183,39 @@ func (cli *DockerCli) CmdImport(args ...string) error { } func (cli *DockerCli) CmdPush(args ...string) error { - cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry") - if err := cmd.Parse(args); err != nil { - return nil - } - name := cmd.Arg(0) + cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true) + cmd.Require(flag.Exact, 1) - if name == "" { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) + + name := cmd.Arg(0) cli.LoadConfigFile() remote, tag := parsers.ParseRepositoryTag(name) - // Resolve the Repository name from fqn to hostname + name - hostname, _, err := registry.ResolveRepositoryName(remote) + // Resolve the Repository name from fqn to RepositoryInfo + repoInfo, err := registry.ParseRepositoryInfo(remote) if err != nil { return err } // Resolve the Auth config relevant for this server - authConfig := cli.configFile.ResolveAuthConfig(hostname) + authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index) // If we're not using a custom registry, we know the restrictions // applied to repository names and can warn the user in advance. // Custom repositories can have different rules, and we must also // allow pushing by image ID. - if len(strings.SplitN(name, "/", 2)) == 1 { - username := cli.configFile.Configs[registry.IndexServerAddress()].Username + if repoInfo.Official { + username := authConfig.Username if username == "" { username = "" } - return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository in / (ex: %s/%s)", username, name) + return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to / (ex: %s/%s)", username, repoInfo.LocalName) } v := url.Values{} v.Set("tag", tag) + push := func(authConfig registry.AuthConfig) error { buf, err := json.Marshal(authConfig) if err != nil { @@ -1253,10 +1233,10 @@ func (cli *DockerCli) CmdPush(args ...string) error { if err := push(authConfig); err != nil { if strings.Contains(err.Error(), "Status 401") { fmt.Fprintln(cli.out, "\nPlease login prior to push:") - if err := cli.CmdLogin(hostname); err != nil { + if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil { return err } - authConfig := cli.configFile.ResolveAuthConfig(hostname) + authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index) return push(authConfig) } return err @@ -1265,16 +1245,12 @@ func (cli *DockerCli) CmdPush(args ...string) error { } func (cli *DockerCli) CmdPull(args ...string) error { - cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry") + cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry", true) allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository") - if err := cmd.Parse(args); err != nil { - return nil - } + cmd.Require(flag.Exact, 1) + + utils.ParseFlags(cmd, args, true) - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } var ( v = url.Values{} remote = cmd.Arg(0) @@ -1290,8 +1266,8 @@ func (cli *DockerCli) CmdPull(args ...string) error { v.Set("fromImage", newRemote) - // Resolve the Repository name from fqn to hostname + name - hostname, _, err := registry.ResolveRepositoryName(taglessRemote) + // Resolve the Repository name from fqn to RepositoryInfo + repoInfo, err := registry.ParseRepositoryInfo(taglessRemote) if err != nil { return err } @@ -1299,7 +1275,7 @@ func (cli *DockerCli) CmdPull(args ...string) error { cli.LoadConfigFile() // Resolve the Auth config relevant for this server - authConfig := cli.configFile.ResolveAuthConfig(hostname) + authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index) pull := func(authConfig registry.AuthConfig) error { buf, err := json.Marshal(authConfig) @@ -1318,10 +1294,10 @@ func (cli *DockerCli) CmdPull(args ...string) error { if err := pull(authConfig); err != nil { if strings.Contains(err.Error(), "Status 401") { fmt.Fprintln(cli.out, "\nPlease login prior to pull:") - if err := cli.CmdLogin(hostname); err != nil { + if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil { return err } - authConfig := cli.configFile.ResolveAuthConfig(hostname) + authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index) return pull(authConfig) } return err @@ -1331,7 +1307,7 @@ func (cli *DockerCli) CmdPull(args ...string) error { } func (cli *DockerCli) CmdImages(args ...string) error { - cmd := cli.Subcmd("images", "[REPOSITORY]", "List images") + cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true) quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs") all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate image layers)") noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") @@ -1340,15 +1316,10 @@ func (cli *DockerCli) CmdImages(args ...string) error { flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format") flFilter := opts.NewListOpts(nil) - cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')") + cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e., 'dangling=true')") + cmd.Require(flag.Max, 1) - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() > 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) // Consolidate all filter flags, and sanity check them early. // They'll get process in the daemon/server. @@ -1361,12 +1332,6 @@ func (cli *DockerCli) CmdImages(args ...string) error { } } - for name := range imageFilterArgs { - if _, ok := acceptedImageFilterTags[name]; !ok { - return fmt.Errorf("Invalid filter '%s'", name) - } - } - matchName := cmd.Arg(0) // FIXME: --viz and --tree are deprecated. Remove them in a future version. if *flViz || *flTree { @@ -1485,7 +1450,7 @@ func (cli *DockerCli) CmdImages(args ...string) error { } if !*quiet { - fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), units.HumanSize(out.GetInt64("VirtualSize"))) + fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), units.HumanSize(float64(out.GetInt64("VirtualSize")))) } else { fmt.Fprintln(w, outID) } @@ -1559,7 +1524,7 @@ func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix stri imageID = utils.TruncateID(image.Get("Id")) } - fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, units.HumanSize(image.GetInt64("VirtualSize"))) + fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, units.HumanSize(float64(image.GetInt64("VirtualSize")))) if image.GetList("RepoTags")[0] != ":" { fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", ")) } else { @@ -1574,7 +1539,7 @@ func (cli *DockerCli) CmdPs(args ...string) error { psFilterArgs = filters.Args{} v = url.Values{} - cmd = cli.Subcmd("ps", "", "List containers") + cmd = cli.Subcmd("ps", "", "List containers", true) quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs") size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes") all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.") @@ -1585,13 +1550,11 @@ func (cli *DockerCli) CmdPs(args ...string) error { last = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.") flFilter = opts.NewListOpts(nil) ) + cmd.Require(flag.Exact, 0) cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited= - containers with exit code of \nstatus=(restarting|running|paused|exited)") - if err := cmd.Parse(args); err != nil { - return nil - } - + utils.ParseFlags(cmd, args, true) if *last == -1 && *nLatest { *last = 1 } @@ -1696,15 +1659,20 @@ func (cli *DockerCli) CmdPs(args ...string) error { ports.ReadListFrom([]byte(out.Get("Ports"))) - fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, out.Get("Image"), outCommand, + image := out.Get("Image") + if image == "" { + image = "" + } + + fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, image, outCommand, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ",")) if *size { if out.GetInt("SizeRootFs") > 0 { - fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(out.GetInt64("SizeRw")), units.HumanSize(out.GetInt64("SizeRootFs"))) + fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(float64(out.GetInt64("SizeRw"))), units.HumanSize(float64(out.GetInt64("SizeRootFs")))) } else { - fmt.Fprintf(w, "%s\n", units.HumanSize(out.GetInt64("SizeRw"))) + fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("SizeRw")))) } continue @@ -1721,29 +1689,24 @@ func (cli *DockerCli) CmdPs(args ...string) error { } func (cli *DockerCli) CmdCommit(args ...string) error { - cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes") + cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true) flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit") flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith \")") // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands") - if err := cmd.Parse(args); err != nil { - return nil - } + cmd.Require(flag.Max, 2) + cmd.Require(flag.Min, 1) + utils.ParseFlags(cmd, args, true) var ( name = cmd.Arg(0) repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1)) ) - if name == "" || len(cmd.Args()) > 2 { - cmd.Usage() - return nil - } - //Check if the given image name can be resolved if repository != "" { - if _, _, err := registry.ResolveRepositoryName(repository); err != nil { + if err := registry.ValidateRepositoryName(repository); err != nil { return err } } @@ -1782,21 +1745,15 @@ func (cli *DockerCli) CmdCommit(args ...string) error { } func (cli *DockerCli) CmdEvents(args ...string) error { - cmd := cli.Subcmd("events", "", "Get real time events from the server") + cmd := cli.Subcmd("events", "", "Get real time events from the server", true) since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp") until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp") - flFilter := opts.NewListOpts(nil) - cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')") + cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e., 'event=stop')") + cmd.Require(flag.Exact, 0) - if err := cmd.Parse(args); err != nil { - return nil - } + utils.ParseFlags(cmd, args, true) - if cmd.NArg() != 0 { - cmd.Usage() - return nil - } var ( v = url.Values{} loc = time.FixedZone(time.Now().Zone()) @@ -1843,15 +1800,10 @@ func (cli *DockerCli) CmdEvents(args ...string) error { } func (cli *DockerCli) CmdExport(args ...string) error { - cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT") - if err := cmd.Parse(args); err != nil { - return nil - } + cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true) + cmd.Require(flag.Exact, 1) - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil { return err @@ -1860,14 +1812,10 @@ func (cli *DockerCli) CmdExport(args ...string) error { } func (cli *DockerCli) CmdDiff(args ...string) error { - cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true) + cmd.Require(flag.Exact, 1) + + utils.ParseFlags(cmd, args, true) body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false)) @@ -1896,20 +1844,15 @@ func (cli *DockerCli) CmdDiff(args ...string) error { func (cli *DockerCli) CmdLogs(args ...string) error { var ( - cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container") + cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true) follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output") times = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps") tail = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)") ) + cmd.Require(flag.Exact, 1) - if err := cmd.Parse(args); err != nil { - return nil - } + utils.ParseFlags(cmd, args, true) - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } name := cmd.Arg(0) stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false) @@ -1940,19 +1883,13 @@ func (cli *DockerCli) CmdLogs(args ...string) error { func (cli *DockerCli) CmdAttach(args ...string) error { var ( - cmd = cli.Subcmd("attach", "CONTAINER", "Attach to a running container") + cmd = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true) noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN") proxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.") ) + cmd.Require(flag.Exact, 1) - if err := cmd.Parse(args); err != nil { - return nil - } - - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) name := cmd.Arg(0) stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false) @@ -2017,18 +1954,14 @@ func (cli *DockerCli) CmdAttach(args ...string) error { } func (cli *DockerCli) CmdSearch(args ...string) error { - cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images") + cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true) noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds") automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds") stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() != 1 { - cmd.Usage() - return nil - } + cmd.Require(flag.Exact, 1) + + utils.ParseFlags(cmd, args, true) v := url.Values{} v.Set("term", cmd.Arg(0)) @@ -2072,15 +2005,11 @@ func (cli *DockerCli) CmdSearch(args ...string) error { type ports []int func (cli *DockerCli) CmdTag(args ...string) error { - cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository") + cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true) force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force") - if err := cmd.Parse(args); err != nil { - return nil - } - if cmd.NArg() != 2 { - cmd.Usage() - return nil - } + cmd.Require(flag.Exact, 2) + + utils.ParseFlags(cmd, args, true) var ( repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1)) @@ -2088,7 +2017,7 @@ func (cli *DockerCli) CmdTag(args ...string) error { ) //Check if the given image name can be resolved - if _, _, err := registry.ResolveRepositoryName(repository); err != nil { + if err := registry.ValidateRepositoryName(repository); err != nil { return err } v.Set("repo", repository) @@ -2118,8 +2047,8 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error { v.Set("fromImage", repos) v.Set("tag", tag) - // Resolve the Repository name from fqn to hostname + name - hostname, _, err := registry.ResolveRepositoryName(repos) + // Resolve the Repository name from fqn to RepositoryInfo + repoInfo, err := registry.ParseRepositoryInfo(repos) if err != nil { return err } @@ -2128,7 +2057,7 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error { cli.LoadConfigFile() // Resolve the Auth config relevant for this server - authConfig := cli.configFile.ResolveAuthConfig(hostname) + authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index) buf, err := json.Marshal(authConfig) if err != nil { return err @@ -2153,6 +2082,7 @@ func newCIDFile(path string) (*cidFile, error) { if _, err := os.Stat(path); err == nil { return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path) } + f, err := os.Create(path) if err != nil { return nil, fmt.Errorf("Failed to create the container ID file: %s", err) @@ -2240,7 +2170,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc } func (cli *DockerCli) CmdCreate(args ...string) error { - cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container") + cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true) // These are flags not stored in Config/HostConfig var ( @@ -2249,7 +2179,7 @@ func (cli *DockerCli) CmdCreate(args ...string) error { config, hostConfig, cmd, err := runconfig.Parse(cmd, args) if err != nil { - return err + utils.ReportError(cmd, err.Error(), true) } if config.Image == "" { cmd.Usage() @@ -2268,7 +2198,7 @@ func (cli *DockerCli) CmdCreate(args ...string) error { func (cli *DockerCli) CmdRun(args ...string) error { // FIXME: just use runconfig.Parse already - cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container") + cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true) // These are flags not stored in Config/HostConfig var ( @@ -2284,8 +2214,9 @@ func (cli *DockerCli) CmdRun(args ...string) error { ) config, hostConfig, cmd, err := runconfig.Parse(cmd, args) + // just in case the Parse does not exit if err != nil { - return err + utils.ReportError(cmd, err.Error(), true) } if config.Image == "" { cmd.Usage() @@ -2468,15 +2399,10 @@ func (cli *DockerCli) CmdRun(args ...string) error { } func (cli *DockerCli) CmdCp(args ...string) error { - cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH") - if err := cmd.Parse(args); err != nil { - return nil - } + cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH", true) + cmd.Require(flag.Exact, 2) - if cmd.NArg() != 2 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) var copyData engine.Env info := strings.Split(cmd.Arg(0), ":") @@ -2508,17 +2434,11 @@ func (cli *DockerCli) CmdCp(args ...string) error { } func (cli *DockerCli) CmdSave(args ...string) error { - cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)") - outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT") + cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true) + outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT") + cmd.Require(flag.Min, 1) - if err := cmd.Parse(args); err != nil { - return err - } - - if cmd.NArg() < 1 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) var ( output io.Writer = cli.out @@ -2551,17 +2471,11 @@ func (cli *DockerCli) CmdSave(args ...string) error { } func (cli *DockerCli) CmdLoad(args ...string) error { - cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN") + cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true) infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN") + cmd.Require(flag.Exact, 0) - if err := cmd.Parse(args); err != nil { - return err - } - - if cmd.NArg() != 0 { - cmd.Usage() - return nil - } + utils.ParseFlags(cmd, args, true) var ( input io.Reader = cli.in @@ -2580,15 +2494,12 @@ func (cli *DockerCli) CmdLoad(args ...string) error { } func (cli *DockerCli) CmdExec(args ...string) error { - cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container") + cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true) execConfig, err := runconfig.ParseExec(cmd, args) - if err != nil { - return err - } - if execConfig.Container == "" { - cmd.Usage() - return nil + // just in case the ParseExec does not exit + if execConfig.Container == "" || err != nil { + return &utils.StatusError{StatusCode: 1} } stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false) @@ -2691,3 +2602,163 @@ func (cli *DockerCli) CmdExec(args ...string) error { return nil } + +type containerStats struct { + Name string + CpuPercentage float64 + Memory float64 + MemoryLimit float64 + MemoryPercentage float64 + NetworkRx float64 + NetworkTx float64 + mu sync.RWMutex + err error +} + +func (s *containerStats) Collect(cli *DockerCli) { + stream, _, err := cli.call("GET", "/containers/"+s.Name+"/stats", nil, false) + if err != nil { + s.err = err + return + } + defer stream.Close() + var ( + previousCpu uint64 + previousSystem uint64 + start = true + dec = json.NewDecoder(stream) + u = make(chan error, 1) + ) + go func() { + for { + var v *stats.Stats + if err := dec.Decode(&v); err != nil { + u <- err + return + } + var ( + memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0 + cpuPercent = 0.0 + ) + if !start { + cpuPercent = calcuateCpuPercent(previousCpu, previousSystem, v) + } + start = false + s.mu.Lock() + s.CpuPercentage = cpuPercent + s.Memory = float64(v.MemoryStats.Usage) + s.MemoryLimit = float64(v.MemoryStats.Limit) + s.MemoryPercentage = memPercent + s.NetworkRx = float64(v.Network.RxBytes) + s.NetworkTx = float64(v.Network.TxBytes) + s.mu.Unlock() + previousCpu = v.CpuStats.CpuUsage.TotalUsage + previousSystem = v.CpuStats.SystemUsage + u <- nil + } + }() + for { + select { + case <-time.After(2 * time.Second): + // zero out the values if we have not received an update within + // the specified duration. + s.mu.Lock() + s.CpuPercentage = 0 + s.Memory = 0 + s.MemoryPercentage = 0 + s.mu.Unlock() + case err := <-u: + if err != nil { + s.mu.Lock() + s.err = err + s.mu.Unlock() + return + } + } + } +} + +func (s *containerStats) Display(w io.Writer) error { + s.mu.RLock() + defer s.mu.RUnlock() + if s.err != nil { + return s.err + } + fmt.Fprintf(w, "%s\t%.2f%%\t%s/%s\t%.2f%%\t%s/%s\n", + s.Name, + s.CpuPercentage, + units.BytesSize(s.Memory), units.BytesSize(s.MemoryLimit), + s.MemoryPercentage, + units.BytesSize(s.NetworkRx), units.BytesSize(s.NetworkTx)) + return nil +} + +func (cli *DockerCli) CmdStats(args ...string) error { + cmd := cli.Subcmd("stats", "CONTAINER", "Display a live stream of one or more containers' resource usage statistics", true) + cmd.Require(flag.Min, 1) + utils.ParseFlags(cmd, args, true) + + names := cmd.Args() + sort.Strings(names) + var ( + cStats []*containerStats + w = tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) + ) + printHeader := func() { + fmt.Fprint(cli.out, "\033[2J") + fmt.Fprint(cli.out, "\033[H") + fmt.Fprintln(w, "CONTAINER\tCPU %\tMEM USAGE/LIMIT\tMEM %\tNET I/O") + } + for _, n := range names { + s := &containerStats{Name: n} + cStats = append(cStats, s) + go s.Collect(cli) + } + // do a quick pause so that any failed connections for containers that do not exist are able to be + // evicted before we display the initial or default values. + time.Sleep(500 * time.Millisecond) + var errs []string + for _, c := range cStats { + c.mu.Lock() + if c.err != nil { + errs = append(errs, fmt.Sprintf("%s: %s", c.Name, c.err.Error())) + } + c.mu.Unlock() + } + if len(errs) > 0 { + return fmt.Errorf("%s", strings.Join(errs, ", ")) + } + for _ = range time.Tick(500 * time.Millisecond) { + printHeader() + toRemove := []int{} + for i, s := range cStats { + if err := s.Display(w); err != nil { + toRemove = append(toRemove, i) + } + } + for j := len(toRemove) - 1; j >= 0; j-- { + i := toRemove[j] + cStats = append(cStats[:i], cStats[i+1:]...) + } + if len(cStats) == 0 { + return nil + } + w.Flush() + } + return nil +} + +func calcuateCpuPercent(previousCpu, previousSystem uint64, v *stats.Stats) float64 { + var ( + cpuPercent = 0.0 + // calculate the change for the cpu usage of the container in between readings + cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCpu) + // calculate the change for the entire system between readings + systemDelta = float64(v.CpuStats.SystemUsage - previousSystem) + ) + + if systemDelta > 0.0 && cpuDelta > 0.0 { + cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0 + } + return cpuPercent +} diff --git a/api/client/hijack.go b/api/client/hijack.go index 617a0b3f6..bb902405c 100644 --- a/api/client/hijack.go +++ b/api/client/hijack.go @@ -72,6 +72,15 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con if err != nil { return nil, err } + // When we set up a TCP connection for hijack, there could be long periods + // of inactivity (a long running command with no output) that in certain + // network setups may cause ECONNTIMEOUT, leaving the client in an unknown + // state. Setting TCP KeepAlive on the socket connection will prohibit + // ECONNTIMEOUT unless the socket connection truly is broken + if tcpConn, ok := rawConn.(*net.TCPConn); ok { + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(30 * time.Second) + } colonPos := strings.LastIndex(addr, ":") if colonPos == -1 { @@ -134,10 +143,21 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea return err } req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION) - req.Header.Set("Content-Type", "plain/text") + req.Header.Set("Content-Type", "text/plain") + req.Header.Set("Connection", "Upgrade") + req.Header.Set("Upgrade", "tcp") req.Host = cli.addr dial, err := cli.dial() + // When we set up a TCP connection for hijack, there could be long periods + // of inactivity (a long running command with no output) that in certain + // network setups may cause ECONNTIMEOUT, leaving the client in an unknown + // state. Setting TCP KeepAlive on the socket connection will prohibit + // ECONNTIMEOUT unless the socket connection truly is broken + if tcpConn, ok := dial.(*net.TCPConn); ok { + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(30 * time.Second) + } if err != nil { if strings.Contains(err.Error(), "connection refused") { return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?") diff --git a/api/client/utils.go b/api/client/utils.go index 8de571bf4..86e221ebf 100644 --- a/api/client/utils.go +++ b/api/client/utils.go @@ -66,7 +66,7 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b if passAuthInfo { cli.LoadConfigFile() // Resolve the Auth config relevant for this server - authConfig := cli.configFile.ResolveAuthConfig(registry.IndexServerAddress()) + authConfig := cli.configFile.Configs[registry.IndexServerAddress()] getHeaders := func(authConfig registry.AuthConfig) (map[string][]string, error) { buf, err := json.Marshal(authConfig) if err != nil { @@ -89,7 +89,7 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b if data != nil { req.Header.Set("Content-Type", "application/json") } else if method == "POST" { - req.Header.Set("Content-Type", "plain/text") + req.Header.Set("Content-Type", "text/plain") } resp, err := cli.HTTPClient().Do(req) if err != nil { @@ -135,7 +135,7 @@ func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in req.URL.Host = cli.addr req.URL.Scheme = cli.scheme if method == "POST" { - req.Header.Set("Content-Type", "plain/text") + req.Header.Set("Content-Type", "text/plain") } if headers != nil { diff --git a/api/common.go b/api/common.go index 71e72f69e..1bbb6d393 100644 --- a/api/common.go +++ b/api/common.go @@ -4,7 +4,7 @@ import ( "fmt" "mime" "os" - "path" + "path/filepath" "strings" log "github.com/Sirupsen/logrus" @@ -15,9 +15,10 @@ import ( ) const ( - APIVERSION version.Version = "1.16" - DEFAULTHTTPHOST = "127.0.0.1" - DEFAULTUNIXSOCKET = "/var/run/docker.sock" + APIVERSION version.Version = "1.17" + DEFAULTHTTPHOST = "127.0.0.1" + DEFAULTUNIXSOCKET = "/var/run/docker.sock" + DefaultDockerfileName string = "Dockerfile" ) func ValidateHost(val string) (string, error) { @@ -54,7 +55,7 @@ func MatchesContentType(contentType, expectedType string) bool { // LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { - err := os.MkdirAll(path.Dir(trustKeyPath), 0700) + err := os.MkdirAll(filepath.Dir(trustKeyPath), 0700) if err != nil { return nil, err } @@ -68,7 +69,7 @@ func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { return nil, fmt.Errorf("Error saving key file: %s", err) } } else if err != nil { - return nil, fmt.Errorf("Error loading key file: %s", err) + return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) } return trustKey, nil } diff --git a/api/server/MAINTAINERS b/api/server/MAINTAINERS index c92a06114..dee1eec04 100644 --- a/api/server/MAINTAINERS +++ b/api/server/MAINTAINERS @@ -1,2 +1,2 @@ Victor Vieux (@vieux) -Johan Euphrosine (@proppy) +# Johan Euphrosine (@proppy) diff --git a/api/server/server.go b/api/server/server.go index 629ad0ba0..9bb42f6c8 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -27,6 +27,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/docker/api" + "github.com/docker/docker/daemon/networkdriver/portallocator" "github.com/docker/docker/engine" "github.com/docker/docker/pkg/listenbuffer" "github.com/docker/docker/pkg/parsers" @@ -410,6 +411,19 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo return nil } +func getContainersStats(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + if err := parseForm(r); err != nil { + return err + } + if vars == nil { + return fmt.Errorf("Missing parameter") + } + name := vars["name"] + job := eng.Job("container_stats", name) + streamJSON(job, w, true) + return job.Run() +} + func getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err @@ -738,6 +752,24 @@ func postContainersRestart(eng *engine.Engine, version version.Version, w http.R return nil } +func postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + if err := parseForm(r); err != nil { + return err + } + if vars == nil { + return fmt.Errorf("Missing parameter") + } + + newName := r.URL.Query().Get("name") + job := eng.Job("container_rename", vars["name"], newName) + job.Setenv("t", r.Form.Get("t")) + if err := job.Run(); err != nil { + return err + } + w.WriteHeader(http.StatusNoContent) + return nil +} + func deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err @@ -887,7 +919,11 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re var errStream io.Writer - fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") + if _, ok := r.Header["Upgrade"]; ok { + fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") + } else { + fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") + } if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") { errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) @@ -1030,6 +1066,7 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite } job.Stdin.Add(r.Body) job.Setenv("remote", r.FormValue("remote")) + job.Setenv("dockerfile", r.FormValue("dockerfile")) job.Setenv("t", r.FormValue("t")) job.Setenv("q", r.FormValue("q")) job.Setenv("nocache", r.FormValue("nocache")) @@ -1137,7 +1174,12 @@ func postContainerExecStart(eng *engine.Engine, version version.Version, w http. var errStream io.Writer - fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") + if _, ok := r.Header["Upgrade"]; ok { + fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") + } else { + fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") + } + if !job.GetenvBool("Tty") && version.GreaterThanOrEqualTo("1.6") { errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) @@ -1250,7 +1292,7 @@ func AttachProfiler(router *mux.Router) { router.HandleFunc("/debug/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP) } -func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion string) (*mux.Router, error) { +func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion string) *mux.Router { r := mux.NewRouter() if os.Getenv("DEBUG") != "" { AttachProfiler(r) @@ -1275,6 +1317,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st "/containers/{name:.*}/json": getContainersByName, "/containers/{name:.*}/top": getContainersTop, "/containers/{name:.*}/logs": getContainersLogs, + "/containers/{name:.*}/stats": getContainersStats, "/containers/{name:.*}/attach/ws": wsContainersAttach, "/exec/{id:.*}/json": getExecByID, }, @@ -1300,6 +1343,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st "/containers/{name:.*}/exec": postContainerExecCreate, "/exec/{name:.*}/start": postContainerExecStart, "/exec/{name:.*}/resize": postContainerExecResize, + "/containers/{name:.*}/rename": postContainerRename, }, "DELETE": { "/containers/{name:.*}": deleteContainers, @@ -1331,30 +1375,23 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st } } - return r, nil + return r } // ServeRequest processes a single http request to the docker remote api. // FIXME: refactor this to be part of Server and not require re-creating a new // router each time. This requires first moving ListenAndServe into Server. -func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) error { - router, err := createRouter(eng, false, true, "") - if err != nil { - return err - } +func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) { + router := createRouter(eng, false, true, "") // Insert APIVERSION into the request as a convenience req.URL.Path = fmt.Sprintf("/v%s%s", apiversion, req.URL.Path) router.ServeHTTP(w, req) - return nil } // serveFd creates an http.Server and sets it up to serve given a socket activated // argument. func serveFd(addr string, job *engine.Job) error { - r, err := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) - if err != nil { - return err - } + r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) ls, e := systemd.ListenFD(addr) if e != nil { @@ -1389,7 +1426,7 @@ func serveFd(addr string, job *engine.Job) error { } func lookupGidByName(nameOrGid string) (int, error) { - groupFile, err := user.GetGroupFile() + groupFile, err := user.GetGroupPath() if err != nil { return -1, err } @@ -1466,10 +1503,7 @@ func setSocketGroup(addr, group string) error { } func setupUnixHttp(addr string, job *engine.Job) (*HttpServer, error) { - r, err := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) - if err != nil { - return nil, err - } + r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) if err := syscall.Unlink(addr); err != nil && !os.IsNotExist(err) { return nil, err @@ -1493,18 +1527,45 @@ func setupUnixHttp(addr string, job *engine.Job) (*HttpServer, error) { return &HttpServer{&http.Server{Addr: addr, Handler: r}, l}, nil } +func allocateDaemonPort(addr string) error { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return err + } + + intPort, err := strconv.Atoi(port) + if err != nil { + return err + } + + var hostIPs []net.IP + if parsedIP := net.ParseIP(host); parsedIP != nil { + hostIPs = append(hostIPs, parsedIP) + } else if hostIPs, err = net.LookupIP(host); err != nil { + return fmt.Errorf("failed to lookup %s address in host specification", host) + } + + for _, hostIP := range hostIPs { + if _, err := portallocator.RequestPort(hostIP, "tcp", intPort); err != nil { + return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err) + } + } + return nil +} + func setupTcpHttp(addr string, job *engine.Job) (*HttpServer, error) { if !strings.HasPrefix(addr, "127.0.0.1") && !job.GetenvBool("TlsVerify") { log.Infof("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") } - r, err := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) + r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) + + l, err := newListener("tcp", addr, job.GetenvBool("BufferRequests")) if err != nil { return nil, err } - l, err := newListener("tcp", addr, job.GetenvBool("BufferRequests")) - if err != nil { + if err := allocateDaemonPort(addr); err != nil { return nil, err } diff --git a/api/server/server_unit_test.go b/api/server/server_unit_test.go index 519652f37..b5ec7c896 100644 --- a/api/server/server_unit_test.go +++ b/api/server/server_unit_test.go @@ -484,9 +484,7 @@ func serveRequestUsingVersion(method, target string, version version.Version, bo if err != nil { t.Fatal(err) } - if err := ServeRequest(eng, version, r, req); err != nil { - t.Fatal(err) - } + ServeRequest(eng, version, r, req) return r } diff --git a/api/stats/stats.go b/api/stats/stats.go new file mode 100644 index 000000000..8edf18fe0 --- /dev/null +++ b/api/stats/stats.go @@ -0,0 +1,87 @@ +// This package is used for API stability in the types and response to the +// consumers of the API stats endpoint. +package stats + +import "time" + +type ThrottlingData struct { + // Number of periods with throttling active + Periods uint64 `json:"periods"` + // Number of periods when the container hit its throttling limit. + ThrottledPeriods uint64 `json:"throttled_periods"` + // Aggregate time the container was throttled for in nanoseconds. + ThrottledTime uint64 `json:"throttled_time"` +} + +// All CPU stats are aggregated since container inception. +type CpuUsage struct { + // Total CPU time consumed. + // Units: nanoseconds. + TotalUsage uint64 `json:"total_usage"` + // Total CPU time consumed per core. + // Units: nanoseconds. + PercpuUsage []uint64 `json:"percpu_usage"` + // Time spent by tasks of the cgroup in kernel mode. + // Units: nanoseconds. + UsageInKernelmode uint64 `json:"usage_in_kernelmode"` + // Time spent by tasks of the cgroup in user mode. + // Units: nanoseconds. + UsageInUsermode uint64 `json:"usage_in_usermode"` +} + +type CpuStats struct { + CpuUsage CpuUsage `json:"cpu_usage"` + SystemUsage uint64 `json:"system_cpu_usage"` + ThrottlingData ThrottlingData `json:"throttling_data,omitempty"` +} + +type MemoryStats struct { + // current res_counter usage for memory + Usage uint64 `json:"usage"` + // maximum usage ever recorded. + MaxUsage uint64 `json:"max_usage"` + // TODO(vishh): Export these as stronger types. + // all the stats exported via memory.stat. + Stats map[string]uint64 `json:"stats"` + // number of times memory usage hits limits. + Failcnt uint64 `json:"failcnt"` + Limit uint64 `json:"limit"` +} + +type BlkioStatEntry struct { + Major uint64 `json:"major"` + Minor uint64 `json:"minor"` + Op string `json:"op"` + Value uint64 `json:"value"` +} + +type BlkioStats struct { + // number of bytes tranferred to and from the block device + IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"` + IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive"` + IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive"` + IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive"` + IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive"` + IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive"` + IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive"` + SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"` +} + +type Network struct { + RxBytes uint64 `json:"rx_bytes"` + RxPackets uint64 `json:"rx_packets"` + RxErrors uint64 `json:"rx_errors"` + RxDropped uint64 `json:"rx_dropped"` + TxBytes uint64 `json:"tx_bytes"` + TxPackets uint64 `json:"tx_packets"` + TxErrors uint64 `json:"tx_errors"` + TxDropped uint64 `json:"tx_dropped"` +} + +type Stats struct { + Read time.Time `json:"read"` + Network Network `json:"network,omitempty"` + CpuStats CpuStats `json:"cpu_stats,omitempty"` + MemoryStats MemoryStats `json:"memory_stats,omitempty"` + BlkioStats BlkioStats `json:"blkio_stats,omitempty"` +} diff --git a/builder/MAINTAINERS b/builder/MAINTAINERS index 4d158aa20..e170c235a 100644 --- a/builder/MAINTAINERS +++ b/builder/MAINTAINERS @@ -1,2 +1,3 @@ Tibor Vass (@tiborvass) Erik Hollensbe (@erikh) +Doug Davis (@duglin) diff --git a/builder/dispatchers.go b/builder/dispatchers.go index db7476c5e..6108967c3 100644 --- a/builder/dispatchers.go +++ b/builder/dispatchers.go @@ -12,6 +12,7 @@ import ( "io/ioutil" "path/filepath" "regexp" + "sort" "strings" log "github.com/Sirupsen/logrus" @@ -20,6 +21,12 @@ import ( "github.com/docker/docker/runconfig" ) +const ( + // NoBaseImageSpecifier is the symbol used by the FROM + // command to specify that no base image is to be used. + NoBaseImageSpecifier string = "scratch" +) + // dispatch with no layer / parsing. This is effectively not a command. func nullDispatch(b *Builder, args []string, attributes map[string]bool, original string) error { return nil @@ -114,6 +121,12 @@ func from(b *Builder, args []string, attributes map[string]bool, original string name := args[0] + if name == NoBaseImageSpecifier { + b.image = "" + b.noBaseImage = true + return nil + } + image, err := b.Daemon.Repositories().LookupImage(name) if b.Pull { image, err = b.pullImage(name) @@ -171,15 +184,12 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str workdir := args[0] - if workdir[0] == '/' { - b.Config.WorkingDir = workdir - } else { - if b.Config.WorkingDir == "" { - b.Config.WorkingDir = "/" - } - b.Config.WorkingDir = filepath.Join(b.Config.WorkingDir, workdir) + if !filepath.IsAbs(workdir) { + workdir = filepath.Join("/", b.Config.WorkingDir, workdir) } + b.Config.WorkingDir = workdir + return b.commit("", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir)) } @@ -193,7 +203,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str // RUN [ "echo", "hi" ] # echo hi // func run(b *Builder, args []string, attributes map[string]bool, original string) error { - if b.image == "" { + if b.image == "" && !b.noBaseImage { return fmt.Errorf("Please provide a source image with `from` prior to run") } @@ -326,14 +336,21 @@ func expose(b *Builder, args []string, attributes map[string]bool, original stri return err } + // instead of using ports directly, we build a list of ports and sort it so + // the order is consistent. This prevents cache burst where map ordering + // changes between builds + portList := make([]string, len(ports)) + var i int for port := range ports { if _, exists := b.Config.ExposedPorts[port]; !exists { b.Config.ExposedPorts[port] = struct{}{} } + portList[i] = string(port) + i++ } + sort.Strings(portList) b.Config.PortSpecs = nil - - return b.commit("", b.Config.Cmd, fmt.Sprintf("EXPOSE %v", ports)) + return b.commit("", b.Config.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " "))) } // USER foo diff --git a/builder/evaluator.go b/builder/evaluator.go index 3d9ebb162..b76c7f29b 100644 --- a/builder/evaluator.go +++ b/builder/evaluator.go @@ -24,13 +24,15 @@ import ( "fmt" "io" "os" - "path" + "path/filepath" "strings" log "github.com/Sirupsen/logrus" "github.com/docker/docker/builder/parser" "github.com/docker/docker/daemon" "github.com/docker/docker/engine" + "github.com/docker/docker/pkg/fileutils" + "github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/tarsum" "github.com/docker/docker/registry" "github.com/docker/docker/runconfig" @@ -104,13 +106,14 @@ type Builder struct { // both of these are controlled by the Remove and ForceRemove options in BuildOpts TmpContainers map[string]struct{} // a map of containers used for removes - dockerfile *parser.Node // the syntax tree of the dockerfile - image string // image name for commit processing - maintainer string // maintainer name. could probably be removed. - cmdSet bool // indicates is CMD was set in current Dockerfile - context tarsum.TarSum // the context is a tarball that is uploaded by the client - contextPath string // the path of the temporary directory the local context is unpacked to (server side) - + dockerfileName string // name of Dockerfile + dockerfile *parser.Node // the syntax tree of the dockerfile + image string // image name for commit processing + maintainer string // maintainer name. could probably be removed. + cmdSet bool // indicates is CMD was set in current Dockerfile + context tarsum.TarSum // the context is a tarball that is uploaded by the client + contextPath string // the path of the temporary directory the local context is unpacked to (server side) + noBaseImage bool // indicates that this build does not start from any base image, but is being built from an empty file system. } // Run the builder with the context. This is the lynchpin of this package. This @@ -136,30 +139,10 @@ func (b *Builder) Run(context io.Reader) (string, error) { } }() - filename := path.Join(b.contextPath, "Dockerfile") - - fi, err := os.Stat(filename) - if os.IsNotExist(err) { - return "", fmt.Errorf("Cannot build a directory without a Dockerfile") - } - if fi.Size() == 0 { - return "", ErrDockerfileEmpty - } - - f, err := os.Open(filename) - if err != nil { + if err := b.readDockerfile(b.dockerfileName); err != nil { return "", err } - defer f.Close() - - ast, err := parser.Parse(f) - if err != nil { - return "", err - } - - b.dockerfile = ast - // some initializations that would not have been supplied by the caller. b.Config = &runconfig.Config{} b.TmpContainers = map[string]struct{}{} @@ -185,6 +168,56 @@ func (b *Builder) Run(context io.Reader) (string, error) { return b.image, nil } +// Reads a Dockerfile from the current context. It assumes that the +// 'filename' is a relative path from the root of the context +func (b *Builder) readDockerfile(origFile string) error { + filename, err := symlink.FollowSymlinkInScope(filepath.Join(b.contextPath, origFile), b.contextPath) + if err != nil { + return fmt.Errorf("The Dockerfile (%s) must be within the build context", origFile) + } + + fi, err := os.Lstat(filename) + if os.IsNotExist(err) { + return fmt.Errorf("Cannot locate specified Dockerfile: %s", origFile) + } + if fi.Size() == 0 { + return ErrDockerfileEmpty + } + + f, err := os.Open(filename) + if err != nil { + return err + } + + b.dockerfile, err = parser.Parse(f) + f.Close() + + if err != nil { + return err + } + + // After the Dockerfile has been parsed, we need to check the .dockerignore + // file for either "Dockerfile" or ".dockerignore", and if either are + // present then erase them from the build context. These files should never + // have been sent from the client but we did send them to make sure that + // we had the Dockerfile to actually parse, and then we also need the + // .dockerignore file to know whether either file should be removed. + // Note that this assumes the Dockerfile has been read into memory and + // is now safe to be removed. + + excludes, _ := utils.ReadDockerIgnore(filepath.Join(b.contextPath, ".dockerignore")) + if rm, _ := fileutils.Matches(".dockerignore", excludes); rm == true { + os.Remove(filepath.Join(b.contextPath, ".dockerignore")) + b.context.(tarsum.BuilderContext).Remove(".dockerignore") + } + if rm, _ := fileutils.Matches(b.dockerfileName, excludes); rm == true { + os.Remove(filepath.Join(b.contextPath, b.dockerfileName)) + b.context.(tarsum.BuilderContext).Remove(b.dockerfileName) + } + + return nil +} + // This method is the entrypoint to all statement handling routines. // // Almost all nodes will have this structure: @@ -212,6 +245,21 @@ func (b *Builder) dispatch(stepN int, ast *parser.Node) error { msg += " " + ast.Value } + // count the number of nodes that we are going to traverse first + // so we can pre-create the argument and message array. This speeds up the + // allocation of those list a lot when they have a lot of arguments + cursor := ast + var n int + for cursor.Next != nil { + cursor = cursor.Next + n++ + } + l := len(strs) + strList := make([]string, n+l) + copy(strList, strs) + msgList := make([]string, n) + + var i int for ast.Next != nil { ast = ast.Next var str string @@ -219,16 +267,18 @@ func (b *Builder) dispatch(stepN int, ast *parser.Node) error { if _, ok := replaceEnvAllowed[cmd]; ok { str = b.replaceEnv(ast.Value) } - strs = append(strs, str) - msg += " " + ast.Value + strList[i+l] = str + msgList[i] = ast.Value + i++ } + msg += " " + strings.Join(msgList, " ") fmt.Fprintln(b.OutStream, msg) // XXX yes, we skip any cmds that are not valid; the parser should have // picked these out already. if f, ok := evaluateTable[cmd]; ok { - return f(b, strs, attrs, original) + return f(b, strList, attrs, original) } fmt.Fprintf(b.ErrStream, "# Skipping unknown instruction %s\n", strings.ToUpper(cmd)) diff --git a/builder/internals.go b/builder/internals.go index c1fd617a5..ddbef108a 100644 --- a/builder/internals.go +++ b/builder/internals.go @@ -25,6 +25,7 @@ import ( imagepkg "github.com/docker/docker/image" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/chrootarchive" + "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/system" @@ -58,7 +59,7 @@ func (b *Builder) readContext(context io.Reader) error { } func (b *Builder) commit(id string, autoCmd []string, comment string) error { - if b.image == "" { + if b.image == "" && !b.noBaseImage { return fmt.Errorf("Please provide a source image with `from` prior to commit") } b.Config.Image = b.image @@ -217,6 +218,18 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri } origPath = strings.TrimPrefix(origPath, "./") + // Twiddle the destPath when its a relative path - meaning, make it + // relative to the WORKINGDIR + if !filepath.IsAbs(destPath) { + hasSlash := strings.HasSuffix(destPath, "/") + destPath = filepath.Join("/", b.Config.WorkingDir, destPath) + + // Make sure we preserve any trailing slash + if hasSlash { + destPath += "/" + } + } + // In the remote/URL case, download it and gen its hashcode if urlutil.IsURL(origPath) { if !allowRemote { @@ -296,22 +309,20 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri ci.destPath = ci.destPath + filename } - // Calc the checksum, only if we're using the cache - if b.UtilizeCache { - r, err := archive.Tar(tmpFileName, archive.Uncompressed) - if err != nil { - return err - } - tarSum, err := tarsum.NewTarSum(r, true, tarsum.Version0) - if err != nil { - return err - } - if _, err := io.Copy(ioutil.Discard, tarSum); err != nil { - return err - } - ci.hash = tarSum.Sum(nil) - r.Close() + // Calc the checksum, even if we're using the cache + r, err := archive.Tar(tmpFileName, archive.Uncompressed) + if err != nil { + return err } + tarSum, err := tarsum.NewTarSum(r, true, tarsum.Version0) + if err != nil { + return err + } + if _, err := io.Copy(ioutil.Discard, tarSum); err != nil { + return err + } + ci.hash = tarSum.Sum(nil) + r.Close() return nil } @@ -346,12 +357,6 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri ci.decompress = allowDecompression *cInfos = append(*cInfos, &ci) - // If not using cache don't need to do anything else. - // If we are using a cache then calc the hash for the src file/dir - if !b.UtilizeCache { - return nil - } - // Deal with the single file case if !fi.IsDir() { // This will match first file in sums of the archive @@ -378,7 +383,15 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri for _, fileInfo := range b.context.GetSums() { absFile := path.Join(b.contextPath, fileInfo.Name()) - if strings.HasPrefix(absFile, absOrigPath) || absFile == absOrigPathNoSlash { + // Any file in the context that starts with the given path will be + // picked up and its hashcode used. However, we'll exclude the + // root dir itself. We do this for a coupel of reasons: + // 1 - ADD/COPY will not copy the dir itself, just its children + // so there's no reason to include it in the hash calc + // 2 - the metadata on the dir will change when any child file + // changes. This will lead to a miss in the cache check if that + // child file is in the .dockerignore list. + if strings.HasPrefix(absFile, absOrigPath) && absFile != absOrigPathNoSlash { subfiles = append(subfiles, fileInfo.Sum()) } } @@ -407,21 +420,21 @@ func (b *Builder) pullImage(name string) (*imagepkg.Image, error) { if tag == "" { tag = "latest" } + job := b.Engine.Job("pull", remote, tag) pullRegistryAuth := b.AuthConfig if len(b.AuthConfigFile.Configs) > 0 { // The request came with a full auth config file, we prefer to use that - endpoint, _, err := registry.ResolveRepositoryName(remote) + repoInfo, err := registry.ResolveRepositoryInfo(job, remote) if err != nil { return nil, err } - resolvedAuth := b.AuthConfigFile.ResolveAuthConfig(endpoint) + resolvedAuth := b.AuthConfigFile.ResolveAuthConfig(repoInfo.Index) pullRegistryAuth = &resolvedAuth } - job := b.Engine.Job("pull", remote, tag) job.SetenvBool("json", b.StreamFormatter.Json()) job.SetenvBool("parallel", true) job.SetenvJson("authConfig", pullRegistryAuth) - job.Stdout.Add(b.OutOld) + job.Stdout.Add(ioutils.NopWriteCloser(b.OutOld)) if err := job.Run(); err != nil { return nil, err } @@ -501,7 +514,7 @@ func (b *Builder) probeCache() (bool, error) { } func (b *Builder) create() (*daemon.Container, error) { - if b.image == "" { + if b.image == "" && !b.noBaseImage { return nil, fmt.Errorf("Please provide a source image with `from` prior to run") } b.Config.Image = b.image @@ -520,9 +533,13 @@ func (b *Builder) create() (*daemon.Container, error) { b.TmpContainers[c.ID] = struct{}{} fmt.Fprintf(b.OutStream, " ---> Running in %s\n", utils.TruncateID(c.ID)) - // override the entry point that may have been picked up from the base image - c.Path = config.Cmd[0] - c.Args = config.Cmd[1:] + if len(config.Cmd) > 0 { + // override the entry point that may have been picked up from the base image + c.Path = config.Cmd[0] + c.Args = config.Cmd[1:] + } else { + config.Cmd = []string{} + } return c, nil } diff --git a/builder/job.go b/builder/job.go index 20299d490..53490b7e5 100644 --- a/builder/job.go +++ b/builder/job.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" + "github.com/docker/docker/api" "github.com/docker/docker/daemon" "github.com/docker/docker/engine" "github.com/docker/docker/graph" @@ -30,6 +31,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { return job.Errorf("Usage: %s\n", job.Name) } var ( + dockerfileName = job.Getenv("dockerfile") remoteURL = job.Getenv("remote") repoName = job.Getenv("t") suppressOutput = job.GetenvBool("q") @@ -42,12 +44,13 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { tag string context io.ReadCloser ) + job.GetenvJson("authConfig", authConfig) job.GetenvJson("configFile", configFile) repoName, tag = parsers.ParseRepositoryTag(repoName) if repoName != "" { - if _, _, err := registry.ResolveRepositoryName(repoName); err != nil { + if err := registry.ValidateRepositoryName(repoName); err != nil { return job.Error(err) } if len(tag) > 0 { @@ -57,6 +60,10 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { } } + if dockerfileName == "" { + dockerfileName = api.DefaultDockerfileName + } + if remoteURL == "" { context = ioutil.NopCloser(job.Stdin) } else if urlutil.IsGitURL(remoteURL) { @@ -88,7 +95,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { if err != nil { return job.Error(err) } - c, err := archive.Generate("Dockerfile", string(dockerFile)) + c, err := archive.Generate(dockerfileName, string(dockerFile)) if err != nil { return job.Error(err) } @@ -118,6 +125,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { StreamFormatter: sf, AuthConfig: authConfig, AuthConfigFile: configFile, + dockerfileName: dockerfileName, } id, err := builder.Run(context) diff --git a/builder/parser/json_test.go b/builder/parser/json_test.go new file mode 100644 index 000000000..a256f845d --- /dev/null +++ b/builder/parser/json_test.go @@ -0,0 +1,55 @@ +package parser + +import ( + "testing" +) + +var invalidJSONArraysOfStrings = []string{ + `["a",42,"b"]`, + `["a",123.456,"b"]`, + `["a",{},"b"]`, + `["a",{"c": "d"},"b"]`, + `["a",["c"],"b"]`, + `["a",true,"b"]`, + `["a",false,"b"]`, + `["a",null,"b"]`, +} + +var validJSONArraysOfStrings = map[string][]string{ + `[]`: {}, + `[""]`: {""}, + `["a"]`: {"a"}, + `["a","b"]`: {"a", "b"}, + `[ "a", "b" ]`: {"a", "b"}, + `[ "a", "b" ]`: {"a", "b"}, + ` [ "a", "b" ] `: {"a", "b"}, + `["abc 123", "♥", "☃", "\" \\ \/ \b \f \n \r \t \u0000"]`: {"abc 123", "♥", "☃", "\" \\ / \b \f \n \r \t \u0000"}, +} + +func TestJSONArraysOfStrings(t *testing.T) { + for json, expected := range validJSONArraysOfStrings { + if node, _, err := parseJSON(json); err != nil { + t.Fatalf("%q should be a valid JSON array of strings, but wasn't! (err: %q)", json, err) + } else { + i := 0 + for node != nil { + if i >= len(expected) { + t.Fatalf("expected result is shorter than parsed result (%d vs %d+) in %q", len(expected), i+1, json) + } + if node.Value != expected[i] { + t.Fatalf("expected %q (not %q) in %q at pos %d", expected[i], node.Value, json, i) + } + node = node.Next + i++ + } + if i != len(expected) { + t.Fatalf("expected result is longer than parsed result (%d vs %d) in %q", len(expected), i+1, json) + } + } + } + for _, json := range invalidJSONArraysOfStrings { + if _, _, err := parseJSON(json); err != errDockerfileNotStringArray { + t.Fatalf("%q should be an invalid JSON array of strings, but wasn't!", json) + } + } +} diff --git a/builder/parser/line_parsers.go b/builder/parser/line_parsers.go index abde85d29..8a94e1e5d 100644 --- a/builder/parser/line_parsers.go +++ b/builder/parser/line_parsers.go @@ -10,13 +10,12 @@ import ( "encoding/json" "errors" "fmt" - "strconv" "strings" "unicode" ) var ( - errDockerfileJSONNesting = errors.New("You may not nest arrays in Dockerfile statements.") + errDockerfileNotStringArray = errors.New("When using JSON array syntax, arrays must be comprised of strings only.") ) // ignore the current argument. This will still leave a command parsed, but @@ -209,34 +208,27 @@ func parseString(rest string) (*Node, map[string]bool, error) { // parseJSON converts JSON arrays to an AST. func parseJSON(rest string) (*Node, map[string]bool, error) { - var ( - myJson []interface{} - next = &Node{} - orignext = next - prevnode = next - ) - + var myJson []interface{} if err := json.Unmarshal([]byte(rest), &myJson); err != nil { return nil, nil, err } + var top, prev *Node for _, str := range myJson { - switch str.(type) { - case string: - case float64: - str = strconv.FormatFloat(str.(float64), 'G', -1, 64) - default: - return nil, nil, errDockerfileJSONNesting + if s, ok := str.(string); !ok { + return nil, nil, errDockerfileNotStringArray + } else { + node := &Node{Value: s} + if prev == nil { + top = node + } else { + prev.Next = node + } + prev = node } - next.Value = str.(string) - next.Next = &Node{} - prevnode = next - next = next.Next } - prevnode.Next = nil - - return orignext, map[string]bool{"json": true}, nil + return top, map[string]bool{"json": true}, nil } // parseMaybeJSON determines if the argument appears to be a JSON array. If @@ -250,7 +242,7 @@ func parseMaybeJSON(rest string) (*Node, map[string]bool, error) { if err == nil { return node, attrs, nil } - if err == errDockerfileJSONNesting { + if err == errDockerfileNotStringArray { return nil, nil, err } @@ -270,7 +262,7 @@ func parseMaybeJSONToList(rest string) (*Node, map[string]bool, error) { if err == nil { return node, attrs, nil } - if err == errDockerfileJSONNesting { + if err == errDockerfileNotStringArray { return nil, nil, err } diff --git a/builder/parser/parser.go b/builder/parser/parser.go index ad42a1586..a0806c6f9 100644 --- a/builder/parser/parser.go +++ b/builder/parser/parser.go @@ -3,6 +3,7 @@ package parser import ( "bufio" + "fmt" "io" "regexp" "strings" @@ -32,7 +33,7 @@ type Node struct { var ( dispatch map[string]func(string) (*Node, map[string]bool, error) TOKEN_WHITESPACE = regexp.MustCompile(`[\t\v\f\r ]+`) - TOKEN_LINE_CONTINUATION = regexp.MustCompile(`\\\s*$`) + TOKEN_LINE_CONTINUATION = regexp.MustCompile(`\\[ \t]*$`) TOKEN_COMMENT = regexp.MustCompile(`^#.*$`) ) @@ -50,8 +51,8 @@ func init() { "env": parseEnv, "maintainer": parseString, "from": parseString, - "add": parseStringsWhitespaceDelimited, - "copy": parseStringsWhitespaceDelimited, + "add": parseMaybeJSONToList, + "copy": parseMaybeJSONToList, "run": parseMaybeJSON, "cmd": parseMaybeJSON, "entrypoint": parseMaybeJSON, @@ -77,6 +78,10 @@ func parseLine(line string) (string, *Node, error) { return "", nil, err } + if len(args) == 0 { + return "", nil, fmt.Errorf("Instruction %q is empty; cannot continue", cmd) + } + node := &Node{} node.Value = cmd @@ -85,10 +90,7 @@ func parseLine(line string) (string, *Node, error) { return "", nil, err } - if sexp.Value != "" || sexp.Next != nil || sexp.Children != nil { - node.Next = sexp - } - + node.Next = sexp node.Attributes = attrs node.Original = line diff --git a/builder/parser/parser_test.go b/builder/parser/parser_test.go index 1b517fcc1..daceb9839 100644 --- a/builder/parser/parser_test.go +++ b/builder/parser/parser_test.go @@ -54,18 +54,14 @@ func TestTestData(t *testing.T) { if err != nil { t.Fatalf("Dockerfile missing for %s: %s", dir.Name(), err.Error()) } - - rf, err := os.Open(resultfile) - if err != nil { - t.Fatalf("Result file missing for %s: %s", dir.Name(), err.Error()) - } + defer df.Close() ast, err := Parse(df) if err != nil { t.Fatalf("Error parsing %s's dockerfile: %s", dir.Name(), err.Error()) } - content, err := ioutil.ReadAll(rf) + content, err := ioutil.ReadFile(resultfile) if err != nil { t.Fatalf("Error reading %s's result file: %s", dir.Name(), err.Error()) } @@ -75,8 +71,5 @@ func TestTestData(t *testing.T) { fmt.Fprintln(os.Stderr, "Expected:\n"+string(content)) t.Fatalf("%s: AST dump of dockerfile does not match result", dir.Name()) } - - df.Close() - rf.Close() } } diff --git a/builder/parser/testfiles-negative/empty-instruction/Dockerfile b/builder/parser/testfiles-negative/empty-instruction/Dockerfile new file mode 100644 index 000000000..74e625a40 --- /dev/null +++ b/builder/parser/testfiles-negative/empty-instruction/Dockerfile @@ -0,0 +1,8 @@ +FROM dockerfile/rabbitmq + +RUN + rabbitmq-plugins enable \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_federation \ + rabbitmq_federation_management diff --git a/builder/parser/testfiles/ADD-COPY-with-JSON/Dockerfile b/builder/parser/testfiles/ADD-COPY-with-JSON/Dockerfile new file mode 100644 index 000000000..49372b060 --- /dev/null +++ b/builder/parser/testfiles/ADD-COPY-with-JSON/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:14.04 +MAINTAINER Seongyeol Lim + +COPY . /go/src/github.com/docker/docker +ADD . / +ADD [ "vimrc", "/tmp" ] +COPY [ "bashrc", "/tmp" ] +COPY [ "test file", "/tmp" ] +ADD [ "test file", "/tmp/test file" ] diff --git a/builder/parser/testfiles/ADD-COPY-with-JSON/result b/builder/parser/testfiles/ADD-COPY-with-JSON/result new file mode 100644 index 000000000..86c3fef72 --- /dev/null +++ b/builder/parser/testfiles/ADD-COPY-with-JSON/result @@ -0,0 +1,8 @@ +(from "ubuntu:14.04") +(maintainer "Seongyeol Lim ") +(copy "." "/go/src/github.com/docker/docker") +(add "." "/") +(add "vimrc" "/tmp") +(copy "bashrc" "/tmp") +(copy "test file" "/tmp") +(add "test file" "/tmp/test file") diff --git a/builder/parser/testfiles/brimstone-consuldock/result b/builder/parser/testfiles/brimstone-consuldock/result index cc8fab213..227f748cd 100644 --- a/builder/parser/testfiles/brimstone-consuldock/result +++ b/builder/parser/testfiles/brimstone-consuldock/result @@ -2,4 +2,4 @@ (maintainer "brimstone@the.narro.ws") (env "GOPATH" "/go") (entrypoint "/usr/local/bin/consuldock") -(run "apt-get update && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean && apt-get install -y --no-install-recommends git golang ca-certificates && apt-get clean && rm -rf /var/lib/apt/lists && go get -v github.com/brimstone/consuldock && mv $GOPATH/bin/consuldock /usr/local/bin/consuldock && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty && apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') && rm /tmp/dpkg.* && rm -rf $GOPATH") +(run "apt-get update \t&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean && apt-get install -y --no-install-recommends git golang ca-certificates && apt-get clean && rm -rf /var/lib/apt/lists \t&& go get -v github.com/brimstone/consuldock && mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \t&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \t&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \t&& rm /tmp/dpkg.* \t&& rm -rf $GOPATH") diff --git a/builder/parser/testfiles/brimstone-docker-consul/result b/builder/parser/testfiles/brimstone-docker-consul/result index 8c989e621..16492e516 100644 --- a/builder/parser/testfiles/brimstone-docker-consul/result +++ b/builder/parser/testfiles/brimstone-docker-consul/result @@ -2,8 +2,8 @@ (cmd) (entrypoint "/usr/bin/consul" "agent" "-server" "-data-dir=/consul" "-client=0.0.0.0" "-ui-dir=/webui") (expose "8500" "8600" "8400" "8301" "8302") -(run "apt-get update && apt-get install -y unzip wget && apt-get clean && rm -rf /var/lib/apt/lists") +(run "apt-get update && apt-get install -y unzip wget \t&& apt-get clean \t&& rm -rf /var/lib/apt/lists") (run "cd /tmp && wget https://dl.bintray.com/mitchellh/consul/0.3.1_web_ui.zip -O web_ui.zip && unzip web_ui.zip && mv dist /webui && rm web_ui.zip") -(run "apt-get update && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean && apt-get install -y --no-install-recommends unzip wget && apt-get clean && rm -rf /var/lib/apt/lists && cd /tmp && wget https://dl.bintray.com/mitchellh/consul/0.3.1_web_ui.zip -O web_ui.zip && unzip web_ui.zip && mv dist /webui && rm web_ui.zip && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty && apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') && rm /tmp/dpkg.*") +(run "apt-get update \t&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean && apt-get install -y --no-install-recommends unzip wget && apt-get clean && rm -rf /var/lib/apt/lists && cd /tmp && wget https://dl.bintray.com/mitchellh/consul/0.3.1_web_ui.zip -O web_ui.zip && unzip web_ui.zip && mv dist /webui && rm web_ui.zip \t&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \t&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \t&& rm /tmp/dpkg.*") (env "GOPATH" "/go") -(run "apt-get update && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean && apt-get install -y --no-install-recommends git golang ca-certificates build-essential && apt-get clean && rm -rf /var/lib/apt/lists && go get -v github.com/hashicorp/consul && mv $GOPATH/bin/consul /usr/bin/consul && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty && apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') && rm /tmp/dpkg.* && rm -rf $GOPATH") +(run "apt-get update \t&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean && apt-get install -y --no-install-recommends git golang ca-certificates build-essential && apt-get clean && rm -rf /var/lib/apt/lists \t&& go get -v github.com/hashicorp/consul \t&& mv $GOPATH/bin/consul /usr/bin/consul \t&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \t&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \t&& rm /tmp/dpkg.* \t&& rm -rf $GOPATH") diff --git a/builder/parser/testfiles/docker/result b/builder/parser/testfiles/docker/result index 80f219ecb..773b640a9 100644 --- a/builder/parser/testfiles/docker/result +++ b/builder/parser/testfiles/docker/result @@ -1,13 +1,13 @@ (from "ubuntu:14.04") (maintainer "Tianon Gravi (@tianon)") -(run "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq apt-utils aufs-tools automake btrfs-tools build-essential curl dpkg-sig git iptables libapparmor-dev libcap-dev libsqlite3-dev lxc=1.0* mercurial pandoc parallel reprepro ruby1.9.1 ruby1.9.1-dev s3cmd=1.1.0* --no-install-recommends") +(run "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \tapt-utils \taufs-tools \tautomake \tbtrfs-tools \tbuild-essential \tcurl \tdpkg-sig \tgit \tiptables \tlibapparmor-dev \tlibcap-dev \tlibsqlite3-dev \tlxc=1.0* \tmercurial \tpandoc \tparallel \treprepro \truby1.9.1 \truby1.9.1-dev \ts3cmd=1.1.0* \t--no-install-recommends") (run "git clone --no-checkout https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2 && cd /usr/local/lvm2 && git checkout -q v2_02_103") (run "cd /usr/local/lvm2 && ./configure --enable-static_link && make device-mapper && make install_device-mapper") (run "curl -sSL https://golang.org/dl/go1.3.src.tar.gz | tar -v -C /usr/local -xz") (env "PATH" "/usr/local/go/bin:$PATH") (env "GOPATH" "/go:/go/src/github.com/docker/docker/vendor") (run "cd /usr/local/go/src && ./make.bash --no-clean 2>&1") -(env "DOCKER_CROSSPLATFORMS" "linux/386 linux/arm darwin/amd64 darwin/386 freebsd/amd64 freebsd/386 freebsd/arm") +(env "DOCKER_CROSSPLATFORMS" "linux/386 linux/arm \tdarwin/amd64 darwin/386 \tfreebsd/amd64 freebsd/386 freebsd/arm") (env "GOARM" "5") (run "cd /usr/local/go/src && bash -xc 'for platform in $DOCKER_CROSSPLATFORMS; do GOOS=${platform%/*} GOARCH=${platform##*/} ./make.bash --no-clean 2>&1; done'") (run "go get golang.org/x/tools/cmd/cover") diff --git a/builder/parser/testfiles/json/Dockerfile b/builder/parser/testfiles/json/Dockerfile new file mode 100644 index 000000000..a58691711 --- /dev/null +++ b/builder/parser/testfiles/json/Dockerfile @@ -0,0 +1,8 @@ +CMD [] +CMD [""] +CMD ["a"] +CMD ["a","b"] +CMD [ "a", "b" ] +CMD [ "a", "b" ] +CMD [ "a", "b" ] +CMD ["abc 123", "♥", "☃", "\" \\ \/ \b \f \n \r \t \u0000"] diff --git a/builder/parser/testfiles/json/result b/builder/parser/testfiles/json/result new file mode 100644 index 000000000..c6553e6e1 --- /dev/null +++ b/builder/parser/testfiles/json/result @@ -0,0 +1,8 @@ +(cmd) +(cmd "") +(cmd "a") +(cmd "a" "b") +(cmd "a" "b") +(cmd "a" "b") +(cmd "a" "b") +(cmd "abc 123" "♥" "☃" "\" \\ / \b \f \n \r \t \x00") diff --git a/builder/parser/utils.go b/builder/parser/utils.go index 096c4e31e..3a8cd24e8 100644 --- a/builder/parser/utils.go +++ b/builder/parser/utils.go @@ -2,30 +2,10 @@ package parser import ( "fmt" + "strconv" "strings" ) -// QuoteString walks characters (after trimming), escapes any quotes and -// escapes, then wraps the whole thing in quotes. Very useful for generating -// argument output in nodes. -func QuoteString(str string) string { - result := "" - chars := strings.Split(strings.TrimSpace(str), "") - - for _, char := range chars { - switch char { - case `"`: - result += `\"` - case `\`: - result += `\\` - default: - result += char - } - } - - return `"` + result + `"` -} - // dumps the AST defined by `node` as a list of sexps. Returns a string // suitable for printing. func (node *Node) Dump() string { @@ -41,7 +21,7 @@ func (node *Node) Dump() string { if len(n.Children) > 0 { str += " " + n.Dump() } else { - str += " " + QuoteString(n.Value) + str += " " + strconv.Quote(n.Value) } } } diff --git a/contrib/check-config.sh b/contrib/check-config.sh index 72e3108fe..4f1754073 100755 --- a/contrib/check-config.sh +++ b/contrib/check-config.sh @@ -138,6 +138,9 @@ flags=( NF_NAT_IPV4 IP_NF_FILTER IP_NF_TARGET_MASQUERADE NETFILTER_XT_MATCH_{ADDRTYPE,CONNTRACK} NF_NAT NF_NAT_NEEDED + + # required for bind-mounting /dev/mqueue into containers + POSIX_MQUEUE ) check_flags "${flags[@]}" echo diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index 5364944fa..1d553941b 100755 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -20,6 +20,11 @@ # bound to the default communication port/socket # If the docker daemon is using a unix socket for communication your user # must have access to the socket for the completions to function correctly +# +# Note for developers: +# Please arrange options sorted alphabetically by long name with the short +# options immediately following their corresponding long form. +# This order should be applied to lists, alternatives and code blocks. __docker_q() { docker 2>/dev/null "$@" @@ -99,6 +104,22 @@ __docker_pos_first_nonflag() { echo $counter } +# Transforms a multiline list of strings into a single line string +# with the words separated by "|". +# This is used to prepare arguments to __docker_pos_first_nonflag(). +__docker_to_alternatives() { + local parts=( $1 ) + local IFS='|' + echo "${parts[*]}" +} + +# Transforms a multiline list of options into an extglob pattern +# suitable for use in case statements. +__docker_to_extglob() { + local extglob=$( __docker_to_alternatives "$1" ) + echo "@($extglob)" +} + __docker_resolve_hostname() { command -v host >/dev/null 2>&1 || return COMPREPLY=( $(host 2>/dev/null "${cur%:}" | awk '/has address/ {print $4}') ) @@ -149,15 +170,47 @@ __docker_capabilities() { } _docker_docker() { + local boolean_options=" + --api-enable-cors + --daemon -d + --debug -D + --help -h + --icc + --ip-forward + --ip-masq + --iptables + --ipv6 + --selinux-enabled + --tls + --tlsverify + --version -v + " + case "$prev" in - -H) + --graph|-g) + _filedir -d + return + ;; + --log-level|-l) + COMPREPLY=( $( compgen -W "debug info warn error fatal" -- "$cur" ) ) + return + ;; + --pidfile|-p|--tlscacert|--tlscert|--tlskey) + _filedir + return + ;; + --storage-driver|-s) + COMPREPLY=( $( compgen -W "aufs devicemapper btrfs overlay" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) ) + return + ;; + $main_options_with_args_glob ) return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "-H" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "$boolean_options $main_options_with_args" -- "$cur" ) ) ;; *) COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) ) @@ -181,7 +234,7 @@ _docker_attach() { _docker_build() { case "$prev" in - -t|--tag) + --tag|-t) __docker_image_repos_and_tags return ;; @@ -189,10 +242,10 @@ _docker_build() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-t --tag -q --quiet --no-cache --rm --force-rm" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--force-rm --no-cache --quiet -q --rm --tag -t" -- "$cur" ) ) ;; *) - local counter="$(__docker_pos_first_nonflag '-t|--tag')" + local counter="$(__docker_pos_first_nonflag '--tag|-t')" if [ $cword -eq $counter ]; then _filedir -d fi @@ -202,17 +255,17 @@ _docker_build() { _docker_commit() { case "$prev" in - -m|--message|-a|--author|--run) + --author|-a|--message|-m|--run) return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "-m --message -a --author --run" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--author -a --message -m --run" -- "$cur" ) ) ;; *) - local counter=$(__docker_pos_first_nonflag '-m|--message|-a|--author|--run') + local counter=$(__docker_pos_first_nonflag '--author|-a|--message|-m|--run') if [ $cword -eq $counter ]; then __docker_containers_all @@ -252,124 +305,7 @@ _docker_cp() { } _docker_create() { - case "$prev" in - -a|--attach) - COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) ) - return - ;; - --cidfile|--env-file) - _filedir - return - ;; - --volumes-from) - __docker_containers_all - return - ;; - -v|--volume|--device) - case "$cur" in - *:*) - # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) - ;; - '') - COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) - compopt -o nospace - ;; - /*) - _filedir - compopt -o nospace - ;; - esac - return - ;; - -e|--env) - COMPREPLY=( $( compgen -e -- "$cur" ) ) - compopt -o nospace - return - ;; - --link) - case "$cur" in - *:*) - ;; - *) - __docker_containers_running - COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) ) - compopt -o nospace - ;; - esac - return - ;; - --add-host) - case "$cur" in - *:) - __docker_resolve_hostname - return - ;; - esac - ;; - --cap-add|--cap-drop) - __docker_capabilities - return - ;; - --net) - case "$cur" in - container:*) - local cur=${cur#*:} - __docker_containers_all - ;; - *) - COMPREPLY=( $( compgen -W "bridge none container: host" -- "$cur") ) - if [ "${COMPREPLY[*]}" = "container:" ] ; then - compopt -o nospace - fi - ;; - esac - return - ;; - --restart) - case "$cur" in - on-failure:*) - ;; - *) - COMPREPLY=( $( compgen -W "no on-failure on-failure: always" -- "$cur") ) - ;; - esac - return - ;; - --security-opt) - case "$cur" in - label:*:*) - ;; - label:*) - local cur=${cur##*:} - COMPREPLY=( $( compgen -W "user: role: type: level: disable" -- "$cur") ) - if [ "${COMPREPLY[*]}" != "disable" ] ; then - compopt -o nospace - fi - ;; - *) - COMPREPLY=( $( compgen -W "label apparmor" -S ":" -- "$cur") ) - compopt -o nospace - ;; - esac - return - ;; - --entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|--cpuset|-c|--cpu-shares|-n|--name|-p|--publish|--expose|--dns|--lxc-conf|--dns-search) - return - ;; - esac - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--privileged -P --publish-all -i --interactive -t --tty --cidfile --entrypoint -h --hostname -m --memory -u --user -w --workdir --cpuset -c --cpu-shares --name -a --attach -v --volume --link -e --env --env-file -p --publish --expose --dns --volumes-from --lxc-conf --security-opt --add-host --cap-add --cap-drop --device --dns-search --net --restart" -- "$cur" ) ) - ;; - *) - local counter=$(__docker_pos_first_nonflag '--cidfile|--volumes-from|-v|--volume|-e|--env|--env-file|--entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|--cpuset|-c|--cpu-shares|-n|--name|-a|--attach|--link|-p|--publish|--expose|--dns|--lxc-conf|--security-opt|--add-host|--cap-add|--cap-drop|--device|--dns-search|--net|--restart') - - if [ $cword -eq $counter ]; then - __docker_image_repos_and_tags_and_ids - fi - ;; - esac + _docker_run } _docker_diff() { @@ -396,7 +332,7 @@ _docker_events() { _docker_exec() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-d --detach -i --interactive -t --tty" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--detach -d --interactive -i -t --tty" -- "$cur" ) ) ;; *) __docker_containers_running @@ -421,7 +357,7 @@ _docker_help() { _docker_history() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-q --quiet --no-trunc" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--no-trunc --quiet -q" -- "$cur" ) ) ;; *) local counter=$(__docker_pos_first_nonflag) @@ -435,7 +371,7 @@ _docker_history() { _docker_images() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-q --quiet -a --all --no-trunc -v --viz -t --tree" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--all -a --no-trunc --quiet -q" -- "$cur" ) ) ;; *) local counter=$(__docker_pos_first_nonflag) @@ -465,14 +401,14 @@ _docker_info() { _docker_inspect() { case "$prev" in - -f|--format) + --format|-f) return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "-f --format" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--format -f" -- "$cur" ) ) ;; *) __docker_containers_and_images @@ -485,19 +421,30 @@ _docker_kill() { } _docker_load() { - return -} - -_docker_login() { case "$prev" in - -u|--username|-p|--password|-e|--email) + --input|-i) + _filedir return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "-u --username -p --password -e --email" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--input -i" -- "$cur" ) ) + ;; + esac +} + +_docker_login() { + case "$prev" in + --email|-e|--password|-p|--username|-u) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--email -e --password -p --username -u" -- "$cur" ) ) ;; esac } @@ -505,7 +452,7 @@ _docker_login() { _docker_logs() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-f --follow" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--follow -f" -- "$cur" ) ) ;; *) local counter=$(__docker_pos_first_nonflag) @@ -532,7 +479,7 @@ _docker_port() { _docker_ps() { case "$prev" in - --since|--before) + --before|--since) __docker_containers_all ;; -n) @@ -542,24 +489,24 @@ _docker_ps() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-q --quiet -s --size -a --all --no-trunc -l --latest --since --before -n" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--all -a --before --latest -l --no-trunc -n --quiet -q --size -s --since" -- "$cur" ) ) ;; esac } _docker_pull() { case "$prev" in - -t|--tag) + --tag|-t) return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "-t --tag" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--tag -t" -- "$cur" ) ) ;; *) - local counter=$(__docker_pos_first_nonflag '-t|--tag') + local counter=$(__docker_pos_first_nonflag '--tag|-t') if [ $cword -eq $counter ]; then __docker_image_repos_and_tags fi @@ -576,14 +523,14 @@ _docker_push() { _docker_restart() { case "$prev" in - -t|--time) + --time|-t) return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "-t --time" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--time -t" -- "$cur" ) ) ;; *) __docker_containers_all @@ -594,13 +541,13 @@ _docker_restart() { _docker_rm() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-f --force -l --link -v --volumes" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--force -f --link -l --volumes -v" -- "$cur" ) ) return ;; *) for arg in "${COMP_WORDS[@]}"; do case "$arg" in - -f|--force) + --force|-f) __docker_containers_all return ;; @@ -617,20 +564,75 @@ _docker_rmi() { } _docker_run() { + local options_with_args=" + --add-host + --attach -a + --cap-add + --cap-drop + --cidfile + --cpuset + --cpu-shares -c + --device + --dns + --dns-search + --entrypoint + --env -e + --env-file + --expose + --hostname -h + --ipc + --link + --lxc-conf + --mac-address + --memory -m + --name + --net + --publish -p + --restart + --security-opt + --user -u + --volumes-from + --volume -v + --workdir -w + " + + local all_options="$options_with_args + --interactive -i + --privileged + --publish-all -P + --tty -t + " + + [ "$command" = "run" ] && all_options="$all_options + --detach -d + --rm + --sig-proxy + " + + local options_with_args_glob=$(__docker_to_extglob "$options_with_args") + case "$prev" in - -a|--attach) + --add-host) + case "$cur" in + *:) + __docker_resolve_hostname + return + ;; + esac + ;; + --attach|-a) COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) ) return ;; + --cap-add|--cap-drop) + __docker_capabilities + return + ;; --cidfile|--env-file) _filedir return ;; - --volumes-from) - __docker_containers_all - return - ;; - -v|--volume|--device) + --device|-d|--volume) case "$cur" in *:*) # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) @@ -646,11 +648,26 @@ _docker_run() { esac return ;; - -e|--env) + --env|-e) COMPREPLY=( $( compgen -e -- "$cur" ) ) compopt -o nospace return ;; + --ipc) + case "$cur" in + *:*) + cur="${cur#*:}" + __docker_containers_running + ;; + *) + COMPREPLY=( $( compgen -W 'host container:' -- "$cur" ) ) + if [ "$COMPREPLY" = "container:" ]; then + compopt -o nospace + fi + ;; + esac + return + ;; --link) case "$cur" in *:*) @@ -663,18 +680,6 @@ _docker_run() { esac return ;; - --add-host) - case "$cur" in - *:) - __docker_resolve_hostname - return - ;; - esac - ;; - --cap-add|--cap-drop) - __docker_capabilities - return - ;; --net) case "$cur" in container:*) @@ -718,17 +723,21 @@ _docker_run() { esac return ;; - --entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|--cpuset|-c|--cpu-shares|-n|--name|-p|--publish|--expose|--dns|--lxc-conf|--dns-search) + --volumes-from) + __docker_containers_all + return + ;; + $options_with_args_glob ) return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "--rm -d --detach --privileged -P --publish-all -i --interactive -t --tty --cidfile --entrypoint -h --hostname -m --memory -u --user -w --workdir --cpuset -c --cpu-shares --sig-proxy --name -a --attach -v --volume --link -e --env --env-file -p --publish --expose --dns --volumes-from --lxc-conf --security-opt --add-host --cap-add --cap-drop --device --dns-search --net --restart" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) ) ;; *) - local counter=$(__docker_pos_first_nonflag '--cidfile|--volumes-from|-v|--volume|-e|--env|--env-file|--entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|--cpuset|-c|--cpu-shares|-n|--name|-a|--attach|--link|-p|--publish|--expose|--dns|--lxc-conf|--security-opt|--add-host|--cap-add|--cap-drop|--device|--dns-search|--net|--restart') + local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) ) if [ $cword -eq $counter ]; then __docker_image_repos_and_tags_and_ids @@ -738,22 +747,33 @@ _docker_run() { } _docker_save() { - local counter=$(__docker_pos_first_nonflag) - if [ $cword -eq $counter ]; then - __docker_image_repos_and_tags_and_ids - fi -} - -_docker_search() { case "$prev" in - -s|--stars) + --output|-o) + _filedir return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "--no-trunc --automated -s --stars" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "-o --output" -- "$cur" ) ) + ;; + *) + __docker_image_repos_and_tags_and_ids + ;; + esac +} + +_docker_search() { + case "$prev" in + --stars|-s) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--automated --no-trunc --stars -s" -- "$cur" ) ) ;; esac } @@ -761,7 +781,7 @@ _docker_search() { _docker_start() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-a --attach -i --interactive" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--attach -a --interactive -i" -- "$cur" ) ) ;; *) __docker_containers_stopped @@ -769,16 +789,20 @@ _docker_start() { esac } +_docker_stats() { + __docker_containers_running +} + _docker_stop() { case "$prev" in - -t|--time) + --time|-t) return ;; esac case "$cur" in -*) - COMPREPLY=( $( compgen -W "-t --time" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--time -t" -- "$cur" ) ) ;; *) __docker_containers_running @@ -789,7 +813,7 @@ _docker_stop() { _docker_tag() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-f --force" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--force -f" -- "$cur" ) ) ;; *) local counter=$(__docker_pos_first_nonflag) @@ -831,6 +855,9 @@ _docker_wait() { } _docker() { + local previous_extglob_setting=$(shopt -p extglob) + shopt -s extglob + local commands=( attach build @@ -863,6 +890,7 @@ _docker() { save search start + stats stop tag top @@ -871,6 +899,33 @@ _docker() { wait ) + local main_options_with_args=" + --bip + --bridge -b + --dns + --dns-search + --exec-driver -e + --fixed-cidr + --fixed-cidr-v6 + --graph -g + --group -G + --host -H + --insecure-registry + --ip + --label + --log-level -l + --mtu + --pidfile -p + --registry-mirror + --storage-driver -s + --storage-opt + --tlscacert + --tlscert + --tlskey + " + + local main_options_with_args_glob=$(__docker_to_extglob "$main_options_with_args") + COMPREPLY=() local cur prev words cword _get_comp_words_by_ref -n : cur prev words cword @@ -879,7 +934,7 @@ _docker() { local counter=1 while [ $counter -lt $cword ]; do case "${words[$counter]}" in - -H) + $main_options_with_args_glob ) (( counter++ )) ;; -*) @@ -897,6 +952,7 @@ _docker() { local completions_func=_docker_${command} declare -F $completions_func >/dev/null && $completions_func + eval "$previous_extglob_setting" return 0 } diff --git a/contrib/completion/fish/docker.fish b/contrib/completion/fish/docker.fish index a082adc02..fe92ecc56 100644 --- a/contrib/completion/fish/docker.fish +++ b/contrib/completion/fish/docker.fish @@ -16,7 +16,7 @@ function __fish_docker_no_subcommand --description 'Test if docker has yet to be given the subcommand' for i in (commandline -opc) - if contains -- $i attach build commit cp create diff events export history images import info insert inspect kill load login logs port ps pull push restart rm rmi run save search start stop tag top version wait + if contains -- $i attach build commit cp create diff events exec export history images import info insert inspect kill load login logout logs pause port ps pull push restart rm rmi run save search start stop tag top unpause version wait return 1 end end @@ -43,92 +43,142 @@ function __fish_print_docker_repositories --description 'Print a list of docker end # common options -complete -c docker -f -n '__fish_docker_no_subcommand' -s D -l debug -d 'Enable debug mode' -complete -c docker -f -n '__fish_docker_no_subcommand' -s G -l group -d "Group to assign the unix socket specified by -H when running in daemon mode; use '' (the empty string) to disable setting of a group" -complete -c docker -f -n '__fish_docker_no_subcommand' -s H -l host -d 'tcp://host:port, unix://path/to/socket, fd://* or fd://socketfd to use in daemon mode. Multiple sockets can be specified' complete -c docker -f -n '__fish_docker_no_subcommand' -l api-enable-cors -d 'Enable CORS headers in the remote API' -complete -c docker -f -n '__fish_docker_no_subcommand' -s b -l bridge -d "Attach containers to a pre-existing network bridge; use 'none' to disable container networking" +complete -c docker -f -n '__fish_docker_no_subcommand' -s b -l bridge -d 'Attach containers to a pre-existing network bridge' complete -c docker -f -n '__fish_docker_no_subcommand' -l bip -d "Use this CIDR notation address for the network bridge's IP, not compatible with -b" +complete -c docker -f -n '__fish_docker_no_subcommand' -s D -l debug -d 'Enable debug mode' complete -c docker -f -n '__fish_docker_no_subcommand' -s d -l daemon -d 'Enable daemon mode' -complete -c docker -f -n '__fish_docker_no_subcommand' -l dns -d 'Force docker to use specific DNS servers' -complete -c docker -f -n '__fish_docker_no_subcommand' -s e -l exec-driver -d 'Force the docker runtime to use a specific exec driver' -complete -c docker -f -n '__fish_docker_no_subcommand' -s g -l graph -d 'Path to use as the root of the docker runtime' +complete -c docker -f -n '__fish_docker_no_subcommand' -l dns -d 'Force Docker to use specific DNS servers' +complete -c docker -f -n '__fish_docker_no_subcommand' -l dns-search -d 'Force Docker to use specific DNS search domains' +complete -c docker -f -n '__fish_docker_no_subcommand' -s e -l exec-driver -d 'Force the Docker runtime to use a specific exec driver' +complete -c docker -f -n '__fish_docker_no_subcommand' -l fixed-cidr -d 'IPv4 subnet for fixed IPs (e.g. 10.20.0.0/16)' +complete -c docker -f -n '__fish_docker_no_subcommand' -l fixed-cidr-v6 -d 'IPv6 subnet for fixed IPs (e.g.: 2001:a02b/48)' +complete -c docker -f -n '__fish_docker_no_subcommand' -s G -l group -d 'Group to assign the unix socket specified by -H when running in daemon mode' +complete -c docker -f -n '__fish_docker_no_subcommand' -s g -l graph -d 'Path to use as the root of the Docker runtime' +complete -c docker -f -n '__fish_docker_no_subcommand' -s H -l host -d 'The socket(s) to bind to in daemon mode or connect to in client mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.' +complete -c docker -f -n '__fish_docker_no_subcommand' -s h -l help -d 'Print usage' complete -c docker -f -n '__fish_docker_no_subcommand' -l icc -d 'Allow unrestricted inter-container and Docker daemon host communication' +complete -c docker -f -n '__fish_docker_no_subcommand' -l insecure-registry -d 'Enable insecure communication with specified registries (no certificate verification for HTTPS and enable HTTP fallback) (e.g., localhost:5000 or 10.20.0.0/16)' complete -c docker -f -n '__fish_docker_no_subcommand' -l ip -d 'Default IP address to use when binding container ports' -complete -c docker -f -n '__fish_docker_no_subcommand' -l ip-forward -d 'Disable enabling of net.ipv4.ip_forward' -complete -c docker -f -n '__fish_docker_no_subcommand' -l iptables -d "Disable docker's addition of iptables rules" -complete -c docker -f -n '__fish_docker_no_subcommand' -l mtu -d 'Set the containers network MTU; if no value is provided: default to the default route MTU or 1500 if no default route is available' +complete -c docker -f -n '__fish_docker_no_subcommand' -l ip-forward -d 'Enable net.ipv4.ip_forward and IPv6 forwarding if --fixed-cidr-v6 is defined. IPv6 forwarding may interfere with your existing IPv6 configuration when using Router Advertisement.' +complete -c docker -f -n '__fish_docker_no_subcommand' -l ip-masq -d "Enable IP masquerading for bridge's IP range" +complete -c docker -f -n '__fish_docker_no_subcommand' -l iptables -d "Enable Docker's addition of iptables rules" +complete -c docker -f -n '__fish_docker_no_subcommand' -l ipv6 -d 'Enable IPv6 networking' +complete -c docker -f -n '__fish_docker_no_subcommand' -s l -l log-level -d 'Set the logging level (debug, info, warn, error, fatal)' +complete -c docker -f -n '__fish_docker_no_subcommand' -l label -d 'Set key=value labels to the daemon (displayed in `docker info`)' +complete -c docker -f -n '__fish_docker_no_subcommand' -l mtu -d 'Set the containers network MTU' complete -c docker -f -n '__fish_docker_no_subcommand' -s p -l pidfile -d 'Path to use for daemon PID file' -complete -c docker -f -n '__fish_docker_no_subcommand' -s r -l restart -d 'Restart previously running containers' -complete -c docker -f -n '__fish_docker_no_subcommand' -s s -l storage-driver -d 'Force the docker runtime to use a specific storage driver' +complete -c docker -f -n '__fish_docker_no_subcommand' -l registry-mirror -d 'Specify a preferred Docker registry mirror' +complete -c docker -f -n '__fish_docker_no_subcommand' -s s -l storage-driver -d 'Force the Docker runtime to use a specific storage driver' +complete -c docker -f -n '__fish_docker_no_subcommand' -l selinux-enabled -d 'Enable selinux support. SELinux does not presently support the BTRFS storage driver' +complete -c docker -f -n '__fish_docker_no_subcommand' -l storage-opt -d 'Set storage driver options' +complete -c docker -f -n '__fish_docker_no_subcommand' -l tls -d 'Use TLS; implied by --tlsverify flag' +complete -c docker -f -n '__fish_docker_no_subcommand' -l tlscacert -d 'Trust only remotes providing a certificate signed by the CA given here' +complete -c docker -f -n '__fish_docker_no_subcommand' -l tlscert -d 'Path to TLS certificate file' +complete -c docker -f -n '__fish_docker_no_subcommand' -l tlskey -d 'Path to TLS key file' +complete -c docker -f -n '__fish_docker_no_subcommand' -l tlsverify -d 'Use TLS and verify the remote (daemon: verify client, client: verify daemon)' complete -c docker -f -n '__fish_docker_no_subcommand' -s v -l version -d 'Print version information and quit' # subcommands # attach complete -c docker -f -n '__fish_docker_no_subcommand' -a attach -d 'Attach to a running container' -complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l no-stdin -d 'Do not attach stdin' -complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l sig-proxy -d 'Proxify all received signal to the process (non-TTY mode only)' +complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l no-stdin -d 'Do not attach STDIN' +complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l sig-proxy -d 'Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.' complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -a '(__fish_print_docker_containers running)' -d "Container" # build complete -c docker -f -n '__fish_docker_no_subcommand' -a build -d 'Build an image from a Dockerfile' +complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s f -l file -d "Name of the Dockerfile(Default is 'Dockerfile' at context root)" complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l force-rm -d 'Always remove intermediate containers, even after unsuccessful builds' +complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l no-cache -d 'Do not use cache when building the image' +complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l pull -d 'Always attempt to pull a newer version of the image' complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s q -l quiet -d 'Suppress the verbose output generated by the containers' complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l rm -d 'Remove intermediate containers after a successful build' complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s t -l tag -d 'Repository name (and optionally a tag) to be applied to the resulting image in case of success' # commit complete -c docker -f -n '__fish_docker_no_subcommand' -a commit -d "Create a new image from a container's changes" -complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s a -l author -d 'Author (e.g., "John Hannibal Smith "' +complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s a -l author -d 'Author (e.g., "John Hannibal Smith ")' +complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s m -l message -d 'Commit message' -complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -l run -d 'Config automatically applied when the image is run. (ex: -run=\'{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}\')' +complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s p -l pause -d 'Pause container during commit' complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -a '(__fish_print_docker_containers all)' -d "Container" # cp complete -c docker -f -n '__fish_docker_no_subcommand' -a cp -d "Copy files/folders from a container's filesystem to the host path" +complete -c docker -A -f -n '__fish_seen_subcommand_from cp' -l help -d 'Print usage' # create -complete -c docker -f -n '__fish_docker_no_subcommand' -a run -d 'Run a command in a new container' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to the host interfaces' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s a -l attach -d 'Attach to stdin, stdout or stderr.' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s c -l cpu-shares -d 'CPU shares (relative weight)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cidfile -d 'Write the container ID to the file' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns -d 'Set custom dns servers' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s e -l env -d 'Set environment variables' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l entrypoint -d 'Overwrite the default entrypoint of the image' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l expose -d 'Expose a port from the container without publishing it to your host' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s h -l hostname -d 'Container host name' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactive -d 'Keep stdin open even if not attached' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container (name:alias)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l lxc-conf -d 'Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: , where unit = b, k, m or g)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s n -l networking -d 'Enable networking for this container' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s p -l publish -d "Publish a container's port to the host (format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort) (use 'docker port' to see the actual mapping)" -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l privileged -d 'Give extended privileges to this container' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-tty' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l volumes-from -d 'Mount volumes from the specified container(s)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s w -l workdir -d 'Working directory inside the container' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -a '(__fish_print_docker_images)' -d "Image" - +complete -c docker -f -n '__fish_docker_no_subcommand' -a create -d 'Create a new container' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s a -l attach -d 'Attach to STDIN, STDOUT or STDERR.' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l add-host -d 'Add a custom host-to-IP mapping (host:ip)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s c -l cpu-shares -d 'CPU shares (relative weight)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cap-add -d 'Add Linux capabilities' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cap-drop -d 'Drop Linux capabilities' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cidfile -d 'Write the container ID to the file' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cpuset -d 'CPUs in which to allow execution (0-3, 0,1)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns -d 'Set custom DNS servers' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns-search -d "Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)" +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s e -l env -d 'Set environment variables' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l entrypoint -d 'Overwrite the default ENTRYPOINT of the image' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l env-file -d 'Read in a line delimited file of environment variables' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l expose -d 'Expose a port or a range of ports (e.g. --expose=3300-3310) from the container without publishing it to your host' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s h -l hostname -d 'Container host name' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s i -l interactive -d 'Keep STDIN open even if not attached' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add link to another container in the form of :alias' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: , where unit = b, k, m or g)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: , where unit = b, k, m or g)" +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s p -l publish -d "Publish a container's port to the host" +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l pid -d 'Default is to create a private PID namespace for the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l privileged -d 'Give extended privileges to this container' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l read-only -d "Mount the container's root filesystem as read only" +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l restart -d 'Restart policy to apply when a container exits (no, on-failure[:max-retry], always)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l security-opt -d 'Security Options' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s t -l tty -d 'Allocate a pseudo-TTY' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s u -l user -d 'Username or UID' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l volumes-from -d 'Mount volumes from the specified container(s)' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s w -l workdir -d 'Working directory inside the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from create' -a '(__fish_print_docker_images)' -d "Image" # diff complete -c docker -f -n '__fish_docker_no_subcommand' -a diff -d "Inspect changes on a container's filesystem" +complete -c docker -A -f -n '__fish_seen_subcommand_from diff' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from diff' -a '(__fish_print_docker_containers all)' -d "Container" # events complete -c docker -f -n '__fish_docker_no_subcommand' -a events -d 'Get real time events from the server' -complete -c docker -A -f -n '__fish_seen_subcommand_from events' -l since -d 'Show previously created events and then stream.' +complete -c docker -A -f -n '__fish_seen_subcommand_from events' -s f -l filter -d "Provide filter values (i.e., 'event=stop')" +complete -c docker -A -f -n '__fish_seen_subcommand_from events' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from events' -l since -d 'Show all events created since timestamp' +complete -c docker -A -f -n '__fish_seen_subcommand_from events' -l until -d 'Stream events until this timestamp' + +# exec +complete -c docker -f -n '__fish_docker_no_subcommand' -a exec -d 'Run a command in a running container' +complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -s d -l detach -d 'Detached mode: run command in the background' +complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -s i -l interactive -d 'Keep STDIN open even if not attached' +complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -s t -l tty -d 'Allocate a pseudo-TTY' +complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -a '(__fish_print_docker_containers running)' -d "Container" # export complete -c docker -f -n '__fish_docker_no_subcommand' -a export -d 'Stream the contents of a container as a tar archive' +complete -c docker -A -f -n '__fish_seen_subcommand_from export' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from export' -a '(__fish_print_docker_containers all)' -d "Container" # history complete -c docker -f -n '__fish_docker_no_subcommand' -a history -d 'Show the history of an image' +complete -c docker -A -f -n '__fish_seen_subcommand_from history' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from history' -l no-trunc -d "Don't truncate output" complete -c docker -A -f -n '__fish_seen_subcommand_from history' -s q -l quiet -d 'Only show numeric IDs' complete -c docker -A -f -n '__fish_seen_subcommand_from history' -a '(__fish_print_docker_images)' -d "Image" @@ -136,51 +186,70 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from history' -a '(__fish_pr # images complete -c docker -f -n '__fish_docker_no_subcommand' -a images -d 'List images' complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s a -l all -d 'Show all images (by default filter out the intermediate image layers)' +complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s f -l filter -d "Provide filter values (i.e., 'dangling=true')" +complete -c docker -A -f -n '__fish_seen_subcommand_from images' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from images' -l no-trunc -d "Don't truncate output" complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s q -l quiet -d 'Only show numeric IDs' -complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s t -l tree -d 'Output graph in tree format' -complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s v -l viz -d 'Output graph in graphviz format' complete -c docker -A -f -n '__fish_seen_subcommand_from images' -a '(__fish_print_docker_repositories)' -d "Repository" # import complete -c docker -f -n '__fish_docker_no_subcommand' -a import -d 'Create a new filesystem image from the contents of a tarball' +complete -c docker -A -f -n '__fish_seen_subcommand_from import' -l help -d 'Print usage' # info complete -c docker -f -n '__fish_docker_no_subcommand' -a info -d 'Display system-wide information' # inspect -complete -c docker -f -n '__fish_docker_no_subcommand' -a inspect -d 'Return low-level information on a container' +complete -c docker -f -n '__fish_docker_no_subcommand' -a inspect -d 'Return low-level information on a container or image' complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -s f -l format -d 'Format the output using the given go template.' +complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -a '(__fish_print_docker_images)' -d "Image" complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -a '(__fish_print_docker_containers all)' -d "Container" # kill complete -c docker -f -n '__fish_docker_no_subcommand' -a kill -d 'Kill a running container' +complete -c docker -A -f -n '__fish_seen_subcommand_from kill' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from kill' -s s -l signal -d 'Signal to send to the container' complete -c docker -A -f -n '__fish_seen_subcommand_from kill' -a '(__fish_print_docker_containers running)' -d "Container" # load complete -c docker -f -n '__fish_docker_no_subcommand' -a load -d 'Load an image from a tar archive' +complete -c docker -A -f -n '__fish_seen_subcommand_from load' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from load' -s i -l input -d 'Read from a tar archive file, instead of STDIN' # login -complete -c docker -f -n '__fish_docker_no_subcommand' -a login -d 'Register or Login to the docker registry server' +complete -c docker -f -n '__fish_docker_no_subcommand' -a login -d 'Register or log in to a Docker registry server' complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s e -l email -d 'Email' +complete -c docker -A -f -n '__fish_seen_subcommand_from login' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s p -l password -d 'Password' complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s u -l username -d 'Username' +# logout +complete -c docker -f -n '__fish_docker_no_subcommand' -a logout -d 'Log out from a Docker registry server' + # logs complete -c docker -f -n '__fish_docker_no_subcommand' -a logs -d 'Fetch the logs of a container' complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -s f -l follow -d 'Follow log output' +complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -s t -l timestamps -d 'Show timestamps' +complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -l tail -d 'Output the specified number of lines at the end of logs (defaults to all logs)' complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -a '(__fish_print_docker_containers running)' -d "Container" # port -complete -c docker -f -n '__fish_docker_no_subcommand' -a port -d 'Lookup the public-facing port which is NAT-ed to PRIVATE_PORT' +complete -c docker -f -n '__fish_docker_no_subcommand' -a port -d 'Lookup the public-facing port that is NAT-ed to PRIVATE_PORT' +complete -c docker -A -f -n '__fish_seen_subcommand_from port' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from port' -a '(__fish_print_docker_containers running)' -d "Container" +# pause +complete -c docker -f -n '__fish_docker_no_subcommand' -a pause -d 'Pause all processes within a container' +complete -c docker -A -f -n '__fish_seen_subcommand_from pause' -a '(__fish_print_docker_containers running)' -d "Container" + # ps complete -c docker -f -n '__fish_docker_no_subcommand' -a ps -d 'List containers' complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s a -l all -d 'Show all containers. Only running containers are shown by default.' complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l before -d 'Show only container created before Id or Name, include non-running ones.' +complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s f -l filter -d 'Provide filter values. Valid filters:' +complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s l -l latest -d 'Show only the latest created container, include non-running ones.' complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s n -d 'Show n last created containers, include non-running ones.' complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l no-trunc -d "Don't truncate output" @@ -189,97 +258,137 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s s -l size -d 'Di complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l since -d 'Show only containers created since Id or Name, include non-running ones.' # pull -complete -c docker -f -n '__fish_docker_no_subcommand' -a pull -d 'Pull an image or a repository from the docker registry server' -complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -s t -l tag -d 'Download tagged image in repository' +complete -c docker -f -n '__fish_docker_no_subcommand' -a pull -d 'Pull an image or a repository from a Docker registry server' +complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -s a -l all-tags -d 'Download all tagged images in the repository' +complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -a '(__fish_print_docker_images)' -d "Image" complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -a '(__fish_print_docker_repositories)' -d "Repository" # push -complete -c docker -f -n '__fish_docker_no_subcommand' -a push -d 'Push an image or a repository to the docker registry server' +complete -c docker -f -n '__fish_docker_no_subcommand' -a push -d 'Push an image or a repository to a Docker registry server' +complete -c docker -A -f -n '__fish_seen_subcommand_from push' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from push' -a '(__fish_print_docker_images)' -d "Image" complete -c docker -A -f -n '__fish_seen_subcommand_from push' -a '(__fish_print_docker_repositories)' -d "Repository" +# rename +complete -c docker -f -n '__fish_docker_no_subcommand' -a rename -d 'Rename an existing container' + # restart complete -c docker -f -n '__fish_docker_no_subcommand' -a restart -d 'Restart a running container' -complete -c docker -A -f -n '__fish_seen_subcommand_from restart' -s t -l time -d 'Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10' +complete -c docker -A -f -n '__fish_seen_subcommand_from restart' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from restart' -s t -l time -d 'Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.' complete -c docker -A -f -n '__fish_seen_subcommand_from restart' -a '(__fish_print_docker_containers running)' -d "Container" # rm complete -c docker -f -n '__fish_docker_no_subcommand' -a rm -d 'Remove one or more containers' -complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s f -l force -d 'Force removal of running container' +complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s f -l force -d 'Force the removal of a running container (uses SIGKILL)' +complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s l -l link -d 'Remove the specified link and not the underlying container' -complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s v -l volumes -d 'Remove the volumes associated to the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s v -l volumes -d 'Remove the volumes associated with the container' complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -a '(__fish_print_docker_containers stopped)' -d "Container" # rmi complete -c docker -f -n '__fish_docker_no_subcommand' -a rmi -d 'Remove one or more images' -complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -s f -l force -d 'Force' +complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -s f -l force -d 'Force removal of the image' +complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -l no-prune -d 'Do not delete untagged parents' complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -a '(__fish_print_docker_images)' -d "Image" # run complete -c docker -f -n '__fish_docker_no_subcommand' -a run -d 'Run a command in a new container' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to the host interfaces' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s a -l attach -d 'Attach to stdin, stdout or stderr.' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s a -l attach -d 'Attach to STDIN, STDOUT or STDERR.' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l add-host -d 'Add a custom host-to-IP mapping (host:ip)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s c -l cpu-shares -d 'CPU shares (relative weight)' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cap-add -d 'Add Linux capabilities' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cap-drop -d 'Drop Linux capabilities' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cidfile -d 'Write the container ID to the file' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s d -l detach -d 'Detached mode: Run container in the background, print new container id' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns -d 'Set custom dns servers' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cpuset -d 'CPUs in which to allow execution (0-3, 0,1)' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s d -l detach -d 'Detached mode: run the container in the background and print the new container ID' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns -d 'Set custom DNS servers' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns-search -d "Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)" complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s e -l env -d 'Set environment variables' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l entrypoint -d 'Overwrite the default entrypoint of the image' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l expose -d 'Expose a port from the container without publishing it to your host' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l entrypoint -d 'Overwrite the default ENTRYPOINT of the image' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l env-file -d 'Read in a line delimited file of environment variables' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l expose -d 'Expose a port or a range of ports (e.g. --expose=3300-3310) from the container without publishing it to your host' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s h -l hostname -d 'Container host name' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactive -d 'Keep stdin open even if not attached' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container (name:alias)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l lxc-conf -d 'Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactive -d 'Keep STDIN open even if not attached' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container in the form of :alias' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: , where unit = b, k, m or g)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s n -l networking -d 'Enable networking for this container' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: , where unit = b, k, m or g)" complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s p -l publish -d "Publish a container's port to the host (format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort) (use 'docker port' to see the actual mapping)" +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s p -l publish -d "Publish a container's port to the host" +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l pid -d 'Default is to create a private PID namespace for the container' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l privileged -d 'Give extended privileges to this container' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l read-only -d "Mount the container's root filesystem as read only" +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l restart -d 'Restart policy to apply when a container exits (no, on-failure[:max-retry], always)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l rm -d 'Automatically remove the container when it exits (incompatible with -d)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxify all received signal to the process (non-TTY mode only)' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-tty' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l security-opt -d 'Security Options' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-TTY' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID' -complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)' +complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l volumes-from -d 'Mount volumes from the specified container(s)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s w -l workdir -d 'Working directory inside the container' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -a '(__fish_print_docker_images)' -d "Image" # save complete -c docker -f -n '__fish_docker_no_subcommand' -a save -d 'Save an image to a tar archive' +complete -c docker -A -f -n '__fish_seen_subcommand_from save' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from save' -s o -l output -d 'Write to an file, instead of STDOUT' complete -c docker -A -f -n '__fish_seen_subcommand_from save' -a '(__fish_print_docker_images)' -d "Image" # search -complete -c docker -f -n '__fish_docker_no_subcommand' -a search -d 'Search for an image in the docker index' -complete -c docker -A -f -n '__fish_seen_subcommand_from search' -l no-trunc -d "Don't truncate output" -complete -c docker -A -f -n '__fish_seen_subcommand_from search' -s s -l stars -d 'Only displays with at least xxx stars' +complete -c docker -f -n '__fish_docker_no_subcommand' -a search -d 'Search for an image on the Docker Hub' complete -c docker -A -f -n '__fish_seen_subcommand_from search' -l automated -d 'Only show automated builds' +complete -c docker -A -f -n '__fish_seen_subcommand_from search' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from search' -l no-trunc -d "Don't truncate output" +complete -c docker -A -f -n '__fish_seen_subcommand_from search' -s s -l stars -d 'Only displays with at least x stars' # start complete -c docker -f -n '__fish_docker_no_subcommand' -a start -d 'Start a stopped container' -complete -c docker -A -f -n '__fish_seen_subcommand_from start' -s a -l attach -d "Attach container's stdout/stderr and forward all signals to the process" -complete -c docker -A -f -n '__fish_seen_subcommand_from start' -s i -l interactive -d "Attach container's stdin" +complete -c docker -A -f -n '__fish_seen_subcommand_from start' -s a -l attach -d "Attach container's STDOUT and STDERR and forward all signals to the process" +complete -c docker -A -f -n '__fish_seen_subcommand_from start' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from start' -s i -l interactive -d "Attach container's STDIN" complete -c docker -A -f -n '__fish_seen_subcommand_from start' -a '(__fish_print_docker_containers stopped)' -d "Container" +# stats +complete -c docker -f -n '__fish_docker_no_subcommand' -a stats -d "Display a live stream of one or more containers' resource usage statistics" +complete -c docker -A -f -n '__fish_seen_subcommand_from stats' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from stats' -a '(__fish_print_docker_containers running)' -d "Container" + # stop complete -c docker -f -n '__fish_docker_no_subcommand' -a stop -d 'Stop a running container' -complete -c docker -A -f -n '__fish_seen_subcommand_from stop' -s t -l time -d 'Number of seconds to wait for the container to stop before killing it.' +complete -c docker -A -f -n '__fish_seen_subcommand_from stop' -l help -d 'Print usage' +complete -c docker -A -f -n '__fish_seen_subcommand_from stop' -s t -l time -d 'Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.' complete -c docker -A -f -n '__fish_seen_subcommand_from stop' -a '(__fish_print_docker_containers running)' -d "Container" # tag complete -c docker -f -n '__fish_docker_no_subcommand' -a tag -d 'Tag an image into a repository' complete -c docker -A -f -n '__fish_seen_subcommand_from tag' -s f -l force -d 'Force' -complete -c docker -A -f -n '__fish_seen_subcommand_from tag' -a '(__fish_print_docker_images)' -d "Image" +complete -c docker -A -f -n '__fish_seen_subcommand_from tag' -l help -d 'Print usage' # top complete -c docker -f -n '__fish_docker_no_subcommand' -a top -d 'Lookup the running processes of a container' +complete -c docker -A -f -n '__fish_seen_subcommand_from top' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from top' -a '(__fish_print_docker_containers running)' -d "Container" +# unpause +complete -c docker -f -n '__fish_docker_no_subcommand' -a unpause -d 'Unpause a paused container' +complete -c docker -A -f -n '__fish_seen_subcommand_from unpause' -a '(__fish_print_docker_containers running)' -d "Container" + # version -complete -c docker -f -n '__fish_docker_no_subcommand' -a version -d 'Show the docker version information' +complete -c docker -f -n '__fish_docker_no_subcommand' -a version -d 'Show the Docker version information' # wait complete -c docker -f -n '__fish_docker_no_subcommand' -a wait -d 'Block until a container stops, then print its exit code' +complete -c docker -A -f -n '__fish_seen_subcommand_from wait' -l help -d 'Print usage' complete -c docker -A -f -n '__fish_seen_subcommand_from wait' -a '(__fish_print_docker_containers running)' -d "Container" diff --git a/contrib/init/systemd/docker.service b/contrib/init/systemd/docker.service index 83c810d13..9738ca1ad 100644 --- a/contrib/init/systemd/docker.service +++ b/contrib/init/systemd/docker.service @@ -6,6 +6,7 @@ Requires=docker.socket [Service] ExecStart=/usr/bin/docker -d -H fd:// +MountFlags=slave LimitNOFILE=1048576 LimitNPROC=1048576 diff --git a/contrib/init/sysvinit-redhat/docker b/contrib/init/sysvinit-redhat/docker index eadf02c75..1994d6b31 100755 --- a/contrib/init/sysvinit-redhat/docker +++ b/contrib/init/sysvinit-redhat/docker @@ -23,6 +23,7 @@ . /etc/rc.d/init.d/functions prog="docker" +unshare=/usr/bin/unshare exec="/usr/bin/$prog" pidfile="/var/run/$prog.pid" lockfile="/var/lock/subsys/$prog" @@ -46,7 +47,7 @@ start() { prestart printf "Starting $prog:\t" echo "\n$(date)\n" >> $logfile - $exec -d $other_args &>> $logfile & + "$unshare" -m -- $exec -d $other_args &>> $logfile & pid=$! touch $lockfile # wait up to 10 seconds for the pidfile to exist. see diff --git a/contrib/init/upstart/docker.conf b/contrib/init/upstart/docker.conf index 5a3f88887..f9930bd39 100644 --- a/contrib/init/upstart/docker.conf +++ b/contrib/init/upstart/docker.conf @@ -39,3 +39,20 @@ script fi exec "$DOCKER" -d $DOCKER_OPTS end script + +# Don't emit "started" event until docker.sock is ready. +# See https://github.com/docker/docker/issues/6647 +post-start script + DOCKER_OPTS= + if [ -f /etc/default/$UPSTART_JOB ]; then + . /etc/default/$UPSTART_JOB + fi + if ! printf "%s" "$DOCKER_OPTS" | grep -qE -e '-H|--host'; then + while ! [ -e /var/run/docker.sock ]; do + initctl status $UPSTART_JOB | grep -q "stop/" && exit 1 + echo "Waiting for /var/run/docker.sock" + sleep 0.1 + done + echo "/var/run/docker.sock is up" + fi +end script diff --git a/contrib/mkimage-arch.sh b/contrib/mkimage-arch.sh index 35cb1617d..382e2f780 100755 --- a/contrib/mkimage-arch.sh +++ b/contrib/mkimage-arch.sh @@ -18,7 +18,32 @@ ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/rootfs-archlinux-XXXXXXXXXX) chmod 755 $ROOTFS # packages to ignore for space savings -PKGIGNORE=linux,jfsutils,lvm2,cryptsetup,groff,man-db,man-pages,mdadm,pciutils,pcmciautils,reiserfsprogs,s-nail,xfsprogs +PKGIGNORE=( + cryptsetup + device-mapper + dhcpcd + iproute2 + jfsutils + linux + lvm2 + man-db + man-pages + mdadm + nano + netctl + openresolv + pciutils + pcmciautils + reiserfsprogs + s-nail + systemd-sysvcompat + usbutils + vi + xfsprogs +) +IFS=',' +PKGIGNORE="${PKGIGNORE[*]}" +unset IFS expect < $ROOTFS/etc/locale.gen arch-chroot $ROOTFS locale-gen diff --git a/contrib/mkimage/debootstrap b/contrib/mkimage/debootstrap index 65f154aa9..c7a2b6683 100755 --- a/contrib/mkimage/debootstrap +++ b/contrib/mkimage/debootstrap @@ -49,6 +49,11 @@ chmod +x "$rootfsDir/usr/sbin/policy-rc.d" # shrink a little, since apt makes us cache-fat (wheezy: ~157.5MB vs ~120MB) ( set -x; chroot "$rootfsDir" apt-get clean ) +# this file is one APT creates to make sure we don't "autoremove" our currently +# in-use kernel, which doesn't really apply to debootstraps/Docker images that +# don't even have kernels installed +rm -f "$rootfsDir/etc/apt/apt.conf.d/01autoremove-kernels" + # Ubuntu 10.04 sucks... :) if strings "$rootfsDir/usr/bin/dpkg" | grep -q unsafe-io; then # force dpkg not to call sync() after package extraction (speeding up installs) diff --git a/contrib/nuke-graph-directory.sh b/contrib/nuke-graph-directory.sh index f44c45a17..8d12a9d64 100755 --- a/contrib/nuke-graph-directory.sh +++ b/contrib/nuke-graph-directory.sh @@ -50,9 +50,10 @@ for mount in $(awk '{ print $5 }' /proc/self/mountinfo); do done # now, let's go destroy individual btrfs subvolumes, if any exist -if command -v btrfs &> /dev/null; then +if command -v btrfs > /dev/null 2>&1; then root="$(df "$dir" | awk 'NR>1 { print $NF }')" - for subvol in $(btrfs subvolume list -o "$root" 2>/dev/null | awk -F' path ' '{ print $2 }'); do + root="${root#/}" # if root is "/", we want it to become "" + for subvol in $(btrfs subvolume list -o "$root/" 2>/dev/null | awk -F' path ' '{ print $2 }' | sort -r); do subvolDir="$root/$subvol" if dir_in_dir "$subvolDir" "$dir"; then ( set -x; btrfs subvolume delete "$subvolDir" ) diff --git a/contrib/syntax/vim/README.md b/contrib/syntax/vim/README.md index b78246617..5aa9bd825 100644 --- a/contrib/syntax/vim/README.md +++ b/contrib/syntax/vim/README.md @@ -5,8 +5,11 @@ Syntax highlighting for Dockerfiles Installation ------------ +With [pathogen](https://github.com/tpope/vim-pathogen), the usual way... -Via pathogen, the usual way... +With [Vundle](https://github.com/gmarik/Vundle.vim) + + Plugin 'docker/docker' , {'rtp': '/contrib/syntax/vim/'} Features -------- diff --git a/daemon/attach.go b/daemon/attach.go index 599b27247..881b021e1 100644 --- a/daemon/attach.go +++ b/daemon/attach.go @@ -4,11 +4,11 @@ import ( "encoding/json" "io" "os" + "sync" "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/engine" - "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/jsonlog" "github.com/docker/docker/pkg/promise" "github.com/docker/docker/utils" @@ -114,137 +114,101 @@ func (daemon *Daemon) ContainerAttach(job *engine.Job) engine.Status { func (daemon *Daemon) attach(streamConfig *StreamConfig, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error { var ( cStdout, cStderr io.ReadCloser - nJobs int + cStdin io.WriteCloser + wg sync.WaitGroup errors = make(chan error, 3) ) - // Connect stdin of container to the http conn. if stdin != nil && openStdin { - nJobs++ - // Get the stdin pipe. - if cStdin, err := streamConfig.StdinPipe(); err != nil { - errors <- err - } else { - go func() { - log.Debugf("attach: stdin: begin") - defer log.Debugf("attach: stdin: end") - if stdinOnce && !tty { - defer cStdin.Close() - } else { - // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr - defer func() { - if cStdout != nil { - cStdout.Close() - } - if cStderr != nil { - cStderr.Close() - } - }() - } - if tty { - _, err = utils.CopyEscapable(cStdin, stdin) - } else { - _, err = io.Copy(cStdin, stdin) + cStdin = streamConfig.StdinPipe() + wg.Add(1) + } - } - if err == io.ErrClosedPipe { - err = nil - } - if err != nil { - log.Errorf("attach: stdin: %s", err) - } - errors <- err - }() - } - } if stdout != nil { - nJobs++ - // Get a reader end of a pipe that is attached as stdout to the container. - if p, err := streamConfig.StdoutPipe(); err != nil { - errors <- err - } else { - cStdout = p - go func() { - log.Debugf("attach: stdout: begin") - defer log.Debugf("attach: stdout: end") - // If we are in StdinOnce mode, then close stdin - if stdinOnce && stdin != nil { - defer stdin.Close() - } - _, err := io.Copy(stdout, cStdout) - if err == io.ErrClosedPipe { - err = nil - } - if err != nil { - log.Errorf("attach: stdout: %s", err) - } - errors <- err - }() - } - } else { - // Point stdout of container to a no-op writer. - go func() { - if cStdout, err := streamConfig.StdoutPipe(); err != nil { - log.Errorf("attach: stdout pipe: %s", err) - } else { - io.Copy(&ioutils.NopWriter{}, cStdout) - } - }() + cStdout = streamConfig.StdoutPipe() + wg.Add(1) } + if stderr != nil { - nJobs++ - if p, err := streamConfig.StderrPipe(); err != nil { - errors <- err - } else { - cStderr = p - go func() { - log.Debugf("attach: stderr: begin") - defer log.Debugf("attach: stderr: end") - // If we are in StdinOnce mode, then close stdin - // Why are we closing stdin here and above while handling stdout? - if stdinOnce && stdin != nil { - defer stdin.Close() - } - _, err := io.Copy(stderr, cStderr) - if err == io.ErrClosedPipe { - err = nil - } - if err != nil { - log.Errorf("attach: stderr: %s", err) - } - errors <- err - }() - } - } else { - // Point stderr at a no-op writer. - go func() { - if cStderr, err := streamConfig.StderrPipe(); err != nil { - log.Errorf("attach: stdout pipe: %s", err) - } else { - io.Copy(&ioutils.NopWriter{}, cStderr) - } - }() + cStderr = streamConfig.StderrPipe() + wg.Add(1) } + // Connect stdin of container to the http conn. + go func() { + if stdin == nil || !openStdin { + return + } + log.Debugf("attach: stdin: begin") + defer func() { + if stdinOnce && !tty { + cStdin.Close() + } else { + // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr + if cStdout != nil { + cStdout.Close() + } + if cStderr != nil { + cStderr.Close() + } + } + wg.Done() + log.Debugf("attach: stdin: end") + }() + + var err error + if tty { + _, err = utils.CopyEscapable(cStdin, stdin) + } else { + _, err = io.Copy(cStdin, stdin) + + } + if err == io.ErrClosedPipe { + err = nil + } + if err != nil { + log.Errorf("attach: stdin: %s", err) + errors <- err + return + } + }() + + attachStream := func(name string, stream io.Writer, streamPipe io.ReadCloser) { + if stream == nil { + return + } + defer func() { + // Make sure stdin gets closed + if stdin != nil { + stdin.Close() + } + streamPipe.Close() + wg.Done() + log.Debugf("attach: %s: end", name) + }() + + log.Debugf("attach: %s: begin", name) + _, err := io.Copy(stream, streamPipe) + if err == io.ErrClosedPipe { + err = nil + } + if err != nil { + log.Errorf("attach: %s: %v", name, err) + errors <- err + } + } + + go attachStream("stdout", stdout, cStdout) + go attachStream("stderr", stderr, cStderr) + return promise.Go(func() error { - defer func() { - if cStdout != nil { - cStdout.Close() - } - if cStderr != nil { - cStderr.Close() - } - }() - - for i := 0; i < nJobs; i++ { - log.Debugf("attach: waiting for job %d/%d", i+1, nJobs) - if err := <-errors; err != nil { - log.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err) + wg.Wait() + close(errors) + for err := range errors { + if err != nil { return err } - log.Debugf("attach: job %d completed successfully", i+1) } - log.Debugf("attach: all jobs completed successfully") return nil }) } diff --git a/daemon/commit.go b/daemon/commit.go index 950925ade..06d0465ad 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -59,17 +59,17 @@ func (daemon *Daemon) Commit(container *Container, repository, tag, comment, aut // Create a new image from the container's base layers + a new layer from container changes var ( - containerID, containerImage string - containerConfig *runconfig.Config + containerID, parentImageID string + containerConfig *runconfig.Config ) if container != nil { containerID = container.ID - containerImage = container.Image + parentImageID = container.ImageID containerConfig = container.Config } - img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config) + img, err := daemon.graph.Create(rwTar, containerID, parentImageID, comment, author, containerConfig, config) if err != nil { return nil, err } diff --git a/daemon/config.go b/daemon/config.go index 4d9041e89..99e5ce4c8 100644 --- a/daemon/config.go +++ b/daemon/config.go @@ -23,7 +23,7 @@ type Config struct { AutoRestart bool Dns []string DnsSearch []string - Mirrors []string + EnableIPv6 bool EnableIptables bool EnableIpForward bool EnableIpMasq bool @@ -31,7 +31,7 @@ type Config struct { BridgeIface string BridgeIP string FixedCIDR string - InsecureRegistries []string + FixedCIDRv6 string InterContainerCommunication bool GraphDriver string GraphOptions []string @@ -53,12 +53,13 @@ func (config *Config) InstallFlags() { flag.StringVar(&config.Root, []string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the Docker runtime") flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run") flag.BoolVar(&config.EnableIptables, []string{"#iptables", "-iptables"}, true, "Enable Docker's addition of iptables rules") - flag.BoolVar(&config.EnableIpForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward") + flag.BoolVar(&config.EnableIpForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward and IPv6 forwarding if --fixed-cidr-v6 is defined. IPv6 forwarding may interfere with your existing IPv6 configuration when using Router Advertisement.") flag.BoolVar(&config.EnableIpMasq, []string{"-ip-masq"}, true, "Enable IP masquerading for bridge's IP range") + flag.BoolVar(&config.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking") flag.StringVar(&config.BridgeIP, []string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b") flag.StringVar(&config.BridgeIface, []string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking") - flag.StringVar(&config.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs (ex: 10.20.0.0/16)\nthis subnet must be nested in the bridge subnet (which is defined by -b or --bip)") - opts.ListVar(&config.InsecureRegistries, []string{"-insecure-registry"}, "Enable insecure communication with specified registries (no certificate verification for HTTPS and enable HTTP fallback) (e.g., localhost:5000 or 10.20.0.0/16)") + flag.StringVar(&config.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs (e.g. 10.20.0.0/16)\nthis subnet must be nested in the bridge subnet (which is defined by -b or --bip)") + flag.StringVar(&config.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs (e.g.: 2001:a02b/48)") flag.BoolVar(&config.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Allow unrestricted inter-container and Docker daemon host communication") flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver") flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver") @@ -69,16 +70,7 @@ func (config *Config) InstallFlags() { // FIXME: why the inconsistency between "hosts" and "sockets"? opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers") opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains") - opts.MirrorListVar(&config.Mirrors, []string{"-registry-mirror"}, "Specify a preferred Docker registry mirror") opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon (displayed in `docker info`)") - - // Localhost is by default considered as an insecure registry - // This is a stop-gap for people who are running a private registry on localhost (especially on Boot2docker). - // - // TODO: should we deprecate this once it is easier for people to set up a TLS registry or change - // daemon flags on boot2docker? - // If so, do not forget to check the TODO in TestIsSecure - config.InsecureRegistries = append(config.InsecureRegistries, "127.0.0.0/8") } func getDefaultNetworkMtu() int { diff --git a/daemon/container.go b/daemon/container.go index 45658c583..c1c215ffe 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -62,8 +62,8 @@ type Container struct { Path string Args []string - Config *runconfig.Config - Image string + Config *runconfig.Config + ImageID string `json:"Image"` NetworkSettings *NetworkSettings @@ -81,6 +81,7 @@ type Container struct { MountLabel, ProcessLabel string AppArmorProfile string RestartCount int + UpdateDns bool // Maps container paths to volume paths. The key in this is the path to which // the volume is being mounted inside the container. Value is the path of the @@ -91,9 +92,10 @@ type Container struct { VolumesRW map[string]bool hostConfig *runconfig.HostConfig - activeLinks map[string]*links.Link - monitor *containerMonitor - execCommands *execStore + activeLinks map[string]*links.Link + monitor *containerMonitor + execCommands *execStore + AppliedVolumesFrom map[string]struct{} } func (container *Container) FromDisk() error { @@ -186,7 +188,7 @@ func (container *Container) WriteHostConfig() error { func (container *Container) LogEvent(action string) { d := container.daemon - if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.Image)).Run(); err != nil { + if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.ImageID)).Run(); err != nil { log.Errorf("Error logging event %s for %s: %s", action, container.ID, err) } } @@ -216,11 +218,15 @@ func populateCommand(c *Container, env []string) error { if !c.Config.NetworkDisabled { network := c.NetworkSettings en.Interface = &execdriver.NetworkInterface{ - Gateway: network.Gateway, - Bridge: network.Bridge, - IPAddress: network.IPAddress, - IPPrefixLen: network.IPPrefixLen, - MacAddress: network.MacAddress, + Gateway: network.Gateway, + Bridge: network.Bridge, + IPAddress: network.IPAddress, + IPPrefixLen: network.IPPrefixLen, + MacAddress: network.MacAddress, + LinkLocalIPv6Address: network.LinkLocalIPv6Address, + GlobalIPv6Address: network.GlobalIPv6Address, + GlobalIPv6PrefixLen: network.GlobalIPv6PrefixLen, + IPv6Gateway: network.IPv6Gateway, } } case "container": @@ -245,6 +251,9 @@ func populateCommand(c *Container, env []string) error { ipc.HostIpc = c.hostConfig.IpcMode.IsHost() } + pid := &execdriver.Pid{} + pid.HostPid = c.hostConfig.PidMode.IsHost() + // Build lists of devices allowed and created within the container. userSpecifiedDevices := make([]*devices.Device, len(c.hostConfig.Devices)) for i, deviceMapping := range c.hostConfig.Devices { @@ -286,10 +295,12 @@ func populateCommand(c *Container, env []string) error { c.command = &execdriver.Command{ ID: c.ID, Rootfs: c.RootfsPath(), + ReadonlyRootfs: c.hostConfig.ReadonlyRootfs, InitPath: "/.dockerinit", WorkingDir: c.Config.WorkingDir, Network: en, Ipc: ipc, + Pid: pid, Resources: resources, AllowedDevices: allowedDevices, AutoCreatedDevices: autoCreatedDevices, @@ -370,10 +381,7 @@ func (container *Container) Run() error { } func (container *Container) Output() (output []byte, err error) { - pipe, err := container.StdoutPipe() - if err != nil { - return nil, err - } + pipe := container.StdoutPipe() defer pipe.Close() if err := container.Start(); err != nil { return nil, err @@ -391,20 +399,20 @@ func (container *Container) Output() (output []byte, err error) { // copied and delivered to all StdoutPipe and StderrPipe consumers, using // a kind of "broadcaster". -func (streamConfig *StreamConfig) StdinPipe() (io.WriteCloser, error) { - return streamConfig.stdinPipe, nil +func (streamConfig *StreamConfig) StdinPipe() io.WriteCloser { + return streamConfig.stdinPipe } -func (streamConfig *StreamConfig) StdoutPipe() (io.ReadCloser, error) { +func (streamConfig *StreamConfig) StdoutPipe() io.ReadCloser { reader, writer := io.Pipe() streamConfig.stdout.AddWriter(writer, "") - return ioutils.NewBufReader(reader), nil + return ioutils.NewBufReader(reader) } -func (streamConfig *StreamConfig) StderrPipe() (io.ReadCloser, error) { +func (streamConfig *StreamConfig) StderrPipe() io.ReadCloser { reader, writer := io.Pipe() streamConfig.stderr.AddWriter(writer, "") - return ioutils.NewBufReader(reader), nil + return ioutils.NewBufReader(reader) } func (streamConfig *StreamConfig) StdoutLogPipe() io.ReadCloser { @@ -542,12 +550,17 @@ func (container *Container) AllocateNetwork() error { container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen") container.NetworkSettings.MacAddress = env.Get("MacAddress") container.NetworkSettings.Gateway = env.Get("Gateway") + container.NetworkSettings.LinkLocalIPv6Address = env.Get("LinkLocalIPv6") + container.NetworkSettings.LinkLocalIPv6PrefixLen = 64 + container.NetworkSettings.GlobalIPv6Address = env.Get("GlobalIPv6") + container.NetworkSettings.GlobalIPv6PrefixLen = env.GetInt("GlobalIPv6PrefixLen") + container.NetworkSettings.IPv6Gateway = env.Get("IPv6Gateway") return nil } func (container *Container) ReleaseNetwork() { - if container.Config.NetworkDisabled { + if container.Config.NetworkDisabled || !container.hostConfig.NetworkMode.IsPrivate() { return } eng := container.daemon.eng @@ -786,7 +799,7 @@ func (container *Container) GetImage() (*image.Image, error) { if container.daemon == nil { return nil, fmt.Errorf("Can't get image of unregistered container") } - return container.daemon.graph.Get(container.Image) + return container.daemon.graph.Get(container.ImageID) } func (container *Container) Unmount() error { @@ -891,8 +904,8 @@ func (container *Container) Copy(resource string) (io.ReadCloser, error) { } archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ - Compression: archive.Uncompressed, - Includes: filter, + Compression: archive.Uncompressed, + IncludeFiles: filter, }) if err != nil { container.Unmount() @@ -945,6 +958,29 @@ func (container *Container) DisableLink(name string) { func (container *Container) setupContainerDns() error { if container.ResolvConfPath != "" { + // check if this is an existing container that needs DNS update: + if container.UpdateDns { + // read the host's resolv.conf, get the hash and call updateResolvConf + log.Debugf("Check container (%s) for update to resolv.conf - UpdateDns flag was set", container.ID) + latestResolvConf, latestHash := resolvconf.GetLastModified() + + // clean container resolv.conf re: localhost nameservers and IPv6 NS (if IPv6 disabled) + updatedResolvConf, modified := resolvconf.FilterResolvDns(latestResolvConf, container.daemon.config.EnableIPv6) + if modified { + // changes have occurred during resolv.conf localhost cleanup: generate an updated hash + newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf)) + if err != nil { + return err + } + latestHash = newHash + } + + if err := container.updateResolvConf(updatedResolvConf, latestHash); err != nil { + return err + } + // successful update of the restarting container; set the flag off + container.UpdateDns = false + } return nil } @@ -982,32 +1018,106 @@ func (container *Container) setupContainerDns() error { return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch) } - // replace any localhost/127.* nameservers - resolvConf = utils.RemoveLocalDns(resolvConf) - // if the resulting resolvConf is empty, use DefaultDns - if !bytes.Contains(resolvConf, []byte("nameserver")) { - log.Infof("No non localhost DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v", DefaultDns) - // prefix the default dns options with nameserver - resolvConf = append(resolvConf, []byte("\nnameserver "+strings.Join(DefaultDns, "\nnameserver "))...) - } + // replace any localhost/127.*, and remove IPv6 nameservers if IPv6 disabled in daemon + resolvConf, _ = resolvconf.FilterResolvDns(resolvConf, daemon.config.EnableIPv6) + } + //get a sha256 hash of the resolv conf at this point so we can check + //for changes when the host resolv.conf changes (e.g. network update) + resolvHash, err := utils.HashData(bytes.NewReader(resolvConf)) + if err != nil { + return err + } + resolvHashFile := container.ResolvConfPath + ".hash" + if err = ioutil.WriteFile(resolvHashFile, []byte(resolvHash), 0644); err != nil { + return err } return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644) } -func (container *Container) updateParentsHosts() error { - parents, err := container.daemon.Parents(container.Name) +// called when the host's resolv.conf changes to check whether container's resolv.conf +// is unchanged by the container "user" since container start: if unchanged, the +// container's resolv.conf will be updated to match the host's new resolv.conf +func (container *Container) updateResolvConf(updatedResolvConf []byte, newResolvHash string) error { + + if container.ResolvConfPath == "" { + return nil + } + if container.Running { + //set a marker in the hostConfig to update on next start/restart + container.UpdateDns = true + return nil + } + + resolvHashFile := container.ResolvConfPath + ".hash" + + //read the container's current resolv.conf and compute the hash + resolvBytes, err := ioutil.ReadFile(container.ResolvConfPath) if err != nil { return err } - for _, cid := range parents { - if cid == "0" { - continue + curHash, err := utils.HashData(bytes.NewReader(resolvBytes)) + if err != nil { + return err + } + + //read the hash from the last time we wrote resolv.conf in the container + hashBytes, err := ioutil.ReadFile(resolvHashFile) + if err != nil { + if !os.IsNotExist(err) { + return err + } + // backwards compat: if no hash file exists, this container pre-existed from + // a Docker daemon that didn't contain this update feature. Given we can't know + // if the user has modified the resolv.conf since container start time, safer + // to just never update the container's resolv.conf during it's lifetime which + // we can control by setting hashBytes to an empty string + hashBytes = []byte("") + } + + //if the user has not modified the resolv.conf of the container since we wrote it last + //we will replace it with the updated resolv.conf from the host + if string(hashBytes) == curHash { + log.Debugf("replacing %q with updated host resolv.conf", container.ResolvConfPath) + + // for atomic updates to these files, use temporary files with os.Rename: + dir := path.Dir(container.ResolvConfPath) + tmpHashFile, err := ioutil.TempFile(dir, "hash") + if err != nil { + return err + } + tmpResolvFile, err := ioutil.TempFile(dir, "resolv") + if err != nil { + return err } - c := container.daemon.Get(cid) + // write the updates to the temp files + if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newResolvHash), 0644); err != nil { + return err + } + if err = ioutil.WriteFile(tmpResolvFile.Name(), updatedResolvConf, 0644); err != nil { + return err + } + + // rename the temp files for atomic replace + if err = os.Rename(tmpHashFile.Name(), resolvHashFile); err != nil { + return err + } + return os.Rename(tmpResolvFile.Name(), container.ResolvConfPath) + } + return nil +} + +func (container *Container) updateParentsHosts() error { + refs := container.daemon.ContainerGraph().RefPaths(container.ID) + for _, ref := range refs { + if ref.ParentID == "0" { + continue + } + c := container.daemon.Get(ref.ParentID) if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() { - if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, container.Name[1:]); err != nil { - log.Errorf("Failed to update /etc/hosts in parent container: %v", err) + log.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress) + if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, ref.Name); err != nil { + log.Errorf("Failed to update /etc/hosts in parent container %s for alias %s: %v", c.ID, ref.Name, err) } } } @@ -1301,3 +1411,7 @@ func (container *Container) getNetworkedContainer() (*Container, error) { return nil, fmt.Errorf("network mode not set to container") } } + +func (container *Container) Stats() (*execdriver.ResourceStats, error) { + return container.daemon.Stats(container) +} diff --git a/daemon/create.go b/daemon/create.go index f9d986491..785b0cc34 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -5,6 +5,7 @@ import ( "github.com/docker/docker/engine" "github.com/docker/docker/graph" + "github.com/docker/docker/image" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/runconfig" "github.com/docker/libcontainer/label" @@ -29,6 +30,9 @@ func (daemon *Daemon) ContainerCreate(job *engine.Job) engine.Status { job.Errorf("Your kernel does not support swap limit capabilities. Limitation discarded.\n") config.MemorySwap = -1 } + if config.Memory > 0 && config.MemorySwap > 0 && config.MemorySwap < config.Memory { + return job.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.\n") + } var hostConfig *runconfig.HostConfig if job.EnvExists("HostConfig") { @@ -68,31 +72,38 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos var ( container *Container warnings []string + img *image.Image + imgID string + err error ) - img, err := daemon.repositories.LookupImage(config.Image) - if err != nil { - return nil, nil, err - } - if err := img.CheckDepth(); err != nil { - return nil, nil, err + if config.Image != "" { + img, err = daemon.repositories.LookupImage(config.Image) + if err != nil { + return nil, nil, err + } + if err = img.CheckDepth(); err != nil { + return nil, nil, err + } + imgID = img.ID } + if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil { return nil, nil, err } if hostConfig != nil && hostConfig.SecurityOpt == nil { - hostConfig.SecurityOpt, err = daemon.GenerateSecurityOpt(hostConfig.IpcMode) + hostConfig.SecurityOpt, err = daemon.GenerateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode) if err != nil { return nil, nil, err } } - if container, err = daemon.newContainer(name, config, img); err != nil { + if container, err = daemon.newContainer(name, config, imgID); err != nil { return nil, nil, err } if err := daemon.Register(container); err != nil { return nil, nil, err } - if err := daemon.createRootfs(container, img); err != nil { + if err := daemon.createRootfs(container); err != nil { return nil, nil, err } if hostConfig != nil { @@ -113,8 +124,8 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos return container, warnings, nil } -func (daemon *Daemon) GenerateSecurityOpt(ipcMode runconfig.IpcMode) ([]string, error) { - if ipcMode.IsHost() { +func (daemon *Daemon) GenerateSecurityOpt(ipcMode runconfig.IpcMode, pidMode runconfig.PidMode) ([]string, error) { + if ipcMode.IsHost() || pidMode.IsHost() { return label.DisableSecOpt(), nil } if ipcContainer := ipcMode.Container(); ipcContainer != "" { diff --git a/daemon/daemon.go b/daemon/daemon.go index a2e6a79bd..c9a730b1f 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -1,11 +1,13 @@ package daemon import ( + "bytes" "fmt" "io" "io/ioutil" "os" "path" + "path/filepath" "regexp" "runtime" "strings" @@ -32,6 +34,7 @@ import ( "github.com/docker/docker/pkg/graphdb" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/namesgenerator" + "github.com/docker/docker/pkg/networkfs/resolvconf" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/sysinfo" @@ -40,10 +43,11 @@ import ( "github.com/docker/docker/trust" "github.com/docker/docker/utils" "github.com/docker/docker/volumes" + + "github.com/go-fsnotify/fsnotify" ) var ( - DefaultDns = []string{"8.8.8.8", "8.8.4.4"} validContainerNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]` validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`) ) @@ -100,6 +104,7 @@ type Daemon struct { driver graphdriver.Driver execDriver execdriver.Driver trustStore *trust.TrustStore + statsCollector *statsCollector } // Install installs daemon capabilities to eng. @@ -110,7 +115,9 @@ func (daemon *Daemon) Install(eng *engine.Engine) error { "commit": daemon.ContainerCommit, "container_changes": daemon.ContainerChanges, "container_copy": daemon.ContainerCopy, + "container_rename": daemon.ContainerRename, "container_inspect": daemon.ContainerInspect, + "container_stats": daemon.ContainerStats, "containers": daemon.Containers, "create": daemon.ContainerCreate, "rm": daemon.ContainerRm, @@ -151,12 +158,18 @@ func (daemon *Daemon) Install(eng *engine.Engine) error { // Get looks for a container by the specified ID or name, and returns it. // If the container is not found, or if an error occurs, nil is returned. func (daemon *Daemon) Get(name string) *Container { - if id, err := daemon.idIndex.Get(name); err == nil { + id, err := daemon.idIndex.Get(name) + if err == nil { return daemon.containers.Get(id) } + if c, _ := daemon.GetByName(name); c != nil { return c } + + if err == truncindex.ErrDuplicateID { + log.Errorf("Short ID %s is ambiguous: please retry with more characters or use the full ID.\n", name) + } return nil } @@ -227,6 +240,8 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err // we'll waste time if we update it for every container daemon.idIndex.Add(container.ID) + container.registerVolumes() + // FIXME: if the container is supposed to be running but is not, auto restart it? // if so, then we need to restart monitor and init a new lock // If the container is supposed to be running, make sure of it @@ -234,7 +249,7 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err log.Debugf("killing old running container %s", container.ID) existingPid := container.Pid - container.SetStopped(&execdriver.ExitStatus{0, false}) + container.SetStopped(&execdriver.ExitStatus{ExitCode: 0}) // We only have to handle this for lxc because the other drivers will ensure that // no processes are left when docker dies @@ -266,7 +281,7 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err log.Debugf("Marking as stopped") - container.SetStopped(&execdriver.ExitStatus{-127, false}) + container.SetStopped(&execdriver.ExitStatus{ExitCode: -127}) if err := container.ToDisk(); err != nil { return err } @@ -390,10 +405,6 @@ func (daemon *Daemon) restore() error { } } - for _, c := range registeredContainers { - c.registerVolumes() - } - if !debug { fmt.Println() log.Infof("Loading containers: done.") @@ -402,6 +413,60 @@ func (daemon *Daemon) restore() error { return nil } +// set up the watch on the host's /etc/resolv.conf so that we can update container's +// live resolv.conf when the network changes on the host +func (daemon *Daemon) setupResolvconfWatcher() error { + + watcher, err := fsnotify.NewWatcher() + if err != nil { + return err + } + + //this goroutine listens for the events on the watch we add + //on the resolv.conf file on the host + go func() { + for { + select { + case event := <-watcher.Events: + if event.Op&fsnotify.Write == fsnotify.Write { + // verify a real change happened before we go further--a file write may have happened + // without an actual change to the file + updatedResolvConf, newResolvConfHash, err := resolvconf.GetIfChanged() + if err != nil { + log.Debugf("Error retrieving updated host resolv.conf: %v", err) + } else if updatedResolvConf != nil { + // because the new host resolv.conf might have localhost nameservers.. + updatedResolvConf, modified := resolvconf.FilterResolvDns(updatedResolvConf, daemon.config.EnableIPv6) + if modified { + // changes have occurred during localhost cleanup: generate an updated hash + newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf)) + if err != nil { + log.Debugf("Error generating hash of new resolv.conf: %v", err) + } else { + newResolvConfHash = newHash + } + } + log.Debugf("host network resolv.conf changed--walking container list for updates") + contList := daemon.containers.List() + for _, container := range contList { + if err := container.updateResolvConf(updatedResolvConf, newResolvConfHash); err != nil { + log.Debugf("Error on resolv.conf update check for container ID: %s: %v", container.ID, err) + } + } + } + } + case err := <-watcher.Errors: + log.Debugf("host resolv.conf notify error: %v", err) + } + } + }() + + if err := watcher.Add("/etc/resolv.conf"); err != nil { + return err + } + return nil +} + func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool { if config != nil { if config.PortSpecs != nil { @@ -417,10 +482,10 @@ func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool { func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) { warnings := []string{} - if daemon.checkDeprecatedExpose(img.Config) || daemon.checkDeprecatedExpose(config) { + if (img != nil && daemon.checkDeprecatedExpose(img.Config)) || daemon.checkDeprecatedExpose(config) { warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.") } - if img.Config != nil { + if img != nil && img.Config != nil { if err := runconfig.Merge(config, img.Config); err != nil { return nil, err } @@ -478,8 +543,8 @@ func (daemon *Daemon) reserveName(id, name string) (string, error) { } else { nameAsKnownByUser := strings.TrimPrefix(name, "/") return "", fmt.Errorf( - "Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser, - utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser) + "Conflict. The name %q is already in use by container %s. You have to delete (or rename) that container to be able to reuse that name.", nameAsKnownByUser, + utils.TruncateID(conflictingContainer.ID)) } } return name, nil @@ -557,7 +622,7 @@ func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error return err } -func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *image.Image) (*Container, error) { +func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) { var ( id string err error @@ -578,7 +643,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i Args: args, //FIXME: de-duplicate from config Config: config, hostConfig: &runconfig.HostConfig{}, - Image: img.ID, // Always use the resolved image id + ImageID: imgID, NetworkSettings: &NetworkSettings{}, Name: name, Driver: daemon.driver.String(), @@ -590,14 +655,14 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i return container, err } -func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error { +func (daemon *Daemon) createRootfs(container *Container) error { // 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 err } initID := fmt.Sprintf("%s-init", container.ID) - if err := daemon.driver.Create(initID, img.ID); err != nil { + if err := daemon.driver.Create(initID, container.ImageID); err != nil { return err } initPath, err := daemon.driver.Get(initID, "") @@ -689,10 +754,7 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig. if err != nil { return err } - child, err := daemon.GetByName(parts["name"]) - if err != nil { - return err - } + child := daemon.Get(parts["name"]) if child == nil { return fmt.Errorf("Could not get container for %s", parts["name"]) } @@ -758,7 +820,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) if os.Geteuid() != 0 { return nil, fmt.Errorf("The Docker daemon needs to be run as root") } - if err := checkKernelAndArch(); err != nil { + if err := checkKernel(); err != nil { return nil, err } @@ -829,13 +891,18 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) return nil, err } - volumes, err := volumes.NewRepository(path.Join(config.Root, "volumes"), volumesDriver) + volumes, err := volumes.NewRepository(filepath.Join(config.Root, "volumes"), volumesDriver) + if err != nil { + return nil, err + } + + trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath) if err != nil { return nil, err } log.Debugf("Creating repository list") - repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g, config.Mirrors, config.InsecureRegistries) + repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g, trustKey) if err != nil { return nil, fmt.Errorf("Couldn't create Tag store: %s", err) } @@ -856,9 +923,11 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication) job.SetenvBool("EnableIpForward", config.EnableIpForward) job.SetenvBool("EnableIpMasq", config.EnableIpMasq) + job.SetenvBool("EnableIPv6", config.EnableIPv6) job.Setenv("BridgeIface", config.BridgeIface) job.Setenv("BridgeIP", config.BridgeIP) job.Setenv("FixedCIDR", config.FixedCIDR) + job.Setenv("FixedCIDRv6", config.FixedCIDRv6) job.Setenv("DefaultBindingIP", config.DefaultIp.String()) if err := job.Run(); err != nil { @@ -898,11 +967,6 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) return nil, err } - trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath) - if err != nil { - return nil, err - } - daemon := &Daemon{ ID: trustKey.PublicKey().KeyID(), repository: daemonRepo, @@ -920,10 +984,17 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) execDriver: ed, eng: eng, trustStore: t, + statsCollector: newStatsCollector(1 * time.Second), } if err := daemon.restore(); err != nil { return nil, err } + + // set up filesystem watch on resolv.conf for network changes + if err := daemon.setupResolvconfWatcher(); err != nil { + return nil, err + } + // Setup shutdown handlers // FIXME: can these shutdown handlers be registered closer to their source? eng.OnShutdown(func() { @@ -1024,6 +1095,28 @@ func (daemon *Daemon) Kill(c *Container, sig int) error { return daemon.execDriver.Kill(c.command, sig) } +func (daemon *Daemon) Stats(c *Container) (*execdriver.ResourceStats, error) { + return daemon.execDriver.Stats(c.ID) +} + +func (daemon *Daemon) SubscribeToContainerStats(name string) (chan interface{}, error) { + c := daemon.Get(name) + if c == nil { + return nil, fmt.Errorf("no such container") + } + ch := daemon.statsCollector.collect(c) + return ch, nil +} + +func (daemon *Daemon) UnsubscribeToContainerStats(name string, ch chan interface{}) error { + c := daemon.Get(name) + if c == nil { + return fmt.Errorf("no such container") + } + daemon.statsCollector.unsubscribe(c, ch) + return nil +} + // Nuke kills all containers then removes all content // from the content root, including images, volumes and // container filesystems. @@ -1099,9 +1192,9 @@ func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*i // Loop on the children of the given image and check the config var match *image.Image for elem := range imageMap[imgID] { - img, err := daemon.Graph().Get(elem) - if err != nil { - return nil, err + img, ok := images[elem] + if !ok { + return nil, fmt.Errorf("unable to find image %q", elem) } if runconfig.Compare(&img.ContainerConfig, config) { if match == nil || match.Created.Before(img.Created) { @@ -1112,11 +1205,7 @@ func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*i return match, nil } -func checkKernelAndArch() error { - // Check for unsupported architectures - if runtime.GOARCH != "amd64" { - return fmt.Errorf("The Docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH) - } +func checkKernel() error { // Check for unsupported kernel versions // FIXME: it would be cleaner to not test for specific versions, but rather // test for specific functionalities. diff --git a/daemon/delete.go b/daemon/delete.go index 55678f90a..59c765178 100644 --- a/daemon/delete.go +++ b/daemon/delete.go @@ -49,13 +49,16 @@ func (daemon *Daemon) ContainerRm(job *engine.Job) engine.Status { } if container != nil { + // stop collection of stats for the container regardless + // if stats are currently getting collected. + daemon.statsCollector.stopCollection(container) if container.IsRunning() { if forceRemove { if err := container.Kill(); err != nil { return job.Errorf("Could not kill running container, cannot remove - %v", err) } } else { - return job.Errorf("You cannot remove a running container. Stop the container before attempting removal or use -f") + return job.Errorf("Conflict, You cannot remove a running container. Stop the container before attempting removal or use -f") } } if err := daemon.Destroy(container); err != nil { diff --git a/daemon/exec.go b/daemon/exec.go index ecdbc58d8..8bb4e72d1 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -1,5 +1,3 @@ -// build linux - package daemon import ( @@ -35,7 +33,7 @@ type execConfig struct { type execStore struct { s map[string]*execConfig - sync.Mutex + sync.RWMutex } func newExecStore() *execStore { @@ -49,9 +47,9 @@ func (e *execStore) Add(id string, execConfig *execConfig) { } func (e *execStore) Get(id string) *execConfig { - e.Lock() + e.RLock() res := e.s[id] - e.Unlock() + e.RUnlock() return res } @@ -61,6 +59,16 @@ func (e *execStore) Delete(id string) { e.Unlock() } +func (e *execStore) List() []string { + var IDs []string + e.RLock() + for id := range e.s { + IDs = append(IDs, id) + } + e.RUnlock() + return IDs +} + func (execConfig *execConfig) Resize(h, w int) error { return execConfig.ProcessConfig.Terminal.Resize(h, w) } @@ -144,6 +152,8 @@ func (d *Daemon) ContainerExecCreate(job *engine.Job) engine.Status { Running: false, } + container.LogEvent("exec_create: " + execConfig.ProcessConfig.Entrypoint + " " + strings.Join(execConfig.ProcessConfig.Arguments, " ")) + d.registerExecCommand(execConfig) job.Printf("%s\n", execConfig.ID) @@ -182,6 +192,8 @@ func (d *Daemon) ContainerExecStart(job *engine.Job) engine.Status { log.Debugf("starting exec command %s in container %s", execConfig.ID, execConfig.Container.ID) container := execConfig.Container + container.LogEvent("exec_start: " + execConfig.ProcessConfig.Entrypoint + " " + strings.Join(execConfig.ProcessConfig.Arguments, " ")) + if execConfig.OpenStdin { r, w := io.Pipe() go func() { @@ -249,6 +261,10 @@ func (d *Daemon) Exec(c *Container, execConfig *execConfig, pipes *execdriver.Pi return exitStatus, err } +func (container *Container) GetExecIDs() []string { + return container.execCommands.List() +} + func (container *Container) Exec(execConfig *execConfig) error { container.Lock() defer container.Unlock() diff --git a/daemon/execdriver/driver.go b/daemon/execdriver/driver.go index 411265814..2215d03cf 100644 --- a/daemon/execdriver/driver.go +++ b/daemon/execdriver/driver.go @@ -5,7 +5,9 @@ import ( "io" "os" "os/exec" + "time" + "github.com/docker/libcontainer" "github.com/docker/libcontainer/devices" ) @@ -14,7 +16,7 @@ import ( type Context map[string]string var ( - ErrNotRunning = errors.New("Process could not be started") + ErrNotRunning = errors.New("Container is not running") ErrWaitTimeoutReached = errors.New("Wait timeout reached") ErrDriverAlreadyRegistered = errors.New("A driver already registered this docker init function") ErrDriverNotFound = errors.New("The requested docker init has not been found") @@ -61,6 +63,7 @@ type Driver interface { GetPidsForContainer(id string) ([]int, error) // Returns a list of pids for the given container. Terminate(c *Command) error // kill it with fire Clean(id string) error // clean all traces of container exec + Stats(id string) (*ResourceStats, error) // Get resource stats for a running container } // Network settings of the container @@ -77,12 +80,21 @@ type Ipc struct { HostIpc bool `json:"host_ipc"` } +// PID settings of the container +type Pid struct { + HostPid bool `json:"host_pid"` +} + type NetworkInterface struct { - Gateway string `json:"gateway"` - IPAddress string `json:"ip"` - IPPrefixLen int `json:"ip_prefix_len"` - MacAddress string `json:"mac_address"` - Bridge string `json:"bridge"` + Gateway string `json:"gateway"` + IPAddress string `json:"ip"` + IPPrefixLen int `json:"ip_prefix_len"` + MacAddress string `json:"mac"` + Bridge string `json:"bridge"` + GlobalIPv6Address string `json:"global_ipv6"` + LinkLocalIPv6Address string `json:"link_local_ipv6"` + GlobalIPv6PrefixLen int `json:"global_ipv6_prefix_len"` + IPv6Gateway string `json:"ipv6_gateway"` } type Resources struct { @@ -92,6 +104,13 @@ type Resources struct { Cpuset string `json:"cpuset"` } +type ResourceStats struct { + *libcontainer.ContainerStats + Read time.Time `json:"read"` + MemoryLimit int64 `json:"memory_limit"` + SystemUsage uint64 `json:"system_usage"` +} + type Mount struct { Source string `json:"source"` Destination string `json:"destination"` @@ -116,12 +135,14 @@ type ProcessConfig struct { // Process wrapps an os/exec.Cmd to add more metadata type Command struct { ID string `json:"id"` - Rootfs string `json:"rootfs"` // root fs of the container + Rootfs string `json:"rootfs"` // root fs of the container + ReadonlyRootfs bool `json:"readonly_rootfs"` InitPath string `json:"initpath"` // dockerinit WorkingDir string `json:"working_dir"` ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver Network *Network `json:"network"` Ipc *Ipc `json:"ipc"` + Pid *Pid `json:"pid"` Resources *Resources `json:"resources"` Mounts []Mount `json:"mounts"` AllowedDevices []*devices.Device `json:"allowed_devices"` diff --git a/daemon/execdriver/execdrivers/execdrivers.go b/daemon/execdriver/execdrivers/execdrivers.go index 2a050b483..be3222a8b 100644 --- a/daemon/execdriver/execdrivers/execdrivers.go +++ b/daemon/execdriver/execdrivers/execdrivers.go @@ -2,11 +2,12 @@ package execdrivers import ( "fmt" + "path" + "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver/lxc" "github.com/docker/docker/daemon/execdriver/native" "github.com/docker/docker/pkg/sysinfo" - "path" ) func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) { diff --git a/daemon/execdriver/lxc/driver.go b/daemon/execdriver/lxc/driver.go index 642247c85..44942b1fe 100644 --- a/daemon/execdriver/lxc/driver.go +++ b/daemon/execdriver/lxc/driver.go @@ -76,11 +76,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba }) if err := d.generateEnvConfig(c); err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } configPath, err := d.generateLXCConfig(c) if err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } params := []string{ "lxc-start", @@ -154,11 +154,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba c.ProcessConfig.Args = append([]string{name}, arg...) if err := nodes.CreateDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } if err := c.ProcessConfig.Start(); err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } var ( @@ -182,7 +182,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba c.ProcessConfig.Process.Kill() c.ProcessConfig.Wait() } - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } c.ContainerPid = pid @@ -193,7 +193,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba <-waitLock - return execdriver.ExitStatus{getExitCode(c), false}, waitErr + return execdriver.ExitStatus{ExitCode: getExitCode(c)}, waitErr } /// Return the exit code of the process @@ -524,3 +524,8 @@ func (t *TtyConsole) Close() error { func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { return -1, ErrExec } + +func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) { + return nil, fmt.Errorf("container stats are not supported with LXC") + +} diff --git a/daemon/execdriver/lxc/lxc_init_linux.go b/daemon/execdriver/lxc/lxc_init_linux.go index 78bdd11fb..956a283fc 100644 --- a/daemon/execdriver/lxc/lxc_init_linux.go +++ b/daemon/execdriver/lxc/lxc_init_linux.go @@ -2,6 +2,8 @@ package lxc import ( "fmt" + + "github.com/docker/libcontainer" "github.com/docker/libcontainer/namespaces" "github.com/docker/libcontainer/utils" ) @@ -10,14 +12,13 @@ func finalizeNamespace(args *InitArgs) error { if err := utils.CloseExecFrom(3); err != nil { return err } - - if err := namespaces.SetupUser(args.User); err != nil { + if err := namespaces.SetupUser(&libcontainer.Config{ + User: args.User, + }); err != nil { return fmt.Errorf("setup user %s", err) } - if err := setupWorkingDirectory(args); err != nil { return err } - return nil } diff --git a/daemon/execdriver/lxc/lxc_template.go b/daemon/execdriver/lxc/lxc_template.go index 9402c0697..4ed2a45c8 100644 --- a/daemon/execdriver/lxc/lxc_template.go +++ b/daemon/execdriver/lxc/lxc_template.go @@ -1,12 +1,17 @@ package lxc import ( - "github.com/docker/docker/daemon/execdriver" - nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template" - "github.com/docker/libcontainer/label" + "fmt" "os" "strings" "text/template" + + log "github.com/Sirupsen/logrus" + "github.com/docker/docker/daemon/execdriver" + nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template" + "github.com/docker/docker/utils" + "github.com/docker/libcontainer/label" + "github.com/docker/libcontainer/security/capabilities" ) const LxcTemplate = ` @@ -16,12 +21,6 @@ lxc.network.type = veth lxc.network.link = {{.Network.Interface.Bridge}} lxc.network.name = eth0 lxc.network.mtu = {{.Network.Mtu}} -{{if .Network.Interface.IPAddress}} -lxc.network.ipv4 = {{.Network.Interface.IPAddress}}/{{.Network.Interface.IPPrefixLen}} -{{end}} -{{if .Network.Interface.Gateway}} -lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}} -{{end}} lxc.network.flags = up {{else if .Network.HostNetworking}} lxc.network.type = none @@ -62,13 +61,24 @@ lxc.cgroup.devices.allow = {{$allowedDevice.GetCgroupAllowString}} lxc.pivotdir = lxc_putold # NOTICE: These mounts must be applied within the namespace - +{{if .ProcessConfig.Privileged}} # WARNING: mounting procfs and/or sysfs read-write is a known attack vector. # See e.g. http://blog.zx2c4.com/749 and http://bit.ly/T9CkqJ # We mount them read-write here, but later, dockerinit will call the Restrict() function to remount them read-only. # We cannot mount them directly read-only, because that would prevent loading AppArmor profiles. lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0 lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0 + {{if .AppArmor}} +lxc.aa_profile = unconfined + {{end}} +{{else}} +# In non-privileged mode, lxc will automatically mount /proc and /sys in readonly mode +# for security. See: http://man7.org/linux/man-pages/man5/lxc.container.conf.5.html +lxc.mount.auto = proc sys + {{if .AppArmorProfile}} +lxc.aa_profile = {{.AppArmorProfile}} + {{end}} +{{end}} {{if .ProcessConfig.Tty}} lxc.mount.entry = {{.ProcessConfig.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0 @@ -86,26 +96,6 @@ lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabS {{end}} {{end}} -{{if .ProcessConfig.Env}} -lxc.utsname = {{getHostname .ProcessConfig.Env}} -{{end}} - -{{if .ProcessConfig.Privileged}} -# No cap values are needed, as lxc is starting in privileged mode -{{else}} -{{range $value := keepCapabilities .CapAdd .CapDrop}} -lxc.cap.keep = {{$value}} -{{end}} -{{end}} - -{{if .ProcessConfig.Privileged}} -{{if .AppArmor}} -lxc.aa_profile = unconfined -{{else}} -# Let AppArmor normal confinement take place (i.e., not unconfined) -{{end}} -{{end}} - # limits {{if .Resources}} {{if .Resources.Memory}} @@ -128,6 +118,35 @@ lxc.cgroup.cpuset.cpus = {{.Resources.Cpuset}} lxc.{{$value}} {{end}} {{end}} + +{{if .Network.Interface}} +{{if .Network.Interface.IPAddress}} +lxc.network.ipv4 = {{.Network.Interface.IPAddress}}/{{.Network.Interface.IPPrefixLen}} +{{end}} +{{if .Network.Interface.Gateway}} +lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}} +{{end}} + +{{if .ProcessConfig.Env}} +lxc.utsname = {{getHostname .ProcessConfig.Env}} +{{end}} + +{{if .ProcessConfig.Privileged}} +# No cap values are needed, as lxc is starting in privileged mode +{{else}} + {{ with keepCapabilities .CapAdd .CapDrop }} + {{range .}} +lxc.cap.keep = {{.}} + {{end}} + {{else}} + {{ with dropList .CapDrop }} + {{range .}} +lxc.cap.drop = {{.}} + {{end}} + {{end}} + {{end}} +{{end}} +{{end}} ` var LxcTemplateCompiled *template.Template @@ -138,17 +157,39 @@ func escapeFstabSpaces(field string) string { return strings.Replace(field, " ", "\\040", -1) } -func keepCapabilities(adds []string, drops []string) []string { +func keepCapabilities(adds []string, drops []string) ([]string, error) { container := nativeTemplate.New() + log.Debugf("adds %s drops %s\n", adds, drops) caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops) + if err != nil { + return nil, err + } var newCaps []string for _, cap := range caps { - newCaps = append(newCaps, strings.ToLower(cap)) + log.Debugf("cap %s\n", cap) + realCap := capabilities.GetCapability(cap) + numCap := fmt.Sprintf("%d", realCap.Value) + newCaps = append(newCaps, numCap) } - if err != nil { - return []string{} + + return newCaps, nil +} + +func dropList(drops []string) ([]string, error) { + if utils.StringsContainsNoCase(drops, "all") { + var newCaps []string + for _, cap := range capabilities.GetAllCapabilities() { + log.Debugf("drop cap %s\n", cap) + realCap := capabilities.GetCapability(cap) + if realCap == nil { + return nil, fmt.Errorf("Invalid capability '%s'", cap) + } + numCap := fmt.Sprintf("%d", realCap.Value) + newCaps = append(newCaps, numCap) + } + return newCaps, nil } - return newCaps + return []string{}, nil } func isDirectory(source string) string { @@ -203,6 +244,7 @@ func init() { "formatMountLabel": label.FormatMountLabel, "isDirectory": isDirectory, "keepCapabilities": keepCapabilities, + "dropList": dropList, "getHostname": getHostname, } LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate) diff --git a/daemon/execdriver/lxc/lxc_template_unit_test.go b/daemon/execdriver/lxc/lxc_template_unit_test.go index 77435114f..bb622d4bc 100644 --- a/daemon/execdriver/lxc/lxc_template_unit_test.go +++ b/daemon/execdriver/lxc/lxc_template_unit_test.go @@ -5,6 +5,11 @@ package lxc import ( "bufio" "fmt" + "github.com/docker/docker/daemon/execdriver" + nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template" + "github.com/docker/libcontainer/devices" + "github.com/docker/libcontainer/security/capabilities" + "github.com/syndtr/gocapability/capability" "io/ioutil" "math/rand" "os" @@ -12,10 +17,6 @@ import ( "strings" "testing" "time" - - "github.com/docker/docker/daemon/execdriver" - nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template" - "github.com/docker/libcontainer/devices" ) func TestLXCConfig(t *testing.T) { @@ -247,7 +248,8 @@ func TestCustomLxcConfigMisc(t *testing.T) { } defer os.RemoveAll(root) os.MkdirAll(path.Join(root, "containers", "1"), 0777) - driver, err := NewDriver(root, "", false) + driver, err := NewDriver(root, "", true) + if err != nil { t.Fatal(err) } @@ -270,9 +272,10 @@ func TestCustomLxcConfigMisc(t *testing.T) { Bridge: "docker0", }, }, - ProcessConfig: processConfig, - CapAdd: []string{"net_admin", "syslog"}, - CapDrop: []string{"kill", "mknod"}, + ProcessConfig: processConfig, + CapAdd: []string{"net_admin", "syslog"}, + CapDrop: []string{"kill", "mknod"}, + AppArmorProfile: "lxc-container-default-with-nesting", } p, err := driver.generateLXCConfig(command) @@ -286,17 +289,82 @@ func TestCustomLxcConfigMisc(t *testing.T) { grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24") grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1") grepFile(t, p, "lxc.network.flags = up") + grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting") + // hostname + grepFile(t, p, "lxc.utsname = testhost") + grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1") + container := nativeTemplate.New() + for _, cap := range container.Capabilities { + realCap := capabilities.GetCapability(cap) + numCap := fmt.Sprintf("%d", realCap.Value) + if cap != "MKNOD" && cap != "KILL" { + grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap)) + } + } + + grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true) + grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true) +} + +func TestCustomLxcConfigMiscOverride(t *testing.T) { + root, err := ioutil.TempDir("", "TestCustomLxcConfig") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(root) + os.MkdirAll(path.Join(root, "containers", "1"), 0777) + driver, err := NewDriver(root, "", false) + if err != nil { + t.Fatal(err) + } + processConfig := execdriver.ProcessConfig{ + Privileged: false, + } + + processConfig.Env = []string{"HOSTNAME=testhost"} + command := &execdriver.Command{ + ID: "1", + LxcConfig: []string{ + "lxc.cgroup.cpuset.cpus = 0,1", + "lxc.network.ipv4 = 172.0.0.1", + }, + Network: &execdriver.Network{ + Mtu: 1500, + Interface: &execdriver.NetworkInterface{ + Gateway: "10.10.10.1", + IPAddress: "10.10.10.10", + IPPrefixLen: 24, + Bridge: "docker0", + }, + }, + ProcessConfig: processConfig, + CapAdd: []string{"NET_ADMIN", "SYSLOG"}, + CapDrop: []string{"KILL", "MKNOD"}, + } + + p, err := driver.generateLXCConfig(command) + if err != nil { + t.Fatal(err) + } + // network + grepFile(t, p, "lxc.network.type = veth") + grepFile(t, p, "lxc.network.link = docker0") + grepFile(t, p, "lxc.network.name = eth0") + grepFile(t, p, "lxc.network.ipv4 = 172.0.0.1") + grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1") + grepFile(t, p, "lxc.network.flags = up") // hostname grepFile(t, p, "lxc.utsname = testhost") grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1") container := nativeTemplate.New() for _, cap := range container.Capabilities { - cap = strings.ToLower(cap) - if cap != "mknod" && cap != "kill" { - grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", cap)) + realCap := capabilities.GetCapability(cap) + numCap := fmt.Sprintf("%d", realCap.Value) + if cap != "MKNOD" && cap != "KILL" { + grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap)) } } - grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = kill"), true) - grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = mknod"), true) + grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true) + grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true) } diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index de103eca8..c5a8da75b 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -31,6 +31,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e container.Cgroups.AllowedDevices = c.AllowedDevices container.MountConfig.DeviceNodes = c.AutoCreatedDevices container.RootFs = c.Rootfs + container.MountConfig.ReadonlyFs = c.ReadonlyRootfs // check to see if we are running in ramdisk to disable pivot root container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != "" @@ -40,6 +41,10 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e return nil, err } + if err := d.createPid(container, c); err != nil { + return nil, err + } + if err := d.createNetwork(container, c); err != nil { return nil, err } @@ -82,7 +87,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Command) error { if c.Network.HostNetworking { - container.Namespaces["NEWNET"] = false + container.Namespaces.Remove(libcontainer.NEWNET) return nil } @@ -105,6 +110,10 @@ func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Com Bridge: c.Network.Interface.Bridge, VethPrefix: "veth", } + if c.Network.Interface.GlobalIPv6Address != "" { + vethNetwork.IPv6Address = fmt.Sprintf("%s/%d", c.Network.Interface.GlobalIPv6Address, c.Network.Interface.GlobalIPv6PrefixLen) + vethNetwork.IPv6Gateway = c.Network.Interface.IPv6Gateway + } container.Networks = append(container.Networks, &vethNetwork) } @@ -119,10 +128,7 @@ func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Com cmd := active.cmd nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net") - container.Networks = append(container.Networks, &libcontainer.Network{ - Type: "netns", - NsPath: nspath, - }) + container.Namespaces.Add(libcontainer.NEWNET, nspath) } return nil @@ -130,7 +136,7 @@ func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Com func (d *driver) createIpc(container *libcontainer.Config, c *execdriver.Command) error { if c.Ipc.HostIpc { - container.Namespaces["NEWIPC"] = false + container.Namespaces.Remove(libcontainer.NEWIPC) return nil } @@ -144,7 +150,16 @@ func (d *driver) createIpc(container *libcontainer.Config, c *execdriver.Command } cmd := active.cmd - container.IpcNsPath = filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "ipc") + container.Namespaces.Add(libcontainer.NEWIPC, filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "ipc")) + } + + return nil +} + +func (d *driver) createPid(container *libcontainer.Config, c *execdriver.Command) error { + if c.Pid.HostPid { + container.Namespaces.Remove(libcontainer.NEWPID) + return nil } return nil diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 01455a810..533e6d61e 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -13,9 +13,11 @@ import ( "strings" "sync" "syscall" + "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/execdriver" + sysinfo "github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/term" "github.com/docker/libcontainer" "github.com/docker/libcontainer/apparmor" @@ -41,30 +43,31 @@ type driver struct { root string initPath string activeContainers map[string]*activeContainer + machineMemory int64 sync.Mutex } func NewDriver(root, initPath string) (*driver, error) { - if err := os.MkdirAll(root, 0700); err != nil { + meminfo, err := sysinfo.ReadMemInfo() + if err != nil { return nil, err } + if err := os.MkdirAll(root, 0700); err != nil { + return nil, err + } // native driver root is at docker_root/execdriver/native. Put apparmor at docker_root if err := apparmor.InstallDefaultProfile(); err != nil { return nil, err } - return &driver{ root: root, initPath: initPath, activeContainers: make(map[string]*activeContainer), + machineMemory: meminfo.MemTotal, }, nil } -func (d *driver) notifyOnOOM(config *libcontainer.Config) (<-chan struct{}, error) { - return fs.NotifyOnOOM(config.Cgroups) -} - type execOutput struct { exitCode int err error @@ -74,7 +77,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba // take the Command and populate the libcontainer.Config from it container, err := d.createContainer(c) if err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } var term execdriver.Terminal @@ -85,7 +88,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes) } if err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } c.ProcessConfig.Terminal = term @@ -102,12 +105,12 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba ) if err := d.createContainerRoot(c.ID); err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } defer d.cleanContainer(c.ID) if err := d.writeContainerFile(container, c.ID); err != nil { - return execdriver.ExitStatus{-1, false}, err + return execdriver.ExitStatus{ExitCode: -1}, err } execOutputChan := make(chan execOutput, 1) @@ -146,22 +149,27 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba select { case execOutput := <-execOutputChan: - return execdriver.ExitStatus{execOutput.exitCode, false}, execOutput.err + return execdriver.ExitStatus{ExitCode: execOutput.exitCode}, execOutput.err case <-waitForStart: break } oomKill := false - oomKillNotification, err := d.notifyOnOOM(container) + state, err := libcontainer.GetState(filepath.Join(d.root, c.ID)) if err == nil { - _, oomKill = <-oomKillNotification + oomKillNotification, err := libcontainer.NotifyOnOOM(state) + if err == nil { + _, oomKill = <-oomKillNotification + } else { + log.Warnf("WARNING: Your kernel does not support OOM notifications: %s", err) + } } else { - log.Warnf("WARNING: Your kernel does not support OOM notifications: %s", err) + log.Warnf("Failed to get container state, oom notify will not work: %s", err) } // wait for the container to exit. execOutput := <-execOutputChan - return execdriver.ExitStatus{execOutput.exitCode, oomKill}, execOutput.err + return execdriver.ExitStatus{ExitCode: execOutput.exitCode, OOMKilled: oomKill}, execOutput.err } func (d *driver) Kill(p *execdriver.Command, sig int) error { @@ -278,6 +286,33 @@ func (d *driver) Clean(id string) error { return os.RemoveAll(filepath.Join(d.root, id)) } +func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) { + c := d.activeContainers[id] + state, err := libcontainer.GetState(filepath.Join(d.root, id)) + if err != nil { + if os.IsNotExist(err) { + return nil, execdriver.ErrNotRunning + } + return nil, err + } + now := time.Now() + stats, err := libcontainer.GetStats(nil, state) + if err != nil { + return nil, err + } + memoryLimit := c.container.Cgroups.Memory + // if the container does not have any memory limit specified set the + // limit to the machines memory + if memoryLimit == 0 { + memoryLimit = d.machineMemory + } + return &execdriver.ResourceStats{ + Read: now, + ContainerStats: stats, + MemoryLimit: memoryLimit, + }, nil +} + func getEnv(key string, env []string) string { for _, pair := range env { parts := strings.Split(pair, "=") diff --git a/daemon/execdriver/native/template/default_template.go b/daemon/execdriver/native/template/default_template.go index be3dd5a5c..f7d6be746 100644 --- a/daemon/execdriver/native/template/default_template.go +++ b/daemon/execdriver/native/template/default_template.go @@ -25,13 +25,13 @@ func New() *libcontainer.Config { "KILL", "AUDIT_WRITE", }, - Namespaces: map[string]bool{ - "NEWNS": true, - "NEWUTS": true, - "NEWIPC": true, - "NEWPID": true, - "NEWNET": true, - }, + Namespaces: libcontainer.Namespaces([]libcontainer.Namespace{ + {Type: "NEWNS"}, + {Type: "NEWUTS"}, + {Type: "NEWIPC"}, + {Type: "NEWPID"}, + {Type: "NEWNET"}, + }), Cgroups: &cgroups.Cgroup{ Parent: "docker", AllowAllDevices: false, diff --git a/daemon/graphdriver/aufs/aufs.go b/daemon/graphdriver/aufs/aufs.go index 55cfd00c1..5e9d747f2 100644 --- a/daemon/graphdriver/aufs/aufs.go +++ b/daemon/graphdriver/aufs/aufs.go @@ -45,6 +45,7 @@ var ( graphdriver.FsMagicBtrfs, graphdriver.FsMagicAufs, } + backingFs = "" ) func init() { @@ -60,20 +61,22 @@ type Driver struct { // New returns a new AUFS driver. // An error is returned if AUFS is not supported. func Init(root string, options []string) (graphdriver.Driver, error) { + // Try to load the aufs kernel module if err := supportsAufs(); err != nil { return nil, graphdriver.ErrNotSupported } - rootdir := path.Dir(root) - - var buf syscall.Statfs_t - if err := syscall.Statfs(rootdir, &buf); err != nil { - return nil, fmt.Errorf("Couldn't stat the root directory: %s", err) + fsMagic, err := graphdriver.GetFSMagic(root) + if err != nil { + return nil, err + } + if fsName, ok := graphdriver.FsNames[fsMagic]; ok { + backingFs = fsName } for _, magic := range incompatibleFsMagic { - if graphdriver.FsMagic(buf.Type) == magic { + if fsMagic == magic { return nil, graphdriver.ErrIncompatibleFS } } @@ -134,25 +137,26 @@ func supportsAufs() error { return ErrAufsNotSupported } -func (a Driver) rootPath() string { +func (a *Driver) rootPath() string { return a.root } -func (Driver) String() string { +func (*Driver) String() string { return "aufs" } -func (a Driver) Status() [][2]string { +func (a *Driver) Status() [][2]string { ids, _ := loadIds(path.Join(a.rootPath(), "layers")) return [][2]string{ {"Root Dir", a.rootPath()}, + {"Backing Filesystem", backingFs}, {"Dirs", fmt.Sprintf("%d", len(ids))}, } } // Exists returns true if the given id is registered with // this driver -func (a Driver) Exists(id string) bool { +func (a *Driver) Exists(id string) bool { if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil { return false } @@ -278,7 +282,7 @@ func (a *Driver) Get(id, mountLabel string) (string, error) { return out, nil } -func (a *Driver) Put(id string) { +func (a *Driver) Put(id string) error { // Protect the a.active from concurrent access a.Lock() defer a.Unlock() @@ -293,6 +297,7 @@ func (a *Driver) Put(id string) { } delete(a.active, id) } + return nil } // Diff produces an archive of the changes between the specified @@ -300,8 +305,8 @@ func (a *Driver) Put(id string) { func (a *Driver) Diff(id, parent string) (archive.Archive, error) { // AUFS doesn't need the parent layer to produce a diff. return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{ - Compression: archive.Uncompressed, - Excludes: []string{".wh..wh.*"}, + Compression: archive.Uncompressed, + ExcludePatterns: []string{".wh..wh.*"}, }) } @@ -312,7 +317,7 @@ func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error { // DiffSize calculates the changes between the specified id // and its parent and returns the size in bytes of the changes // relative to its base filesystem directory. -func (a *Driver) DiffSize(id, parent string) (bytes int64, err error) { +func (a *Driver) DiffSize(id, parent string) (size int64, err error) { // AUFS doesn't need the parent layer to calculate the diff size. return utils.TreeSize(path.Join(a.rootPath(), "diff", id)) } @@ -320,7 +325,7 @@ func (a *Driver) DiffSize(id, parent string) (bytes int64, err error) { // ApplyDiff extracts the changeset from the given diff into the // layer with the specified id and parent, returning the size of the // new layer in bytes. -func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) { +func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) { // AUFS doesn't need the parent id to apply the diff. if err = a.applyDiff(id, diff); err != nil { return diff --git a/daemon/graphdriver/aufs/aufs_test.go b/daemon/graphdriver/aufs/aufs_test.go index c17a5dcce..6dea9bb51 100644 --- a/daemon/graphdriver/aufs/aufs_test.go +++ b/daemon/graphdriver/aufs/aufs_test.go @@ -568,7 +568,7 @@ func TestStatus(t *testing.T) { t.Fatal("Status should not be nil or empty") } rootDir := status[0] - dirs := status[1] + dirs := status[2] if rootDir[0] != "Root Dir" { t.Fatalf("Expected Root Dir got %s", rootDir[0]) } diff --git a/daemon/graphdriver/btrfs/btrfs.go b/daemon/graphdriver/btrfs/btrfs.go index a3964b963..1830ad4e8 100644 --- a/daemon/graphdriver/btrfs/btrfs.go +++ b/daemon/graphdriver/btrfs/btrfs.go @@ -220,9 +220,10 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { return dir, nil } -func (d *Driver) Put(id string) { +func (d *Driver) Put(id string) error { // Get() creates no runtime resources (like e.g. mounts) // so this doesn't need to do anything. + return nil } func (d *Driver) Exists(id string) bool { diff --git a/daemon/graphdriver/devmapper/README.md b/daemon/graphdriver/devmapper/README.md index 3b69cef84..8c6f1d6ac 100644 --- a/daemon/graphdriver/devmapper/README.md +++ b/daemon/graphdriver/devmapper/README.md @@ -28,6 +28,45 @@ containers. All base images are snapshots of this device and those images are then in turn used as snapshots for other images and eventually containers. +### Information on `docker info` + +As of docker-1.4.1, `docker info` when using the `devicemapper` storage driver +will display something like: + + $ sudo docker info + [...] + Storage Driver: devicemapper + Pool Name: docker-253:1-17538953-pool + Pool Blocksize: 65.54 kB + Data file: /dev/loop4 + Metadata file: /dev/loop4 + Data Space Used: 2.536 GB + Data Space Total: 107.4 GB + Metadata Space Used: 7.93 MB + Metadata Space Total: 2.147 GB + Udev Sync Supported: true + Data loop file: /home/docker/devicemapper/devicemapper/data + Metadata loop file: /home/docker/devicemapper/devicemapper/metadata + Library Version: 1.02.82-git (2013-10-04) + [...] + +#### status items + +Each item in the indented section under `Storage Driver: devicemapper` are +status information about the driver. + * `Pool Name` name of the devicemapper pool for this driver. + * `Pool Blocksize` tells the blocksize the thin pool was initialized with. This only changes on creation. + * `Data file` blockdevice file used for the devicemapper data + * `Metadata file` blockdevice file used for the devicemapper metadata + * `Data Space Used` tells how much of `Data file` is currently used + * `Data Space Total` tells max size the `Data file` + * `Metadata Space Used` tells how much of `Metadata file` is currently used + * `Metadata Space Total` tells max size the `Metadata file` + * `Udev Sync Supported` tells whether devicemapper is able to sync with Udev. Should be `true`. + * `Data loop file` file attached to `Data file`, if loopback device is used + * `Metadata loop file` file attached to `Metadata file`, if loopback device is used + * `Library Version` from the libdevmapper used + ### options The devicemapper backend supports some options that you can specify @@ -162,7 +201,7 @@ Here is the list of supported options: Enables or disables the use of blkdiscard when removing devicemapper devices. This is enabled by default (only) if using - loopback devices and is required to res-parsify the loopback file + loopback devices and is required to resparsify the loopback file on image/container removal. Disabling this on loopback can lead to *much* faster container diff --git a/daemon/graphdriver/devmapper/deviceset.go b/daemon/graphdriver/devmapper/deviceset.go index 71502a483..51ce54941 100644 --- a/daemon/graphdriver/devmapper/deviceset.go +++ b/daemon/graphdriver/devmapper/deviceset.go @@ -45,15 +45,15 @@ type Transaction struct { } type DevInfo struct { - Hash string `json:"-"` - DeviceId int `json:"device_id"` - Size uint64 `json:"size"` - TransactionId uint64 `json:"transaction_id"` - Initialized bool `json:"initialized"` - devices *DeviceSet `json:"-"` + Hash string `json:"-"` + DeviceId int `json:"device_id"` + Size uint64 `json:"size"` + TransactionId uint64 `json:"transaction_id"` + Initialized bool `json:"initialized"` + devices *DeviceSet - mountCount int `json:"-"` - mountPath string `json:"-"` + mountCount int + mountPath string // The global DeviceSet lock guarantees that we serialize all // the calls to libdevmapper (which is not threadsafe), but we @@ -65,12 +65,12 @@ type DevInfo struct { // the global lock while holding the per-device locks all // device locks must be aquired *before* the device lock, and // multiple device locks should be aquired parent before child. - lock sync.Mutex `json:"-"` + lock sync.Mutex } type MetaData struct { Devices map[string]*DevInfo `json:"Devices"` - devicesLock sync.Mutex `json:"-"` // Protects all read/writes to Devices map + devicesLock sync.Mutex // Protects all read/writes to Devices map } type DeviceSet struct { @@ -89,8 +89,10 @@ type DeviceSet struct { filesystem string mountOptions string mkfsArgs []string - dataDevice string - metadataDevice string + dataDevice string // block or loop dev + dataLoopFile string // loopback file, if used + metadataDevice string // block or loop dev + metadataLoopFile string // loopback file, if used doBlkDiscard bool thinpBlockSize uint32 thinPoolDevice string @@ -103,12 +105,15 @@ type DiskUsage struct { } type Status struct { - PoolName string - DataLoopback string - MetadataLoopback string - Data DiskUsage - Metadata DiskUsage - SectorSize uint64 + PoolName string + DataFile string // actual block device for data + DataLoopback string // loopback file, if used + MetadataFile string // actual block device for metadata + MetadataLoopback string // loopback file, if used + Data DiskUsage + Metadata DiskUsage + SectorSize uint64 + UdevSyncSupported bool } type DevStatus struct { @@ -712,8 +717,10 @@ func setCloseOnExec(name string) { } func (devices *DeviceSet) DMLog(level int, file string, line int, dmError int, message string) { - if level >= 7 { - return // Ignore _LOG_DEBUG + if level >= devicemapper.LogLevelDebug { + // (vbatts) libdm debug is very verbose. If you're debugging libdm, you can + // comment out this check yourself + level = devicemapper.LogLevelInfo } // FIXME(vbatts) push this back into ./pkg/devicemapper/ @@ -934,6 +941,11 @@ func (devices *DeviceSet) closeTransaction() error { } func (devices *DeviceSet) initDevmapper(doInit bool) error { + if os.Getenv("DEBUG") != "" { + devicemapper.LogInitVerbose(devicemapper.LogLevelDebug) + } else { + devicemapper.LogInitVerbose(devicemapper.LogLevelWarn) + } // give ourselves to libdm as a log handler devicemapper.LogInit(devices) @@ -943,6 +955,12 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error { return graphdriver.ErrNotSupported } + // https://github.com/docker/docker/issues/4036 + if supported := devicemapper.UdevSetSyncSupport(true); !supported { + log.Warnf("WARNING: Udev sync is not supported. This will lead to unexpected behavior, data loss and errors") + } + log.Debugf("devicemapper: udev sync support: %v", devicemapper.UdevSyncSupported()) + if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) { return err } @@ -1013,6 +1031,8 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error { if err != nil { return err } + devices.dataLoopFile = data + devices.dataDevice = dataFile.Name() } else { dataFile, err = os.OpenFile(devices.dataDevice, os.O_RDWR, 0600) if err != nil { @@ -1044,6 +1064,8 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error { if err != nil { return err } + devices.metadataLoopFile = metadata + devices.metadataDevice = metadataFile.Name() } else { metadataFile, err = os.OpenFile(devices.metadataDevice, os.O_RDWR, 0600) if err != nil { @@ -1084,7 +1106,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error { func (devices *DeviceSet) AddDevice(hash, baseHash string) error { log.Debugf("[deviceset] AddDevice() hash=%s basehash=%s", hash, baseHash) - defer log.Debugf("[deviceset] AddDevice END") + defer log.Debugf("[deviceset] AddDevice(hash=%s basehash=%s) END", hash, baseHash) baseInfo, err := devices.lookupDevice(baseHash) if err != nil { @@ -1188,7 +1210,7 @@ func (devices *DeviceSet) deactivatePool() error { func (devices *DeviceSet) deactivateDevice(info *DevInfo) error { log.Debugf("[devmapper] deactivateDevice(%s)", info.Hash) - defer log.Debugf("[devmapper] deactivateDevice END") + defer log.Debugf("[devmapper] deactivateDevice END(%s)", info.Hash) // Wait for the unmount to be effective, // by watching the value of Info.OpenCount for the device @@ -1410,7 +1432,7 @@ func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error { func (devices *DeviceSet) UnmountDevice(hash string) error { log.Debugf("[devmapper] UnmountDevice(hash=%s)", hash) - defer log.Debugf("[devmapper] UnmountDevice END") + defer log.Debugf("[devmapper] UnmountDevice(hash=%s) END", hash) info, err := devices.lookupDevice(hash) if err != nil { @@ -1424,7 +1446,7 @@ func (devices *DeviceSet) UnmountDevice(hash string) error { defer devices.Unlock() if info.mountCount == 0 { - return fmt.Errorf("UnmountDevice: device not-mounted id %s\n", hash) + return fmt.Errorf("UnmountDevice: device not-mounted id %s", hash) } info.mountCount-- @@ -1433,7 +1455,7 @@ func (devices *DeviceSet) UnmountDevice(hash string) error { } log.Debugf("[devmapper] Unmount(%s)", info.mountPath) - if err := syscall.Unmount(info.mountPath, 0); err != nil { + if err := syscall.Unmount(info.mountPath, syscall.MNT_DETACH); err != nil { return err } log.Debugf("[devmapper] Unmount done") @@ -1540,6 +1562,19 @@ func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionId, dataU return } +// MetadataDevicePath returns the path to the metadata storage for this deviceset, +// regardless of loopback or block device +func (devices *DeviceSet) DataDevicePath() string { + return devices.dataDevice +} + +// MetadataDevicePath returns the path to the metadata storage for this deviceset, +// regardless of loopback or block device +func (devices *DeviceSet) MetadataDevicePath() string { + return devices.metadataDevice +} + +// Status returns the current status of this deviceset func (devices *DeviceSet) Status() *Status { devices.Lock() defer devices.Unlock() @@ -1547,16 +1582,11 @@ func (devices *DeviceSet) Status() *Status { status := &Status{} status.PoolName = devices.getPoolName() - if len(devices.dataDevice) > 0 { - status.DataLoopback = devices.dataDevice - } else { - status.DataLoopback = path.Join(devices.loopbackDir(), "data") - } - if len(devices.metadataDevice) > 0 { - status.MetadataLoopback = devices.metadataDevice - } else { - status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata") - } + status.DataFile = devices.DataDevicePath() + status.DataLoopback = devices.dataLoopFile + status.MetadataFile = devices.MetadataDevicePath() + status.MetadataLoopback = devices.metadataLoopFile + status.UdevSyncSupported = devicemapper.UdevSyncSupported() totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus() if err == nil { diff --git a/daemon/graphdriver/devmapper/driver.go b/daemon/graphdriver/devmapper/driver.go index b20f3e545..2feed5720 100644 --- a/daemon/graphdriver/devmapper/driver.go +++ b/daemon/graphdriver/devmapper/driver.go @@ -29,7 +29,17 @@ type Driver struct { home string } +var backingFs = "" + func Init(home string, options []string) (graphdriver.Driver, error) { + fsMagic, err := graphdriver.GetFSMagic(home) + if err != nil { + return nil, err + } + if fsName, ok := graphdriver.FsNames[fsMagic]; ok { + backingFs = fsName + } + deviceSet, err := NewDeviceSet(home, true, options) if err != nil { return nil, err @@ -56,13 +66,21 @@ func (d *Driver) Status() [][2]string { status := [][2]string{ {"Pool Name", s.PoolName}, - {"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(int64(s.SectorSize)))}, - {"Data file", s.DataLoopback}, - {"Metadata file", s.MetadataLoopback}, - {"Data Space Used", fmt.Sprintf("%s", units.HumanSize(int64(s.Data.Used)))}, - {"Data Space Total", fmt.Sprintf("%s", units.HumanSize(int64(s.Data.Total)))}, - {"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(int64(s.Metadata.Used)))}, - {"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(int64(s.Metadata.Total)))}, + {"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(float64(s.SectorSize)))}, + {"Backing Filesystem", backingFs}, + {"Data file", s.DataFile}, + {"Metadata file", s.MetadataFile}, + {"Data Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Used)))}, + {"Data Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Total)))}, + {"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Used)))}, + {"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Total)))}, + {"Udev Sync Supported", fmt.Sprintf("%v", s.UdevSyncSupported)}, + } + if len(s.DataLoopback) > 0 { + status = append(status, [2]string{"Data loop file", s.DataLoopback}) + } + if len(s.MetadataLoopback) > 0 { + status = append(status, [2]string{"Metadata loop file", s.MetadataLoopback}) } if vStr, err := devicemapper.GetLibraryVersion(); err == nil { status = append(status, [2]string{"Library Version", vStr}) @@ -141,10 +159,12 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { return rootFs, nil } -func (d *Driver) Put(id string) { - if err := d.DeviceSet.UnmountDevice(id); err != nil { +func (d *Driver) Put(id string) error { + err := d.DeviceSet.UnmountDevice(id) + if err != nil { log.Errorf("Warning: error unmounting device %s: %s", id, err) } + return err } func (d *Driver) Exists(id string) bool { diff --git a/daemon/graphdriver/driver.go b/daemon/graphdriver/driver.go index 95479bf64..c63e1b45d 100644 --- a/daemon/graphdriver/driver.go +++ b/daemon/graphdriver/driver.go @@ -5,15 +5,61 @@ import ( "fmt" "os" "path" + "strings" + log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/archive" ) -type FsMagic uint64 +type FsMagic uint32 const ( - FsMagicBtrfs = FsMagic(0x9123683E) - FsMagicAufs = FsMagic(0x61756673) + FsMagicBtrfs = FsMagic(0x9123683E) + FsMagicAufs = FsMagic(0x61756673) + FsMagicExtfs = FsMagic(0x0000EF53) + FsMagicCramfs = FsMagic(0x28cd3d45) + FsMagicRamFs = FsMagic(0x858458f6) + FsMagicTmpFs = FsMagic(0x01021994) + FsMagicSquashFs = FsMagic(0x73717368) + FsMagicNfsFs = FsMagic(0x00006969) + FsMagicReiserFs = FsMagic(0x52654973) + FsMagicSmbFs = FsMagic(0x0000517B) + FsMagicJffs2Fs = FsMagic(0x000072b6) + FsMagicUnsupported = FsMagic(0x00000000) +) + +var ( + DefaultDriver string + // All registred drivers + drivers map[string]InitFunc + // Slice of drivers that should be used in an order + priority = []string{ + "aufs", + "btrfs", + "devicemapper", + "vfs", + // experimental, has to be enabled manually for now + "overlay", + } + + ErrNotSupported = errors.New("driver not supported") + ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") + ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") + + FsNames = map[FsMagic]string{ + FsMagicAufs: "aufs", + FsMagicBtrfs: "btrfs", + FsMagicExtfs: "extfs", + FsMagicCramfs: "cramfs", + FsMagicRamFs: "ramfs", + FsMagicTmpFs: "tmpfs", + FsMagicSquashFs: "squashfs", + FsMagicNfsFs: "nfs", + FsMagicReiserFs: "reiserfs", + FsMagicSmbFs: "smb", + FsMagicJffs2Fs: "jffs2", + FsMagicUnsupported: "unsupported", + } ) type InitFunc func(root string, options []string) (Driver, error) @@ -38,7 +84,7 @@ type ProtoDriver interface { Get(id, mountLabel string) (dir string, err error) // Put releases the system resources for the specified id, // e.g, unmounting layered filesystem. - Put(id string) + Put(id string) error // Exists returns whether a filesystem layer with the specified // ID exists on this driver. Exists(id string) bool @@ -63,32 +109,13 @@ type Driver interface { // ApplyDiff extracts the changeset from the given diff into the // layer with the specified id and parent, returning the size of the // new layer in bytes. - ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) + ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) // DiffSize calculates the changes between the specified id // and its parent and returns the size in bytes of the changes // relative to its base filesystem directory. - DiffSize(id, parent string) (bytes int64, err error) + DiffSize(id, parent string) (size int64, err error) } -var ( - DefaultDriver string - // All registred drivers - drivers map[string]InitFunc - // Slice of drivers that should be used in an order - priority = []string{ - "aufs", - "btrfs", - "devicemapper", - "vfs", - // experimental, has to be enabled manually for now - "overlay", - } - - ErrNotSupported = errors.New("driver not supported") - ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") - ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") -) - func init() { drivers = make(map[string]InitFunc) } @@ -125,18 +152,34 @@ func New(root string, options []string) (driver Driver, err error) { } return nil, err } + checkPriorDriver(name, root) return driver, nil } // Check all registered drivers if no priority driver is found - for _, initFunc := range drivers { + for name, initFunc := range drivers { if driver, err = initFunc(root, options); err != nil { if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { continue } return nil, err } + checkPriorDriver(name, root) return driver, nil } return nil, fmt.Errorf("No supported storage backend found") } + +func checkPriorDriver(name, root string) { + priorDrivers := []string{} + for prior := range drivers { + if prior != name && prior != "vfs" { + if _, err := os.Stat(path.Join(root, prior)); err == nil { + priorDrivers = append(priorDrivers, prior) + } + } + } + if len(priorDrivers) > 0 { + log.Warnf("graphdriver %s selected. Warning: your graphdriver directory %s already contains data managed by other graphdrivers: %s", name, root, strings.Join(priorDrivers, ",")) + } +} diff --git a/daemon/graphdriver/driver_linux.go b/daemon/graphdriver/driver_linux.go new file mode 100644 index 000000000..acf96d1b4 --- /dev/null +++ b/daemon/graphdriver/driver_linux.go @@ -0,0 +1,14 @@ +package graphdriver + +import ( + "path" + "syscall" +) + +func GetFSMagic(rootpath string) (FsMagic, error) { + var buf syscall.Statfs_t + if err := syscall.Statfs(path.Dir(rootpath), &buf); err != nil { + return 0, err + } + return FsMagic(buf.Type), nil +} diff --git a/daemon/graphdriver/driver_unsupported.go b/daemon/graphdriver/driver_unsupported.go new file mode 100644 index 000000000..27933b6d6 --- /dev/null +++ b/daemon/graphdriver/driver_unsupported.go @@ -0,0 +1,7 @@ +// +build !linux + +package graphdriver + +func GetFSMagic(rootpath string) (FsMagic, error) { + return FsMagicUnsupported, nil +} diff --git a/daemon/graphdriver/fsdiff.go b/daemon/graphdriver/fsdiff.go index 48852a563..ab1b08f62 100644 --- a/daemon/graphdriver/fsdiff.go +++ b/daemon/graphdriver/fsdiff.go @@ -3,14 +3,12 @@ package graphdriver import ( - "fmt" "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/pkg/ioutils" - "github.com/docker/docker/utils" ) // naiveDiffDriver takes a ProtoDriver and adds the @@ -27,8 +25,8 @@ type naiveDiffDriver struct { // it may or may not support on its own: // Diff(id, parent string) (archive.Archive, error) // Changes(id, parent string) ([]archive.Change, error) -// ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) -// DiffSize(id, parent string) (bytes int64, err error) +// ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) +// DiffSize(id, parent string) (size int64, err error) func NaiveDiffDriver(driver ProtoDriver) Driver { return &naiveDiffDriver{ProtoDriver: driver} } @@ -111,7 +109,7 @@ func (gdw *naiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) // ApplyDiff extracts the changeset from the given diff into the // layer with the specified id and parent, returning the size of the // new layer in bytes. -func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) { +func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) { driver := gdw.ProtoDriver // Mount the root filesystem so we can apply the diff/layer. @@ -123,34 +121,18 @@ func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveRea start := time.Now().UTC() log.Debugf("Start untar layer") - if err = chrootarchive.ApplyLayer(layerFs, diff); err != nil { + if size, err = chrootarchive.ApplyLayer(layerFs, diff); err != nil { return } log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) - if parent == "" { - return utils.TreeSize(layerFs) - } - - parentFs, err := driver.Get(parent, "") - if err != nil { - err = fmt.Errorf("Driver %s failed to get image parent %s: %s", driver, parent, err) - return - } - defer driver.Put(parent) - - changes, err := archive.ChangesDirs(layerFs, parentFs) - if err != nil { - return - } - - return archive.ChangesSize(layerFs, changes), nil + return } // DiffSize calculates the changes between the specified layer // and its parent and returns the size in bytes of the changes // relative to its base filesystem directory. -func (gdw *naiveDiffDriver) DiffSize(id, parent string) (bytes int64, err error) { +func (gdw *naiveDiffDriver) DiffSize(id, parent string) (size int64, err error) { driver := gdw.ProtoDriver changes, err := gdw.Changes(id, parent) diff --git a/daemon/graphdriver/graphtest/graphtest.go b/daemon/graphdriver/graphtest/graphtest.go index 67f15c594..af93ea829 100644 --- a/daemon/graphdriver/graphtest/graphtest.go +++ b/daemon/graphdriver/graphtest/graphtest.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path" + "strings" "syscall" "testing" @@ -73,7 +74,7 @@ func newDriver(t *testing.T, name string) *Driver { d, err := graphdriver.GetDriver(name, root, nil) if err != nil { - if err == graphdriver.ErrNotSupported || err == graphdriver.ErrPrerequisites { + if err == graphdriver.ErrNotSupported || err == graphdriver.ErrPrerequisites || strings.Contains(err.Error(), "'overlay' is not supported over") { t.Skipf("Driver %s not supported", name) } t.Fatal(err) diff --git a/daemon/graphdriver/overlay/overlay.go b/daemon/graphdriver/overlay/overlay.go index 2569ccb6d..27784c14a 100644 --- a/daemon/graphdriver/overlay/overlay.go +++ b/daemon/graphdriver/overlay/overlay.go @@ -28,7 +28,7 @@ var ( type ApplyDiffProtoDriver interface { graphdriver.ProtoDriver - ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) + ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) } type naiveDiffDriverWithApply struct { @@ -90,15 +90,36 @@ type Driver struct { active map[string]*ActiveMount } +var backingFs = "" + func init() { graphdriver.Register("overlay", Init) } func Init(home string, options []string) (graphdriver.Driver, error) { + if err := supportsOverlay(); err != nil { return nil, graphdriver.ErrNotSupported } + fsMagic, err := graphdriver.GetFSMagic(home) + if err != nil { + return nil, err + } + if fsName, ok := graphdriver.FsNames[fsMagic]; ok { + backingFs = fsName + } + + // check if they are running over btrfs or aufs + switch fsMagic { + case graphdriver.FsMagicBtrfs: + log.Error("'overlay' is not supported over btrfs.") + return nil, graphdriver.ErrIncompatibleFS + case graphdriver.FsMagicAufs: + log.Error("'overlay' is not supported over aufs.") + return nil, graphdriver.ErrIncompatibleFS + } + // Create the driver home dir if err := os.MkdirAll(home, 0755); err != nil && !os.IsExist(err) { return nil, err @@ -138,7 +159,9 @@ func (d *Driver) String() string { } func (d *Driver) Status() [][2]string { - return nil + return [][2]string{ + {"Backing Filesystem", backingFs}, + } } func (d *Driver) Cleanup() error { @@ -284,7 +307,7 @@ func (d *Driver) Get(id string, mountLabel string) (string, error) { return mount.path, nil } -func (d *Driver) Put(id string) { +func (d *Driver) Put(id string) error { // Protect the d.active from concurrent access d.Lock() defer d.Unlock() @@ -292,24 +315,26 @@ func (d *Driver) Put(id string) { mount := d.active[id] if mount == nil { log.Debugf("Put on a non-mounted device %s", id) - return + return nil } mount.count-- if mount.count > 0 { - return + return nil } + defer delete(d.active, id) if mount.mounted { - if err := syscall.Unmount(mount.path, 0); err != nil { + err := syscall.Unmount(mount.path, 0) + if err != nil { log.Debugf("Failed to unmount %s overlay: %v", id, err) } + return err } - - delete(d.active, id) + return nil } -func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) (bytes int64, err error) { +func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) (size int64, err error) { dir := d.dir(id) if parent == "" { @@ -347,7 +372,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) return 0, err } - if err := chrootarchive.ApplyLayer(tmpRootDir, diff); err != nil { + if size, err = chrootarchive.ApplyLayer(tmpRootDir, diff); err != nil { return 0, err } @@ -356,12 +381,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) return 0, err } - changes, err := archive.ChangesDirs(rootDir, parentRootDir) - if err != nil { - return 0, err - } - - return archive.ChangesSize(rootDir, changes), nil + return } func (d *Driver) Exists(id string) bool { diff --git a/daemon/graphdriver/vfs/driver.go b/daemon/graphdriver/vfs/driver.go index aa104500b..fe4d38230 100644 --- a/daemon/graphdriver/vfs/driver.go +++ b/daemon/graphdriver/vfs/driver.go @@ -1,10 +1,8 @@ package vfs import ( - "bytes" "fmt" "os" - "os/exec" "path" "github.com/docker/docker/daemon/graphdriver" @@ -39,14 +37,6 @@ func (d *Driver) Cleanup() error { return nil } -func isGNUcoreutils() bool { - if stdout, err := exec.Command("cp", "--version").Output(); err == nil { - return bytes.Contains(stdout, []byte("GNU coreutils")) - } - - return false -} - func (d *Driver) Create(id, parent string) error { dir := d.dir(id) if err := os.MkdirAll(path.Dir(dir), 0700); err != nil { @@ -93,9 +83,10 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { return dir, nil } -func (d *Driver) Put(id string) { +func (d *Driver) Put(id string) error { // The vfs driver has no runtime resources (e.g. mounts) // to clean up, so we don't need anything here + return nil } func (d *Driver) Exists(id string) bool { diff --git a/daemon/image_delete.go b/daemon/image_delete.go index b0b0c3a02..19f81f11a 100644 --- a/daemon/image_delete.go +++ b/daemon/image_delete.go @@ -113,7 +113,7 @@ func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine. return err } out := &engine.Env{} - out.Set("Deleted", img.ID) + out.SetJson("Deleted", img.ID) imgs.Add(out) eng.Job("log", "delete", img.ID, "").Run() if img.Parent != "" && !noprune { @@ -131,7 +131,7 @@ func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine. func (daemon *Daemon) canDeleteImage(imgID string, force bool) error { for _, container := range daemon.List() { - parent, err := daemon.Repositories().LookupImage(container.Image) + parent, err := daemon.Repositories().LookupImage(container.ImageID) if err != nil { if daemon.Graph().IsNotExist(err) { return nil diff --git a/daemon/info.go b/daemon/info.go index 518722b6c..8eb4358f4 100644 --- a/daemon/info.go +++ b/daemon/info.go @@ -55,8 +55,17 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) engine.Status { if err := cjob.Run(); err != nil { return job.Error(err) } + registryJob := job.Eng.Job("registry_config") + registryEnv, _ := registryJob.Stdout.AddEnv() + if err := registryJob.Run(); err != nil { + return job.Error(err) + } + registryConfig := registry.ServiceConfig{} + if err := registryEnv.GetJson("config", ®istryConfig); err != nil { + return job.Error(err) + } v := &engine.Env{} - v.Set("ID", daemon.ID) + v.SetJson("ID", daemon.ID) v.SetInt("Containers", len(daemon.List())) v.SetInt("Images", imgcount) v.Set("Driver", daemon.GraphDriver().String()) @@ -72,13 +81,14 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) engine.Status { v.Set("KernelVersion", kernelVersion) v.Set("OperatingSystem", operatingSystem) v.Set("IndexServerAddress", registry.IndexServerAddress()) + v.SetJson("RegistryConfig", registryConfig) v.Set("InitSha1", dockerversion.INITSHA1) v.Set("InitPath", initPath) v.SetInt("NCPU", runtime.NumCPU()) v.SetInt64("MemTotal", meminfo.MemTotal) v.Set("DockerRootDir", daemon.Config().Root) if hostname, err := os.Hostname(); err == nil { - v.Set("Name", hostname) + v.SetJson("Name", hostname) } v.SetList("Labels", daemon.Config().Labels) if _, err := v.WriteTo(job.Stdout); err != nil { diff --git a/daemon/inspect.go b/daemon/inspect.go index a6ff2de69..37d00573b 100644 --- a/daemon/inspect.go +++ b/daemon/inspect.go @@ -29,18 +29,19 @@ func (daemon *Daemon) ContainerInspect(job *engine.Job) engine.Status { } out := &engine.Env{} - out.Set("Id", container.ID) + out.SetJson("Id", container.ID) out.SetAuto("Created", container.Created) out.SetJson("Path", container.Path) out.SetList("Args", container.Args) out.SetJson("Config", container.Config) out.SetJson("State", container.State) - out.Set("Image", container.Image) + out.Set("Image", container.ImageID) out.SetJson("NetworkSettings", container.NetworkSettings) out.Set("ResolvConfPath", container.ResolvConfPath) out.Set("HostnamePath", container.HostnamePath) out.Set("HostsPath", container.HostsPath) - out.Set("Name", container.Name) + out.SetJson("Name", container.Name) + out.SetInt("RestartCount", container.RestartCount) out.Set("Driver", container.Driver) out.Set("ExecDriver", container.ExecDriver) out.Set("MountLabel", container.MountLabel) @@ -49,6 +50,8 @@ func (daemon *Daemon) ContainerInspect(job *engine.Job) engine.Status { out.SetJson("VolumesRW", container.VolumesRW) out.SetJson("AppArmorProfile", container.AppArmorProfile) + out.SetList("ExecIDs", container.GetExecIDs()) + if children, err := daemon.Children(container.Name); err == nil { for linkAlias, child := range children { container.hostConfig.Links = append(container.hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias)) diff --git a/daemon/list.go b/daemon/list.go index 29d7298fc..5197d9986 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -45,6 +45,14 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { } } + if i, ok := psFilters["status"]; ok { + for _, value := range i { + if value == "exited" { + all = true + } + } + } + names := map[string][]string{} daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error { names[e.ID()] = append(names[e.ID()], p) @@ -73,7 +81,6 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { if !container.Running && !all && n <= 0 && since == "" && before == "" { return nil } - if !psFilters.Match("name", container.Name) { return nil } @@ -96,10 +103,10 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { return errLast } } - if len(filt_exited) > 0 && !container.Running { + if len(filt_exited) > 0 { should_skip := true for _, code := range filt_exited { - if code == container.ExitCode { + if code == container.ExitCode && !container.Running { should_skip = false break } @@ -114,9 +121,9 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { } displayed++ out := &engine.Env{} - out.Set("Id", container.ID) + out.SetJson("Id", container.ID) out.SetList("Names", names[container.ID]) - out.Set("Image", daemon.Repositories().ImageName(container.Image)) + out.SetJson("Image", daemon.Repositories().ImageName(container.ImageID)) if len(container.Args) > 0 { args := []string{} for _, arg := range container.Args { diff --git a/daemon/monitor.go b/daemon/monitor.go index 12a699633..9e7d3062f 100644 --- a/daemon/monitor.go +++ b/daemon/monitor.go @@ -9,12 +9,13 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/runconfig" + "github.com/docker/docker/utils" ) const defaultTimeIncrement = 100 // containerMonitor monitors the execution of a container's main process. -// If a restart policy is specified for the cotnainer the monitor will ensure that the +// If a restart policy is specified for the container the monitor will ensure that the // process is restarted based on the rules of the policy. When the container is finally stopped // the monitor will reset and cleanup any of the container resources such as networking allocations // and the rootfs @@ -154,6 +155,9 @@ func (m *containerMonitor) Start() error { if m.shouldRestart(exitStatus.ExitCode) { m.container.SetRestarting(&exitStatus) + if exitStatus.OOMKilled { + m.container.LogEvent("oom") + } m.container.LogEvent("die") m.resetContainer(true) @@ -170,6 +174,9 @@ func (m *containerMonitor) Start() error { continue } m.container.ExitCode = exitStatus.ExitCode + if exitStatus.OOMKilled { + m.container.LogEvent("oom") + } m.container.LogEvent("die") m.resetContainer(true) return err @@ -223,8 +230,9 @@ func (m *containerMonitor) shouldRestart(exitCode int) bool { return true case "on-failure": // the default value of 0 for MaximumRetryCount means that we will not enforce a maximum count - if max := m.restartPolicy.MaximumRetryCount; max != 0 && m.failureCount >= max { - log.Debugf("stopping restart of container %s because maximum failure could of %d has been reached", max) + if max := m.restartPolicy.MaximumRetryCount; max != 0 && m.failureCount > max { + log.Debugf("stopping restart of container %s because maximum failure could of %d has been reached", + utils.TruncateID(m.container.ID), max) return false } diff --git a/daemon/network_settings.go b/daemon/network_settings.go index 69c15be3d..97c2e3ab4 100644 --- a/daemon/network_settings.go +++ b/daemon/network_settings.go @@ -9,13 +9,18 @@ import ( type PortMapping map[string]string // Deprecated type NetworkSettings struct { - IPAddress string - IPPrefixLen int - MacAddress string - Gateway string - Bridge string - PortMapping map[string]PortMapping // Deprecated - Ports nat.PortMap + IPAddress string + IPPrefixLen int + MacAddress string + LinkLocalIPv6Address string + LinkLocalIPv6PrefixLen int + GlobalIPv6Address string + GlobalIPv6PrefixLen int + Gateway string + IPv6Gateway string + Bridge string + PortMapping map[string]PortMapping // Deprecated + Ports nat.PortMap } func (settings *NetworkSettings) PortMappingAPI() *engine.Table { diff --git a/daemon/networkdriver/bridge/driver.go b/daemon/networkdriver/bridge/driver.go index e0467b6bd..e7ddfd210 100644 --- a/daemon/networkdriver/bridge/driver.go +++ b/daemon/networkdriver/bridge/driver.go @@ -1,11 +1,13 @@ package bridge import ( + "encoding/hex" + "errors" "fmt" "io/ioutil" "net" "os" - "strconv" + "strings" "sync" log "github.com/Sirupsen/logrus" @@ -28,6 +30,7 @@ const ( // Network interface represents the networking stack of a container type networkInterface struct { IP net.IP + IPv6 net.IP PortMappings []net.Addr // there are mappings to the host interfaces } @@ -70,8 +73,10 @@ var ( "192.168.44.1/24", } - bridgeIface string - bridgeNetwork *net.IPNet + bridgeIface string + bridgeIPv4Network *net.IPNet + bridgeIPv6Addr net.IP + globalIPv6Network *net.IPNet defaultBindingIP = net.ParseIP("0.0.0.0") currentInterfaces = ifaces{c: make(map[string]*networkInterface)} @@ -79,13 +84,19 @@ var ( func InitDriver(job *engine.Job) engine.Status { var ( - network *net.IPNet + networkv4 *net.IPNet + networkv6 *net.IPNet + addrv4 net.Addr + addrsv6 []net.Addr enableIPTables = job.GetenvBool("EnableIptables") + enableIPv6 = job.GetenvBool("EnableIPv6") icc = job.GetenvBool("InterContainerCommunication") ipMasq = job.GetenvBool("EnableIpMasq") ipForward = job.GetenvBool("EnableIpForward") bridgeIP = job.Getenv("BridgeIP") + bridgeIPv6 = "fe80::1/64" fixedCIDR = job.Getenv("FixedCIDR") + fixedCIDRv6 = job.Getenv("FixedCIDRv6") ) if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" { @@ -99,41 +110,97 @@ func InitDriver(job *engine.Job) engine.Status { bridgeIface = DefaultNetworkBridge } - addr, err := networkdriver.GetIfaceAddr(bridgeIface) + addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface) + if err != nil { + // No Bridge existent. Create one // If we're not using the default bridge, fail without trying to create it if !usingDefaultBridge { return job.Error(err) } - // If the bridge interface is not found (or has no address), try to create it and/or add an address - if err := configureBridge(bridgeIP); err != nil { + + // If the iface is not found, try to create it + if err := configureBridge(bridgeIP, bridgeIPv6, enableIPv6); err != nil { return job.Error(err) } - addr, err = networkdriver.GetIfaceAddr(bridgeIface) + addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return job.Error(err) } - network = addr.(*net.IPNet) + + if fixedCIDRv6 != "" { + // Setting route to global IPv6 subnet + log.Infof("Adding route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) + if err := netlink.AddRoute(fixedCIDRv6, "", "", bridgeIface); err != nil { + log.Fatalf("Could not add route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) + } + } } else { - network = addr.(*net.IPNet) + // Bridge exists already. Getting info... // validate that the bridge ip matches the ip specified by BridgeIP if bridgeIP != "" { + networkv4 = addrv4.(*net.IPNet) bip, _, err := net.ParseCIDR(bridgeIP) if err != nil { return job.Error(err) } - if !network.IP.Equal(bip) { - return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", network.IP, bip) + if !networkv4.IP.Equal(bip) { + return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip) } } + + // a bridge might exist but not have any IPv6 addr associated with it yet + // (for example, an existing Docker installation that has only been used + // with IPv4 and docker0 already is set up) In that case, we can perform + // the bridge init for IPv6 here, else we will error out below if --ipv6=true + if len(addrsv6) == 0 && enableIPv6 { + if err := setupIPv6Bridge(bridgeIPv6); err != nil { + return job.Error(err) + } + // recheck addresses now that IPv6 is setup on the bridge + addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) + if err != nil { + return job.Error(err) + } + } + + // TODO: Check if route to fixedCIDRv6 is set + } + + if enableIPv6 { + bip6, _, err := net.ParseCIDR(bridgeIPv6) + if err != nil { + return job.Error(err) + } + found := false + for _, addrv6 := range addrsv6 { + networkv6 = addrv6.(*net.IPNet) + if networkv6.IP.Equal(bip6) { + found = true + break + } + } + if !found { + return job.Errorf("bridge IPv6 does not match existing bridge configuration %s", bip6) + } + } + + networkv4 = addrv4.(*net.IPNet) + + if enableIPv6 { + if len(addrsv6) == 0 { + return job.Error(errors.New("IPv6 enabled but no IPv6 detected")) + } + bridgeIPv6Addr = networkv6.IP } // Configure iptables for link support if enableIPTables { - if err := setupIPTables(addr, icc, ipMasq); err != nil { + if err := setupIPTables(addrv4, icc, ipMasq); err != nil { return job.Error(err) } + } if ipForward { @@ -141,35 +208,64 @@ func InitDriver(job *engine.Job) engine.Status { if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil { job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err) } + + if fixedCIDRv6 != "" { + // Enable IPv6 forwarding + if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil { + job.Logf("WARNING: unable to enable IPv6 default forwarding: %s\n", err) + } + if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil { + job.Logf("WARNING: unable to enable IPv6 all forwarding: %s\n", err) + } + } } // We can always try removing the iptables - if err := iptables.RemoveExistingChain("DOCKER"); err != nil { + if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil { return job.Error(err) } if enableIPTables { - chain, err := iptables.NewChain("DOCKER", bridgeIface) + _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat) + if err != nil { + return job.Error(err) + } + chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) if err != nil { return job.Error(err) } portmapper.SetIptablesChain(chain) } - bridgeNetwork = network + bridgeIPv4Network = networkv4 if fixedCIDR != "" { _, subnet, err := net.ParseCIDR(fixedCIDR) if err != nil { return job.Error(err) } log.Debugf("Subnet: %v", subnet) - if err := ipallocator.RegisterSubnet(bridgeNetwork, subnet); err != nil { + if err := ipallocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil { return job.Error(err) } } + if fixedCIDRv6 != "" { + _, subnet, err := net.ParseCIDR(fixedCIDRv6) + if err != nil { + return job.Error(err) + } + log.Debugf("Subnet: %v", subnet) + if err := ipallocator.RegisterSubnet(subnet, subnet); err != nil { + return job.Error(err) + } + globalIPv6Network = subnet + } + + // Block BridgeIP in IP allocator + ipallocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP) + // https://github.com/docker/docker/issues/2768 - job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP) + job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP) for name, f := range map[string]engine.Handler{ "allocate_interface": Allocate, @@ -257,7 +353,7 @@ func setupIPTables(addr net.Addr, icc, ipmasq bool) error { // If the bridge `bridgeIface` already exists, it will only perform the IP address association with the existing // bridge (fixes issue #8444) // If an address which doesn't conflict with existing interfaces can't be found, an error is returned. -func configureBridge(bridgeIP string) error { +func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error { nameservers := []string{} resolvConf, _ := resolvconf.Get() // we don't check for an error here, because we don't really care @@ -314,15 +410,46 @@ func configureBridge(bridgeIP string) error { return err } - if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil { + if err := netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil { return fmt.Errorf("Unable to add private network: %s", err) } + + if enableIPv6 { + if err := setupIPv6Bridge(bridgeIPv6); err != nil { + return err + } + } + if err := netlink.NetworkLinkUp(iface); err != nil { return fmt.Errorf("Unable to start network bridge: %s", err) } return nil } +func setupIPv6Bridge(bridgeIPv6 string) error { + + iface, err := net.InterfaceByName(bridgeIface) + if err != nil { + return err + } + // Enable IPv6 on the bridge + procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6" + if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil { + return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err) + } + + ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6) + if err != nil { + return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err) + } + + if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil { + return fmt.Errorf("Unable to add private IPv6 network: %v", err) + } + + return nil +} + func createBridgeIface(name string) error { kv, err := kernel.GetKernelVersion() // only set the bridge's mac address if the kernel version is > 3.3 @@ -357,20 +484,34 @@ func generateMacAddr(ip net.IP) net.HardwareAddr { return hw } +func linkLocalIPv6FromMac(mac string) (string, error) { + hx := strings.Replace(mac, ":", "", -1) + hw, err := hex.DecodeString(hx) + if err != nil { + return "", errors.New("Could not parse MAC address " + mac) + } + + hw[0] ^= 0x2 + + return fmt.Sprintf("fe80::%x%x:%xff:fe%x:%x%x/64", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]), nil +} + // Allocate a network interface func Allocate(job *engine.Job) engine.Status { var ( - ip net.IP - mac net.HardwareAddr - err error - id = job.Args[0] - requestedIP = net.ParseIP(job.Getenv("RequestedIP")) + ip net.IP + mac net.HardwareAddr + err error + id = job.Args[0] + requestedIP = net.ParseIP(job.Getenv("RequestedIP")) + requestedIPv6 = net.ParseIP(job.Getenv("RequestedIPv6")) + globalIPv6 net.IP ) if requestedIP != nil { - ip, err = ipallocator.RequestIP(bridgeNetwork, requestedIP) + ip, err = ipallocator.RequestIP(bridgeIPv4Network, requestedIP) } else { - ip, err = ipallocator.RequestIP(bridgeNetwork, nil) + ip, err = ipallocator.RequestIP(bridgeIPv4Network, nil) } if err != nil { return job.Error(err) @@ -381,18 +522,53 @@ func Allocate(job *engine.Job) engine.Status { mac = generateMacAddr(ip) } + if globalIPv6Network != nil { + // if globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address + netmask_ones, _ := globalIPv6Network.Mask.Size() + if requestedIPv6 == nil && netmask_ones <= 80 { + requestedIPv6 = globalIPv6Network.IP + for i, h := range mac { + requestedIPv6[i+10] = h + } + } + + globalIPv6, err = ipallocator.RequestIP(globalIPv6Network, requestedIPv6) + if err != nil { + log.Errorf("Allocator: RequestIP v6: %s", err.Error()) + return job.Error(err) + } + log.Infof("Allocated IPv6 %s", globalIPv6) + } + out := engine.Env{} out.Set("IP", ip.String()) - out.Set("Mask", bridgeNetwork.Mask.String()) - out.Set("Gateway", bridgeNetwork.IP.String()) + out.Set("Mask", bridgeIPv4Network.Mask.String()) + out.Set("Gateway", bridgeIPv4Network.IP.String()) out.Set("MacAddress", mac.String()) out.Set("Bridge", bridgeIface) - size, _ := bridgeNetwork.Mask.Size() + size, _ := bridgeIPv4Network.Mask.Size() out.SetInt("IPPrefixLen", size) + // if linklocal IPv6 + localIPv6Net, err := linkLocalIPv6FromMac(mac.String()) + if err != nil { + return job.Error(err) + } + localIPv6, _, _ := net.ParseCIDR(localIPv6Net) + out.Set("LinkLocalIPv6", localIPv6.String()) + out.Set("MacAddress", mac.String()) + + if globalIPv6Network != nil { + out.Set("GlobalIPv6", globalIPv6.String()) + sizev6, _ := globalIPv6Network.Mask.Size() + out.SetInt("GlobalIPv6PrefixLen", sizev6) + out.Set("IPv6Gateway", bridgeIPv6Addr.String()) + } + currentInterfaces.Set(id, &networkInterface{ - IP: ip, + IP: ip, + IPv6: globalIPv6, }) out.WriteTo(job.Stdout) @@ -417,8 +593,13 @@ func Release(job *engine.Job) engine.Status { } } - if err := ipallocator.ReleaseIP(bridgeNetwork, containerInterface.IP); err != nil { - log.Infof("Unable to release ip %s", err) + if err := ipallocator.ReleaseIP(bridgeIPv4Network, containerInterface.IP); err != nil { + log.Infof("Unable to release IPv4 %s", err) + } + if globalIPv6Network != nil { + if err := ipallocator.ReleaseIP(globalIPv6Network, containerInterface.IPv6); err != nil { + log.Infof("Unable to release IPv6 %s", err) + } } return engine.StatusOK } @@ -501,35 +682,38 @@ func AllocatePort(job *engine.Job) engine.Status { func LinkContainers(job *engine.Job) engine.Status { var ( action = job.Args[0] + nfAction iptables.Action childIP = job.Getenv("ChildIP") parentIP = job.Getenv("ParentIP") ignoreErrors = job.GetenvBool("IgnoreErrors") ports = job.GetenvList("Ports") ) - for _, value := range ports { - port := nat.Port(value) - if output, err := iptables.Raw(action, "FORWARD", - "-i", bridgeIface, "-o", bridgeIface, - "-p", port.Proto(), - "-s", parentIP, - "--dport", strconv.Itoa(port.Int()), - "-d", childIP, - "-j", "ACCEPT"); !ignoreErrors && err != nil { - return job.Error(err) - } else if len(output) != 0 { - return job.Errorf("Error toggle iptables forward: %s", output) - } - if output, err := iptables.Raw(action, "FORWARD", - "-i", bridgeIface, "-o", bridgeIface, - "-p", port.Proto(), - "-s", childIP, - "--sport", strconv.Itoa(port.Int()), - "-d", parentIP, - "-j", "ACCEPT"); !ignoreErrors && err != nil { + switch action { + case "-A": + nfAction = iptables.Append + case "-I": + nfAction = iptables.Insert + case "-D": + nfAction = iptables.Delete + default: + return job.Errorf("Invalid action '%s' specified", action) + } + + ip1 := net.ParseIP(parentIP) + if ip1 == nil { + return job.Errorf("parent IP '%s' is invalid", parentIP) + } + ip2 := net.ParseIP(childIP) + if ip2 == nil { + return job.Errorf("child IP '%s' is invalid", childIP) + } + + chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface} + for _, p := range ports { + port := nat.Port(p) + if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil { return job.Error(err) - } else if len(output) != 0 { - return job.Errorf("Error toggle iptables forward: %s", output) } } return engine.StatusOK diff --git a/daemon/networkdriver/bridge/driver_test.go b/daemon/networkdriver/bridge/driver_test.go index 1bda2f437..02bea9ce1 100644 --- a/daemon/networkdriver/bridge/driver_test.go +++ b/daemon/networkdriver/bridge/driver_test.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/daemon/networkdriver/portmapper" "github.com/docker/docker/engine" + "github.com/docker/docker/pkg/iptables" ) func init() { @@ -118,3 +119,43 @@ func TestMacAddrGeneration(t *testing.T) { t.Fatal("Non-unique MAC address") } } + +func TestLinkContainers(t *testing.T) { + eng := engine.New() + eng.Logging = false + + // Init driver + job := eng.Job("initdriver") + if res := InitDriver(job); res != engine.StatusOK { + t.Fatal("Failed to initialize network driver") + } + + // Allocate interface + job = eng.Job("allocate_interface", "container_id") + if res := Allocate(job); res != engine.StatusOK { + t.Fatal("Failed to allocate network interface") + } + + job.Args[0] = "-I" + + job.Setenv("ChildIP", "172.17.0.2") + job.Setenv("ParentIP", "172.17.0.1") + job.SetenvBool("IgnoreErrors", false) + job.SetenvList("Ports", []string{"1234"}) + + bridgeIface = "lo" + _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) + if err != nil { + t.Fatal(err) + } + + if res := LinkContainers(job); res != engine.StatusOK { + t.Fatalf("LinkContainers failed") + } + + // flush rules + if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil { + t.Fatal(err) + } + +} diff --git a/daemon/networkdriver/ipallocator/allocator.go b/daemon/networkdriver/ipallocator/allocator.go index a8625c030..40c3eb823 100644 --- a/daemon/networkdriver/ipallocator/allocator.go +++ b/daemon/networkdriver/ipallocator/allocator.go @@ -121,7 +121,6 @@ func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) { // Register the IP. allocated.p[ip.String()] = struct{}{} - allocated.last.Set(pos) return ip, nil } diff --git a/daemon/networkdriver/portmapper/mapper.go b/daemon/networkdriver/portmapper/mapper.go index 4bf8cd142..9f2ca5a75 100644 --- a/daemon/networkdriver/portmapper/mapper.go +++ b/daemon/networkdriver/portmapper/mapper.go @@ -93,7 +93,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er } containerIP, containerPort := getIPAndPort(m.container) - if err := forward(iptables.Add, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { + if err := forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { return nil, err } diff --git a/daemon/networkdriver/utils.go b/daemon/networkdriver/utils.go index 07d95445a..9f0c88cd5 100644 --- a/daemon/networkdriver/utils.go +++ b/daemon/networkdriver/utils.go @@ -44,11 +44,13 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error { // Detects overlap between one IPNet and another func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool { - if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) { - return true - } - if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) { - return true + if len(netX.IP) == len(netY.IP) { + if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) { + return true + } + if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) { + return true + } } return false } @@ -72,31 +74,34 @@ func NetworkRange(network *net.IPNet) (net.IP, net.IP) { return netIP.Mask(network.Mask), net.IP(lastIP) } -// Return the IPv4 address of a network interface -func GetIfaceAddr(name string) (net.Addr, error) { +// Return the first IPv4 address and slice of IPv6 addresses for the specified network interface +func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) { iface, err := net.InterfaceByName(name) if err != nil { - return nil, err + return nil, nil, err } addrs, err := iface.Addrs() if err != nil { - return nil, err + return nil, nil, err } var addrs4 []net.Addr + var addrs6 []net.Addr for _, addr := range addrs { ip := (addr.(*net.IPNet)).IP if ip4 := ip.To4(); ip4 != nil { addrs4 = append(addrs4, addr) + } else if ip6 := ip.To16(); len(ip6) == net.IPv6len { + addrs6 = append(addrs6, addr) } } switch { case len(addrs4) == 0: - return nil, fmt.Errorf("Interface %v has no IP addresses", name) + return nil, nil, fmt.Errorf("Interface %v has no IPv4 addresses", name) case len(addrs4) > 1: fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n", name, (addrs4[0].(*net.IPNet)).IP) } - return addrs4[0], nil + return addrs4[0], addrs6, nil } func GetDefaultRouteIface() (*net.Interface, error) { diff --git a/daemon/rename.go b/daemon/rename.go new file mode 100644 index 000000000..1dedc7d3a --- /dev/null +++ b/daemon/rename.go @@ -0,0 +1,34 @@ +package daemon + +import ( + "github.com/docker/docker/engine" +) + +func (daemon *Daemon) ContainerRename(job *engine.Job) engine.Status { + if len(job.Args) != 2 { + return job.Errorf("usage: %s OLD_NAME NEW_NAME", job.Name) + } + oldName := job.Args[0] + newName := job.Args[1] + + container := daemon.Get(oldName) + if container == nil { + return job.Errorf("No such container: %s", oldName) + } + + oldName = container.Name + + container.Lock() + defer container.Unlock() + if _, err := daemon.reserveName(container.ID, newName); err != nil { + return job.Errorf("Error when allocating new name: %s", err) + } + + container.Name = newName + + if err := daemon.containerGraph.Delete(oldName); err != nil { + return job.Errorf("Failed to delete container %q: %v", oldName, err) + } + + return engine.StatusOK +} diff --git a/daemon/start.go b/daemon/start.go index f72407e3f..d6655189d 100644 --- a/daemon/start.go +++ b/daemon/start.go @@ -22,6 +22,10 @@ func (daemon *Daemon) ContainerStart(job *engine.Job) engine.Status { return job.Errorf("No such container: %s", name) } + if container.IsPaused() { + return job.Errorf("Cannot start a paused container, try unpause instead.") + } + if container.IsRunning() { return job.Errorf("Container already started") } @@ -44,9 +48,13 @@ func (daemon *Daemon) ContainerStart(job *engine.Job) engine.Status { } func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.HostConfig) error { + container.Lock() + defer container.Unlock() if err := parseSecurityOpt(container, hostConfig); err != nil { return err } + + // FIXME: this should be handled by the volume subsystem // Validate the HostConfig binds. Make sure that: // the source exists for _, bind := range hostConfig.Binds { @@ -66,8 +74,8 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig. if err := daemon.RegisterLinks(container, hostConfig); err != nil { return err } - container.SetHostConfig(hostConfig) - container.ToDisk() + container.hostConfig = hostConfig + container.toDisk() return nil } diff --git a/daemon/state_test.go b/daemon/state_test.go index 32c005cf2..861076aeb 100644 --- a/daemon/state_test.go +++ b/daemon/state_test.go @@ -49,7 +49,7 @@ func TestStateRunStop(t *testing.T) { atomic.StoreInt64(&exit, int64(exitCode)) close(stopped) }() - s.SetStopped(&execdriver.ExitStatus{i, false}) + s.SetStopped(&execdriver.ExitStatus{ExitCode: i}) if s.IsRunning() { t.Fatal("State is running") } diff --git a/daemon/stats.go b/daemon/stats.go new file mode 100644 index 000000000..e047497ec --- /dev/null +++ b/daemon/stats.go @@ -0,0 +1,98 @@ +package daemon + +import ( + "encoding/json" + + "github.com/docker/docker/api/stats" + "github.com/docker/docker/daemon/execdriver" + "github.com/docker/docker/engine" + "github.com/docker/libcontainer" + "github.com/docker/libcontainer/cgroups" +) + +func (daemon *Daemon) ContainerStats(job *engine.Job) engine.Status { + updates, err := daemon.SubscribeToContainerStats(job.Args[0]) + if err != nil { + return job.Error(err) + } + enc := json.NewEncoder(job.Stdout) + for v := range updates { + update := v.(*execdriver.ResourceStats) + ss := convertToAPITypes(update.ContainerStats) + ss.MemoryStats.Limit = uint64(update.MemoryLimit) + ss.Read = update.Read + ss.CpuStats.SystemUsage = update.SystemUsage + if err := enc.Encode(ss); err != nil { + // TODO: handle the specific broken pipe + daemon.UnsubscribeToContainerStats(job.Args[0], updates) + return job.Error(err) + } + } + return engine.StatusOK +} + +// convertToAPITypes converts the libcontainer.ContainerStats to the api specific +// structs. This is done to preserve API compatibility and versioning. +func convertToAPITypes(ls *libcontainer.ContainerStats) *stats.Stats { + s := &stats.Stats{} + if ls.NetworkStats != nil { + s.Network = stats.Network{ + RxBytes: ls.NetworkStats.RxBytes, + RxPackets: ls.NetworkStats.RxPackets, + RxErrors: ls.NetworkStats.RxErrors, + RxDropped: ls.NetworkStats.RxDropped, + TxBytes: ls.NetworkStats.TxBytes, + TxPackets: ls.NetworkStats.TxPackets, + TxErrors: ls.NetworkStats.TxErrors, + TxDropped: ls.NetworkStats.TxDropped, + } + } + cs := ls.CgroupStats + if cs != nil { + s.BlkioStats = stats.BlkioStats{ + IoServiceBytesRecursive: copyBlkioEntry(cs.BlkioStats.IoServiceBytesRecursive), + IoServicedRecursive: copyBlkioEntry(cs.BlkioStats.IoServicedRecursive), + IoQueuedRecursive: copyBlkioEntry(cs.BlkioStats.IoQueuedRecursive), + IoServiceTimeRecursive: copyBlkioEntry(cs.BlkioStats.IoServiceTimeRecursive), + IoWaitTimeRecursive: copyBlkioEntry(cs.BlkioStats.IoWaitTimeRecursive), + IoMergedRecursive: copyBlkioEntry(cs.BlkioStats.IoMergedRecursive), + IoTimeRecursive: copyBlkioEntry(cs.BlkioStats.IoTimeRecursive), + SectorsRecursive: copyBlkioEntry(cs.BlkioStats.SectorsRecursive), + } + cpu := cs.CpuStats + s.CpuStats = stats.CpuStats{ + CpuUsage: stats.CpuUsage{ + TotalUsage: cpu.CpuUsage.TotalUsage, + PercpuUsage: cpu.CpuUsage.PercpuUsage, + UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode, + UsageInUsermode: cpu.CpuUsage.UsageInUsermode, + }, + ThrottlingData: stats.ThrottlingData{ + Periods: cpu.ThrottlingData.Periods, + ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods, + ThrottledTime: cpu.ThrottlingData.ThrottledTime, + }, + } + mem := cs.MemoryStats + s.MemoryStats = stats.MemoryStats{ + Usage: mem.Usage, + MaxUsage: mem.MaxUsage, + Stats: mem.Stats, + Failcnt: mem.Failcnt, + } + } + return s +} + +func copyBlkioEntry(entries []cgroups.BlkioStatEntry) []stats.BlkioStatEntry { + out := make([]stats.BlkioStatEntry, len(entries)) + for i, re := range entries { + out[i] = stats.BlkioStatEntry{ + Major: re.Major, + Minor: re.Minor, + Op: re.Op, + Value: re.Value, + } + } + return out +} diff --git a/daemon/stats_collector.go b/daemon/stats_collector.go new file mode 100644 index 000000000..779bd1a59 --- /dev/null +++ b/daemon/stats_collector.go @@ -0,0 +1,129 @@ +package daemon + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" + "sync" + "time" + + log "github.com/Sirupsen/logrus" + "github.com/docker/docker/daemon/execdriver" + "github.com/docker/docker/pkg/pubsub" + "github.com/docker/libcontainer/system" +) + +// newStatsCollector returns a new statsCollector that collections +// network and cgroup stats for a registered container at the specified +// interval. The collector allows non-running containers to be added +// and will start processing stats when they are started. +func newStatsCollector(interval time.Duration) *statsCollector { + s := &statsCollector{ + interval: interval, + publishers: make(map[*Container]*pubsub.Publisher), + clockTicks: uint64(system.GetClockTicks()), + } + go s.run() + return s +} + +// statsCollector manages and provides container resource stats +type statsCollector struct { + m sync.Mutex + interval time.Duration + clockTicks uint64 + publishers map[*Container]*pubsub.Publisher +} + +// collect registers the container with the collector and adds it to +// the event loop for collection on the specified interval returning +// a channel for the subscriber to receive on. +func (s *statsCollector) collect(c *Container) chan interface{} { + s.m.Lock() + defer s.m.Unlock() + publisher, exists := s.publishers[c] + if !exists { + publisher = pubsub.NewPublisher(100*time.Millisecond, 1024) + s.publishers[c] = publisher + } + return publisher.Subscribe() +} + +// stopCollection closes the channels for all subscribers and removes +// the container from metrics collection. +func (s *statsCollector) stopCollection(c *Container) { + s.m.Lock() + if publisher, exists := s.publishers[c]; exists { + publisher.Close() + delete(s.publishers, c) + } + s.m.Unlock() +} + +// unsubscribe removes a specific subscriber from receiving updates for a container's stats. +func (s *statsCollector) unsubscribe(c *Container, ch chan interface{}) { + s.m.Lock() + publisher := s.publishers[c] + if publisher != nil { + publisher.Evict(ch) + if publisher.Len() == 0 { + delete(s.publishers, c) + } + } + s.m.Unlock() +} + +func (s *statsCollector) run() { + for _ = range time.Tick(s.interval) { + for container, publisher := range s.publishers { + systemUsage, err := s.getSystemCpuUsage() + if err != nil { + log.Errorf("collecting system cpu usage for %s: %v", container.ID, err) + continue + } + stats, err := container.Stats() + if err != nil { + if err != execdriver.ErrNotRunning { + log.Errorf("collecting stats for %s: %v", container.ID, err) + } + continue + } + stats.SystemUsage = systemUsage + publisher.Publish(stats) + } + } +} + +const nanoSeconds = 1e9 + +// getSystemCpuUSage returns the host system's cpu usage in nanoseconds +// for the system to match the cgroup readings are returned in the same format. +func (s *statsCollector) getSystemCpuUsage() (uint64, error) { + f, err := os.Open("/proc/stat") + if err != nil { + return 0, err + } + defer f.Close() + sc := bufio.NewScanner(f) + for sc.Scan() { + parts := strings.Fields(sc.Text()) + switch parts[0] { + case "cpu": + if len(parts) < 8 { + return 0, fmt.Errorf("invalid number of cpu fields") + } + var sum uint64 + for _, i := range parts[1:8] { + v, err := strconv.ParseUint(i, 10, 64) + if err != nil { + return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err) + } + sum += v + } + return (sum * nanoSeconds) / s.clockTicks, nil + } + } + return 0, fmt.Errorf("invalid stat format") +} diff --git a/daemon/utils_test.go b/daemon/utils_test.go index 8a2fa719e..ff5b082ba 100644 --- a/daemon/utils_test.go +++ b/daemon/utils_test.go @@ -16,7 +16,7 @@ func TestMergeLxcConfig(t *testing.T) { out, err := mergeLxcConfIntoOptions(hostConfig) if err != nil { - t.Fatalf("Failed to merge Lxc Config ", err) + t.Fatalf("Failed to merge Lxc Config: %s", err) } cpuset := out[0] @@ -24,34 +24,3 @@ func TestMergeLxcConfig(t *testing.T) { t.Fatalf("expected %s got %s", expected, cpuset) } } - -func TestRemoveLocalDns(t *testing.T) { - ns0 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\n" - - if result := utils.RemoveLocalDns([]byte(ns0)); result != nil { - if ns0 != string(result) { - t.Fatalf("Failed No Localhost: expected \n<%s> got \n<%s>", ns0, string(result)) - } - } - - ns1 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n" - if result := utils.RemoveLocalDns([]byte(ns1)); result != nil { - if ns0 != string(result) { - t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result)) - } - } - - ns1 = "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n" - if result := utils.RemoveLocalDns([]byte(ns1)); result != nil { - if ns0 != string(result) { - t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result)) - } - } - - ns1 = "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n" - if result := utils.RemoveLocalDns([]byte(ns1)); result != nil { - if ns0 != string(result) { - t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result)) - } - } -} diff --git a/daemon/volumes.go b/daemon/volumes.go index ad2dd3a6a..7b4973383 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -119,8 +119,23 @@ func (container *Container) VolumePaths() map[string]struct{} { } func (container *Container) registerVolumes() { - for _, mnt := range container.VolumeMounts() { - mnt.volume.AddContainer(container.ID) + for path := range container.VolumePaths() { + if v := container.daemon.volumes.Get(path); v != nil { + v.AddContainer(container.ID) + continue + } + + // if container was created with an old daemon, this volume may not be registered so we need to make sure it gets registered + writable := true + if rw, exists := container.VolumesRW[path]; exists { + writable = rw + } + v, err := container.daemon.volumes.FindOrCreateVolume(path, writable) + if err != nil { + log.Debugf("error registering volume %s: %v", path, err) + continue + } + v.AddContainer(container.ID) } } @@ -214,20 +229,61 @@ func parseBindMountSpec(spec string) (string, string, bool, error) { return path, mountToPath, writable, nil } +func parseVolumesFromSpec(spec string) (string, string, error) { + specParts := strings.SplitN(spec, ":", 2) + if len(specParts) == 0 { + return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec) + } + + var ( + id = specParts[0] + mode = "rw" + ) + if len(specParts) == 2 { + mode = specParts[1] + if !validMountMode(mode) { + return "", "", fmt.Errorf("invalid mode for volumes-from: %s", mode) + } + } + return id, mode, nil +} + func (container *Container) applyVolumesFrom() error { volumesFrom := container.hostConfig.VolumesFrom + if len(volumesFrom) > 0 && container.AppliedVolumesFrom == nil { + container.AppliedVolumesFrom = make(map[string]struct{}) + } - mountGroups := make([]map[string]*Mount, 0, len(volumesFrom)) + mountGroups := make(map[string][]*Mount) for _, spec := range volumesFrom { - mountGroup, err := parseVolumesFromSpec(container.daemon, spec) + id, mode, err := parseVolumesFromSpec(spec) if err != nil { return err } - mountGroups = append(mountGroups, mountGroup) + if _, exists := container.AppliedVolumesFrom[id]; exists { + // Don't try to apply these since they've already been applied + continue + } + + c := container.daemon.Get(id) + if c == nil { + return fmt.Errorf("container %s not found, impossible to mount its volumes", id) + } + + var ( + fromMounts = c.VolumeMounts() + mounts []*Mount + ) + + for _, mnt := range fromMounts { + mnt.Writable = mnt.Writable && (mode == "rw") + mounts = append(mounts, mnt) + } + mountGroups[id] = mounts } - for _, mounts := range mountGroups { + for id, mounts := range mountGroups { for _, mnt := range mounts { mnt.from = mnt.container mnt.container = container @@ -235,6 +291,7 @@ func (container *Container) applyVolumesFrom() error { return err } } + container.AppliedVolumesFrom[id] = struct{}{} } return nil } @@ -284,36 +341,6 @@ func (container *Container) setupMounts() error { return nil } -func parseVolumesFromSpec(daemon *Daemon, spec string) (map[string]*Mount, error) { - specParts := strings.SplitN(spec, ":", 2) - if len(specParts) == 0 { - return nil, fmt.Errorf("Malformed volumes-from specification: %s", spec) - } - - c := daemon.Get(specParts[0]) - if c == nil { - return nil, fmt.Errorf("Container %s not found. Impossible to mount its volumes", specParts[0]) - } - - mounts := c.VolumeMounts() - - if len(specParts) == 2 { - mode := specParts[1] - if !validMountMode(mode) { - return nil, fmt.Errorf("Invalid mode for volumes-from: %s", mode) - } - - // Set the mode for the inheritted volume - for _, mnt := range mounts { - // Ensure that if the inherited volume is not writable, that we don't make - // it writable here - mnt.Writable = mnt.Writable && (mode == "rw") - } - } - - return mounts, nil -} - func (container *Container) VolumeMounts() map[string]*Mount { mounts := make(map[string]*Mount) diff --git a/docker/daemon.go b/docker/daemon.go index 3128f7ee5..092399737 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -3,6 +3,11 @@ package main import ( + "fmt" + "io" + "os" + "path/filepath" + log "github.com/Sirupsen/logrus" "github.com/docker/docker/builder" "github.com/docker/docker/builtins" @@ -14,16 +19,59 @@ import ( flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/signal" "github.com/docker/docker/registry" + "github.com/docker/docker/utils" ) const CanDaemon = true var ( - daemonCfg = &daemon.Config{} + daemonCfg = &daemon.Config{} + registryCfg = ®istry.Options{} ) func init() { daemonCfg.InstallFlags() + registryCfg.InstallFlags() +} + +func migrateKey() (err error) { + // Migrate trust key if exists at ~/.docker/key.json and owned by current user + oldPath := filepath.Join(getHomeDir(), ".docker", defaultTrustKeyFile) + newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile) + if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && utils.IsFileOwner(oldPath) { + defer func() { + // Ensure old path is removed if no error occurred + if err == nil { + err = os.Remove(oldPath) + } else { + log.Warnf("Key migration failed, key file not removed at %s", oldPath) + } + }() + + if err := os.MkdirAll(getDaemonConfDir(), os.FileMode(0644)); err != nil { + return fmt.Errorf("Unable to create daemon configuration directory: %s", err) + } + + newFile, err := os.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return fmt.Errorf("error creating key file %q: %s", newPath, err) + } + defer newFile.Close() + + oldFile, err := os.Open(oldPath) + if err != nil { + return fmt.Errorf("error opening key file %q: %s", oldPath, err) + } + defer oldFile.Close() + + if _, err := io.Copy(newFile, oldFile); err != nil { + return fmt.Errorf("error copying key: %s", err) + } + + log.Infof("Migrated key from %s to %s", oldPath, newPath) + } + + return nil } func mainDaemon() { @@ -34,6 +82,9 @@ func mainDaemon() { eng := engine.New() signal.Trap(eng.Shutdown) + if err := migrateKey(); err != nil { + log.Fatal(err) + } daemonCfg.TrustKeyPath = *flTrustKey // Load builtins @@ -42,7 +93,7 @@ func mainDaemon() { } // load registry service - if err := registry.NewService(daemonCfg.InsecureRegistries).Install(eng); err != nil { + if err := registry.NewService(registryCfg).Install(eng); err != nil { log.Fatal(err) } diff --git a/docker/docker.go b/docker/docker.go index 3137f5c99..80d5e13f1 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -67,6 +67,8 @@ func main() { flHosts = append(flHosts, defaultHost) } + setDefaultConfFlag(flTrustKey, defaultTrustKeyFile) + if *flDaemon { mainDaemon() return @@ -118,9 +120,9 @@ func main() { } if *flTls || *flTlsVerify { - cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, nil, protoAddrParts[0], protoAddrParts[1], &tlsConfig) + cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], &tlsConfig) } else { - cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, nil, protoAddrParts[0], protoAddrParts[1], nil) + cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], nil) } if err := cli.Cmd(flag.Args()...); err != nil { diff --git a/docker/flags.go b/docker/flags.go index 6601b4fe8..d91a9a1de 100644 --- a/docker/flags.go +++ b/docker/flags.go @@ -28,14 +28,23 @@ func getHomeDir() string { return os.Getenv("HOME") } +func getDaemonConfDir() string { + // TODO: update for Windows daemon + if runtime.GOOS == "windows" { + return filepath.Join(os.Getenv("USERPROFILE"), ".docker") + } + return "/etc/docker" +} + var ( flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit") flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode") flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode") flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group") - flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level") + flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level (debug, info, warn, error, fatal)") flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") flTls = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by --tlsverify flag") + flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage") flTlsVerify = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)") // these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs @@ -46,10 +55,20 @@ var ( flHosts []string ) +func setDefaultConfFlag(flag *string, def string) { + if *flag == "" { + if *flDaemon { + *flag = filepath.Join(getDaemonConfDir(), def) + } else { + *flag = filepath.Join(getHomeDir(), ".docker", def) + } + } +} + func init() { - // placeholder for trust key flag - trustKeyDefault := filepath.Join(dockerCertPath, defaultTrustKeyFile) - flTrustKey = &trustKeyDefault + var placeholderTrustKey string + // TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file") + flTrustKey = &placeholderTrustKey flCa = flag.String([]string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust only remotes providing a certificate signed by the CA given here") flCert = flag.String([]string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file") @@ -57,8 +76,9 @@ func init() { opts.HostListVar(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode or connect to in client mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.") flag.Usage = func() { - fmt.Fprint(os.Stderr, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n") + fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n") + flag.CommandLine.SetOutput(os.Stdout) flag.PrintDefaults() help := "\nCommands:\n" @@ -77,7 +97,7 @@ func init() { {"images", "List images"}, {"import", "Create a new filesystem image from the contents of a tarball"}, {"info", "Display system-wide information"}, - {"inspect", "Return low-level information on a container"}, + {"inspect", "Return low-level information on a container or image"}, {"kill", "Kill a running container"}, {"load", "Load an image from a tar archive"}, {"login", "Register or log in to a Docker registry server"}, @@ -88,6 +108,7 @@ func init() { {"ps", "List containers"}, {"pull", "Pull an image or a repository from a Docker registry server"}, {"push", "Push an image or a repository to a Docker registry server"}, + {"rename", "Rename an existing container"}, {"restart", "Restart a running container"}, {"rm", "Remove one or more containers"}, {"rmi", "Remove one or more images"}, @@ -95,6 +116,7 @@ func init() { {"save", "Save an image to a tar archive"}, {"search", "Search for an image on the Docker Hub"}, {"start", "Start a stopped container"}, + {"stats", "Display a live stream of one or more containers' resource usage statistics"}, {"stop", "Stop a running container"}, {"tag", "Tag an image into a repository"}, {"top", "Lookup the running processes of a container"}, @@ -105,6 +127,6 @@ func init() { help += fmt.Sprintf(" %-10.10s%s\n", command[0], command[1]) } help += "\nRun 'docker COMMAND --help' for more information on a command." - fmt.Fprintf(os.Stderr, "%s\n", help) + fmt.Fprintf(os.Stdout, "%s\n", help) } } diff --git a/dockerversion/dockerversion.go b/dockerversion/dockerversion.go index c130ac281..1898d5c61 100644 --- a/dockerversion/dockerversion.go +++ b/dockerversion/dockerversion.go @@ -9,7 +9,7 @@ var ( GITCOMMIT string VERSION string - IAMSTATIC bool // whether or not Docker itself was compiled statically via ./hack/make.sh binary + IAMSTATIC string // whether or not Docker itself was compiled statically via ./hack/make.sh binary ("true" or not "true") INITSHA1 string // sha1sum of separate static dockerinit, if Docker itself was compiled dynamically via ./hack/make.sh dynbinary INITPATH string // custom location to search for a valid dockerinit binary (available for packagers as a last resort escape hatch) ) diff --git a/docs/Dockerfile b/docs/Dockerfile index d801ec213..ad23d3389 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -56,4 +56,31 @@ RUN VERSION=$(cat VERSION) \ EXPOSE 8000 +RUN cd sources && rgrep --files-with-matches '{{ include ".*" }}' | xargs sed -i~ 's/{{ include "\(.*\)" }}/cat include\/\1/ge' + CMD ["mkdocs", "serve"] + +# Initial Dockerfile driven documenation aggregation +# Sven plans to move each Dockerfile into the respective repository + +# Docker Swarm +#ADD https://raw.githubusercontent.com/docker/swarm/master/userguide.md /docs/sources/swarm/README.md +#ADD https://raw.githubusercontent.com/docker/swarm/master/discovery/README.md /docs/sources/swarm/discovery.md +#ADD https://raw.githubusercontent.com/docker/swarm/master/api/README.md /docs/sources/swarm/API.md +#ADD https://raw.githubusercontent.com/docker/swarm/master/scheduler/filter/README.md /docs/sources/swarm/scheduler/filter.md +#ADD https://raw.githubusercontent.com/docker/swarm/master/scheduler/strategy/README.md /docs/sources/swarm/scheduler/strategy.md + +# Docker Machine +# ADD https://raw.githubusercontent.com/docker/machine/master/docs/dockermachine.md /docs/sources/machine/userguide.md + +# Docker Compose +# ADD https://raw.githubusercontent.com/docker/fig/master/docs/index.md /docs/sources/compose/userguide.md +# ADD https://raw.githubusercontent.com/docker/fig/master/docs/install.md /docs/sources/compose/install.md +# ADD https://raw.githubusercontent.com/docker/fig/master/docs/cli.md /docs/sources/compose/cli.md +# ADD https://raw.githubusercontent.com/docker/fig/master/docs/yml.md /docs/sources/compose/yml.md + +# add the project docs from the `mkdocs-.yml` files +# RUN cd /docs && ./build.sh + +# remove `^---*` lines from md's +# RUN cd /docs/sources && find . -name "*.md" | xargs sed -i~ -n '/^---*/!p' diff --git a/docs/README.md b/docs/README.md index de3999ba7..3b471555c 100755 --- a/docs/README.md +++ b/docs/README.md @@ -25,7 +25,7 @@ In the root of the `docker` source directory: $ make docs .... (lots of output) .... - $ docker run --rm -it -e AWS_S3_BUCKET -p 8000:8000 "docker-docs:master" mkdocs serve + docker run --rm -it -e AWS_S3_BUCKET -p 8000:8000 "docker-docs:master" mkdocs serve Running at: http://0.0.0.0:8000/ Live reload enabled. Hold ctrl+c to quit. @@ -33,6 +33,11 @@ In the root of the `docker` source directory: If you have any issues you need to debug, you can use `make docs-shell` and then run `mkdocs serve` +## Testing the links + +You can use `make docs-test` to generate a report of missing links that are referenced in +the documentation - there should be none. + ## Adding a new document New document (`.md`) files are added to the documentation builds by adding them @@ -84,8 +89,10 @@ you need to access the AWS bucket you'll be deploying to. The release script will create an s3 if needed, and will then push the files to it. - [profile dowideit-docs] aws_access_key_id = IHOIUAHSIDH234rwf.... - aws_secret_access_key = OIUYSADJHLKUHQWIUHE...... region = ap-southeast-2 + [profile dowideit-docs] + aws_access_key_id = IHOIUAHSIDH234rwf.... + aws_secret_access_key = OIUYSADJHLKUHQWIUHE...... + region = ap-southeast-2 The `profile` name must be the same as the name of the bucket you are deploying to - which you call from the `docker` directory: @@ -140,11 +147,13 @@ to view your results and make sure what you published is what you wanted. When you're happy with it, publish the docs to our live site: - make AWS_S3_BUCKET=docs.docker.com BUILD_ROOT=yes docs-release + make AWS_S3_BUCKET=docs.docker.com BUILD_ROOT=yes DISTRIBUTION_ID=C2K6......FL2F docs-release Test the uncached version of the live docs at http://docs.docker.com.s3-website-us-east-1.amazonaws.com/ Note that the new docs will not appear live on the site until the cache (a complex, -distributed CDN system) is flushed. This requires someone with S3 keys. Contact Docker -(Sven Dowideit or John Costa) for assistance. +distributed CDN system) is flushed. The `make docs-release` command will do this +_if_ the `DISTRIBUTION_ID` is set to the Cloudfront distribution ID (ask the meta +team) - this will take at least 15 minutes to run and you can check its progress +with the CDN Cloudfront Chrome addin. diff --git a/docs/build.sh b/docs/build.sh new file mode 100755 index 000000000..033820c67 --- /dev/null +++ b/docs/build.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -e + +set -o pipefail + +usage() { + exit 1 +} + + +extrafiles=($(find . -name "mkdocs-*.yml")) +extralines=() + +for file in "${extrafiles[@]}" +do + #echo "LOADING $file" + while read line + do + if [[ "$line" != "" ]] + then + extralines+=("$line") + + #echo "LINE (${#extralines[@]}): $line" + fi + done < <(cat "$file") +done + +#echo "extra count (${#extralines[@]})" +mv mkdocs.yml mkdocs.yml.bak +echo "# Generated mkdocs.yml from ${extrafiles[@]}" +echo "# Generated mkdocs.yml from ${extrafiles[@]}" > mkdocs.yml + +while read line +do + menu=$(echo $line | sed "s/^- \['\([^']*\)', '\([^']*\)'.*/\2/") + if [[ "$menu" != "**HIDDEN**" ]] + # or starts with a '#'? + then + if [[ "$lastmenu" != "" && "$lastmenu" != "$menu" ]] + then + # insert extra elements here + for extra in "${extralines[@]}" + do + #echo "EXTRA $extra" + extramenu=$(echo $extra | sed "s/^- \['\([^']*\)', '\([^']*\)'.*/\2/") + if [[ "$extramenu" == "$lastmenu" ]] + then + echo "$extra" >> mkdocs.yml + fi + done + #echo "# JUST FINISHED $lastmenu" + fi + lastmenu="$menu" + fi + echo "$line" >> mkdocs.yml + +done < <(cat "mkdocs.yml.bak") diff --git a/docs/docs-update.py b/docs/docs-update.py index 586bde482..c40da773e 100755 --- a/docs/docs-update.py +++ b/docs/docs-update.py @@ -56,14 +56,14 @@ def update_cli_reference(): # Prose match = re.match("( \s*)Usage: docker ([a-z]+)", line) if match: - # the begining of a Docker command usage block + # the beginning of a Docker command usage block space = match.group(1) command = match.group(2) mode = 'c' else: match = re.match("( \s*)Usage of .*docker.*:", line) if match: - # the begining of the Docker --help usage block + # the beginning of the Docker --help usage block space = match.group(1) command = "" mode = 'c' diff --git a/docs/docvalidate.py b/docs/docvalidate.py new file mode 100755 index 000000000..582b8521d --- /dev/null +++ b/docs/docvalidate.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +""" I honestly don't even know how the hell this works, just use it. """ +__author__ = "Scott Stamp " + +from HTMLParser import HTMLParser +from urlparse import urljoin +from sys import setrecursionlimit +import re +import requests + +setrecursionlimit(10000) +root = 'http://localhost:8000' + + +class DataHolder: + + def __init__(self, value=None, attr_name='value'): + self._attr_name = attr_name + self.set(value) + + def __call__(self, value): + return self.set(value) + + def set(self, value): + setattr(self, self._attr_name, value) + return value + + def get(self): + return getattr(self, self._attr_name) + + +class Parser(HTMLParser): + global root + + ids = set() + crawled = set() + anchors = {} + pages = set() + save_match = DataHolder(attr_name='match') + + def __init__(self, origin): + self.origin = origin + HTMLParser.__init__(self) + + def handle_starttag(self, tag, attrs): + attrs = dict(attrs) + if 'href' in attrs: + href = attrs['href'] + + if re.match('^{0}|\/|\#[\S]{{1,}}'.format(root), href): + if self.save_match(re.search('.*\#(.*?)$', href)): + if self.origin not in self.anchors: + self.anchors[self.origin] = set() + self.anchors[self.origin].add( + self.save_match.match.groups(1)[0]) + + url = urljoin(root, href) + + if url not in self.crawled and not re.match('^\#', href): + self.crawled.add(url) + Parser(url).feed(requests.get(url).content) + + if 'id' in attrs: + self.ids.add(attrs['id']) + # explicit references + if 'name' in attrs: + self.ids.add(attrs['name']) + + +r = requests.get(root) +parser = Parser(root) +parser.feed(r.content) +for anchor in sorted(parser.anchors): + if not re.match('.*/\#.*', anchor): + for anchor_name in parser.anchors[anchor]: + if anchor_name not in parser.ids: + print 'Missing - ({0}): #{1}'.format( + anchor.replace(root, ''), anchor_name) diff --git a/docs/man/Dockerfile.5.md b/docs/man/Dockerfile.5.md index 4104dc232..dd1d8b2ce 100644 --- a/docs/man/Dockerfile.5.md +++ b/docs/man/Dockerfile.5.md @@ -120,7 +120,8 @@ or **ENV** --**ENV ** The ENV instruction sets the environment variable to - the value . This value is passed to all future RUN instructions. This is + the value . This value is passed to all future + RUN, ENTRYPOINT, and CMD instructions. This is functionally equivalent to prefixing the command with **=**. The environment variables that are set with ENV persist when a container is run from the resulting image. Use docker inspect to inspect these values, and @@ -131,13 +132,31 @@ or interactively, as with the following command: **docker run -t -i image bash** **ADD** - --**ADD ... ** The ADD instruction copies new files, directories - or remote file URLs to the filesystem of the container at path . - Mutliple resources may be specified but if they are files or directories - then they must be relative to the source directory that is being built - (the context of the build). is the absolute path to - which the source is copied inside the target container. All new files and - directories are created with mode 0755, with uid and gid 0. + --ADD has two forms: + **ADD ... ** + **ADD [""... ""]** This form is required for paths containing + whitespace. + The ADD instruction copies new files, directories + or remote file URLs to the filesystem of the container at path . + Multiple resources may be specified but if they are files or directories + then they must be relative to the source directory that is being built + (the context of the build). The is the absolute path, or path relative + to `WORKDIR`, into which the source is copied inside the target container. + All new files and directories are created with mode 0755 and with the uid + and gid of 0. + +**COPY** + --COPY has two forms: + **COPY ... ** + **COPY [""... ""]** This form is required for paths containing + whitespace. + The COPY instruction copies new files from and + adds them to the filesystem of the container at path . The must be + the path to a file or directory relative to the source directory that is + being built (the context of the build) or a remote file URL. The `` is an + absolute path, or a path relative to `WORKDIR`, into which the source will + be copied inside the target container. All new files and directories are + created with mode 0755 and with the uid and gid of 0. **ENTRYPOINT** --**ENTRYPOINT** has two forms: ENTRYPOINT ["executable", "param1", "param2"] @@ -176,7 +195,7 @@ or **WORKDIR** -- **WORKDIR /path/to/workdir** - The WORKDIR instruction sets the working directory for the **RUN**, **CMD**, and **ENTRYPOINT** Dockerfile commands that follow it. + The WORKDIR instruction sets the working directory for the **RUN**, **CMD**, **ENTRYPOINT**, **COPY** and **ADD** Dockerfile commands that follow it. It can be used multiple times in a single Dockerfile. Relative paths are defined relative to the path of the previous **WORKDIR** instruction. For example: **WORKDIR /a WORKDIR b WORKDIR c RUN pwd** In the above example, the output of the **pwd** command is **a/b/c**. diff --git a/docs/man/README.md b/docs/man/README.md index a52e0cbe6..402178a9c 100644 --- a/docs/man/README.md +++ b/docs/man/README.md @@ -5,43 +5,6 @@ This directory contains the Docker user manual in the Markdown format. Do *not* edit the man pages in the man1 directory. Instead, amend the Markdown (*.md) files. -# File List - - docker.md - docker-attach.md - docker-build.md - docker-commit.md - docker-cp.md - docker-diff.md - docker-events.md - docker-export.md - docker-history.md - docker-images.md - docker-import.md - docker-info.md - docker-inspect.md - docker-kill.md - docker-load.md - docker-login.md - docker-logs.md - docker-port.md - docker-ps.md - docker-pull.md - docker-push.md - docker-restart.md - docker-rmi.md - docker-rm.md - docker-run.md - docker-save.md - docker-search.md - docker-start.md - docker-stop.md - docker-tag.md - docker-top.md - docker-wait.md - Dockerfile - md2man-all.sh - # Generating man pages from the Markdown files The recommended approach for generating the man pages is via a Docker diff --git a/docs/man/docker-attach.1.md b/docs/man/docker-attach.1.md index 19fbaceb4..1f73d8c9b 100644 --- a/docs/man/docker-attach.1.md +++ b/docs/man/docker-attach.1.md @@ -6,24 +6,30 @@ docker-attach - Attach to a running container # SYNOPSIS **docker attach** +[**--help**]/ [**--no-stdin**[=*false*]] [**--sig-proxy**[=*true*]] CONTAINER # DESCRIPTION -If you **docker run** a container in detached mode (**-d**), you can reattach to -the detached container with **docker attach** using the container's ID or name. +The **docker attach** command allows you to attach to a running container using +the container's ID or name, either to view its ongoing output or to control it +interactively. You can attach to the same contained process multiple times +simultaneously, screen sharing style, or quickly view the progress of your +daemonized process. -You can detach from the container again (and leave it running) with `CTRL-p -CTRL-q` (for a quiet exit), or `CTRL-c` which will send a SIGKILL to the -container, or `CTRL-\` to get a stacktrace of the Docker client when it quits. -When you detach from a container the exit code will be returned to -the client. +You can detach from the container (and leave it running) with `CTRL-p CTRL-q` +(for a quiet exit) or `CTRL-c` which will send a `SIGKILL` to the container. +When you are attached to a container, and exit its main process, the process's +exit code will be returned to the client. -It is forbidden to redirect the standard input of a docker attach command while -attaching to a tty-enabled container (i.e.: launched with -t`). +It is forbidden to redirect the standard input of a `docker attach` command while +attaching to a tty-enabled container (i.e.: launched with `-t`). # OPTIONS +**--help** + Print usage statement + **--no-stdin**=*true*|*false* Do not attach STDIN. The default is *false*. diff --git a/docs/man/docker-build.1.md b/docs/man/docker-build.1.md index 67d7343af..f6a89b54e 100644 --- a/docs/man/docker-build.1.md +++ b/docs/man/docker-build.1.md @@ -6,8 +6,11 @@ docker-build - Build a new image from the source code at PATH # SYNOPSIS **docker build** +[**--help**] +[**-f**|**--file**[=*Dockerfile*]] [**--force-rm**[=*false*]] [**--no-cache**[=*false*]] +[**--pull**[=*false*]] [**-q**|**--quiet**[=*false*]] [**--rm**[=*true*]] [**-t**|**--tag**[=*TAG*]] @@ -30,12 +33,21 @@ When a Git repository is set as the **URL**, the repository is used as context. # OPTIONS +**-f**, **--file**=*Dockerfile* + Path to the Dockerfile to use. If the path is a relative path then it must be relative to the current directory. The file must be within the build context. The default is *Dockerfile*. + **--force-rm**=*true*|*false* Always remove intermediate containers, even after unsuccessful builds. The default is *false*. **--no-cache**=*true*|*false* Do not use cache when building the image. The default is *false*. +**--help** + Print usage statement + +**--pull**=*true*|*false* + Always attempt to pull a newer version of the image. The default is *false*. + **-q**, **--quiet**=*true*|*false* Suppress the verbose output generated by the containers. The default is *false*. @@ -47,7 +59,7 @@ as context. # EXAMPLES -## Building an image using a Dockefile located inside the current directory +## Building an image using a Dockerfile located inside the current directory Docker images can be built using the build command and a Dockerfile: @@ -65,10 +77,12 @@ directory called httpd may be used to store Dockerfiles for Apache web server images. It is also a good practice to add the files required for the image to the -sub-directory. These files will then be specified with the `ADD` instruction -in the Dockerfile. Note: If you include a tar file (a good practice!), then -Docker will automatically extract the contents of the tar file -specified within the `ADD` instruction into the specified target. +sub-directory. These files will then be specified with the `COPY` or `ADD` +instructions in the `Dockerfile`. + +Note: If you include a tar file (a good practice), then Docker will +automatically extract the contents of the tar file specified within the `ADD` +instruction into the specified target. ## Building an image and naming that image @@ -77,7 +91,7 @@ no hard rules here but it is best to give the names consideration. The **-t**/**--tag** flag is used to rename an image. Here are some examples: -Though it is not a good practice, image names can be arbtrary: +Though it is not a good practice, image names can be arbitrary: docker build -t myimage . diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index 0d1d5406c..d7619133d 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -7,6 +7,7 @@ docker-commit - Create a new image from a container's changes # SYNOPSIS **docker commit** [**-a**|**--author**[=*AUTHOR*]] +[**--help**] [**-m**|**--message**[=*MESSAGE*]] [**-p**|**--pause**[=*true*]] CONTAINER [REPOSITORY[:TAG]] @@ -18,6 +19,9 @@ Using an existing container's name or ID you can create a new image. **-a**, **--author**="" Author (e.g., "John Hannibal Smith ") +**--help** + Print usage statement + **-m**, **--message**="" Commit message diff --git a/docs/man/docker-cp.1.md b/docs/man/docker-cp.1.md index dc8f295bb..ac49a47a5 100644 --- a/docs/man/docker-cp.1.md +++ b/docs/man/docker-cp.1.md @@ -6,6 +6,7 @@ docker-cp - Copy files/folders from the PATH to the HOSTPATH # SYNOPSIS **docker cp** +[**--help**] CONTAINER:PATH HOSTPATH # DESCRIPTION @@ -14,7 +15,8 @@ path. Paths are relative to the root of the filesystem. Files can be copied from a running or stopped container. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES An important shell script file, created in a bash shell, is copied from diff --git a/docs/man/docker-create.1.md b/docs/man/docker-create.1.md index a83873794..8a0b91f7c 100644 --- a/docs/man/docker-create.1.md +++ b/docs/man/docker-create.1.md @@ -21,6 +21,7 @@ docker-create - Create a new container [**--env-file**[=*[]*]] [**--expose**[=*[]*]] [**-h**|**--hostname**[=*HOSTNAME*]] +[**--help**] [**-i**|**--interactive**[=*false*]] [**--ipc**[=*IPC*]] [**--link**[=*[]*]] @@ -31,7 +32,9 @@ docker-create - Create a new container [**--net**[=*"bridge"*]] [**-P**|**--publish-all**[=*false*]] [**-p**|**--publish**[=*[]*]] +[**--pid**[=*[]*]] [**--privileged**[=*false*]] +[**--read-only**[=*false*]] [**--restart**[=*RESTART*]] [**--security-opt**[=*[]*]] [**-t**|**--tty**[=*false*]] @@ -87,6 +90,9 @@ IMAGE [COMMAND] [ARG...] **-h**, **--hostname**="" Container host name +**--help** + Print usage statement + **-i**, **--interactive**=*true*|*false* Keep STDIN open even if not attached. The default is *false*. @@ -96,7 +102,7 @@ IMAGE [COMMAND] [ARG...] 'host': use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. **--link**=[] - Add link to another container in the form of name:alias + Add link to another container in the form of :alias **--lxc-conf**=[] (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" @@ -118,16 +124,26 @@ IMAGE [COMMAND] [ARG...] 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. **-P**, **--publish-all**=*true*|*false* - Publish all exposed ports to the host interfaces. The default is *false*. + Publish all exposed ports to random ports on the host interfaces. The default is *false*. **-p**, **--publish**=[] - Publish a container's port to the host + Publish a container's port, or a range of ports, to the host format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort + Both hostPort and containerPort can be specified as a range of ports. + When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. (e.g., `-p 1234-1236:1234-1236/tcp`) (use 'docker port' to see the actual mapping) +**--pid**=host + Set the PID mode for the container + **host**: use the host's PID namespace inside the container. + Note: the host mode gives the container full access to local PID and is therefore considered insecure. + **--privileged**=*true*|*false* Give extended privileges to this container. The default is *false*. +**--read-only**=*true*|*false* + Mount the container's root filesystem as read only. + **--restart**="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always) diff --git a/docs/man/docker-diff.1.md b/docs/man/docker-diff.1.md index acf0911b0..6c6c50253 100644 --- a/docs/man/docker-diff.1.md +++ b/docs/man/docker-diff.1.md @@ -6,6 +6,7 @@ docker-diff - Inspect changes on a container's filesystem # SYNOPSIS **docker diff** +[**--help**] CONTAINER # DESCRIPTION @@ -14,7 +15,8 @@ shortened container ID or the container name set using **docker run --name** option. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES Inspect the changes to on a nginx container: diff --git a/docs/man/docker-events.1.md b/docs/man/docker-events.1.md index c88843970..bff04a6d1 100644 --- a/docs/man/docker-events.1.md +++ b/docs/man/docker-events.1.md @@ -6,6 +6,8 @@ docker-events - Get real time events from the server # SYNOPSIS **docker events** +[**--help**] +[**-f**|**--filter**[=*[]*]] [**--since**[=*SINCE*]] [**--until**[=*UNTIL*]] @@ -23,6 +25,12 @@ and Docker images will report: untag, delete # OPTIONS +**--help** + Print usage statement + +**-f**, **--filter**=[] + Provide filter values (i.e., 'event=stop') + **--since**="" Show all events created since timestamp @@ -37,23 +45,23 @@ After running docker events a container 786d698004576 is started and stopped (The container name has been shortened in the output below): # docker events - [2014-04-12 18:23:04 -0400 EDT] 786d69800457: (from whenry/testimage:latest) start - [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) die - [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) stop + 2015-01-28T20:21:31.000000000-08:00 59211849bc10: (from whenry/testimage:latest) start + 2015-01-28T20:21:31.000000000-08:00 59211849bc10: (from whenry/testimage:latest) die + 2015-01-28T20:21:32.000000000-08:00 59211849bc10: (from whenry/testimage:latest) stop ## Listening for events since a given date Again the output container IDs have been shortened for the purposes of this document: - # docker events --since '2014-04-12' - [2014-04-12 18:11:28 -0400 EDT] c655dbf640dc: (from whenry/testimage:latest) create - [2014-04-12 18:11:28 -0400 EDT] c655dbf640dc: (from whenry/testimage:latest) start - [2014-04-12 18:14:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) create - [2014-04-12 18:14:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) start - [2014-04-12 18:22:44 -0400 EDT] 786d69800457: (from whenry/testimage:latest) die - [2014-04-12 18:22:44 -0400 EDT] 786d69800457: (from whenry/testimage:latest) stop - [2014-04-12 18:23:04 -0400 EDT] 786d69800457: (from whenry/testimage:latest) start - [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) die - [2014-04-12 18:23:13 -0400 EDT] 786d69800457: (from whenry/testimage:latest) stop + # docker events --since '2015-01-28' + 2015-01-28T20:25:38.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) create + 2015-01-28T20:25:38.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) start + 2015-01-28T20:25:39.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) create + 2015-01-28T20:25:39.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) start + 2015-01-28T20:25:40.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) die + 2015-01-28T20:25:42.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) stop + 2015-01-28T20:25:45.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) start + 2015-01-28T20:25:45.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) die + 2015-01-28T20:25:46.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) stop # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) diff --git a/docs/man/docker-exec.1.md b/docs/man/docker-exec.1.md index 3db296ed7..e7554419e 100644 --- a/docs/man/docker-exec.1.md +++ b/docs/man/docker-exec.1.md @@ -7,6 +7,7 @@ docker-exec - Run a command in a running container # SYNOPSIS **docker exec** [**-d**|**--detach**[=*false*]] +[**--help**] [**-i**|**--interactive**[=*false*]] [**-t**|**--tty**[=*false*]] CONTAINER COMMAND [ARG...] @@ -25,6 +26,9 @@ container is unpaused, and then run **-d**, **--detach**=*true*|*false* Detached mode: run command in the background. The default is *false*. +**--help** + Print usage statement + **-i**, **--interactive**=*true*|*false* Keep STDIN open even if not attached. The default is *false*. diff --git a/docs/man/docker-export.1.md b/docs/man/docker-export.1.md index 8fd7834a1..d2b22d221 100644 --- a/docs/man/docker-export.1.md +++ b/docs/man/docker-export.1.md @@ -6,6 +6,7 @@ docker-export - Export the contents of a filesystem as a tar archive to STDOUT # SYNOPSIS **docker export** +[**--help**] CONTAINER # DESCRIPTION @@ -14,7 +15,8 @@ container ID or container name. The output is exported to STDOUT and can be redirected to a tar file. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES Export the contents of the container called angry_bell to a tar file diff --git a/docs/man/docker-history.1.md b/docs/man/docker-history.1.md index 65ec9cd17..47350f887 100644 --- a/docs/man/docker-history.1.md +++ b/docs/man/docker-history.1.md @@ -6,6 +6,7 @@ docker-history - Show the history of an image # SYNOPSIS **docker history** +[**--help**] [**--no-trunc**[=*false*]] [**-q**|**--quiet**[=*false*]] IMAGE @@ -15,6 +16,9 @@ IMAGE Show the history of when and how an image was created. # OPTIONS +**--help** + Print usage statement + **--no-trunc**=*true*|*false* Don't truncate output. The default is *false*. diff --git a/docs/man/docker-images.1.md b/docs/man/docker-images.1.md index 6c9e6a60b..16fad991c 100644 --- a/docs/man/docker-images.1.md +++ b/docs/man/docker-images.1.md @@ -6,6 +6,7 @@ docker-images - List images # SYNOPSIS **docker images** +[**--help**] [**-a**|**--all**[=*false*]] [**-f**|**--filter**[=*[]*]] [**--no-trunc**[=*false*]] @@ -33,7 +34,10 @@ versions. Show all images (by default filter out the intermediate image layers). The default is *false*. **-f**, **--filter**=[] - Provide filter values (i.e. 'dangling=true') + Provide filter values (i.e., 'dangling=true') + +**--help** + Print usage statement **--no-trunc**=*true*|*false* Don't truncate output. The default is *false*. diff --git a/docs/man/docker-import.1.md b/docs/man/docker-import.1.md index 2d67b8bc7..974288c72 100644 --- a/docs/man/docker-import.1.md +++ b/docs/man/docker-import.1.md @@ -6,6 +6,7 @@ docker-import - Create an empty filesystem image and import the contents of the # SYNOPSIS **docker import** +[**--help**] URL|- [REPOSITORY[:TAG]] # DESCRIPTION @@ -13,7 +14,8 @@ Create a new filesystem image from the contents of a tarball (`.tar`, `.tar.gz`, `.tgz`, `.bzip`, `.tar.xz`, `.txz`) into it, then optionally tag it. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES diff --git a/docs/man/docker-info.1.md b/docs/man/docker-info.1.md index 0547b44b0..346df866a 100644 --- a/docs/man/docker-info.1.md +++ b/docs/man/docker-info.1.md @@ -6,6 +6,7 @@ docker-info - Display system-wide information # SYNOPSIS **docker info** +[**--help**] # DESCRIPTION @@ -20,7 +21,8 @@ allocates a certain amount of data space and meta data space from the space available on the volume where `/var/lib/docker` is mounted. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES diff --git a/docs/man/docker-inspect.1.md b/docs/man/docker-inspect.1.md index a52d57c97..8cbef0f91 100644 --- a/docs/man/docker-inspect.1.md +++ b/docs/man/docker-inspect.1.md @@ -6,6 +6,7 @@ docker-inspect - Return low-level information on a container or image # SYNOPSIS **docker inspect** +[**--help**] [**-f**|**--format**[=*FORMAT*]] CONTAINER|IMAGE [CONTAINER|IMAGE...] @@ -17,6 +18,9 @@ array. If a format is specified, the given template will be executed for each result. # OPTIONS +**--help** + Print usage statement + **-f**, **--format**="" Format the output using the given go template. diff --git a/docs/man/docker-kill.1.md b/docs/man/docker-kill.1.md index d1d0ee7ad..cfab3f8e4 100644 --- a/docs/man/docker-kill.1.md +++ b/docs/man/docker-kill.1.md @@ -6,6 +6,7 @@ docker-kill - Kill a running container using SIGKILL or a specified signal # SYNOPSIS **docker kill** +[**--help**] [**-s**|**--signal**[=*"KILL"*]] CONTAINER [CONTAINER...] @@ -15,6 +16,9 @@ The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal. # OPTIONS +**--help** + Print usage statement + **-s**, **--signal**="KILL" Signal to send to the container diff --git a/docs/man/docker-load.1.md b/docs/man/docker-load.1.md index 07dac4613..71bd28adf 100644 --- a/docs/man/docker-load.1.md +++ b/docs/man/docker-load.1.md @@ -6,6 +6,7 @@ docker-load - Load an image from a tar archive on STDIN # SYNOPSIS **docker load** +[**--help**] [**-i**|**--input**[=*INPUT*]] @@ -15,6 +16,9 @@ Loads a tarred repository from a file or the standard input stream. Restores both images and tags. # OPTIONS +**--help** + Print usage statement + **-i**, **--input**="" Read from a tar archive file, instead of STDIN diff --git a/docs/man/docker-login.1.md b/docs/man/docker-login.1.md index e367050be..5ee6aa1c6 100644 --- a/docs/man/docker-login.1.md +++ b/docs/man/docker-login.1.md @@ -7,6 +7,7 @@ docker-login - Register or log in to a Docker registry server, if no server is s # SYNOPSIS **docker login** [**-e**|**--email**[=*EMAIL*]] +[**--help**] [**-p**|**--password**[=*PASSWORD*]] [**-u**|**--username**[=*USERNAME*]] [SERVER] @@ -20,6 +21,9 @@ login to a private registry you can specify this by adding the server name. **-e**, **--email**="" Email +**--help** + Print usage statement + **-p**, **--password**="" Password diff --git a/docs/man/docker-logs.1.md b/docs/man/docker-logs.1.md index 1fbd229d5..d55e8d836 100644 --- a/docs/man/docker-logs.1.md +++ b/docs/man/docker-logs.1.md @@ -7,6 +7,7 @@ docker-logs - Fetch the logs of a container # SYNOPSIS **docker logs** [**-f**|**--follow**[=*false*]] +[**--help**] [**-t**|**--timestamps**[=*false*]] [**--tail**[=*"all"*]] CONTAINER @@ -14,7 +15,7 @@ CONTAINER # DESCRIPTION The **docker logs** command batch-retrieves whatever logs are present for a container at the time of execution. This does not guarantee execution -order when combined with a docker run (i.e. your run may not have generated +order when combined with a docker run (i.e., your run may not have generated any logs at the time you execute docker logs). The **docker logs --follow** command combines commands **docker logs** and @@ -22,6 +23,9 @@ The **docker logs --follow** command combines commands **docker logs** and then continue streaming new output from the container’s stdout and stderr. # OPTIONS +**--help** + Print usage statement + **-f**, **--follow**=*true*|*false* Follow log output. The default is *false*. diff --git a/docs/man/docker-port.1.md b/docs/man/docker-port.1.md index 8c4c870dc..a297c3921 100644 --- a/docs/man/docker-port.1.md +++ b/docs/man/docker-port.1.md @@ -6,13 +6,15 @@ docker-port - List port mappings for the CONTAINER, or lookup the public-facing # SYNOPSIS **docker port** +[**--help**] CONTAINER [PRIVATE_PORT[/PROTO]] # DESCRIPTION List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or diff --git a/docs/man/docker-ps.1.md b/docs/man/docker-ps.1.md index d34d98396..4c94545e3 100644 --- a/docs/man/docker-ps.1.md +++ b/docs/man/docker-ps.1.md @@ -8,6 +8,7 @@ docker-ps - List containers **docker ps** [**-a**|**--all**[=*false*]] [**--before**[=*BEFORE*]] +[**--help**] [**-f**|**--filter**[=*[]*]] [**-l**|**--latest**[=*false*]] [**-n**[=*-1*]] @@ -29,6 +30,9 @@ the running containers. **--before**="" Show only container created before Id or Name, include non-running ones. +**--help** + Print usage statement + **-f**, **--filter**=[] Provide filter values. Valid filters: exited= - containers with exit code of diff --git a/docs/man/docker-pull.1.md b/docs/man/docker-pull.1.md index 01c664f56..f1963df55 100644 --- a/docs/man/docker-pull.1.md +++ b/docs/man/docker-pull.1.md @@ -7,6 +7,7 @@ docker-pull - Pull an image or a repository from the registry # SYNOPSIS **docker pull** [**-a**|**--all-tags**[=*false*]] +[**--help**] NAME[:TAG] # DESCRIPTION @@ -19,8 +20,10 @@ It is also possible to specify a non-default registry to pull from. # OPTIONS **-a**, **--all-tags**=*true*|*false* Download all tagged images in the repository. The default is *false*. +**--help** + Print usage statement -# EXAMPLES +# EXAMPLE # Pull a repository with multiple images # Note that if the image is previously downloaded then the status would be diff --git a/docs/man/docker-push.1.md b/docs/man/docker-push.1.md index 8523cb539..2d4dc8f89 100644 --- a/docs/man/docker-push.1.md +++ b/docs/man/docker-push.1.md @@ -6,6 +6,7 @@ docker-push - Push an image or a repository to the registry # SYNOPSIS **docker push** +[**--help**] NAME[:TAG] # DESCRIPTION @@ -15,7 +16,8 @@ image can be pushed to another, perhaps private, registry as demonstrated in the example below. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES diff --git a/docs/man/docker-rename.1.md b/docs/man/docker-rename.1.md new file mode 100644 index 000000000..f741a15b4 --- /dev/null +++ b/docs/man/docker-rename.1.md @@ -0,0 +1,13 @@ +% DOCKER(1) Docker User Manuals +% Docker Community +% OCTOBER 2014 +# NAME +docker-rename - Rename a container + +# SYNOPSIS +**docker rename** +OLD_NAME NEW_NAME + +# OPTIONS +There are no available options. + diff --git a/docs/man/docker-restart.1.md b/docs/man/docker-restart.1.md index 9a2268800..77f99d51a 100644 --- a/docs/man/docker-restart.1.md +++ b/docs/man/docker-restart.1.md @@ -6,6 +6,7 @@ docker-restart - Restart a running container # SYNOPSIS **docker restart** +[**--help**] [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...] @@ -13,6 +14,9 @@ CONTAINER [CONTAINER...] Restart each container listed. # OPTIONS +**--help** + Print usage statement + **-t**, **--time**=10 Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds. diff --git a/docs/man/docker-rm.1.md b/docs/man/docker-rm.1.md index b8f31bd68..82850a395 100644 --- a/docs/man/docker-rm.1.md +++ b/docs/man/docker-rm.1.md @@ -19,6 +19,9 @@ remove a running container unless you use the \fB-f\fR option. To see all containers on a host use the **docker ps -a** command. # OPTIONS +**--help** + Print usage statement + **-f**, **--force**=*true*|*false* Force the removal of a running container (uses SIGKILL). The default is *false*. diff --git a/docs/man/docker-rmi.1.md b/docs/man/docker-rmi.1.md index 08d740a3b..c1f131f40 100644 --- a/docs/man/docker-rmi.1.md +++ b/docs/man/docker-rmi.1.md @@ -7,6 +7,7 @@ docker-rmi - Remove one or more images # SYNOPSIS **docker rmi** [**-f**|**--force**[=*false*]] +[**--help**] [**--no-prune**[=*false*]] IMAGE [IMAGE...] @@ -21,6 +22,9 @@ use the **docker images** command. **-f**, **--force**=*true*|*false* Force removal of the image. The default is *false*. +**--help** + Print usage statement + **--no-prune**=*true*|*false* Do not delete untagged parents. The default is *false*. diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index 44c554508..61ce465c3 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -22,17 +22,21 @@ docker-run - Run a command in a new container [**--env-file**[=*[]*]] [**--expose**[=*[]*]] [**-h**|**--hostname**[=*HOSTNAME*]] +[**--help**] [**-i**|**--interactive**[=*false*]] [**--ipc**[=*IPC*]] [**--link**[=*[]*]] [**--lxc-conf**[=*[]*]] [**-m**|**--memory**[=*MEMORY*]] +[**--memory-swap**[=*MEMORY-SWAP]] [**--mac-address**[=*MAC-ADDRESS*]] [**--name**[=*NAME*]] [**--net**[=*"bridge"*]] [**-P**|**--publish-all**[=*false*]] [**-p**|**--publish**[=*[]*]] +[**--pid**[=*[]*]] [**--privileged**[=*false*]] +[**--read-only**[=*false*]] [**--restart**[=*RESTART*]] [**--rm**[=*false*]] [**--security-opt**[=*[]*]] @@ -146,13 +150,16 @@ ENTRYPOINT. Read in a line delimited file of environment variables **--expose**=[] - Expose a port or a range of ports (e.g. --expose=3300-3310) from the container without publishing it to your host + Expose a port, or a range of ports (e.g. --expose=3300-3310), from the container without publishing it to your host **-h**, **--hostname**="" Container host name Sets the container host name that is available inside the container. +**--help** + Print usage statement + **-i**, **--interactive**=*true*|*false* Keep STDIN open even if not attached. The default is *false*. @@ -164,7 +171,7 @@ ENTRYPOINT. 'host': use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. **--link**=[] - Add link to another container in the form of name:alias + Add link to another container in the form of :alias If the operator uses **--link** when starting the new client container, then the client @@ -185,6 +192,11 @@ actual limit may be rounded up to a multiple of the operating system's page size, if it is not already. The memory limit should be formatted as follows: ``, where unit = b, k, m or g. +**--memory-swap**="" + Total memory usage (memory + swap) + + Set '-1' to disable swap (format: , where unit = b, k, m or g) + **--mac-address**="" Container MAC address (e.g. 92:d0:c6:0a:29:33) @@ -196,7 +208,6 @@ according to RFC4862. Assign a name to the container The operator can identify a container in three ways: - UUID long identifier (“f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”) UUID short identifier (“f78375b1c487”) Name (“jonah”) @@ -215,7 +226,7 @@ and foreground Docker containers. 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. **-P**, **--publish-all**=*true*|*false* - Publish all exposed ports to the host interfaces. The default is *false*. + Publish all exposed ports to random ports on the host interfaces. The default is *false*. When set to true publish all exposed ports to the host interfaces. The default is false. If the operator uses -P (or -p) then Docker will make the @@ -225,10 +236,17 @@ ports to a random port on the host between 49153 and 65535. To find the mapping between the host ports and the exposed ports, use **docker port**. **-p**, **--publish**=[] - Publish a container's port to the host + Publish a container's port, or range of ports, to the host. format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort + Both hostPort and containerPort can be specified as a range of ports. + When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. (e.g., `-p 1234-1236:1234-1236/tcp`) (use 'docker port' to see the actual mapping) +**--pid**=host + Set the PID mode for the container + **host**: use the host's PID namespace inside the container. + Note: the host mode gives the container full access to local PID and is therefore considered insecure. + **--privileged**=*true*|*false* Give extended privileges to this container. The default is *false*. @@ -242,6 +260,13 @@ to all devices on the host as well as set some configuration in AppArmor to allow the container nearly all the same access to the host as processes running outside of a container on the host. +**--read-only**=*true*|*false* + Mount the container's root filesystem as read only. + + By default a container will have its root filesystem writable allowing processes +to write files anywhere. By specifying the `--read-only` flag the container will have +its root filesystem mounted as read only prohibiting any writes. + **--restart**="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always) diff --git a/docs/man/docker-save.1.md b/docs/man/docker-save.1.md index c02ffb101..987d18b84 100644 --- a/docs/man/docker-save.1.md +++ b/docs/man/docker-save.1.md @@ -6,6 +6,7 @@ docker-save - Save an image(s) to a tar archive (streamed to STDOUT by default) # SYNOPSIS **docker save** +[**--help**] [**-o**|**--output**[=*OUTPUT*]] IMAGE [IMAGE...] @@ -16,6 +17,9 @@ parent layers, and all tags + versions, or specified repo:tag. Stream to a file instead of STDOUT by using **-o**. # OPTIONS +**--help** + Print usage statement + **-o**, **--output**="" Write to a file, instead of STDOUT diff --git a/docs/man/docker-search.1.md b/docs/man/docker-search.1.md index 3937b870a..0b9df1015 100644 --- a/docs/man/docker-search.1.md +++ b/docs/man/docker-search.1.md @@ -7,6 +7,7 @@ docker-search - Search the Docker Hub for images # SYNOPSIS **docker search** [**--automated**[=*false*]] +[**--help**] [**--no-trunc**[=*false*]] [**-s**|**--stars**[=*0*]] TERM @@ -18,10 +19,15 @@ of images returned displays the name, description (truncated by default), number of stars awarded, whether the image is official, and whether it is automated. +*Note* - Search queries will only return up to 25 results + # OPTIONS **--automated**=*true*|*false* Only show automated builds. The default is *false*. +**--help** + Print usage statement + **--no-trunc**=*true*|*false* Don't truncate output. The default is *false*. diff --git a/docs/man/docker-start.1.md b/docs/man/docker-start.1.md index e23fd70ab..965c5bcaf 100644 --- a/docs/man/docker-start.1.md +++ b/docs/man/docker-start.1.md @@ -7,6 +7,7 @@ docker-start - Restart a stopped container # SYNOPSIS **docker start** [**-a**|**--attach**[=*false*]] +[**--help**] [**-i**|**--interactive**[=*false*]] CONTAINER [CONTAINER...] @@ -18,6 +19,9 @@ Start a stopped container. **-a**, **--attach**=*true*|*false* Attach container's STDOUT and STDERR and forward all signals to the process. The default is *false*. +**--help** + Print usage statement + **-i**, **--interactive**=*true*|*false* Attach container's STDIN. The default is *false*. diff --git a/docs/man/docker-stats.1.md b/docs/man/docker-stats.1.md new file mode 100644 index 000000000..968babab5 --- /dev/null +++ b/docs/man/docker-stats.1.md @@ -0,0 +1,30 @@ +% DOCKER(1) Docker User Manuals +% Docker Community +% JUNE 2014 +# NAME +docker-stats - Display a live stream of one or more containers' resource usage statistics + +# SYNOPSIS +**docker stats** +[**--help**] +[CONTAINERS] + +# DESCRIPTION + +Display a live stream of one or more containers' resource usage statistics + +Note: this functionality currently only works when using the *libcontainer* exec-driver. + +# OPTIONS +**--help** + Print usage statement + +# EXAMPLES + +Run **docker stats** with multiple containers. + + $ sudo docker stats redis1 redis2 + CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O + redis1 0.07% 796 KiB/64 MiB 1.21% 788 B/648 B + redis2 0.07% 2.746 MiB/64 MiB 4.29% 1.266 KiB/648 B + diff --git a/docs/man/docker-stop.1.md b/docs/man/docker-stop.1.md index 1b73e387e..09972347a 100644 --- a/docs/man/docker-stop.1.md +++ b/docs/man/docker-stop.1.md @@ -6,6 +6,7 @@ docker-stop - Stop a running container by sending SIGTERM and then SIGKILL after # SYNOPSIS **docker stop** +[**--help**] [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...] @@ -14,6 +15,9 @@ Stop a running container (Send SIGTERM, and then SIGKILL after grace period) # OPTIONS +**--help** + Print usage statement + **-t**, **--time**=10 Number of seconds to wait for the container to stop before killing it. Default is 10 seconds. diff --git a/docs/man/docker-tag.1.md b/docs/man/docker-tag.1.md index e8550ec55..20125e5df 100644 --- a/docs/man/docker-tag.1.md +++ b/docs/man/docker-tag.1.md @@ -7,6 +7,7 @@ docker-tag - Tag an image into a repository # SYNOPSIS **docker tag** [**-f**|**--force**[=*false*]] +[**--help**] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG] # DESCRIPTION diff --git a/docs/man/docker-top.1.md b/docs/man/docker-top.1.md index 9781739cd..be2bed221 100644 --- a/docs/man/docker-top.1.md +++ b/docs/man/docker-top.1.md @@ -6,6 +6,7 @@ docker-top - Display the running processes of a container # SYNOPSIS **docker top** +[**--help**] CONTAINER [ps OPTIONS] # DESCRIPTION @@ -14,7 +15,8 @@ Look up the running process of the container. ps-OPTION can be any of the options you would pass to a Linux ps command. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES diff --git a/docs/man/docker-wait.1.md b/docs/man/docker-wait.1.md index 798f6d652..a1e2aa212 100644 --- a/docs/man/docker-wait.1.md +++ b/docs/man/docker-wait.1.md @@ -6,6 +6,7 @@ docker-wait - Block until a container stops, then print its exit code. # SYNOPSIS **docker wait** +[**--help**] CONTAINER [CONTAINER...] # DESCRIPTION @@ -13,7 +14,8 @@ CONTAINER [CONTAINER...] Block until a container stops, then print its exit code. # OPTIONS -There are no available options. +**--help** + Print usage statement # EXAMPLES diff --git a/docs/man/docker.1.md b/docs/man/docker.1.md index e07687c18..1e0016f53 100644 --- a/docs/man/docker.1.md +++ b/docs/man/docker.1.md @@ -26,6 +26,9 @@ To see the man page for a command run **man docker **. **-D**=*true*|*false* Enable debug mode. Default is false. +**--help** + Print usage statement + **-H**, **--host**=[unix:///var/run/docker.sock]: tcp://[host:port] to bind or unix://[/path/to/socket] to use. The socket(s) to bind to in daemon mode specified using one or more @@ -49,9 +52,11 @@ unix://[/path/to/socket] to use. **-g**="" Path to use as the root of the Docker runtime. Default is `/var/lib/docker`. - **--fixed-cidr**="" - IPv4 subnet for fixed IPs (ex: 10.20.0.0/16); this subnet must be nested in the bridge subnet (which is defined by \-b or \-\-bip) + IPv4 subnet for fixed IPs (e.g., 10.20.0.0/16); this subnet must be nested in the bridge subnet (which is defined by \-b or \-\-bip) + +**--fixed-cidr-v6**="" + IPv6 subnet for global IPv6 addresses (e.g., 2a00:1450::/64) **--icc**=*true*|*false* Allow unrestricted inter\-container and Docker daemon host communication. If disabled, containers can still be linked together using **--link** option (see **docker-run(1)**). Default is true. @@ -59,13 +64,19 @@ unix://[/path/to/socket] to use. **--ip**="" Default IP address to use when binding container ports. Default is `0.0.0.0`. +**--ip-forward**=*true*|*false* + Docker will enable IP forwarding. Default is true. If `--fixed-cidr-v6` is set. IPv6 forwarding will be activated, too. This may reject Router Advertisements and interfere with the host's existing IPv6 configuration. For more information please consult the documentation about "Advanced Networking - IPv6". + **--ip-masq**=*true*|*false* Enable IP masquerading for bridge's IP range. Default is true. **--iptables**=*true*|*false* Disable Docker's addition of iptables rules. Default is true. -**-l**, **--log-level**="*debug*|*info*|*error*|*fatal*"" +**--ipv6**=*true*|*false* + Enable IPv6 support. Default is false. Docker will create an IPv6-enabled bridge with address fe80::1 which will allow you to create IPv6-enabled containers. Use together with `--fixed-cidr-v6` to provide globally routable IPv6 addresses. IPv6 forwarding will be enabled if not used with `--ip-forward=false`. This may collide with your host's current IPv6 settings. For more information please consult the documentation about "Advanced Networking - IPv6". + +**-l**, **--log-level**="*debug*|*info*|*warn*|*error*|*fatal*"" Set the logging level. Default is `info`. **--label**="[]" @@ -133,7 +144,7 @@ unix://[/path/to/socket] to use. Display system-wide information **docker-inspect(1)** - Return low-level information on a container + Return low-level information on a container or image **docker-kill(1)** Kill a running container (which includes the wrapper process and everything @@ -266,7 +277,7 @@ is 64K. #### dm.blkdiscard Enables or disables the use of blkdiscard when removing devicemapper devices. This is enabled by default (only) if using loopback devices and is required to -res-parsify the loopback file on image/container removal. +resparsify the loopback file on image/container removal. Disabling this on loopback can lead to *much* faster container removal times, but will prevent the space used in `/var/lib/docker` directory from being returned to diff --git a/docs/mkdocs-compose.yml b/docs/mkdocs-compose.yml new file mode 100644 index 000000000..e2738f328 --- /dev/null +++ b/docs/mkdocs-compose.yml @@ -0,0 +1,5 @@ + +- ['compose/userguide.md', 'User Guide', 'Docker Compose' ] +- ['compose/install.md', 'Installation', 'Docker Compose'] +- ['compose/cli.md', 'Reference', 'Compose command line'] +- ['compose/yml.md', 'Reference', 'Compose yml'] diff --git a/docs/mkdocs-machine.yml b/docs/mkdocs-machine.yml new file mode 100644 index 000000000..45b2c5c84 --- /dev/null +++ b/docs/mkdocs-machine.yml @@ -0,0 +1,2 @@ + +- ['machine/userguide.md', 'User Guide', 'Docker Machine' ] diff --git a/docs/mkdocs-swarm.yml b/docs/mkdocs-swarm.yml new file mode 100644 index 000000000..5c9654f8f --- /dev/null +++ b/docs/mkdocs-swarm.yml @@ -0,0 +1,5 @@ + +- ['swarm/README.md', 'User Guide', 'Docker Swarm' ] +- ['swarm/discovery.md', 'Reference', 'Swarm discovery'] +- ['swarm/API.md', 'Reference', 'Swarm API'] +- ['swarm/scheduler/filter.md', 'Reference', 'Swarm filters'] diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 06f9064d9..332be55bf 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -18,7 +18,7 @@ use_absolute_urls: true theme_dir: ./theme/mkdocs/ theme_center_lead: false -copyright: Copyright © 2014, Docker, Inc. +copyright: Copyright © 2014-2015, Docker, Inc. google_analytics: ['UA-6096819-11', 'docker.io'] pages: @@ -45,7 +45,7 @@ pages: - ['installation/archlinux.md', 'Installation', 'Arch Linux'] - ['installation/frugalware.md', 'Installation', 'FrugalWare'] - ['installation/fedora.md', 'Installation', 'Fedora'] -- ['installation/openSUSE.md', 'Installation', 'openSUSE'] +- ['installation/SUSE.md', 'Installation', 'SUSE'] - ['installation/cruxlinux.md', 'Installation', 'CRUX Linux'] - ['installation/windows.md', 'Installation', 'Microsoft Windows'] - ['installation/binaries.md', 'Installation', 'Binaries'] @@ -69,6 +69,11 @@ pages: - ['docker-hub/builds.md', 'Docker Hub', 'Automated Builds'] - ['docker-hub/official_repos.md', 'Docker Hub', 'Official Repo Guidelines'] +# Docker Hub Enterprise +#- ['docker-hub-enterprise/index.md', '**HIDDEN**' ] +#- ['docker-hub-enterprise/install-config.md', 'Docker Hub Enterprise', 'Installation and Configuration' ] +#- ['docker-hub-enterprise/usage.md', 'Docker Hub Enterprise', 'User Guide' ] + # Examples: - ['examples/index.md', '**HIDDEN**'] - ['examples/nodejs_web_app.md', 'Examples', 'Dockerizing a Node.js web application'] @@ -86,6 +91,7 @@ pages: - ['articles/networking.md', 'Articles', 'Advanced networking'] - ['articles/security.md', 'Articles', 'Security'] - ['articles/https.md', 'Articles', 'Running Docker with HTTPS'] +- ['articles/registry_mirror.md', 'Articles', 'Run a local registry mirror'] - ['articles/host_integration.md', 'Articles', 'Automatically starting containers'] - ['articles/baseimages.md', 'Articles', 'Creating a base image'] - ['articles/dockerfile_best-practices.md', 'Articles', 'Best practices for writing Dockerfiles'] @@ -113,12 +119,13 @@ pages: - ['reference/api/registry_api_client_libraries.md', 'Reference', 'Docker Registry API Client Libraries'] - ['reference/api/hub_registry_spec.md', 'Reference', 'Docker Hub and Registry Spec'] - ['reference/api/docker_remote_api.md', 'Reference', 'Docker Remote API'] +- ['reference/api/docker_remote_api_v1.17.md', 'Reference', 'Docker Remote API v1.17'] - ['reference/api/docker_remote_api_v1.16.md', 'Reference', 'Docker Remote API v1.16'] -- ['reference/api/docker_remote_api_v1.15.md', 'Reference', 'Docker Remote API v1.15'] -- ['reference/api/docker_remote_api_v1.14.md', 'Reference', 'Docker Remote API v1.14'] -- ['reference/api/docker_remote_api_v1.13.md', 'Reference', 'Docker Remote API v1.13'] -- ['reference/api/docker_remote_api_v1.12.md', 'Reference', 'Docker Remote API v1.12'] -- ['reference/api/docker_remote_api_v1.11.md', 'Reference', 'Docker Remote API v1.11'] +- ['reference/api/docker_remote_api_v1.15.md', '**HIDDEN**'] +- ['reference/api/docker_remote_api_v1.14.md', '**HIDDEN**'] +- ['reference/api/docker_remote_api_v1.13.md', '**HIDDEN**'] +- ['reference/api/docker_remote_api_v1.12.md', '**HIDDEN**'] +- ['reference/api/docker_remote_api_v1.11.md', '**HIDDEN**'] - ['reference/api/docker_remote_api_v1.10.md', '**HIDDEN**'] - ['reference/api/docker_remote_api_v1.9.md', '**HIDDEN**'] - ['reference/api/docker_remote_api_v1.8.md', '**HIDDEN**'] diff --git a/docs/release.sh b/docs/release.sh index 8df8960c7..975940f5d 100755 --- a/docs/release.sh +++ b/docs/release.sh @@ -72,31 +72,84 @@ setup_s3() { build_current_documentation() { mkdocs build + cd site/ + gzip -9k -f search_content.json + cd .. } upload_current_documentation() { src=site/ dst=s3://$BUCKET$1 + cache=max-age=3600 + if [ "$NOCACHE" ]; then + cache=no-cache + fi + echo echo "Uploading $src" echo " to $dst" echo - #s3cmd --recursive --follow-symlinks --preserve --acl-public sync "$src" "$dst" - #aws s3 cp --profile $BUCKET --cache-control "max-age=3600" --acl public-read "site/search_content.json" "$dst" # a really complicated way to send only the files we want # if there are too many in any one set, aws s3 sync seems to fall over with 2 files to go # versions.html_fragment include="--recursive --include \"*.$i\" " echo "uploading *.$i" - run="aws s3 cp $src $dst $OPTIONS --profile $BUCKET --cache-control \"max-age=3600\" --acl public-read $include" + run="aws s3 cp $src $dst $OPTIONS --profile $BUCKET --cache-control $cache --acl public-read $include" echo "=======================" echo "$run" echo "=======================" $run + + # Make sure the search_content.json.gz file has the right content-encoding + aws s3 cp --profile $BUCKET --cache-control $cache --content-encoding="gzip" --acl public-read "site/search_content.json.gz" "$dst" } +invalidate_cache() { + if [ "" == "$DISTRIBUTION_ID" ]; then + echo "Skipping Cloudfront cache invalidation" + return + fi + + dst=$1 + + #aws cloudfront create-invalidation --profile docs.docker.com --distribution-id $DISTRIBUTION_ID --invalidation-batch '{"Paths":{"Quantity":1, "Items":["'+$file+'"]},"CallerReference":"19dec2014sventest1"}' + aws configure set preview.cloudfront true + + files=($(cat changed-files | grep 'sources/.*$' | sed -E 's#.*docs/sources##' | sed -E 's#index\.md#index.html#' | sed -E 's#\.md#/index.html#')) + files[${#files[@]}]="/index.html" + files[${#files[@]}]="/versions.html_fragment" + + len=${#files[@]} + + echo "aws cloudfront create-invalidation --profile $AWS_S3_BUCKET --distribution-id $DISTRIBUTION_ID --invalidation-batch '" > batchfile + echo "{\"Paths\":{\"Quantity\":$len," >> batchfile + echo "\"Items\": [" >> batchfile + + #for file in $(cat changed-files | grep 'sources/.*$' | sed -E 's#.*docs/sources##' | sed -E 's#index\.md#index.html#' | sed -E 's#\.md#/index.html#') + for file in "${files[@]}" + do + if [ "$file" == "${files[${#files[@]}-1]}" ]; then + comma="" + else + comma="," + fi + echo "\"$dst$file\"$comma" >> batchfile + done + + echo "]}, \"CallerReference\":" >> batchfile + echo "\"$(date)\"}'" >> batchfile + + + echo "-----" + cat batchfile + echo "-----" + sh batchfile + echo "-----" +} + + if [ "$OPTIONS" != "--dryrun" ]; then setup_s3 fi @@ -106,6 +159,7 @@ if [ "$BUILD_ROOT" == "yes" ]; then echo "Building root documentation" build_current_documentation upload_current_documentation + [ "$NOCACHE" ] || invalidate_cache fi #build again with /v1.0/ prefix @@ -113,3 +167,4 @@ sed -i "s/^site_url:.*/site_url: \/$MAJOR_MINOR\//" mkdocs.yml echo "Building the /$MAJOR_MINOR/ documentation" build_current_documentation upload_current_documentation "/$MAJOR_MINOR/" +[ "$NOCACHE" ] || invalidate_cache "/$MAJOR_MINOR" diff --git a/docs/s3_website.json b/docs/s3_website.json index 224ba816e..e468b678a 100644 --- a/docs/s3_website.json +++ b/docs/s3_website.json @@ -30,7 +30,8 @@ { "Condition": { "KeyPrefixEquals": "examples/ambassador_pattern_linking/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "articles/ambassador_pattern_linking/" } }, { "Condition": { "KeyPrefixEquals": "examples/using_supervisord/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "articles/using_supervisord/" } }, { "Condition": { "KeyPrefixEquals": "reference/api/registry_index_spec/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "reference/api/hub_registry_spec/" } }, - { "Condition": { "KeyPrefixEquals": "use/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "examples/" } } + { "Condition": { "KeyPrefixEquals": "use/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "examples/" } }, + { "Condition": { "KeyPrefixEquals": "installation/openSUSE/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "installation/SUSE/" } } ] } diff --git a/docs/sources/article-img/ipv6_basic_host_config.gliffy b/docs/sources/article-img/ipv6_basic_host_config.gliffy new file mode 100644 index 000000000..f28c3f6f9 --- /dev/null +++ b/docs/sources/article-img/ipv6_basic_host_config.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":420,"height":127,"nodeIndex":173,"autoFit":true,"exportBorder":false,"gridOn":false,"snapToGrid":false,"drawingGuidesOn":false,"pageBreaksOn":false,"printGridOn":false,"printPaper":"LETTER","printShrinkToFit":false,"printPortrait":true,"maxWidth":5000,"maxHeight":5000,"themeData":null,"viewportType":"default","fitBB":{"min":{"x":8.5,"y":0.5},"max":{"x":419.75,"y":126.5}},"objects":[{"x":6.5,"y":106.0,"rotation":0.0,"id":9,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":20,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

docker0 fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":19.5,"y":8.0,"rotation":0.0,"id":7,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":19,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:0:1::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":31.5,"y":23.5,"rotation":0.0,"id":4,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":16,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#a4c2f4","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":5,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Host2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":11.75,"y":0.5,"rotation":0.0,"id":60,"width":402.0,"height":126.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":2,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":146.5,"y":82.0,"rotation":0.0,"id":164,"width":249.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":44,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 2001:db8:0:2::/64 dev docker0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":146.5,"y":27.5,"rotation":0.0,"id":73,"width":249.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":35,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]}],"shapeStyles":{"com.gliffy.shape.basic.basic_v1.default":{"fill":"#fff2cc","stroke":"#333333","strokeWidth":2,"dashStyle":"2.0,2.0","gradient":true,"shadow":true}},"lineStyles":{"global":{"stroke":"#d9d9d9"}},"textStyles":{"global":{"italic":false,"size":"12px","color":"#b7b7b7"}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","libraries":["com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"],"autosaveDisabled":false},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/docs/sources/article-img/ipv6_basic_host_config.svg b/docs/sources/article-img/ipv6_basic_host_config.svg new file mode 100644 index 000000000..b5f9eeebe --- /dev/null +++ b/docs/sources/article-img/ipv6_basic_host_config.svg @@ -0,0 +1 @@ +Host2eth0 2001:db8:0:1::1/64docker0 fe80::1/64route -A inet6 default gw fe80::1 dev eth0route -A inet6 2001:db8:0:2::/64 dev docker0 \ No newline at end of file diff --git a/docs/sources/article-img/ipv6_routed_network_example.gliffy b/docs/sources/article-img/ipv6_routed_network_example.gliffy new file mode 100644 index 000000000..aea452b62 --- /dev/null +++ b/docs/sources/article-img/ipv6_routed_network_example.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":757,"height":503,"nodeIndex":174,"autoFit":true,"exportBorder":false,"gridOn":false,"snapToGrid":false,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":"LETTER","printShrinkToFit":false,"printPortrait":true,"maxWidth":5000,"maxHeight":5000,"themeData":null,"viewportType":"default","fitBB":{"min":{"x":-9.000680271168676,"y":-4.75},"max":{"x":756.0183424505415,"y":502.5}},"objects":[{"x":765.0,"y":250.0,"rotation":0.0,"id":169,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":47,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-12.982306425886122,0.0],[-41.25,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":663.0,"y":362.5,"rotation":270.0,"id":168,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":46,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

managed by Docker

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":747.0,"y":472.0,"rotation":0.0,"id":166,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":45,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":2,"endArrow":2,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[0.0,14.008510484195028],[0.0,-221.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":25.5,"y":254.0,"rotation":0.0,"id":162,"width":194.49999999999997,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":43,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 2001:db8:1:1::/64 \\

    dev docker0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":239.28932188134524,"y":150.0,"rotation":0.0,"id":32,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":8,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":4,"py":0.0,"px":0.2928932188134524}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":0,"py":1.0,"px":0.7071067811865476}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[196.5,47.5],[151.9213562373095,-37.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":195.0,"y":261.5,"rotation":0.0,"id":35,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":11,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":2,"py":0.9999999999999998,"px":0.29289321881345254}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":13,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[66.28932188134524,11.0],[-92.0,91.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":182.0,"y":272.5,"rotation":0.0,"id":34,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":10,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":2,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":15,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[100.0,0.0],[82.0,80.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":11.5,"y":463.0,"rotation":0.0,"id":53,"width":346.49999999999994,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":33,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":11.5,"y":323.5,"rotation":0.0,"id":56,"width":346.49999999999994,"height":163.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":5,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":245.0,"y":109.0,"rotation":0.0,"id":33,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":9,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":0,"py":0.9999999999999998,"px":0.29289321881345254}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":2,"py":0.0,"px":0.7071067811865476}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[104.78932188134524,3.999999999999986],[57.710678118654755,88.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":76.5,"y":141.5,"rotation":0.0,"id":31,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":7,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":4,"py":1.0,"px":0.7071067811865476}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":25,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[400.71067811865476,131.0],[560.0,211.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":37.5,"y":145.5,"rotation":0.0,"id":30,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":6,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":4,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":27,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[419.0,127.0],[431.0,207.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":296.0,"y":21.0,"rotation":0.0,"id":87,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":41,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":293.0,"y":120.0,"rotation":0.0,"id":83,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":40,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth1 fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":433.5,"y":42.5,"rotation":0.0,"id":82,"width":291.0,"height":70.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":39,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

 

 

route -A inet6 2001:db8:1::/48 gw fe80::1:1 dev eth1

route -A inet6 2001:db8:2::/48 gw fe80::2:1 dev eth1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":320.5,"y":38.0,"rotation":0.0,"id":0,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":12,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#fff2cc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":1,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Router

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":369.0,"y":40.0,"rotation":0.0,"id":89,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":1,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":0,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#d9d9d9","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":10.0,"controlPath":[[1.5,-2.0],[1.5,-21.125],[1.5,-21.125],[1.5,-40.25]],"lockSegments":{},"ortho":true}},"linkMap":[],"children":[]},{"x":297.75,"y":10.5,"rotation":0.0,"id":80,"width":425.99999999999994,"height":133.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":0,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":528.5,"y":197.5,"rotation":0.0,"id":73,"width":195.25,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":35,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 \\

    dev eth0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":793.0,"y":250.0,"rotation":0.0,"id":64,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":34,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":60,"py":0.6205673758865248,"px":1.0}}},"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":"8.0,8.0","startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-69.25,0.0],[-798.0006802711687,-3.410605131648481E-13]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":25.5,"y":199.5,"rotation":0.0,"id":47,"width":291.0,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":31,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 \\

   dev eth0 

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":207.0,"y":281.0,"rotation":0.0,"id":11,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":21,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

docker0 fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":220.0,"y":168.0,"rotation":0.0,"id":6,"width":150.0,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":18,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:1:0::1/64

        fe80::1:1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":232.0,"y":197.5,"rotation":0.0,"id":2,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":14,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#a4c2f4","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":3,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Host1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":11.5,"y":162.5,"rotation":0.0,"id":59,"width":346.50000000000006,"height":141.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":3,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":384.75,"y":162.5,"rotation":0.0,"id":60,"width":339.0,"height":141.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":2,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":189.0,"y":336.0,"rotation":0.0,"id":74,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":36,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:1:1::2/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":28.000000000000014,"y":336.0,"rotation":0.0,"id":19,"width":149.99999999999997,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":26,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:1:1::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":214.0,"y":353.0,"rotation":0.0,"id":15,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":24,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":16,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container1-2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":53.0,"y":353.0,"rotation":0.0,"id":13,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":22,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":14,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container1-1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":395.0,"y":336.0,"rotation":0.0,"id":77,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":37,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:2:1::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":384.75,"y":323.5,"rotation":0.0,"id":58,"width":339.75,"height":163.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":4,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":384.75,"y":462.0,"rotation":0.0,"id":51,"width":339.75,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":32,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":418.5,"y":353.0,"rotation":0.0,"id":27,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":27,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":28,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container2-1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":563.0,"y":336.0,"rotation":0.0,"id":78,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":38,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:2:1::2/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":586.5,"y":353.0,"rotation":0.0,"id":25,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":29,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":26,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container2-2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":259.0,"y":491.5,"rotation":0.0,"id":107,"width":223.00000000000003,"height":11.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":42,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

containers' link-local addresses are not displayed

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":394.5,"y":168.0,"rotation":0.0,"id":7,"width":150.0,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":19,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:2:0::1/64
        fe80::2:1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":381.5,"y":280.0,"rotation":0.0,"id":9,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":20,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

docker0 fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":406.5,"y":197.5,"rotation":0.0,"id":4,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":16,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#a4c2f4","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":5,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Host2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":528.5,"y":252.0,"rotation":0.0,"id":164,"width":194.49999999999997,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":44,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 2001:db8:2:1::/64 \\

    dev docker0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":766.0,"y":487.0,"rotation":0.0,"id":171,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":48,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-13.981657549458532,0.0],[-41.25,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]}],"shapeStyles":{"com.gliffy.shape.basic.basic_v1.default":{"fill":"#fff2cc","stroke":"#333333","strokeWidth":2,"dashStyle":"2.0,2.0","gradient":true,"shadow":true}},"lineStyles":{"global":{"stroke":"#000000","strokeWidth":1}},"textStyles":{"global":{"size":"12px"}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","libraries":["com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"],"autosaveDisabled":false},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/docs/sources/article-img/ipv6_routed_network_example.svg b/docs/sources/article-img/ipv6_routed_network_example.svg new file mode 100644 index 000000000..7050657f9 --- /dev/null +++ b/docs/sources/article-img/ipv6_routed_network_example.svg @@ -0,0 +1 @@ +RouterHost1Host2eth0 2001:db8:1:0::1/64        fe80::1:1/64eth0 2001:db8:2:0::1/64        fe80::2:1/64docker0 fe80::1/64docker0 fe80::1/64Container1-1Container1-2eth0 2001:db8:1:1::1/64Container2-1Container2-2route -A inet6 default gw fe80::1 \   dev eth0 route -A inet6 default gw fe80::1 dev eth0route -A inet6 default gw fe80::1 dev eth0route -A inet6 default gw fe80::1 \    dev eth0eth0 2001:db8:1:1::2/64eth0 2001:db8:2:1::1/64eth0 2001:db8:2:1::2/64route -A inet6 default gw fe80::1 dev eth0  route -A inet6 2001:db8:1::/48 gw fe80::1:1 dev eth1route -A inet6 2001:db8:2::/48 gw fe80::2:1 dev eth1eth1 fe80::1/64eth0 2001:db8::1/64containers' link-local addresses are not displayedroute -A inet6 2001:db8:1:1::/64 \    dev docker0route -A inet6 2001:db8:2:1::/64 \    dev docker0managed by Docker \ No newline at end of file diff --git a/docs/sources/article-img/ipv6_slash64_subnet_config.gliffy b/docs/sources/article-img/ipv6_slash64_subnet_config.gliffy new file mode 100644 index 000000000..efafc02ef --- /dev/null +++ b/docs/sources/article-img/ipv6_slash64_subnet_config.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":550,"height":341,"nodeIndex":88,"autoFit":true,"exportBorder":false,"gridOn":false,"snapToGrid":false,"drawingGuidesOn":false,"pageBreaksOn":false,"printGridOn":false,"printPaper":"LETTER","printShrinkToFit":false,"printPortrait":true,"maxWidth":5000,"maxHeight":5000,"themeData":null,"viewportType":"default","fitBB":{"min":{"x":2.5,"y":2.5},"max":{"x":550,"y":341}},"objects":[{"x":10.5,"y":53.5,"rotation":0.0,"id":74,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":26,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":37.0,"y":2.5,"rotation":0.0,"id":72,"width":100.0,"height":46.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":24,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#d9d9d9","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":73,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Router

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":89.5,"y":83.5,"rotation":0.0,"id":59,"width":150.0,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":17,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Routed Network:
2001:db8::/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":313.0,"y":313.0,"rotation":0.0,"id":39,"width":235.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":16,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":352.0,"y":185.5,"rotation":0.0,"id":36,"width":169.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":15,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:0:0:1::2/80

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":351.0,"y":49.5,"rotation":0.0,"id":29,"width":171.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":14,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8:0:0:1::1/80

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":382.1250000000001,"y":202.5,"rotation":0.0,"id":30,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":12,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":31,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

container1-2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":382.0,"y":65.5,"rotation":0.0,"id":32,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":10,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":33,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

container1-1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":15.125000000000057,"y":261.0,"rotation":0.0,"id":20,"width":273.0,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":9,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

route -A inet6 2001:db8:0:0:1::/80 dev docker0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":120.0,"y":178.5,"rotation":0.0,"id":21,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":8,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

docker0 fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":13.0,"y":132.5,"rotation":0.0,"id":22,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":7,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001:db8::1/80

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":38.0,"y":149.0,"rotation":0.0,"id":23,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":5,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#a4c2f4","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":24,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

host1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":-118.0,"y":123.0,"rotation":0.0,"id":44,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":4,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":23,"py":0.7071067811865475,"px":0.9999999999999998}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":30,"py":0.5,"px":0.0}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[255.99999999999997,79.03300858899107],[500.1250000000001,129.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":-138.0,"y":129.0,"rotation":0.0,"id":43,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":3,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":23,"py":0.29289321881345237,"px":1.0}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":32,"py":0.5,"px":0.0}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[276.0,41.966991411008934],[520.0,-13.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":313.0,"y":40.0,"rotation":0.0,"id":34,"width":237.00000000000003,"height":301.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":2,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":87.0,"y":150.0,"rotation":0.0,"id":58,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":1,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":23,"py":0.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":72,"py":1.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[1.0,-1.0],[0.0,-101.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":2.5,"y":118.50000000000001,"rotation":0.0,"id":25,"width":292.0,"height":178.99999999999997,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":0,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]}],"shapeStyles":{},"lineStyles":{"global":{"stroke":"#cccccc"}},"textStyles":{"global":{"bold":true,"italic":true}}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","libraries":["com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v1.default","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v2.forms_components","com.gliffy.libraries.network.network_v3.home","com.gliffy.libraries.images"],"autosaveDisabled":false},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/docs/sources/article-img/ipv6_slash64_subnet_config.svg b/docs/sources/article-img/ipv6_slash64_subnet_config.svg new file mode 100644 index 000000000..c731eddd3 --- /dev/null +++ b/docs/sources/article-img/ipv6_slash64_subnet_config.svg @@ -0,0 +1 @@ +host1eth0 2001:db8::1/80docker0 fe80::1/64route -A inet6 default gw fe80::1 dev eth0route -A inet6 2001:db8:0:0:1::/80 dev docker0container1-1container1-2eth0 2001:db8:0:0:1::1/80eth0 2001:db8:0:0:1::2/80route -A inet6 default gw fe80::1 dev eth0Routed Network:2001:db8::/64Routerfe80::1/64 \ No newline at end of file diff --git a/docs/sources/article-img/ipv6_switched_network_example.gliffy b/docs/sources/article-img/ipv6_switched_network_example.gliffy new file mode 100644 index 000000000..7f2b73f18 --- /dev/null +++ b/docs/sources/article-img/ipv6_switched_network_example.gliffy @@ -0,0 +1 @@ +{"contentType":"application/gliffy+json","version":"1.3","stage":{"background":"#FFFFFF","width":748,"height":448,"nodeIndex":182,"autoFit":true,"exportBorder":false,"gridOn":false,"snapToGrid":false,"drawingGuidesOn":true,"pageBreaksOn":false,"printGridOn":false,"printPaper":"LETTER","printShrinkToFit":false,"printPortrait":true,"maxWidth":5000,"maxHeight":5000,"themeData":null,"viewportType":"default","fitBB":{"min":{"x":-17.000680271168676,"y":5},"max":{"x":747.7683424505416,"y":447.5}},"objects":[{"x":17.5,"y":202.0,"rotation":0.0,"id":167,"width":204.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":38,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 2001::/64 dev docker0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":231.28932188134524,"y":95.0,"rotation":0.0,"id":120,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":6,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":161,"py":0.0,"px":0.2928932188134524}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":131,"py":1.0,"px":0.7071067811865476}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[196.5,47.5],[151.9213562373095,-15.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":187.0,"y":206.5,"rotation":0.0,"id":121,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":9,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":140,"py":0.9999999999999998,"px":0.29289321881345254}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":148,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[66.28932188134524,11.0],[-92.0,91.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":174.0,"y":217.5,"rotation":0.0,"id":122,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":8,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":140,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":146,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[100.0,0.0],[82.0,80.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":3.5000000000000284,"y":408.0,"rotation":0.0,"id":123,"width":346.49999999999994,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":31,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":3.5000000000000284,"y":268.5,"rotation":0.0,"id":124,"width":346.49999999999994,"height":163.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":3,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":237.0,"y":54.0,"rotation":0.0,"id":125,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":7,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":131,"py":0.9999999999999998,"px":0.29289321881345254}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":140,"py":0.0,"px":0.7071067811865476}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[104.78932188134524,25.999999999999986],[57.710678118654755,88.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":68.5,"y":86.5,"rotation":0.0,"id":126,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":5,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":161,"py":1.0,"px":0.7071067811865476}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":156,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[400.71067811865476,131.0],[560.0,211.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":29.5,"y":90.5,"rotation":0.0,"id":127,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":4,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":161,"py":1.0,"px":0.5}},"endConstraint":{"type":"EndPositionConstraint","EndPositionConstraint":{"nodeId":153,"py":0.0,"px":0.5}}},"graphic":{"type":"Line","Line":{"strokeWidth":2.0,"strokeColor":"#cccccc","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[419.0,127.0],[431.0,207.5]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":312.5,"y":5.0,"rotation":0.0,"id":131,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":10,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#e2e2e2","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":132,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Level 2 Switch

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":785.0,"y":195.0,"rotation":0.0,"id":136,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":32,"lockAspectRatio":false,"lockShape":false,"constraints":{"constraints":[],"startConstraint":{"type":"StartPositionConstraint","StartPositionConstraint":{"nodeId":143,"py":0.6187943262411347,"px":1.0}}},"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":"8.0,8.0","startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-69.25,-0.25],[-798.0006802711687,-3.410605131648481E-13]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":199.0,"y":224.0,"rotation":0.0,"id":138,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":19,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

docker0 fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":229.0,"y":126.0,"rotation":0.0,"id":139,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":16,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2000::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":224.0,"y":142.5,"rotation":0.0,"id":140,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":12,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#a4c2f4","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":141,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Host1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":3.4999999999999716,"y":107.5,"rotation":0.0,"id":142,"width":346.50000000000006,"height":141.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":1,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":376.75,"y":107.5,"rotation":0.0,"id":143,"width":339.0,"height":141.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":0,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":181.0,"y":281.0,"rotation":0.0,"id":144,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":34,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001::2/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":20.000000000000014,"y":281.0,"rotation":0.0,"id":145,"width":149.99999999999997,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":24,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2001::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":206.0,"y":298.0,"rotation":0.0,"id":146,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":22,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":147,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container1-2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":45.0,"y":298.0,"rotation":0.0,"id":148,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":20,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":149,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container1-1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":387.0,"y":281.0,"rotation":0.0,"id":150,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":35,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2002::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":376.75,"y":268.5,"rotation":0.0,"id":151,"width":339.75,"height":163.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":2,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#FFFFFF","gradient":false,"dashStyle":"2,2","dropShadow":false,"state":0,"opacity":1.0,"shadowX":0.0,"shadowY":0.0}},"linkMap":[],"children":[]},{"x":376.75,"y":407.0,"rotation":0.0,"id":152,"width":339.75,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":30,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 default gw fe80::1 dev eth0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":410.5,"y":298.0,"rotation":0.0,"id":153,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":25,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":154,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container2-1

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":555.0,"y":281.0,"rotation":0.0,"id":155,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":36,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2002::2/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":578.5,"y":298.0,"rotation":0.0,"id":156,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.square","order":27,"lockAspectRatio":true,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#ead1dc","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":157,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Container2-2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":251.0,"y":436.5,"rotation":0.0,"id":158,"width":223.00000000000003,"height":11.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":37,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

containers' link-local addresses are not displayed

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":403.5,"y":126.0,"rotation":0.0,"id":159,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":17,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

eth0 2000::2/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":373.5,"y":223.0,"rotation":0.0,"id":160,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":18,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

docker0 fe80::1/64

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":398.5,"y":142.5,"rotation":0.0,"id":161,"width":100.0,"height":75.0,"uid":"com.gliffy.shape.basic.basic_v1.default.rectangle","order":14,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Shape","Shape":{"tid":"com.gliffy.stencil.rectangle.basic_v1","strokeWidth":2.0,"strokeColor":"#333333","fillColor":"#a4c2f4","gradient":true,"dashStyle":null,"dropShadow":true,"state":0,"opacity":1.0,"shadowX":4.0,"shadowY":4.0}},"linkMap":[],"children":[{"x":2.0,"y":0.0,"rotation":0.0,"id":162,"width":96.0,"height":14.0,"uid":null,"order":"auto","lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":8,"paddingRight":8,"paddingBottom":8,"paddingLeft":8,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

Host2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"children":[]}]},{"x":17.5,"y":143.5,"rotation":0.0,"id":137,"width":291.0,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":29,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 2000::/64 dev eth0

route -A inet6 2002::/64 gw 2000::2

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":507.5,"y":144.0,"rotation":0.0,"id":135,"width":209.0,"height":28.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":33,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 2000::/64 dev eth0

route -A inet6 2001::/64 gw 2000::1 

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":508.0,"y":195.0,"rotation":0.0,"id":168,"width":204.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":39,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

route -A inet6 2002::/64 dev docker0

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":756.7500000000001,"y":195.0,"rotation":0.0,"id":172,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":43,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-12.982306425886122,0.0],[-41.25,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":757.7500000000001,"y":432.0,"rotation":0.0,"id":171,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":42,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":0,"endArrow":0,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[-13.981657549458532,0.0],[-41.25,0.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]},{"x":654.7500000000001,"y":307.5,"rotation":270.0,"id":173,"width":150.0,"height":14.0,"uid":"com.gliffy.shape.basic.basic_v1.default.text","order":41,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Text","Text":{"overflow":"none","paddingTop":2,"paddingRight":2,"paddingBottom":2,"paddingLeft":2,"outerPaddingTop":6,"outerPaddingRight":6,"outerPaddingBottom":2,"outerPaddingLeft":6,"type":"fixed","lineTValue":null,"linePerpValue":null,"cardinalityType":null,"html":"

managed by Docker

","tid":null,"valign":"middle","vposition":"none","hposition":"none"}},"linkMap":[],"children":[]},{"x":738.7500000000001,"y":417.0,"rotation":0.0,"id":174,"width":100.0,"height":100.0,"uid":"com.gliffy.shape.basic.basic_v1.default.line","order":40,"lockAspectRatio":false,"lockShape":false,"graphic":{"type":"Line","Line":{"strokeWidth":1.0,"strokeColor":"#000000","fillColor":"none","dashStyle":null,"startArrow":2,"endArrow":2,"startArrowRotation":"auto","endArrowRotation":"auto","interpolationType":"linear","cornerRadius":null,"controlPath":[[0.0,14.008510484195028],[0.0,-221.0]],"lockSegments":{},"ortho":false}},"linkMap":[],"children":[]}],"shapeStyles":{"com.gliffy.shape.basic.basic_v1.default":{"fill":"#e2e2e2","stroke":"#333333","strokeWidth":2,"dashStyle":"2.0,2.0","gradient":true,"shadow":true}},"lineStyles":{"global":{"stroke":"#000000","dashStyle":"8.0,8.0","strokeWidth":1}},"textStyles":{}},"metadata":{"title":"untitled","revision":0,"exportBorder":false,"loadPosition":"default","libraries":["com.gliffy.libraries.basic.basic_v1.default","com.gliffy.libraries.flowchart.flowchart_v1.default","com.gliffy.libraries.swimlanes.swimlanes_v1.default","com.gliffy.libraries.uml.uml_v2.class","com.gliffy.libraries.uml.uml_v2.sequence","com.gliffy.libraries.uml.uml_v2.activity","com.gliffy.libraries.erd.erd_v1.default","com.gliffy.libraries.ui.ui_v3.containers_content","com.gliffy.libraries.ui.ui_v3.forms_controls","com.gliffy.libraries.images"],"autosaveDisabled":false},"embeddedResources":{"index":0,"resources":[]}} \ No newline at end of file diff --git a/docs/sources/article-img/ipv6_switched_network_example.svg b/docs/sources/article-img/ipv6_switched_network_example.svg new file mode 100644 index 000000000..5c391c24a --- /dev/null +++ b/docs/sources/article-img/ipv6_switched_network_example.svg @@ -0,0 +1 @@ +Level 2 SwitchHost1Host2eth0 2000::1/64eth0 2000::2/64docker0 fe80::1/64docker0 fe80::1/64Container1-1Container1-2eth0 2001::1/64Container2-1Container2-2route -A inet6 2000::/64 dev eth0route -A inet6 2002::/64 gw 2000::2route -A inet6 default gw fe80::1 dev eth0route -A inet6 default gw fe80::1 dev eth0route -A inet6 2000::/64 dev eth0route -A inet6 2001::/64 gw 2000::1 eth0 2001::2/64eth0 2002::1/64eth0 2002::2/64containers' link-local addresses are not displayedroute -A inet6 2001::/64 dev docker0route -A inet6 2002::/64 dev docker0managed by Docker \ No newline at end of file diff --git a/docs/sources/articles.md b/docs/sources/articles.md deleted file mode 100644 index 37f2cd80f..000000000 --- a/docs/sources/articles.md +++ /dev/null @@ -1,15 +0,0 @@ -# Articles - - - [Docker Basics](basics/) - - [Docker Security](security/) - - [Running the Docker daemon with HTTPS](https/) - - [Configure Networking](networking/) - - [Using Supervisor with Docker](using_supervisord/) - - [Process Management with CFEngine](cfengine_process_management/) - - [Using Puppet](puppet/) - - [Create a Base Image](baseimages/) - - [Runtime Metrics](runmetrics/) - - [Automatically Start Containers](host_integration/) - - [Link via an Ambassador Container](ambassador_pattern_linking/) - - [Increase a Boot2Docker Volume](b2d_volume_resize/) - - [Run a Local Registry Mirror](registry_mirror/) diff --git a/docs/sources/articles/baseimages.md b/docs/sources/articles/baseimages.md index 3f53c8a84..5a5addd1a 100644 --- a/docs/sources/articles/baseimages.md +++ b/docs/sources/articles/baseimages.md @@ -5,7 +5,7 @@ page_keywords: Examples, Usage, base image, docker, documentation, examples # Create a Base Image So you want to create your own [*Base Image*]( -/terms/image/#base-image-def)? Great! +/terms/image/#base-image)? Great! The specific process will depend heavily on the Linux distribution you want to package. We have some examples below, and you are encouraged to diff --git a/docs/sources/articles/basics.md b/docs/sources/articles/basics.md index 8f3e1dc1a..4cdcab4aa 100644 --- a/docs/sources/articles/basics.md +++ b/docs/sources/articles/basics.md @@ -17,7 +17,7 @@ If you get `docker: command not found` or something like incomplete Docker installation or insufficient privileges to access Docker on your machine. -Please refer to [*Installation*](/installation/#installation-list) +Please refer to [*Installation*](/installation) for installation instructions. ## Download a pre-built image @@ -26,7 +26,7 @@ for installation instructions. $ sudo docker pull ubuntu This will find the `ubuntu` image by name on -[*Docker Hub*](/userguide/dockerrepos/#find-public-images-on-docker-hub) +[*Docker Hub*](/userguide/dockerrepos/#searching-for-images) and download it from [Docker Hub](https://hub.docker.com) to a local image cache. @@ -37,7 +37,7 @@ image cache. > characters of the full image ID - which can be found using > `docker inspect` or `docker images --no-trunc=true` -**If you're using OS X** then you shouldn't use `sudo`. +{{ include "no-remote-sudo.md" }} ## Running an interactive shell @@ -174,6 +174,6 @@ will be stored (as a diff). See which images you already have using the You now have an image state from which you can create new instances. Read more about [*Share Images via -Repositories*](/userguide/dockerrepos/#working-with-the-repository) or +Repositories*](/userguide/dockerrepos) or continue to the complete [*Command -Line*](/reference/commandline/cli/#cli) +Line*](/reference/commandline/cli) diff --git a/docs/sources/articles/certificates.md b/docs/sources/articles/certificates.md index e03167640..ebd606f38 100644 --- a/docs/sources/articles/certificates.md +++ b/docs/sources/articles/certificates.md @@ -45,7 +45,7 @@ Our example is set up like this: ## Creating the client certificates You will use OpenSSL's `genrsa` and `req` commands to first generate an RSA -key and then use the key to create the certificate request. +key and then use the key to create the certificate. $ openssl genrsa -out client.key 1024 $ openssl req -new -x509 -text -key client.key -out client.cert diff --git a/docs/sources/articles/chef.md b/docs/sources/articles/chef.md index 6ca0eba73..cb70215c5 100644 --- a/docs/sources/articles/chef.md +++ b/docs/sources/articles/chef.md @@ -7,7 +7,7 @@ page_keywords: chef, installation, usage, docker, documentation > **Note**: > Please note this is a community contributed installation path. The only > `official` installation is using the -> [*Ubuntu*](/installation/ubuntulinux/#ubuntu-linux) installation +> [*Ubuntu*](/installation/ubuntulinux) installation > path. This version may sometimes be out of date. ## Requirements diff --git a/docs/sources/articles/dockerfile_best-practices.md b/docs/sources/articles/dockerfile_best-practices.md index 85095f1c0..21334c16e 100644 --- a/docs/sources/articles/dockerfile_best-practices.md +++ b/docs/sources/articles/dockerfile_best-practices.md @@ -359,7 +359,7 @@ like `RUN groupadd -r postgres && useradd -r -g postgres postgres`. > rebuilds. So, if it’s critical, you should assign an explicit UID/GID. You should avoid installing or using `sudo` since it has unpredictable TTY and -signal-forwarding behavior that can cause more more problems than it solves. If +signal-forwarding behavior that can cause more problems than it solves. If you absolutely need functionality similar to `sudo` (e.g., initializing the daemon as root but running it as non-root), you may be able to use [“gosu”](https://github.com/tianon/gosu). diff --git a/docs/sources/articles/https.md b/docs/sources/articles/https.md index c8873bcbe..b65ec667a 100644 --- a/docs/sources/articles/https.md +++ b/docs/sources/articles/https.md @@ -1,8 +1,8 @@ -page_title: Running Docker with HTTPS +page_title: Protecting the Docker daemon Socket with HTTPS page_description: How to setup and run Docker with HTTPS page_keywords: docker, docs, article, example, https, daemon, tls, ca, certificate -# Running Docker with https +# Protecting the Docker daemon Socket with HTTPS By default, Docker runs via a non-networked Unix socket. It can also optionally communicate using a HTTP socket. @@ -15,63 +15,64 @@ In the daemon mode, it will only allow connections from clients authenticated by a certificate signed by that CA. In the client mode, it will only connect to servers with a certificate signed by that CA. -> **Warning**: +> **Warning**: > Using TLS and managing a CA is an advanced topic. Please familiarize yourself > with OpenSSL, x509 and TLS before using it in production. > **Warning**: > These TLS commands will only generate a working set of certificates on Linux. -> Mac OS X comes with a version of OpenSSL that is incompatible with the +> Mac OS X comes with a version of OpenSSL that is incompatible with the > certificates that Docker requires. ## Create a CA, server and client keys with OpenSSL -First, initialize the CA serial file and generate CA private and public -keys: +> **Note**: replace all instances of `$HOST` in the following example with the +> DNS name of your Docker daemon's host. - $ echo 01 > ca.srl - $ openssl genrsa -des3 -out ca-key.pem 2048 +First generate CA private and public keys: + + $ openssl genrsa -aes256 -out ca-key.pem 2048 Generating RSA private key, 2048 bit long modulus ......+++ ...............+++ e is 65537 (0x10001) Enter pass phrase for ca-key.pem: Verifying - Enter pass phrase for ca-key.pem: - $ openssl req -new -x509 -days 365 -key ca-key.pem -out ca.pem + $ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem Enter pass phrase for ca-key.pem: - You are about to be asked to enter information that will be incorporated - into your certificate request. - What you are about to enter is what is called a Distinguished Name or a DN. - There are quite a few fields but you can leave some blank - For some fields there will be a default value, - If you enter '.', the field will be left blank. - ----- - Country Name (2 letter code) [AU]: - State or Province Name (full name) [Some-State]:Queensland - Locality Name (eg, city) []:Brisbane - Organization Name (eg, company) [Internet Widgits Pty Ltd]:Docker Inc - Organizational Unit Name (eg, section) []:Boot2Docker - Common Name (e.g. server FQDN or YOUR name) []:your.host.com - Email Address []:Sven@home.org.au + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]: + State or Province Name (full name) [Some-State]:Queensland + Locality Name (eg, city) []:Brisbane + Organization Name (eg, company) [Internet Widgits Pty Ltd]:Docker Inc + Organizational Unit Name (eg, section) []:Boot2Docker + Common Name (e.g. server FQDN or YOUR name) []:$HOST + Email Address []:Sven@home.org.au Now that we have a CA, you can create a server key and certificate -signing request (CSR). Make sure that "Common Name" (i.e. server FQDN or YOUR +signing request (CSR). Make sure that "Common Name" (i.e., server FQDN or YOUR name) matches the hostname you will use to connect to Docker: - $ openssl genrsa -des3 -out server-key.pem 2048 +> **Note**: replace all instances of `$HOST` in the following example with the +> DNS name of your Docker daemon's host. + + $ openssl genrsa -out server-key.pem 2048 Generating RSA private key, 2048 bit long modulus ......................................................+++ ............................................+++ e is 65537 (0x10001) - Enter pass phrase for server-key.pem: - Verifying - Enter pass phrase for server-key.pem: - $ openssl req -subj '/CN=' -new -key server-key.pem -out server.csr - Enter pass phrase for server-key.pem: + $ openssl req -subj "/CN=$HOST" -new -key server-key.pem -out server.csr -Next, we're going to sign the key with our CA: +Next, we're going to sign the public key with our CA: $ openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \ - -out server-cert.pem + -CAcreateserial -out server-cert.pem Signature ok subject=/CN=your.host.com Getting CA Private Key @@ -80,55 +81,64 @@ Next, we're going to sign the key with our CA: For client authentication, create a client key and certificate signing request: - $ openssl genrsa -des3 -out key.pem 2048 + $ openssl genrsa -out key.pem 2048 Generating RSA private key, 2048 bit long modulus ...............................................+++ ...............................................................+++ e is 65537 (0x10001) - Enter pass phrase for key.pem: - Verifying - Enter pass phrase for key.pem: $ openssl req -subj '/CN=client' -new -key key.pem -out client.csr - Enter pass phrase for key.pem: To make the key suitable for client authentication, create an extensions config file: $ echo extendedKeyUsage = clientAuth > extfile.cnf -Now sign the key: +Now sign the public key: $ openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem \ - -out cert.pem -extfile extfile.cnf + -CAcreateserial -out cert.pem -extfile extfile.cnf Signature ok subject=/CN=client Getting CA Private Key Enter pass phrase for ca-key.pem: -Finally, you need to remove the passphrase from the client and server key: +After generating `cert.pem` and `server-cert.pem` you can safely remove the +two certificate signing requests: - $ openssl rsa -in server-key.pem -out server-key.pem - Enter pass phrase for server-key.pem: - writing RSA key - $ openssl rsa -in key.pem -out key.pem - Enter pass phrase for key.pem: - writing RSA key + $ rm -v client.csr server.csr + +With a default `umask` of 022, your secret keys will be *world-readable* and +writable for you and your group. + +In order to protect your keys from accidental damage, you will want to remove their +write permissions. To make them only readable by you, change file modes as follows: + + $ chmod -v 0400 ca-key.pem key.pem server-key.pem + +Certificates can be world-readable, but you might want to remove write access to +prevent accidental damage: + + $ chmod -v 0444 ca.pem server-cert.pem cert.pem Now you can make the Docker daemon only accept connections from clients providing a certificate trusted by our CA: - $ sudo docker -d --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem \ + $ docker -d --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem \ -H=0.0.0.0:2376 To be able to connect to Docker and validate its certificate, you now need to provide your client keys, certificates and trusted CA: - $ sudo docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem \ - -H=dns-name-of-docker-host:2376 version +> **Note**: replace all instances of `$HOST` in the following example with the +> DNS name of your Docker daemon's host. + + $ docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem \ + -H=$HOST:2376 version > **Note**: > Docker over TLS should run on TCP port 2376. -> **Warning**: +> **Warning**: > As shown in the example above, you don't have to run the `docker` client > with `sudo` or the `docker` group when you use certificate authentication. > That means anyone with the keys can give any instructions to your Docker @@ -137,20 +147,18 @@ need to provide your client keys, certificates and trusted CA: ## Secure by default -If you want to secure your Docker client connections by default, you can move -the files to the `.docker` directory in your home directory - and set the +If you want to secure your Docker client connections by default, you can move +the files to the `.docker` directory in your home directory -- and set the `DOCKER_HOST` and `DOCKER_TLS_VERIFY` variables as well (instead of passing -`-H=tcp://:2376` and `--tlsverify` on every call). +`-H=tcp://$HOST:2376` and `--tlsverify` on every call). - $ cp ca.pem ~/.docker/ca.pem - $ cp cert.pem ~/.docker/cert.pem - $ cp key.pem ~/.docker/key.pem - $ export DOCKER_HOST=tcp://:2376 - $ export DOCKER_TLS_VERIFY=1 + $ mkdir -pv ~/.docker + $ cp -v {ca,cert,key}.pem ~/.docker + $ export DOCKER_HOST=tcp://$HOST:2376 DOCKER_TLS_VERIFY=1 Docker will now connect securely by default: - $ sudo docker ps + $ docker ps ## Other modes @@ -172,16 +180,19 @@ Docker in various other modes by mixing the flags. certificate and authenticate server based on given CA If found, the client will send its client certificate, so you just need -to drop your keys into `~/.docker/.pem`. Alternatively, +to drop your keys into `~/.docker/{ca,cert,key}.pem`. Alternatively, if you want to store your keys in another location, you can specify that location using the environment variable `DOCKER_CERT_PATH`. - $ export DOCKER_CERT_PATH=${HOME}/.docker/zone1/ - $ sudo docker --tlsverify ps + $ export DOCKER_CERT_PATH=~/.docker/zone1/ + $ docker --tlsverify ps ### Connecting to the Secure Docker port using `curl` To use `curl` to make test API requests, you need to use three extra command line flags: - $ curl --insecure --cert ~/.docker/cert.pem --key ~/.docker/key.pem https://boot2docker:2376/images/json` + $ curl https://$HOST:2376/images/json \ + --cert ~/.docker/cert.pem \ + --key ~/.docker/key.pem \ + --cacert ~/.docker/ca.pem diff --git a/docs/sources/articles/https/Dockerfile b/docs/sources/articles/https/Dockerfile new file mode 100644 index 000000000..494aa3030 --- /dev/null +++ b/docs/sources/articles/https/Dockerfile @@ -0,0 +1,10 @@ +FROM debian + +RUN apt-get update && apt-get install -yq openssl + +ADD make_certs.sh / + + +WORKDIR /data +VOLUMES ["/data"] +CMD /make_certs.sh diff --git a/docs/sources/articles/https/Makefile b/docs/sources/articles/https/Makefile new file mode 100644 index 000000000..b751c1e43 --- /dev/null +++ b/docs/sources/articles/https/Makefile @@ -0,0 +1,24 @@ + +HOST:=boot2docker + +makescript: + ./parsedocs.sh > make_certs.sh + +build: makescript + docker build -t makecerts . + +cert: build + docker run --rm -it -v $(CURDIR):/data -e HOST=$(HOST) makecerts + +certs: cert + +run: + sudo docker -d -D --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:6666 --pidfile=$(pwd)/docker.pid --graph=$(pwd)/graph + +client: + sudo docker --tls --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=$(HOST):6666 version + sudo docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=$(HOST):6666 info + sudo curl https://$(HOST):6666/images/json --cert cert.pem --key key.pem --cacert ca.pem + +clean: + rm ca-key.pem ca.pem ca.srl cert.pem client.csr extfile.cnf key.pem server-cert.pem server-key.pem server.csr diff --git a/docs/sources/articles/https/README.md b/docs/sources/articles/https/README.md new file mode 100644 index 000000000..3e1dd27f6 --- /dev/null +++ b/docs/sources/articles/https/README.md @@ -0,0 +1,26 @@ + + +This is an initial attempt to make it easier to test the examples in the https.md +doc + +at this point, it has to be a manual thing, and I've been running it in boot2docker + +so my process is + +$ boot2docker ssh +$$ git clone https://github.com/docker/docker +$$ cd docker/docs/sources/articles/https +$$ make cert +lots of things to see and manually answer, as openssl wants to be interactive +**NOTE:** make sure you enter the hostname (`boot2docker` in my case) when prompted for `Computer Name`) +$$ sudo make run + +start another terminal + +$ boot2docker ssh +$$ cd docker/docs/sources/articles/https +$$ make client + +the last will connect first with `--tls` and then with `--tlsverify` + +both should succeed diff --git a/docs/sources/articles/https/make_certs.sh b/docs/sources/articles/https/make_certs.sh new file mode 100755 index 000000000..85b7ae153 --- /dev/null +++ b/docs/sources/articles/https/make_certs.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +openssl genrsa -aes256 -out ca-key.pem 2048 + +echo "enter your Docker daemon's hostname as the 'Common Name'= ($HOST)" + +#TODO add this as an ENV to docker run? +openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem + + +# server cert +openssl genrsa -out server-key.pem 2048 +openssl req -subj "/CN=$HOST" -new -key server-key.pem -out server.csr +openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \ + -CAcreateserial -out server-cert.pem + +#client cert +openssl genrsa -out key.pem 2048 +openssl req -subj '/CN=client' -new -key key.pem -out client.csr + +echo extendedKeyUsage = clientAuth > extfile.cnf +openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem \ + -CAcreateserial -out cert.pem -extfile extfile.cnf diff --git a/docs/sources/articles/https/parsedocs.sh b/docs/sources/articles/https/parsedocs.sh new file mode 100755 index 000000000..f9df33c33 --- /dev/null +++ b/docs/sources/articles/https/parsedocs.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +echo "#!/bin/sh" +cat ../https.md | awk '{if (sub(/\\$/,"")) printf "%s", $0; else print $0}' \ + | grep ' $ ' \ + | sed 's/ $ //g' \ + | sed 's/2375/7777/g' \ + | sed 's/2376/7778/g' \ + | sed 's/^docker/# docker/g' \ + | sed 's/^curl/# curl/g' diff --git a/docs/sources/articles/networking.md b/docs/sources/articles/networking.md index 6587efc52..03693eb4d 100644 --- a/docs/sources/articles/networking.md +++ b/docs/sources/articles/networking.md @@ -12,7 +12,9 @@ private range defined by [RFC 1918](http://tools.ietf.org/html/rfc1918) that are not in use on the host machine, and assigns it to `docker0`. Docker made the choice `172.17.42.1/16` when I started it a few minutes ago, for example — a 16-bit netmask providing 65,534 addresses for the -host machine and its containers. +host machine and its containers. The MAC address is generated using the +IP address allocated to the container to avoid ARP collisions, using a +range from `02:42:ac:11:00:00` to `02:42:ac:11:ff:ff`. > **Note:** > This document discusses advanced networking configuration @@ -57,6 +59,9 @@ server when it starts up, and cannot be changed once it is running: * `--fixed-cidr` — see [Customizing docker0](#docker0) + * `--fixed-cidr-v6` — see + [IPv6](#ipv6) + * `-H SOCKET...` or `--host=SOCKET...` — This might sound like it would affect container networking, but it actually faces in the other direction: @@ -70,8 +75,11 @@ server when it starts up, and cannot be changed once it is running: * `--ip=IP_ADDRESS` — see [Binding container ports](#binding-ports) + * `--ipv6=true|false` — see + [IPv6](#ipv6) + * `--ip-forward=true|false` — see - [Communication between containers](#between-containers) + [Communication between containers and the wider world](#the-world) * `--iptables=true|false` — see [Communication between containers](#between-containers) @@ -97,7 +105,7 @@ Finally, several networking options can only be provided when calling [Configuring DNS](#dns) and [How Docker networks a container](#container-networking) - * `--link=CONTAINER_NAME:ALIAS` — see + * `--link=CONTAINER_NAME_or_ID:ALIAS` — see [Configuring DNS](#dns) and [Communication between containers](#between-containers) @@ -130,7 +138,7 @@ information. You can see this by running `mount` inside a container: ... /dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ... /dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ... - tmpfs on /etc/resolv.conf type tmpfs ... + /dev/disk/by-uuid/1fec...ebdf on /etc/resolv.conf type ext4 ... ... This arrangement allows Docker to do clever things like keep @@ -150,10 +158,10 @@ Four different options affect container domain name services. outside the container. It will not appear in `docker ps` nor in the `/etc/hosts` file of any other container. - * `--link=CONTAINER_NAME:ALIAS` — using this option as you `run` a + * `--link=CONTAINER_NAME_or_ID:ALIAS` — using this option as you `run` a container gives the new container's `/etc/hosts` an extra entry - named `ALIAS` that points to the IP address of the container named - `CONTAINER_NAME`. This lets processes inside the new container + named `ALIAS` that points to the IP address of the container identified by + `CONTAINER_NAME_or_ID`. This lets processes inside the new container connect to the hostname `ALIAS` without having to know its IP. The `--link=` option is discussed in more detail below, in the section [Communication between containers](#between-containers). Because @@ -178,36 +186,72 @@ Four different options affect container domain name services. Note that Docker, in the absence of either of the last two options above, will make `/etc/resolv.conf` inside of each container look like the `/etc/resolv.conf` of the host machine where the `docker` daemon is -running. The options then modify this default configuration. +running. You might wonder what happens when the host machine's +`/etc/resolv.conf` file changes. The `docker` daemon has a file change +notifier active which will watch for changes to the host DNS configuration. +When the host file changes, all stopped containers which have a matching +`resolv.conf` to the host will be updated immediately to this newest host +configuration. Containers which are running when the host configuration +changes will need to stop and start to pick up the host changes due to lack +of a facility to ensure atomic writes of the `resolv.conf` file while the +container is running. If the container's `resolv.conf` has been edited since +it was started with the default configuration, no replacement will be +attempted as it would overwrite the changes performed by the container. +If the options (`--dns` or `--dns-search`) have been used to modify the +default host configuration, then the replacement with an updated host's +`/etc/resolv.conf` will not happen as well. + +> **Note**: +> For containers which were created prior to the implementation of +> the `/etc/resolv.conf` update feature in Docker 1.5.0: those +> containers will **not** receive updates when the host `resolv.conf` +> file changes. Only containers created with Docker 1.5.0 and above +> will utilize this auto-update feature. ## Communication between containers and the wider world -Whether a container can talk to the world is governed by one main factor. +Whether a container can talk to the world is governed by two factors. -Is the host machine willing to forward IP packets? This is governed -by the `ip_forward` system parameter. Packets can only pass between -containers if this parameter is `1`. Usually you will simply leave -the Docker server at its default setting `--ip-forward=true` and -Docker will go set `ip_forward` to `1` for you when the server -starts up. To check the setting or turn it on manually: - - # Usually not necessary: turning on forwarding, - # on the host where your Docker server is running +1. Is the host machine willing to forward IP packets? This is governed + by the `ip_forward` system parameter. Packets can only pass between + containers if this parameter is `1`. Usually you will simply leave + the Docker server at its default setting `--ip-forward=true` and + Docker will go set `ip_forward` to `1` for you when the server + starts up. To check the setting or turn it on manually: + ``` $ cat /proc/sys/net/ipv4/ip_forward 0 - $ sudo echo 1 > /proc/sys/net/ipv4/ip_forward + $ echo 1 > /proc/sys/net/ipv4/ip_forward $ cat /proc/sys/net/ipv4/ip_forward 1 + ``` -Many using Docker will want `ip_forward` to be on, to at -least make communication *possible* between containers and -the wider world. + Many using Docker will want `ip_forward` to be on, to at + least make communication *possible* between containers and + the wider world. -May also be needed for inter-container communication if you are -in a multiple bridge setup. + May also be needed for inter-container communication if you are + in a multiple bridge setup. + +2. Do your `iptables` allow this particular connection? Docker will + never make changes to your system `iptables` rules if you set + `--iptables=false` when the daemon starts. Otherwise the Docker + server will append forwarding rules to the `DOCKER` filter chain. + +Docker will not delete or modify any pre-existing rules from the `DOCKER` +filter chain. This allows the user to create in advance any rules required +to further restrict access to the containers. + +Docker's forward rules permit all external source IPs by default. To allow +only a specific IP or network to access the containers, insert a negated +rule at the top of the `DOCKER` filter chain. For example, to restrict +external access such that *only* source IP 8.8.8.8 can access the +containers, the following rule could be added: + + $ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP ## Communication between containers @@ -222,12 +266,12 @@ system level, by two factors. between them. See the later sections of this document for other possible topologies. -2. Do your `iptables` allow this particular connection to be made? - Docker will never make changes to your system `iptables` rules if - you set `--iptables=false` when the daemon starts. Otherwise the - Docker server will add a default rule to the `FORWARD` chain with a - blanket `ACCEPT` policy if you retain the default `--icc=true`, or - else will set the policy to `DROP` if `--icc=false`. +2. Do your `iptables` allow this particular connection? Docker will never + make changes to your system `iptables` rules if you set + `--iptables=false` when the daemon starts. Otherwise the Docker server + will add a default rule to the `FORWARD` chain with a blanket `ACCEPT` + policy if you retain the default `--icc=true`, or else will set the + policy to `DROP` if `--icc=false`. It is a strategic question whether to leave `--icc=true` or change it to `--icc=false` (on Ubuntu, by editing the `DOCKER_OPTS` variable in @@ -240,7 +284,7 @@ If you choose the most secure setting of `--icc=false`, then how can containers communicate in those cases where you *want* them to provide each other services? -The answer is the `--link=CONTAINER_NAME:ALIAS` option, which was +The answer is the `--link=CONTAINER_NAME_or_ID:ALIAS` option, which was mentioned in the previous section because of its effect upon name services. If the Docker daemon is running with both `--icc=false` and `--iptables=true` then, when it sees `docker run` invoked with the @@ -267,6 +311,7 @@ the `FORWARD` chain has a default policy of `ACCEPT` or `DROP`: ... Chain FORWARD (policy ACCEPT) target prot opt source destination + DOCKER all -- 0.0.0.0/0 0.0.0.0/0 DROP all -- 0.0.0.0/0 0.0.0.0/0 ... @@ -278,9 +323,13 @@ the `FORWARD` chain has a default policy of `ACCEPT` or `DROP`: ... Chain FORWARD (policy ACCEPT) target prot opt source destination + DOCKER all -- 0.0.0.0/0 0.0.0.0/0 + DROP all -- 0.0.0.0/0 0.0.0.0/0 + + Chain DOCKER (1 references) + target prot opt source destination ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80 ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80 - DROP all -- 0.0.0.0/0 0.0.0.0/0 > **Note**: > Docker is careful that its host-wide `iptables` rules fully expose @@ -363,6 +412,183 @@ Again, this topic is covered without all of these low-level networking details in the [Docker User Guide](/userguide/dockerlinks/) document if you would like to use that as your port redirection reference instead. +## IPv6 + + + +As we are [running out of IPv4 addresses](http://en.wikipedia.org/wiki/IPv4_address_exhaustion) +the IETF has standardized an IPv4 successor, [Internet Protocol Version 6](http://en.wikipedia.org/wiki/IPv6) +, in [RFC 2460](https://www.ietf.org/rfc/rfc2460.txt). Both protocols, IPv4 and +IPv6, reside on layer 3 of the [OSI model](http://en.wikipedia.org/wiki/OSI_model). + + +### IPv6 with Docker +By default, the Docker server configures the container network for IPv4 only. +You can enable IPv4/IPv6 dualstack support by running the Docker daemon with the +`--ipv6` flag. Docker will set up the bridge `docker0` with the IPv6 +[link-local address](http://en.wikipedia.org/wiki/Link-local_address) `fe80::1`. + +By default, containers that are created will only get a link-local IPv6 address. +To assign globally routable IPv6 addresses to your containers you have to +specify an IPv6 subnet to pick the addresses from. Set the IPv6 subnet via the +`--fixed-cidr-v6` parameter when starting Docker daemon: + + docker -d --ipv6 --fixed-cidr-v6="2001:db8:0:2::/64" + +The subnet for Docker containers should at least have a size of `/80`. This way +an IPv6 address can end with the container's MAC address and you prevent NDP +neighbor cache invalidation issues in the Docker layer. + +With the `--fixed-cidr-v6` parameter set Docker will add a new route to the +routing table. Further IPv6 routing will be enabled (you may prevent this by +starting Docker daemon with `--ip-forward=false`): + + $ route -A inet6 add 2001:db8:0:2::/64 dev docker0 + $ echo 1 > /proc/sys/net/ipv6/conf/default/forwarding + $ echo 1 > /proc/sys/net/ipv6/conf/all/forwarding + +All traffic to the subnet `2001:db8:0:2::/64` will now be routed +via the `docker0` interface. + +Be aware that IPv6 forwarding may interfere with your existing IPv6 +configuration: If you are using Router Advertisements to get IPv6 settings for +your host's interfaces you should set `accept_ra` to `2`. Otherwise IPv6 +enabled forwarding will result in rejecting Router Advertisements. E.g., if you +want to configure `eth0` via Router Advertisements you should set: + + ``` + $ echo 2 > /proc/sys/net/ipv6/conf/eth0/accept_ra + ``` + +![](/article-img/ipv6_basic_host_config.svg) + +Every new container will get an IPv6 address from the defined subnet. Further +a default route will be added via the gateway `fe80::1` on `eth0`: + + docker run -it ubuntu bash -c "ifconfig eth0; route -A inet6" + + eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02 + inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 + inet6 addr: 2001:db8:0:2::1/64 Scope:Global + inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link + UP BROADCAST MTU:1500 Metric:1 + RX packets:1 errors:0 dropped:0 overruns:0 frame:0 + TX packets:1 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:110 (110.0 B) TX bytes:110 (110.0 B) + + Kernel IPv6 routing table + Destination Next Hop Flag Met Ref Use If + 2001:db8:0:2::/64 :: U 256 0 0 eth0 + fe80::/64 :: U 256 0 0 eth0 + ::/0 fe80::1 UG 1024 0 0 eth0 + ::/0 :: !n -1 1 1 lo + ::1/128 :: Un 0 1 0 lo + ff00::/8 :: U 256 1 0 eth0 + ::/0 :: !n -1 1 1 lo + +In this example the Docker container is assigned a link-local address with the +network suffix `/64` (here: `fe80::42:acff:fe11:2/64`) and a globally routable +IPv6 address (here: `2001:db8:0:2::1/64`). The container will create connections +to addresses outside of the `2001:db8:0:2::/64` network via the link-local +gateway at `fe80::1` on `eth0`. + +Often servers or virtual machines get a `/64` IPv6 subnet assigned. In this case +you can split it up further and provide Docker a `/80` subnet while using a +separate `/80` subnet for other applications on the host: + +![](/article-img/ipv6_slash64_subnet_config.svg) + +In this setup the subnet `2001:db8::/80` with a range from `2001:db8::0:0:0:0` +to `2001:db8::0:ffff:ffff:ffff` is attached to `eth0`, with the host listening +at `2001:db8::1`. The subnet `2001:db8:0:0:0:1::/80` with an address range from +`2001:db8::1:0:0:0` to `2001:db8::1:ffff:ffff:ffff` is attached to `docker0` and +will be used by containers. + +### Docker IPv6 Cluster + +#### Switched Network Environment +Using routable IPv6 addresses allows you to realize communication between +containers on different hosts. Let's have a look at a simple Docker IPv6 cluster +example: + +![](/article-img/ipv6_switched_network_example.svg) + +The Docker hosts are in the `2000::/64` subnet. Host1 is configured +to provide addresses from the `2001::/64` subnet to its containers. It has three +routes configured: + +- Route all traffic to `2000::/64` via `eth0` +- Route all traffic to `2001::/64` via `docker0` +- Route all traffic to `2002::/64` via Host2 with IP `2000::2` + +Host1 also acts as a router on OSI layer 3. When one of the network clients +tries to contact a target that is specified in Host1's routing table Host1 will +forward the traffic accordingly. It acts as a router for all networks it knows: +`2000:/64`, `2001:/64` and `2002::/64`. + +On Host2 we have nearly the same configuration. Host2's containers will get IPv6 +addresses from `2002::/64`. Host2 has three routes configured: + +- Route all traffic to `2000::/64` via `eth0` +- Route all traffic to `2002::/64` via `docker0` +- Route all traffic to `2001::/64` via Host1 with IP `2000::1` + +The difference to Host1 is that the network `2002::/64` is directly attached to +the host via its `docker0` interface whereas it reaches `2001::/64` via Host1's +IPv6 address `2000::1`. + +This way every container is able to contact every other container. The +containers `Container1-*` share the same subnet and contact each other directly. +The traffic between `Container1-*` and `Container2-*` will be routed via Host1 +and Host2 because those containers do not share the same subnet. + +In a switched environment every host has to know all routes to every subnet. You +always have to update the hosts' routing tables once you add or remove a host +to the cluster. + +Every configuration in the diagram that is shown below the dashed line is +handled by Docker: The `docker0` bridge IP address configuration, the route to +the Docker subnet on the host, the container IP addresses and the routes on the +containers. The configuration above the line is up to the user and can be +adapted to the individual environment. + +#### Routed Network Environment + +In a routed network environment you replace the level 2 switch with a level 3 +router. Now the hosts just have to know their default gateway (the router) and +the route to their own containers (managed by Docker). The router holds all +routing information about the Docker subnets. When you add or remove a host to +this environment you just have to update the routing table in the router - not +on every host. + +![](/article-img/ipv6_routed_network_example.svg) + +In this scenario containers of the same host can communicate directly with each +other. The traffic between containers on different hosts will be routed via +their hosts and the router. For example packet from `Container1-1` to +`Container2-1` will be routed through `Host1`, `Router` and `Host2` until it +arrives at `Container2-1`. + +To keep the IPv6 addresses short in this example a `/48` network is assigned to +every host. The hosts use a `/64` subnet of this for its own services and one +for Docker. When adding a third host you would add a route for the subnet +`2001:db8:3::/48` in the router and configure Docker on Host3 with +`--fixed-cidr-v6=2001:db8:3:1::/64`. + +Remember the subnet for Docker containers should at least have a size of `/80`. +This way an IPv6 address can end with the container's MAC address and you +prevent NDP neighbor cache invalidation issues in the Docker layer. So if you +have a `/64` for your whole environment use `/68` subnets for the hosts and +`/80` for the containers. This way you can use 4096 hosts with 16 `/80` subnets +each. + +Every configuration in the diagram that is visualized below the dashed line is +handled by Docker: The `docker0` bridge IP address configuration, the route to +the Docker subnet on the host, the container IP addresses and the routes on the +containers. The configuration above the line is up to the user and can be +adapted to the individual environment. + ## Customizing docker0 @@ -461,6 +687,7 @@ stopping the service and removing the interface: $ sudo service docker stop $ sudo ip link set dev docker0 down $ sudo brctl delbr docker0 + $ sudo iptables -t nat -F POSTROUTING Then, before starting the Docker service, create your own bridge and give it whatever configuration you want. Here we will create a simple @@ -487,6 +714,15 @@ illustrate the technique. $ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker $ sudo service docker start + # Confirming new outgoing NAT masquerade is set up + + $ sudo iptables -t nat -L -n + ... + Chain POSTROUTING (policy ACCEPT) + target prot opt source destination + MASQUERADE all -- 192.168.5.0/24 0.0.0.0/0 + + The result should be that the Docker server starts successfully and is now prepared to bind containers to the new bridge. After pausing to verify the bridge's configuration, try creating a container — you will diff --git a/docs/sources/articles/puppet.md b/docs/sources/articles/puppet.md index e664d35c9..d9a7ceb70 100644 --- a/docs/sources/articles/puppet.md +++ b/docs/sources/articles/puppet.md @@ -6,7 +6,7 @@ page_keywords: puppet, installation, usage, docker, documentation > *Note:* Please note this is a community contributed installation path. The > only `official` installation is using the -> [*Ubuntu*](/installation/ubuntulinux/#ubuntu-linux) installation +> [*Ubuntu*](/installation/ubuntulinux) installation > path. This version may sometimes be out of date. ## Requirements diff --git a/docs/sources/articles/registry_mirror.md b/docs/sources/articles/registry_mirror.md index 5d5378e23..a7493e9ae 100644 --- a/docs/sources/articles/registry_mirror.md +++ b/docs/sources/articles/registry_mirror.md @@ -38,7 +38,7 @@ For example, if your mirror is serving on `http://10.0.0.2:5000`, you would run: **NOTE:** Depending on your local host setup, you may be able to add the `--registry-mirror` options to the `DOCKER_OPTS` variable in -`/etc/defaults/docker`. +`/etc/default/docker`. ### Step 2: Run the local registry mirror diff --git a/docs/sources/articles/runmetrics.md b/docs/sources/articles/runmetrics.md index b78de2403..327640969 100644 --- a/docs/sources/articles/runmetrics.md +++ b/docs/sources/articles/runmetrics.md @@ -105,9 +105,9 @@ The first half (without the `total_` prefix) contains statistics relevant to the processes within the cgroup, excluding sub-cgroups. The second half (with the `total_` prefix) includes sub-cgroups as well. -Some metrics are "gauges", i.e. values that can increase or decrease +Some metrics are "gauges", i.e., values that can increase or decrease (e.g., swap, the amount of swap space used by the members of the cgroup). -Some others are "counters", i.e. values that can only go up, because +Some others are "counters", i.e., values that can only go up, because they represent occurrences of a specific event (e.g., pgfault, which indicates the number of page faults which happened since the creation of the cgroup; this number can never decrease). @@ -211,7 +211,7 @@ For each container, you will find a pseudo-file `cpuacct.stat`, containing the CPU usage accumulated by the processes of the container, broken down between `user` and `system` time. If you're not familiar with the distinction, `user` is the time during which the processes were -in direct control of the CPU (i.e. executing process code), and `system` +in direct control of the CPU (i.e., executing process code), and `system` is the time during which the CPU was executing system calls on behalf of those processes. @@ -366,7 +366,7 @@ Please review [*Enumerating Cgroups*](#enumerating-cgroups) to learn how to find the cgroup of a process running in the container of which you want to measure network usage. From there, you can examine the pseudo-file named `tasks`, which contains the PIDs that are in the -control group (i.e. in the container). Pick any one of them. +control group (i.e., in the container). Pick any one of them. Putting everything together, if the "short ID" of a container is held in the environment variable `$CID`, then you can do this: diff --git a/docs/sources/articles/security.md b/docs/sources/articles/security.md index 12f7b350e..a26f79cf9 100644 --- a/docs/sources/articles/security.md +++ b/docs/sources/articles/security.md @@ -4,21 +4,20 @@ page_keywords: Docker, Docker documentation, security # Docker Security -> *Adapted from* [Containers & Docker: How Secure are -> They?](http://blog.docker.com/2013/08/containers-docker-how-secure-are-they/) - There are three major areas to consider when reviewing Docker security: - - the intrinsic security of containers, as implemented by kernel + - the intrinsic security of the kernel and its support for namespaces and cgroups; - the attack surface of the Docker daemon itself; + - loopholes in the container configuration profile, either by default, + or when customized by users. - the "hardening" security features of the kernel and how they interact with containers. ## Kernel Namespaces -Docker containers are very similar to LXC containers, and they come with -the similar security features. When you start a container with `docker +Docker containers are very similar to LXC containers, and they have +similar security features. When you start a container with `docker run`, behind the scenes Docker creates a set of namespaces and control groups for the container. @@ -28,12 +27,12 @@ less affect, processes running in another container, or in the host system. **Each container also gets its own network stack**, meaning that a -container doesn't get a privileged access to the sockets or interfaces +container doesn't get privileged access to the sockets or interfaces of another container. Of course, if the host system is setup accordingly, containers can interact with each other through their respective network interfaces — just like they can interact with external hosts. When you specify public ports for your containers or use -[*links*](/userguide/dockerlinks/#working-with-links-names) +[*links*](/userguide/dockerlinks) then IP traffic is allowed between containers. They can ping each other, send/receive UDP packets, and establish TCP connections, but that can be restricted if necessary. From a network architecture point of view, all @@ -56,9 +55,9 @@ in 2005, so both the design and the implementation are pretty mature. ## Control Groups -Control Groups are the other key component of Linux Containers. They -implement resource accounting and limiting. They provide a lot of very -useful metrics, but they also help to ensure that each container gets +Control Groups are another key component of Linux Containers. They +implement resource accounting and limiting. They provide many +useful metrics, but they also help ensure that each container gets its fair share of memory, CPU, disk I/O; and, more importantly, that a single container cannot bring the system down by exhausting one of those resources. @@ -86,10 +85,9 @@ the Docker host and a guest container; and it allows you to do so without limiting the access rights of the container. This means that you can start a container where the `/host` directory will be the `/` directory on your host; and the container will be able to alter your host filesystem -without any restriction. This sounds crazy? Well, you have to know that -**all virtualization systems allowing filesystem resource sharing behave the -same way**. Nothing prevents you from sharing your root filesystem (or -even your root block device) with a virtual machine. +without any restriction. This is similar to how virtualization systems +allow filesystem resource sharing. Nothing prevents you from sharing your +root filesystem (or even your root block device) with a virtual machine. This has a strong security implication: for example, if you instrument Docker from a web server to provision containers through an API, you should be @@ -112,25 +110,21 @@ trusted network or VPN; or protected with e.g., `stunnel` and client SSL certificates. You can also secure them with [HTTPS and certificates](/articles/https/). -Recent improvements in Linux namespaces will soon allow to run -full-featured containers without root privileges, thanks to the new user -namespace. This is covered in detail [here]( -http://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/). -Moreover, this will solve the problem caused by sharing filesystems -between host and guest, since the user namespace allows users within -containers (including the root user) to be mapped to other users in the -host system. +The daemon is also potentially vulnerable to other inputs, such as image +loading from either disk with 'docker load', or from the network with +'docker pull'. This has been a focus of improvement in the community, +especially for 'pull' security. While these overlap, it should be noted +that 'docker load' is a mechanism for backup and restore and is not +currently considered a secure mechanism for loading images. As of +Docker 1.3.2, images are now extracted in a chrooted subprocess on +Linux/Unix platforms, being the first-step in a wider effort toward +privilege separation. -The end goal for Docker is therefore to implement two additional -security improvements: - - - map the root user of a container to a non-root user of the Docker - host, to mitigate the effects of a container-to-host privilege - escalation; - - allow the Docker daemon to run without root privileges, and delegate - operations requiring those privileges to well-audited sub-processes, - each with its own (very limited) scope: virtual network setup, - filesystem management, etc. +Eventually, it is expected that the Docker daemon will run restricted +privileges, delegating operations well-audited sub-processes, +each with its own (very limited) scope of Linux capabilities, +virtual network setup, filesystem management, etc. That is, most likely, +pieces of the Docker engine itself will run inside of containers. Finally, if you run Docker on a server, it is recommended to run exclusively Docker in the server, and move all other services within @@ -140,7 +134,7 @@ existing monitoring/supervision processes (e.g., NRPE, collectd, etc). ## Linux Kernel Capabilities -By default, Docker starts containers with a very restricted set of +By default, Docker starts containers with a restricted set of capabilities. What does that mean? Capabilities turn the binary "root/non-root" dichotomy into a @@ -159,7 +153,7 @@ tools (e.g., to handle DHCP, WPA, or VPNs), and much more. A container is very different, because almost all of those tasks are handled by the infrastructure around the container: - - SSH access will typically be managed by a single server running in + - SSH access will typically be managed by a single server running on the Docker host; - `cron`, when necessary, should run as a user process, dedicated and tailored for the app that needs its @@ -201,11 +195,16 @@ a whitelist instead of a blacklist approach. You can see a full list of available capabilities in [Linux manpages](http://man7.org/linux/man-pages/man7/capabilities.7.html). -Of course, you can always enable extra capabilities if you really need -them (for instance, if you want to use a FUSE-based filesystem), but by -default, Docker containers use only a -[whitelist](https://github.com/docker/docker/blob/master/daemon/execdriver/native/template/default_template.go) -of kernel capabilities by default. +One primary risk with running Docker containers is that the default set +of capabilities and mounts given to a container may provide incomplete +isolation, either independently, or when used in combination with +kernel vulnerabilities. + +Docker supports the addition and removal of capabilities, allowing use +of a non-default profile. This may make Docker more secure through +capability removal, or less secure through the addition of capabilities. +The best practice for users would be to remove all capabilities except +those explicitly required for their processes. ## Other Kernel Security Features @@ -222,7 +221,7 @@ harden a Docker host. Here are a few examples. checks, both at compile-time and run-time; it will also defeat many exploits, thanks to techniques like address randomization. It doesn't require Docker-specific configuration, since those security features - apply system-wide, independently of containers. + apply system-wide, independent of containers. - If your distribution comes with security model templates for Docker containers, you can use them out of the box. For instance, we ship a template that works with AppArmor and Red Hat comes with SELinux @@ -236,19 +235,42 @@ with e.g., special network topologies or shared filesystems, you can expect to see tools to harden existing Docker containers without affecting Docker's core. +Recent improvements in Linux namespaces will soon allow to run +full-featured containers without root privileges, thanks to the new user +namespace. This is covered in detail [here]( +http://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/). +Moreover, this will solve the problem caused by sharing filesystems +between host and guest, since the user namespace allows users within +containers (including the root user) to be mapped to other users in the +host system. + +Today, Docker does not directly support user namespaces, but they +may still be utilized by Docker containers on supported kernels, +by directly using the clone syscall, or utilizing the 'unshare' +utility. Using this, some users may find it possible to drop +more capabilities from their process as user namespaces provide +an artifical capabilities set. Likewise, however, this artifical +capabilities set may require use of 'capsh' to restrict the +user-namespace capabilities set when using 'unshare'. + +Eventually, it is expected that Docker will direct, native support +for user-namespaces, simplifying the process of hardening containers. + ## Conclusions Docker containers are, by default, quite secure; especially if you take care of running your processes inside the containers as non-privileged -users (i.e. non-`root`). +users (i.e., non-`root`). You can add an extra layer of safety by enabling Apparmor, SELinux, GRSEC, or your favorite hardening solution. Last but not least, if you see interesting security features in other -containerization systems, you will be able to implement them as well -with Docker, since everything is provided by the kernel anyway. +containerization systems, these are simply kernels features that may +be implemented in Docker as well. We welcome users to submit issues, +pull requests, and communicate via the mailing list. -For more context and especially for comparisons with VMs and other -container systems, please also see the [original blog post]( +References: +* [Docker Containers: How Secure Are They? (2013)]( http://blog.docker.com/2013/08/containers-docker-how-secure-are-they/). +* [On the Security of Containers (2014)](https://medium.com/@ewindisch/on-the-security-of-containers-2c60ffe25a9e). diff --git a/docs/sources/articles/systemd.md b/docs/sources/articles/systemd.md index 141deac30..fddd146b0 100644 --- a/docs/sources/articles/systemd.md +++ b/docs/sources/articles/systemd.md @@ -59,7 +59,7 @@ In this example, we'll assume that your `docker.service` file looks something li This will allow us to add extra flags to the `/etc/sysconfig/docker` file by setting `OPTIONS`: - OPTIONS="--graph /mnt/docker-data --storage btrfs" + OPTIONS="--graph /mnt/docker-data --storage-driver btrfs" You can also set other environment variables in this file, for example, the `HTTP_PROXY` environment variables described below. diff --git a/docs/sources/articles/using_supervisord.md b/docs/sources/articles/using_supervisord.md index 10f32c7d1..5806707ee 100644 --- a/docs/sources/articles/using_supervisord.md +++ b/docs/sources/articles/using_supervisord.md @@ -6,7 +6,7 @@ page_keywords: docker, supervisor, process management > **Note**: > - **If you don't like sudo** then see [*Giving non-root -> access*](/installation/binaries/#dockergroup) +> access*](/installation/binaries/#giving-non-root-access) Traditionally a Docker container runs a single process when it is launched, for example an Apache daemon or a SSH server daemon. Often @@ -39,7 +39,7 @@ our container. Here we're installing the `openssh-server`, `apache2` and `supervisor` -(which provides the Supervisor daemon) packages. We're also creating two +(which provides the Supervisor daemon) packages. We're also creating four new directories that are needed to run our SSH daemon and Supervisor. ## Adding Supervisor's configuration file diff --git a/docs/sources/contributing/devenvironment.md b/docs/sources/contributing/devenvironment.md index f39dec670..607ed4d9e 100644 --- a/docs/sources/contributing/devenvironment.md +++ b/docs/sources/contributing/devenvironment.md @@ -10,6 +10,12 @@ used for all tests, builds and releases. The standard development environment defines all build dependencies: system libraries and binaries, go environment, go dependencies, etc. +**Things you need:** + + * Docker + * git + * make + ## Install Docker Docker's build environment itself is a Docker container, so the first @@ -40,34 +46,37 @@ with the name of branch or revision number. ## Build the Environment -This following command will build a development environment using the -Dockerfile in the current directory. Essentially, it will install all +This following command builds a development environment using the +`Dockerfile` in the current directory. Essentially, it installs all the build and runtime dependencies necessary to build and test Docker. -This command will take some time to complete when you first execute it. +Your first build will take some time to complete. On Linux systems and on Mac +OS X from within the `boot2docker` shell: - $ sudo make build + $ make build + +> **Note**: +> On Mac OS X, the Docker make targets such as `build`, `binary`, and `test` +> should **not** be built by the 'root' user. Therefore, you shouldn't use `sudo` when +> running these commands on OS X. +> On Linux, we suggest you add your current user to the `docker` group via +> [these +> instructions](http://docs.docker.com/installation/ubuntulinux/#giving-non-root-access). If the build is successful, congratulations! You have produced a clean build of docker, neatly encapsulated in a standard build environment. -> **Note**: -> On Mac OS X, make targets such as `build`, `binary`, and `test` -> must **not** be built under root. So, for example, instead of the above -> command, issue: -> -> $ make build ## Build the Docker Binary To create the Docker binary, run this command: - $ sudo make binary + $ make binary This will create the Docker binary in `./bundles/-dev/binary/`. If you do not see files in the `./bundles` directory in your host, your `BINDDIR` setting is not set quite right. You want to run the following command: - $ sudo make BINDDIR=. binary + $ make BINDDIR=. binary If you are on a non-Linux platform, e.g., OSX, you'll want to run `make cross` or `make BINDDIR=. cross`. @@ -88,7 +97,7 @@ on ubuntu: To execute the test cases, run this command: - $ sudo make test + $ make test If the test are successful then the tail of the output should look something like this @@ -135,7 +144,7 @@ is recommended. You can run an interactive session in the newly built container: - $ sudo make shell + $ make shell # type 'exit' or Ctrl-D to exit @@ -145,7 +154,7 @@ If you want to read the documentation from a local website, or are making changes to it, you can build the documentation and then serve it by: - $ sudo make docs + $ make docs # when its done, you can point your browser to http://yourdockerhost:8000 # type Ctrl-C to exit diff --git a/docs/sources/docker-hub-enterprise/install-config.md b/docs/sources/docker-hub-enterprise/install-config.md new file mode 100644 index 000000000..0b7bcfd6f --- /dev/null +++ b/docs/sources/docker-hub-enterprise/install-config.md @@ -0,0 +1,8 @@ +page_title: Using Docker Hub Enterprise Installation +page_description: Docker Hub Enterprise Installation +page_keywords: docker hub enterprise + +# Docker Hub Enterprise Installation + +Documenation coming soon. + diff --git a/docs/sources/docker-hub-enterprise/usage.md b/docs/sources/docker-hub-enterprise/usage.md new file mode 100644 index 000000000..252223ef7 --- /dev/null +++ b/docs/sources/docker-hub-enterprise/usage.md @@ -0,0 +1,9 @@ +page_title: Using Docker Hub Enterprise +page_description: Docker Hub Enterprise +page_keywords: docker hub enterprise + +# Docker Hub Enterprise + +Documenation coming soon. + + diff --git a/docs/sources/docker-hub/accounts.md b/docs/sources/docker-hub/accounts.md index 304010fb5..be3212005 100644 --- a/docs/sources/docker-hub/accounts.md +++ b/docs/sources/docker-hub/accounts.md @@ -37,8 +37,8 @@ page. Also available on the Docker Hub are organizations and groups that allow you to collaborate across your organization or team. You can see what organizations [you belong to and add new organizations]( -https://hub.docker.com/account/organizations/) from the Account -tab. +https://hub.docker.com/account/organizations/) from the Account Settings +tab. They are also listed below your user name on your repositories page and in your account profile. ![organizations](/docker-hub/orgs.png) @@ -47,3 +47,8 @@ further manage who can interact with your repositories. ![groups](/docker-hub/groups.png) +You can add or invite users to join groups by clicking on the organization and then clicking the edit button for the group to which you want to add members. Enter a user-name (for current Hub users) or email address (if they are not yet Hub users) for the person you want to invite. They will receive an email invitation to join the group. + +![invite members](/docker-hub/invite.png) + + diff --git a/docs/sources/docker-hub/builds.md b/docs/sources/docker-hub/builds.md index 5d73e4aae..164018e82 100644 --- a/docs/sources/docker-hub/builds.md +++ b/docs/sources/docker-hub/builds.md @@ -8,7 +8,7 @@ page_keywords: Docker, docker, registry, accounts, plans, Dockerfile, Docker Hub *Automated Builds* are a special feature of Docker Hub which allow you to use [Docker Hub's](https://hub.docker.com) build clusters to automatically -create images from a specified `Dockerfile` and a GitHub or Bitbucket repo +create images from a specified `Dockerfile` and a GitHub or Bitbucket repository (or "context"). The system will clone your repository and build the image described by the `Dockerfile` using the repository as the context. The resulting automated image will then be uploaded to the Docker Hub registry @@ -148,7 +148,7 @@ https://registry.hub.docker.com/associate/bitbucket/). Then follow the onscreen instructions to authorize and link your Bitbucket account to Docker Hub. Once it is linked, you'll be able -to choose a repo from which to create the Automatic Build. +to choose a repository from which to create the Automatic Build. ### Creating an Automated Build @@ -159,7 +159,7 @@ public or private Bitbucket repositories with a `Dockerfile`. ### Adding a Hook When you link your Docker Hub account, a `POST` hook should get automatically -added to your Bitbucket repo. Follow the steps below to confirm or modify the +added to your Bitbucket repository. Follow the steps below to confirm or modify the Bitbucket hooks for your Automated Build: @@ -195,8 +195,8 @@ Bitbucket hooks for your Automated Build: During the build process, Docker will copy the contents of your `Dockerfile`. It will also add it to the [Docker Hub](https://hub.docker.com) for the Docker -community (for public repos) or approved team members/orgs (for private repos) -to see on the repository page. +community (for public repositories) or approved team members/orgs (for private +repositories) to see on the repository page. ### README.md @@ -217,7 +217,7 @@ Automated Build, it will give you a URL to which you can send POST requests. This will trigger the Automated Build, much as with a GitHub webhook. Build triggers are available under the Settings menu of each Automated Build -repo on the Docker Hub. +repository on the Docker Hub. ![Build trigger screen](/docker-hub/hub-images/build-trigger.png) @@ -249,7 +249,11 @@ payload: { "callback_url": "https://registry.hub.docker.com/u/svendowideit/testhook/hook/2141b5bi5i5b02bec211i4eeih0242eg11000a/", "push_data": { - "images": [], + "images": [ + "27d47432a69bca5f2700e4dff7de0388ed65f9d3fb1ec645e2bc24c223dc1cc3", + "51a9c7c1f8bb2fa19bcd09789a34e63f35abb80044bc10196e304f6634cc582c", + ... + ], "pushed_at": 1.417566161e+09, "pusher": "trustedbuilder" }, @@ -278,6 +282,10 @@ Webhooks are available under the Settings menu of each Repository. > **Note:** If you want to test your webhook out we recommend using > a tool like [requestb.in](http://requestb.in/). +> **Note**: The Docker Hub servers are currently in the IP range +> `162.242.195.64 - 162.242.195.127`, so you can restrict your webhooks to +> accept webhook requests from that set of IP addresses. + ### Webhook chains Webhook chains allow you to chain calls to multiple services. For example, @@ -332,7 +340,7 @@ another. If one gets updated,the linking system triggers a rebuild for the other Automated Build. This makes it easy to keep all your Automated Builds up to date. -To add a link, go to the repo for the Automated Build you want to +To add a link, go to the repository for the Automated Build you want to link to and click on *Repository Links* under the Settings menu at right. Then, enter the name of the repository that you want have linked. diff --git a/docs/sources/docker-hub/hub-images/invite.png b/docs/sources/docker-hub/hub-images/invite.png new file mode 100644 index 000000000..e6b74d061 Binary files /dev/null and b/docs/sources/docker-hub/hub-images/invite.png differ diff --git a/docs/sources/docker-hub/invite.png b/docs/sources/docker-hub/invite.png new file mode 100644 index 000000000..5534d2b88 Binary files /dev/null and b/docs/sources/docker-hub/invite.png differ diff --git a/docs/sources/docker-hub/orgs.png b/docs/sources/docker-hub/orgs.png index f205d7f8f..6a49cc65d 100644 Binary files a/docs/sources/docker-hub/orgs.png and b/docs/sources/docker-hub/orgs.png differ diff --git a/docs/sources/docker-hub/repos.md b/docs/sources/docker-hub/repos.md index 0749c0814..042cb572f 100644 --- a/docs/sources/docker-hub/repos.md +++ b/docs/sources/docker-hub/repos.md @@ -105,16 +105,17 @@ Settings page. A webhook is called only after a successful `push` is made. The webhook calls are HTTP POST requests with a JSON payload similar to the example shown below. -> **Note:** For testing, you can try an HTTP request tool like -> [requestb.in](http://requestb.in/). - *Example webhook JSON payload:* ``` { "callback_url": "https://registry.hub.docker.com/u/svendowideit/busybox/hook/2141bc0cdec4hebec411i4c1g40242eg110020/", "push_data": { - "images": [], + "images": [ + "27d47432a69bca5f2700e4dff7de0388ed65f9d3fb1ec645e2bc24c223dc1cc3", + "51a9c7c1f8bb2fa19bcd09789a34e63f35abb80044bc10196e304f6634cc582c", + ... + ], "pushed_at": 1.417566822e+09, "pusher": "svendowideit" }, @@ -138,9 +139,16 @@ similar to the example shown below. Webhooks allow you to notify people, services and other applications of new updates to your images and repositories. To get started adding webhooks, -go to the desired repo in the Hub, and click "Webhooks" under the "Settings" +go to the desired repository in the Hub, and click "Webhooks" under the "Settings" box. +> **Note:** For testing, you can try an HTTP request tool like +> [requestb.in](http://requestb.in/). + +> **Note**: The Docker Hub servers are currently in the IP range +> `162.242.195.64 - 162.242.195.127`, so you can restrict your webhooks to +> accept webhook requests from that set of IP addresses. + ### Webhook chains Webhook chains allow you to chain calls to multiple services. For example, diff --git a/docs/sources/examples/apt-cacher-ng.md b/docs/sources/examples/apt-cacher-ng.md index 7dafec159..cd92cb59a 100644 --- a/docs/sources/examples/apt-cacher-ng.md +++ b/docs/sources/examples/apt-cacher-ng.md @@ -6,7 +6,7 @@ page_keywords: docker, example, package installation, networking, debian, ubuntu > **Note**: > - **If you don't like sudo** then see [*Giving non-root -> access*](/installation/binaries/#dockergroup). +> access*](/installation/binaries/#giving-non-root-access). > - **If you're using OS X or docker via TCP** then you shouldn't use > sudo. diff --git a/docs/sources/examples/couchdb_data_volumes.md b/docs/sources/examples/couchdb_data_volumes.md index 44043d641..8cd2408e4 100644 --- a/docs/sources/examples/couchdb_data_volumes.md +++ b/docs/sources/examples/couchdb_data_volumes.md @@ -6,7 +6,7 @@ page_keywords: docker, example, package installation, networking, couchdb, data > **Note**: > - **If you don't like sudo** then see [*Giving non-root -> access*](/installation/binaries/#dockergroup) +> access*](/installation/binaries/#giving-non-root-access) Here's an example of using data volumes to share the same data between two CouchDB containers. This could be used for hot upgrades, testing diff --git a/docs/sources/examples/nodejs_web_app.md b/docs/sources/examples/nodejs_web_app.md index 3a9183e32..7358a3f50 100644 --- a/docs/sources/examples/nodejs_web_app.md +++ b/docs/sources/examples/nodejs_web_app.md @@ -6,7 +6,7 @@ page_keywords: docker, example, package installation, node, centos > **Note**: > - **If you don't like sudo** then see [*Giving non-root -> access*](/installation/binaries/#dockergroup) +> access*](/installation/binaries/#giving-non-root-access) The goal of this example is to show you how you can build your own Docker images from a parent image using a `Dockerfile` @@ -181,6 +181,11 @@ Now you can call your app using `curl` (install if needed via: Hello world +If you use Boot2docker on OS X, the port is actually mapped to the Docker host VM, +and you should use the following command: + + $ curl $(boot2docker ip):49160 + We hope this tutorial helped you get up and running with Node.js and CentOS on Docker. You can get the full source code at [https://github.com/enokd/docker-node-hello/](https://github.com/enokd/docker-node-hello/). diff --git a/docs/sources/examples/postgresql_service.md b/docs/sources/examples/postgresql_service.md index 9a4c1816d..21044d369 100644 --- a/docs/sources/examples/postgresql_service.md +++ b/docs/sources/examples/postgresql_service.md @@ -6,7 +6,7 @@ page_keywords: docker, example, package installation, postgresql > **Note**: > - **If you don't like sudo** then see [*Giving non-root -> access*](/installation/binaries/#dockergroup) +> access*](/installation/binaries/#giving-non-root-access) ## Installing PostgreSQL on Docker diff --git a/docs/sources/examples/running_redis_service.md b/docs/sources/examples/running_redis_service.md index 6d052da09..99036a042 100644 --- a/docs/sources/examples/running_redis_service.md +++ b/docs/sources/examples/running_redis_service.md @@ -12,7 +12,7 @@ using a link. Firstly, we create a `Dockerfile` for our new Redis image. - FROM ubuntu:12.10 + FROM ubuntu:14.04 RUN apt-get update && apt-get install -y redis-server EXPOSE 6379 ENTRYPOINT ["/usr/bin/redis-server"] @@ -43,7 +43,7 @@ created with an alias of `db`. This will create a secure tunnel to the `redis` container and expose the Redis instance running inside that container to only this container. - $ sudo docker run --link redis:db -i -t ubuntu:12.10 /bin/bash + $ sudo docker run --link redis:db -i -t ubuntu:14.04 /bin/bash Once inside our freshly created container we need to install Redis to get the `redis-cli` binary to test our connection. diff --git a/docs/sources/faq.md b/docs/sources/faq.md index 5e1669843..f517db73a 100644 --- a/docs/sources/faq.md +++ b/docs/sources/faq.md @@ -8,7 +8,7 @@ page_keywords: faq, questions, documentation, docker ### How much does Docker cost? -Docker is 100% free, it is open source, so you can use it without +Docker is 100% free. It is open source, so you can use it without paying. ### What open source license are you using? @@ -19,12 +19,14 @@ https://github.com/docker/docker/blob/master/LICENSE) ### 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 [*Mac OS X*](../installation/mac/#macosx) -and [*Microsoft Windows*](../installation/windows/#windows) installation -guides. The small Linux distribution boot2docker can be run inside virtual -machines on these two operating systems. +Docker currently runs only 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 [*Mac OS X*](../installation/mac/#macosx) and [*Microsoft +Windows*](../installation/windows/#windows) installation guides. The small +Linux distribution boot2docker can be run inside virtual machines on these +two operating systems. + +{{ include "no-remote-sudo.md" }} ### How do containers compare to virtual machines? diff --git a/docs/sources/http-routingtable.md b/docs/sources/http-routingtable.md index ff66c7a19..07029d2ca 100644 --- a/docs/sources/http-routingtable.md +++ b/docs/sources/http-routingtable.md @@ -42,7 +42,7 @@ [`POST /containers/(id)/stop`](../reference/api/docker_remote_api_v1.9/#post--containers-(id)-stop) ** [`GET /containers/(id)/top`](../reference/api/docker_remote_api_v1.9/#get--containers-(id)-top) ** [`POST /containers/(id)/wait`](../reference/api/docker_remote_api_v1.9/#post--containers-(id)-wait) ** - [`POST /containers/create`](../reference/api/docker_remote_api_v1.9/#post--containers-create) ** + [`POST /containers/create`](/reference/api/docker_remote_api_v1.9/#create-a-container) ** [`GET /containers/json`](../reference/api/docker_remote_api_v1.9/#get--containers-json) ** [`POST /containers/(id)/resize`](../reference/api/docker_remote_api_v1.9/#get--containers-resize) **   diff --git a/docs/sources/include/no-remote-sudo.md b/docs/sources/include/no-remote-sudo.md new file mode 100644 index 000000000..065b0cbfd --- /dev/null +++ b/docs/sources/include/no-remote-sudo.md @@ -0,0 +1,3 @@ +> **Note:** if you are using a remote Docker daemon, such as Boot2Docker, +> then _do not_ type the `sudo` before the `docker` commands shown in the +> documentation's examples. diff --git a/docs/sources/installation/amazon.md b/docs/sources/installation/amazon.md index 58d269ad7..6a28685dc 100644 --- a/docs/sources/installation/amazon.md +++ b/docs/sources/installation/amazon.md @@ -40,10 +40,10 @@ over to the [User Guide](/userguide). ## Standard Ubuntu Installation If you want a more hands-on installation, then you can follow the -[*Ubuntu*](../ubuntulinux/#ubuntu-linux) instructions installing Docker -on any EC2 instance running Ubuntu. Just follow Step 1 from [*Amazon -QuickStart*](#amazon-quickstart) to pick an image (or use one of your +[*Ubuntu*](/installation/ubuntulinux) instructions installing Docker +on any EC2 instance running Ubuntu. Just follow Step 1 from the Amazon +QuickStart above to pick an image (or use one of your own) and skip the step with the *User Data*. Then continue with the -[*Ubuntu*](../ubuntulinux/#ubuntu-linux) instructions. +[*Ubuntu*](/installation/ubuntulinux) instructions. Continue with the [User Guide](/userguide/). diff --git a/docs/sources/installation/binaries.md b/docs/sources/installation/binaries.md index da2b195c0..ef9f5cafa 100644 --- a/docs/sources/installation/binaries.md +++ b/docs/sources/installation/binaries.md @@ -32,18 +32,52 @@ runtime: Docker in daemon mode has specific kernel requirements. For details, check your distribution in [*Installation*](../#installation-list). -In general, a 3.8 Linux kernel is the minimum requirement for Docker, as -some of the prior versions have known issues that are triggered by Docker. -Linux kernel versions older than 3.8 are known to cause kernel panics and -to break Docker. +A 3.10 Linux kernel is the minimum requirement for Docker. +Kernels older than 3.10 lack some of the features required to run Docker +containers. These older versions are known to have bugs which cause data loss +and frequently panic under certain conditions. The latest minor version (3.x.y) of the 3.10 (or a newer maintained version) Linux kernel is recommended. Keeping the kernel up to date with the latest minor version will ensure critical kernel bugs get fixed. +> **Warning**: +> Installing custom kernels and kernel packages is probably not +> supported by your Linux distribution's vendor. Please make sure to +> ask your vendor about Docker support first before attempting to +> install custom kernels on your distribution. + +> **Warning**: +> Installing a newer kernel might not be enough for some distributions +> which provide packages which are too old or incompatible with +> newer kernels. + Note that Docker also has a client mode, which can run on virtually any Linux kernel (it even builds on OS X!). +## Enable AppArmor and SELinux when possible + +Please use AppArmor or SELinux if your Linux distribution supports +either of the two. This helps improve security and blocks certain +types of exploits. Your distribution's documentation should provide +detailed steps on how to enable the recommended security mechanism. + +Some Linux distributions enable AppArmor or SELinux by default and +they run a kernel which doesn't meet the minimum requirements (3.10 +or newer). Updating the kernel to 3.10 or newer on such a system +might not be enough to start Docker and run containers. +Incompatibilities between the version of AppArmor/SELinux user +space utilities provided by the system and the kernel could prevent +Docker from running, from starting containers or, cause containers to +exhibit unexpected behaviour. + +> **Warning**: +> If either of the security mechanisms is enabled, it should not be +> disabled to make Docker or its containers run. This will reduce +> security in that environment, lose support from the distribution's +> vendor for the system, and might break regulations and security +> policies in heavily regulated environments. + ## Get the docker binary: $ wget https://get.docker.com/builds/Linux/x86_64/docker-latest -O docker @@ -77,7 +111,7 @@ need to add `sudo` to all the client commands. > **Warning**: > The *docker* group (or the group specified with `-G`) is root-equivalent; > see [*Docker Daemon Attack Surface*]( -> /articles/security/#dockersecurity-daemon) details. +> /articles/security/#docker-daemon-attack-surface) details. ## Upgrades diff --git a/docs/sources/installation/centos.md b/docs/sources/installation/centos.md index 707afc959..06dc8bfee 100644 --- a/docs/sources/installation/centos.md +++ b/docs/sources/installation/centos.md @@ -4,41 +4,34 @@ page_keywords: Docker, Docker documentation, requirements, linux, centos, epel, # CentOS -While the Docker package is provided by default as part of CentOS-7, -it is provided by the EPEL repository for CentOS-6. Please note that -this changes the installation instructions slightly between versions. If you -need the latest version, you can always use the latest binary which works on -kernel 3.8 and above. +Docker is supported on the following versions of CentOS: -These instructions work for CentOS 6 and later. They will likely work for -other binary compatible EL6 distributions such as Scientific Linux, but -they haven't been tested. +- [*CentOS 7 (64-bit)*](#installing-docker---centos-7) +- [*CentOS 6.5 (64-bit)*](#installing-docker---centos-6.5) or later + +These instructions are likely work for other binary compatible EL6/EL7 distributions +such as Scientific Linux, but they haven't been tested. Please note that due to the current Docker limitations, Docker is able to run only on the **64 bit** architecture. -To run Docker, you will need [CentOS6](http://www.centos.org) or higher, -with a kernel version 2.6.32-431 or higher as this has specific kernel -fixes to allow Docker to run. +## Kernel support + +Currently the CentOS project will only support Docker when running on kernels +shipped by the distribution. There are kernel changes which will cause issues +if one decides to step outside that box and run non-distribution kernel packages. + +To run Docker on [CentOS-6.5](http://www.centos.org) or later, you will need +kernel version 2.6.32-431 or higher as this has specific kernel fixes to allow +Docker to run. ## Installing Docker - CentOS-7 Docker is included by default in the CentOS-Extras repository. To install -simply run the following command. +run the following command: $ sudo yum install docker -### Manual installation of latest version - -While using a package is the recommended way of installing Docker, -the above package might not be the latest version. If you need the latest -version, [you can install the binary directly]( -https://docs.docker.com/installation/binaries/). - -When installing the binary without a package, you may want -to integrate Docker with systemd. For this, simply install the two unit files -(service and socket) from [the github -repository](https://github.com/docker/docker/tree/master/contrib/init/systemd) -to `/etc/systemd/system`. +Please continue with the [Starting the Docker daemon](#starting-the-docker-daemon). ### FirewallD @@ -48,32 +41,49 @@ conflict with Docker. When `firewalld` is started or restarted it will remove the `DOCKER` chain from iptables, preventing Docker from working properly. -When using systemd, `firewalld` is started before Docker, but if you +When using Systemd, `firewalld` is started before Docker, but if you start or restart `firewalld` after Docker, you will have to restart the Docker daemon. -## Installing Docker - CentOS-6 -Please note that this for CentOS-6, this package is part of [Extra Packages -for Enterprise Linux (EPEL)](https://fedoraproject.org/wiki/EPEL), a community effort -to create and maintain additional packages for the RHEL distribution. +## Installing Docker - CentOS-6.5 + +For Centos-6.5, the Docker package is part of [Extra Packages +for Enterprise Linux (EPEL)](https://fedoraproject.org/wiki/EPEL) repository, +a community effort to create and maintain additional packages for the RHEL distribution. Firstly, you need to ensure you have the EPEL repository enabled. Please follow the [EPEL installation instructions]( https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F). -The `docker-io` package provides Docker on EPEL. +For CentOS-6, there is a package name conflict with a system tray application +and its executable, so the Docker RPM package was called `docker-io`. -If you already have the (unrelated) `docker` package -installed, it will conflict with `docker-io`. -There's a [bug report]( -https://bugzilla.redhat.com/show_bug.cgi?id=1043676) filed for it. -To proceed with `docker-io` installation, please remove `docker` first. +To proceed with `docker-io` installation on CentOS-6, you may need to remove the +`docker` package first. -Next, let's install the `docker-io` package which -will install Docker on our host. + $ sudo yum -y remove docker + +Next, let's install the `docker-io` package which will install Docker on our host. $ sudo yum install docker-io -## Using Docker +Please continue with the [Starting the Docker daemon](#starting-the-docker-daemon). + +## Manual installation of latest Docker release + +While using a package is the recommended way of installing Docker, +the above package might not be the current release version. If you need the latest +version, [you can install the binary directly]( +https://docs.docker.com/installation/binaries/). + +When installing the binary without a package, you may want +to integrate Docker with Systemd. For this, install the two unit files +(service and socket) from [the GitHub +repository](https://github.com/docker/docker/tree/master/contrib/init/systemd) +to `/etc/systemd/system`. + +Please continue with the [Starting the Docker daemon](#starting-the-docker-daemon). + +## Starting the Docker daemon Once Docker is installed, you will need to start the docker daemon. @@ -108,13 +118,13 @@ If everything is working properly, you'll get a simple bash prompt. Type ## Custom daemon options If you need to add an HTTP Proxy, set a different directory or partition for the -Docker runtime files, or make other customizations, read our systemd article to -learn how to [customize your systemd Docker daemon options](/articles/systemd/). +Docker runtime files, or make other customizations, read our Systemd article to +learn how to [customize your Systemd Docker daemon options](/articles/systemd/). ## Dockerfiles The CentOS Project provides a number of sample Dockerfiles which you may use either as templates or to familiarize yourself with docker. These templates -are available on github at [https://github.com/CentOS/CentOS-Dockerfiles]( +are available on GitHub at [https://github.com/CentOS/CentOS-Dockerfiles]( https://github.com/CentOS/CentOS-Dockerfiles) **Done!** You can either continue with the [Docker User diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index 1db160969..74acd1d42 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -6,8 +6,8 @@ page_keywords: Docker, Docker documentation, installation, debian Docker is supported on the following versions of Debian: - - [*Debian 8.0 Jessie (64-bit)*](#debian-jessie-8-64-bit) - - [*Debian 7.5 Wheezy (64-bit)*](#debian-wheezy-7-64-bit) + - [*Debian 8.0 Jessie (64-bit)*](#debian-jessie-80-64-bit) + - [*Debian 7.7 Wheezy (64-bit)*](#debian-wheezystable-7x-64-bit) ## Debian Jessie 8.0 (64-bit) @@ -41,13 +41,13 @@ Docker requires Kernel 3.8+, while Wheezy ships with Kernel 3.2 (for more detail on why 3.8 is required, see discussion on [bug #407](https://github.com/docker/docker/issues/407%20kernel%20versions)). -Fortunately, wheezy-backports currently has [Kernel 3.14 +Fortunately, wheezy-backports currently has [Kernel 3.16 ](https://packages.debian.org/search?suite=wheezy-backports§ion=all&arch=any&searchon=names&keywords=linux-image-amd64), which is officially supported by Docker. ### Installation -1. Install Kernel 3.14 from wheezy-backports +1. Install Kernel from wheezy-backports Add the following line to your `/etc/apt/sources.list` @@ -81,7 +81,7 @@ use the `-G` flag to specify an alternative group. > **Warning**: > The `docker` group (or the group specified with the `-G` flag) is > `root`-equivalent; see [*Docker Daemon Attack Surface*]( -> /articles/security/#dockersecurity-daemon) details. +> /articles/security/#docker-daemon-attack-surface) details. **Example:** diff --git a/docs/sources/installation/fedora.md b/docs/sources/installation/fedora.md index 925314404..ed4e8372a 100644 --- a/docs/sources/installation/fedora.md +++ b/docs/sources/installation/fedora.md @@ -1,41 +1,49 @@ page_title: Installation on Fedora -page_description: Installation instructions for Docker on Fedora. -page_keywords: Docker, Docker documentation, Fedora, requirements, virtualbox, vagrant, git, ssh, putty, cygwin, linux +page_description: Instructions for installing Docker on Fedora. +page_keywords: Docker, Docker documentation, Fedora, requirements, linux # Fedora -Docker is available in **Fedora 19 and later**. Please note that due to -the current Docker limitations Docker is able to run only on the **64 -bit** architecture. +Docker is supported on the following versions of Fedora: -## Installation +- [*Fedora 20 (64-bit)*](#fedora-20-installation) +- [*Fedora 21 and later (64-bit)*](#fedora-21-and-later-installation) -The `docker-io` package provides Docker on Fedora. +Currently the Fedora project will only support Docker when running on kernels +shipped by the distribution. There are kernel changes which will cause issues +if one decides to step outside that box and run non-distribution kernel packages. -If you have the (unrelated) `docker` package installed already, it will -conflict with `docker-io`. There's a [bug -report](https://bugzilla.redhat.com/show_bug.cgi?id=1043676) filed for -it. To proceed with `docker-io` installation on Fedora 19, please remove -`docker` first. +## Fedora 21 and later installation + +Install the `docker` package which will install Docker on our host. + + $ sudo yum -y install docker + +To update the `docker` package: + + $ sudo yum -y update docker + +Please continue with the [Starting the Docker daemon](#starting-the-docker-daemon). + +## Fedora 20 installation + +For `Fedora 20`, there is a package name conflict with a system tray application +and its executable, so the Docker RPM package was called `docker-io`. + +To proceed with `docker-io` installation on Fedora 20, please remove the `docker` +package first. $ sudo yum -y remove docker - -For Fedora 21 and later, the `wmdocker` package will -provide the same functionality as `docker` and will -also not conflict with `docker-io`. - - $ sudo yum -y install wmdocker - $ sudo yum -y remove docker - -Install the `docker-io` package which will install -Docker on our host. - $ sudo yum -y install docker-io -To update the `docker-io` package: +To update the `docker` package: $ sudo yum -y update docker-io +Please continue with the [Starting the Docker daemon](#starting-the-docker-daemon). + +## Starting the Docker daemon + Now that it's installed, let's start the Docker daemon. $ sudo systemctl start docker @@ -54,24 +62,21 @@ Now let's verify that Docker is working. ## Granting rights to users to use Docker -Fedora 19 and 20 shipped with Docker 0.11. The package has already been updated -to 1.0 in Fedora 20. If you are still using the 0.11 version you will need to -grant rights to users of Docker. - The `docker` command line tool contacts the `docker` daemon process via a -socket file `/var/run/docker.sock` owned by group `docker`. One must be -member of that group in order to contact the `docker -d` process. +socket file `/var/run/docker.sock` owned by `root:root`. Though it's +[recommended](https://lists.projectatomic.io/projectatomic-archives/atomic-devel/2015-January/msg00034.html) +to use `sudo` for docker commands, if users wish to avoid it, an administrator can +create a `docker` group, have it own `/var/run/docker.sock`, and add users to this group. - $ usermod -a -G docker login_name - -Adding users to the `docker` group is *not* necessary for Docker versions 1.0 -and above. + $ sudo groupadd docker + $ sudo chown root:docker /var/run/docker.sock + $ sudo usermod -a -G docker $USERNAME ## Custom daemon options If you need to add an HTTP Proxy, set a different directory or partition for the -Docker runtime files, or make other customizations, read our systemd article to -learn how to [customize your systemd Docker daemon options](/articles/systemd/). +Docker runtime files, or make other customizations, read our Systemd article to +learn how to [customize your Systemd Docker daemon options](/articles/systemd/). ## What next? diff --git a/docs/sources/installation/google.md b/docs/sources/installation/google.md index cbd1f8b63..1cee5290d 100644 --- a/docs/sources/installation/google.md +++ b/docs/sources/installation/google.md @@ -20,8 +20,7 @@ page_keywords: Docker, Docker documentation, installation, google, Google Comput (select a zone close to you and the desired instance size) $ gcloud compute instances create docker-playground \ - --image container-vm-v20140925 \ - --image-project google-containers \ + --image container-vm \ --zone us-central1-a \ --machine-type f1-micro diff --git a/docs/sources/installation/mac.md b/docs/sources/installation/mac.md index 89fed1711..d31cd697b 100644 --- a/docs/sources/installation/mac.md +++ b/docs/sources/installation/mac.md @@ -72,6 +72,8 @@ complete. You can test it by following the directions below. ## Running Docker +{{ include "no-remote-sudo.md" }} + From your terminal, you can test that Docker is running with our small `hello-world` example image: Start the vm (`boot2docker start`) and then run: diff --git a/docs/sources/installation/rhel.md b/docs/sources/installation/rhel.md index 59ab04964..58b2316c6 100644 --- a/docs/sources/installation/rhel.md +++ b/docs/sources/installation/rhel.md @@ -1,10 +1,24 @@ page_title: Installation on Red Hat Enterprise Linux -page_description: Installation instructions for Docker on Red Hat Enterprise Linux. -page_keywords: Docker, Docker documentation, requirements, linux, rhel, centos +page_description: Instructions for installing Docker on Red Hat Enterprise Linux. +page_keywords: Docker, Docker documentation, requirements, linux, rhel -# Red Hat Enterprise Linux 7 +# Red Hat Enterprise Linux -**Red Hat Enterprise Linux 7** has [shipped with +Docker is supported on the following versions of RHEL: + +- [*Red Hat Enterprise Linux 7 (64-bit)*](#red-hat-enterprise-linux-7-installation) +- [*Red Hat Enterprise Linux 6.5 (64-bit)*](#red-hat-enterprise-linux-6.5-installation) or later + +## Kernel support + +RHEL will only support Docker via the *extras* channel or EPEL package when +running on kernels shipped by the distribution. There are kernel changes which +will cause issues if one decides to step outside that box and run +non-distribution kernel packages. + +## Red Hat Enterprise Linux 7 Installation + +**Red Hat Enterprise Linux 7 (64 bit)** has [shipped with Docker](https://access.redhat.com/site/products/red-hat-enterprise-linux/docker-and-containers). An overview and some guidance can be found in the [Release Notes](https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/7.0_Release_Notes/chap-Red_Hat_Enterprise_Linux-7.0_Release_Notes-Linux_Containers_with_Docker_Format.html). @@ -25,20 +39,32 @@ Enterprise Linux 7](https://access.redhat.com/site/articles/881893) guide, can be found by Red Hat customers on the [Red Hat Customer Portal](https://access.redhat.com/). -# Red Hat Enterprise Linux 6 +Please continue with the [Starting the Docker daemon](#starting-the-docker-daemon). -Docker is available for **RHEL** on EPEL. Please note that +## Red Hat Enterprise Linux 6.5 Installation + +You will need **64 bit** [RHEL +6.5](https://access.redhat.com/site/articles/3078#RHEL6) or later, with +a RHEL 6 kernel version 2.6.32-431 or higher as this has specific kernel +fixes to allow Docker to work. + +Docker is available for **RHEL6.5** on EPEL. Please note that this package is part of [Extra Packages for Enterprise Linux (EPEL)](https://fedoraproject.org/wiki/EPEL), a community effort to create and maintain additional packages for the RHEL distribution. -Also note that due to the current Docker limitations, Docker is able to -run only on the **64 bit** architecture. +### Kernel support -You will need [RHEL -6.5](https://access.redhat.com/site/articles/3078#RHEL6) or higher, with -a RHEL 6 kernel version 2.6.32-431 or higher as this has specific kernel -fixes to allow Docker to work. +RHEL will only support Docker via the *extras* channel or EPEL package when +running on kernels shipped by the distribution. There are things like namespace +changes which will cause issues if one decides to step outside that box and run +non-distro kernel packages. + +> **Warning**: +> Please keep your system up to date using `yum update` and rebooting +> your system. Keeping your system updated ensures critical security +> vulnerabilities and severe bugs (such as those found in kernel 2.6.32) +> are fixed. ## Installation @@ -46,23 +72,26 @@ Firstly, you need to install the EPEL repository. Please follow the [EPEL installation instructions](https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F). -The `docker-io` package provides Docker on EPEL. +There is a package name conflict with a system tray application +and its executable, so the Docker RPM package was called `docker-io`. -If you already have the (unrelated) `docker` package -installed, it will conflict with `docker-io`. -There's a [bug report]( -https://bugzilla.redhat.com/show_bug.cgi?id=1043676) filed for it. -To proceed with `docker-io` installation, please remove `docker` first. +To proceed with `docker-io` installation, you may need to remove the +`docker` package first. -Next, let's install the `docker-io` package which -will install Docker on our host. + $ sudo yum -y remove docker - $ sudo yum -y install docker-io +Next, let's install the `docker-io` package which will install Docker on our host. + + $ sudo yum install docker-io To update the `docker-io` package $ sudo yum -y update docker-io +Please continue with the [Starting the Docker daemon](#starting-the-docker-daemon). + +## Starting the Docker daemon + Now that it's installed, let's start the Docker daemon. $ sudo service docker start @@ -86,8 +115,8 @@ Continue with the [User Guide](/userguide/). ## Custom daemon options If you need to add an HTTP Proxy, set a different directory or partition for the -Docker runtime files, or make other customizations, read our systemd article to -learn how to [customize your systemd Docker daemon options](/articles/systemd/). +Docker runtime files, or make other customizations, read our Systemd article to +learn how to [customize your Systemd Docker daemon options](/articles/systemd/). ## Issues? diff --git a/docs/sources/installation/ubuntulinux.md b/docs/sources/installation/ubuntulinux.md index 09b776f08..5f36b2a58 100644 --- a/docs/sources/installation/ubuntulinux.md +++ b/docs/sources/installation/ubuntulinux.md @@ -17,15 +17,15 @@ Please read [*Docker and UFW*](#docker-and-ufw), if you plan to use [UFW ## Ubuntu Trusty 14.04 (LTS) (64-bit) Ubuntu Trusty comes with a 3.13.0 Linux kernel, and a `docker.io` package which -installs Docker 0.9.1 and all its prerequisites from Ubuntu's repository. +installs Docker 1.0.1 and all its prerequisites from Ubuntu's repository. > **Note**: > Ubuntu (and Debian) contain a much older KDE3/GNOME2 package called ``docker``, so the -> package and the executable are called ``docker.io``. +> Ubuntu-maintained package and executable are named ``docker.io``. -### Installation +### Ubuntu-maintained Package Installation -To install the latest Ubuntu package (may not be the latest Docker release): +To install the latest Ubuntu package (this is **not** the most recent Docker release): $ sudo apt-get update $ sudo apt-get install docker.io @@ -34,6 +34,13 @@ Then, to enable tab-completion of Docker commands in BASH, either restart BASH o $ source /etc/bash_completion.d/docker.io +> **Note**: +> Since the Ubuntu package is quite dated at this point, you may want to use +> the following section to install the most recent release of Docker. +> If you install the Docker version, you do not need to install ``docker.io`` from Ubuntu. + +### Docker-maintained Package Installation + If you'd like to try the latest version of Docker: First, check that your APT system can deal with `https` @@ -73,21 +80,33 @@ To verify that everything has worked as expected: Which should download the `ubuntu` image, and then start `bash` in a container. +Type `exit` to exit + +**Done!**, continue with the [User Guide](/userguide/). + + ## Ubuntu Precise 12.04 (LTS) (64-bit) This installation path should work at all times. ### Dependencies -**Linux kernel 3.8** +**Linux kernel 3.13** -Due to a bug in LXC, Docker works best on the 3.8 kernel. Precise comes -with a 3.2 kernel, so we need to upgrade it. The kernel you'll install -when following these steps comes with AUFS built in. We also include the -generic headers to enable packages that depend on them, like ZFS and the -VirtualBox guest additions. If you didn't install the headers for your -"precise" kernel, then you can skip these headers for the "raring" -kernel. But it is safer to include them if you're not sure. +For Ubuntu Precise, the currently recommended kernel version is 3.13. +Ubuntu Precise installations with older kernels must be upgraded. The +kernel you'll install when following these steps has AUFS built in. +We also include the generic headers to enable packages that depend on them, +like ZFS and the VirtualBox guest additions. If you didn't install the +headers for your "precise" kernel, then you can skip these headers for the +"trusty" kernel. If you're unsure, you should include the headers for safety. + +> **Warning**: +> Kernels 3.8 and 3.11 are no longer supported by Canonical. Systems +> running these kernels need to be updated using the instructions below. +> Running Docker on these unsupported systems isn't supported either. +> These old kernels are no longer patched for security vulnerabilities +> and severe bugs which lead to data loss. Please read the installation instructions for backported kernels at Ubuntu.org to understand why you also need to install the Xorg packages @@ -97,10 +116,10 @@ each version. # install the backported kernel $ sudo apt-get update - $ sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring + $ sudo apt-get install linux-image-generic-lts-trusty linux-headers-generic-lts-trusty # install the backported kernel and xorg if using Unity/Xorg - $ sudo apt-get install --install-recommends linux-generic-lts-raring xserver-xorg-lts-raring libgl1-mesa-glx-lts-raring + $ sudo apt-get install --install-recommends linux-generic-lts-trusty xserver-xorg-lts-trusty libgl1-mesa-glx-lts-trusty # reboot $ sudo reboot @@ -233,7 +252,7 @@ alternative group. > **Warning**: > The `docker` group (or the group specified with the `-G` flag) is > `root`-equivalent; see [*Docker Daemon Attack Surface*]( -> /articles/security/#dockersecurity-daemon) for details. +> /articles/security/#docker-daemon-attack-surface) for details. **Example:** diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 667ce2935..26b2a42a4 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -49,6 +49,8 @@ and the Boot2Docker management tool. ## Running Docker +{{ include "no-remote-sudo.md" }} + Boot2Docker will log you in automatically so you can start using Docker right away. Let's try the `hello-world` example image. Run @@ -57,6 +59,20 @@ Let's try the `hello-world` example image. Run This should download the very small `hello-world` image and print a `Hello from Docker.` message. +## Login with PUTTY instead of using the CMD + +Boot2Docker generates and uses the public/private key pair in your `%HOMEPATH%\.ssh` +directory so to log in you need to use the private key from this same directory. + +The private key needs to be converted into the format PuTTY uses. + +You can do this with +[puttygen](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html): + +- Open `puttygen.exe` and load ("File"->"Load" menu) the private key from + `%HOMEPATH%\.ssh\id_boot2docker` +- then click: "Save Private Key". +- Then use the saved file to login with PuTTY using `docker@127.0.0.1:2022`. # Further Details diff --git a/docs/sources/reference/api/docker_remote_api.md b/docs/sources/reference/api/docker_remote_api.md index 03613d938..30448b040 100644 --- a/docs/sources/reference/api/docker_remote_api.md +++ b/docs/sources/reference/api/docker_remote_api.md @@ -30,13 +30,51 @@ page_keywords: API, Docker, rcli, REST, documentation Client applications need to take this into account to ensure they will not break when talking to newer Docker daemons. -The current version of the API is v1.16 +The current version of the API is v1.17 Calling `/info` is the same as calling -`/v1.16/info`. +`/v1.17/info`. You can still call an old version of the API using -`/v1.15/info`. +`/v1.16/info`. + +## v1.17 + +### Full Documentation + +[*Docker Remote API v1.17*](/reference/api/docker_remote_api_v1.17/) + +### What's new + +`POST /containers/(id)/attach` and `POST /exec/(id)/start` + +**New!** +Docker client now hints potential proxies about connection hijacking using HTTP Upgrade headers. + +`GET /containers/(id)/json` + +**New!** +This endpoint now returns the list current execs associated with the container (`ExecIDs`). + +`POST /containers/(id)/rename` + +**New!** +New endpoint to rename a container `id` to a new name. + +`POST /containers/create` +`POST /containers/(id)/start` + +**New!** +(`ReadonlyRootfs`) can be passed in the host config to mount the container's +root filesystem as read only. + +`GET /containers/(id)/stats` + +**New!** +This endpoint returns a live stream of a container's resource usage statistics. + +> **Note**: this functionality currently only works when using the *libcontainer* exec-driver. + ## v1.16 @@ -366,7 +404,7 @@ output is now generated in the client, using the You can now split stderr from stdout. This is done by prefixing a header to each transmission. See [`POST /containers/(id)/attach`]( -/reference/api/docker_remote_api_v1.9/#post--containers-(id)-attach "POST /containers/(id)/attach"). +/reference/api/docker_remote_api_v1.9/#attach-to-a-container "POST /containers/(id)/attach"). The WebSocket attach is unchanged. Note that attach calls on the previous API version didn't change. Stdout and stderr are merged. diff --git a/docs/sources/reference/api/docker_remote_api_v1.0.md b/docs/sources/reference/api/docker_remote_api_v1.0.md index 3d8eedacf..399bf7f14 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.0.md +++ b/docs/sources/reference/api/docker_remote_api_v1.0.md @@ -218,16 +218,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -385,6 +385,41 @@ Status Codes: - **404** – no such container - **500** – server error +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -400,7 +435,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -625,14 +660,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -906,7 +941,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.1.md b/docs/sources/reference/api/docker_remote_api_v1.1.md index 705544bd9..7ddb4ee0e 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.1.md +++ b/docs/sources/reference/api/docker_remote_api_v1.1.md @@ -218,16 +218,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -385,6 +385,41 @@ Status Codes: - **404** – no such container - **500** – server error +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -400,7 +435,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -632,14 +667,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -919,7 +954,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.10.md b/docs/sources/reference/api/docker_remote_api_v1.10.md index eb3f5cc1e..7837b82ed 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.10.md +++ b/docs/sources/reference/api/docker_remote_api_v1.10.md @@ -35,27 +35,27 @@ List containers [ { "Id": "8dfafdbc3a40", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 3333333333333333", "Created": 1367854154, "Status": "Exit 0", @@ -65,13 +65,13 @@ List containers }, { "Id": "4cb07b47f9fb", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -119,7 +119,7 @@ Create a container "Cmd":[ "date" ], - "Image":"base", + "Image":"ubuntu", "Volumes":{ "/tmp": {} }, @@ -194,7 +194,7 @@ Return low-level information on the container `id` "Cmd": [ "date" ], - "Image": "base", + "Image": "ubuntu", "Volumes": {}, "WorkingDir":"" @@ -257,7 +257,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -270,7 +270,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -305,16 +305,16 @@ Inspect changes on container `id` 's filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -499,7 +499,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` -](../docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), +](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -539,6 +539,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1) +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -555,7 +590,7 @@ Block until container `id` stops, then returns HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -602,7 +637,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -667,16 +702,16 @@ Create an image, either by pull it from the registry or by importing **Example request**: - POST /images/create?fromImage=base HTTP/1.1 + POST /images/create?fromImage=ubuntu HTTP/1.1 **Example response**: HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -739,7 +774,7 @@ Return low-level information on the image `name` **Example request**: - GET /images/base/json HTTP/1.1 + GET /images/ubuntu/json HTTP/1.1 **Example response**: @@ -766,7 +801,7 @@ Return low-level information on the image `name` "StdinOnce":false, "Env":null, "Cmd": ["/bin/bash"] - "Image":"base", + "Image":"ubuntu", "Volumes":null, "WorkingDir":"" }, @@ -787,7 +822,7 @@ Return the history of the image `name` **Example request**: - GET /images/base/history HTTP/1.1 + GET /images/ubuntu/history HTTP/1.1 **Example response**: @@ -796,14 +831,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -828,9 +863,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... If you wish to push an image on to a private registry, that image must already have been tagged @@ -899,9 +934,9 @@ Status Codes: Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Query Parameters: @@ -988,9 +1023,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -998,12 +1033,13 @@ Build an image from Dockerfile via stdin The archive must include a file called `Dockerfile` at its root. It may include any number of other files, which will be accessible in the build context (See the [*ADD build - command*](/reference/builder/#dockerbuilder)). + command*](/reference/builder/#add)). Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** - remove intermediate containers after a successful build @@ -1030,10 +1066,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1146,7 +1182,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1194,10 +1230,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} Query Parameters: @@ -1273,7 +1309,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` diff --git a/docs/sources/reference/api/docker_remote_api_v1.11.md b/docs/sources/reference/api/docker_remote_api_v1.11.md index 838d199ea..6bcabfc79 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.11.md +++ b/docs/sources/reference/api/docker_remote_api_v1.11.md @@ -35,27 +35,27 @@ List containers [ { "Id": "8dfafdbc3a40", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 3333333333333333", "Created": 1367854154, "Status": "Exit 0", @@ -65,13 +65,13 @@ List containers }, { "Id": "4cb07b47f9fb", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -119,7 +119,7 @@ Create a container "Cmd":[ "date" ], - "Image":"base", + "Image":"ubuntu", "Volumes":{ "/tmp": {} }, @@ -195,11 +195,10 @@ Return low-level information on the container `id` "date" ], "Dns": null, - "Image": "base", + "Image": "ubuntu", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -259,7 +258,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -272,7 +271,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -341,16 +340,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -535,7 +534,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](../docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -575,6 +574,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1) +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -590,7 +624,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -638,7 +672,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -702,16 +736,16 @@ Create an image, either by pull it from the registry or by importing i **Example request**: - POST /images/create?fromImage=base HTTP/1.1 + POST /images/create?fromImage=ubuntu HTTP/1.1 **Example response**: HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -743,7 +777,7 @@ Return low-level information on the image `name` **Example request**: - GET /images/base/json HTTP/1.1 + GET /images/ubuntu/json HTTP/1.1 **Example response**: @@ -771,7 +805,7 @@ Return low-level information on the image `name` "Env":null, "Cmd": ["/bin/bash"], "Dns":null, - "Image":"base", + "Image":"ubuntu", "Volumes":null, "VolumesFrom":"", "WorkingDir":"" @@ -793,7 +827,7 @@ Return the history of the image `name` **Example request**: - GET /images/base/history HTTP/1.1 + GET /images/ubuntu/history HTTP/1.1 **Example response**: @@ -802,14 +836,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -834,9 +868,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... If you wish to push an image on to a private registry, that image must already have been tagged @@ -906,9 +940,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Query Parameters: @@ -995,9 +1029,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1011,6 +1045,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** - remove intermediate containers after a successful build @@ -1037,10 +1072,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1069,20 +1104,20 @@ Display system-wide information Content-Type: application/json { - "Containers":11, - "Images":16, - "Driver":"btrfs", - "ExecutionDriver":"native-0.1", - "KernelVersion":"3.12.0-1-amd64" - "Debug":false, + "Containers": 11, + "Images": 16, + "Driver": "btrfs", + "ExecutionDriver": "native-0.1", + "KernelVersion": "3.12.0-1-amd64" + "Debug": false, "NFd": 11, - "NGoroutines":21, - "NEventsListener":0, - "InitPath":"/usr/bin/docker", - "IndexServerAddress":["https://index.docker.io/v1/"], - "MemoryLimit":true, - "SwapLimit":false, - "IPv4Forwarding":true + "NGoroutines": 21, + "NEventsListener": 0, + "InitPath": "/usr/bin/docker", + "IndexServerAddress": ["https://index.docker.io/v1/"], + "MemoryLimit": true, + "SwapLimit": false, + "IPv4Forwarding": true } Status Codes: @@ -1180,7 +1215,7 @@ Create a new image from a container's changes HTTP/1.1 201 Created Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1225,10 +1260,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} Query Parameters: @@ -1305,7 +1340,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` diff --git a/docs/sources/reference/api/docker_remote_api_v1.12.md b/docs/sources/reference/api/docker_remote_api_v1.12.md index f38b018ef..58f3bc3a3 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.12.md +++ b/docs/sources/reference/api/docker_remote_api_v1.12.md @@ -36,27 +36,27 @@ List containers [ { "Id": "8dfafdbc3a40", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 3333333333333333", "Created": 1367854154, "Status": "Exit 0", @@ -66,13 +66,13 @@ List containers }, { "Id": "4cb07b47f9fb", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -127,7 +127,7 @@ Create a container "Cmd":[ "date" ], - "Image":"base", + "Image":"ubuntu", "Volumes":{ "/tmp": {} }, @@ -204,11 +204,10 @@ Return low-level information on the container `id` "date" ], "Dns": null, - "Image": "base", + "Image": "ubuntu", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -268,7 +267,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -281,7 +280,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -350,16 +349,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -583,7 +582,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](../docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -623,6 +622,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1 +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -638,7 +672,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -686,7 +720,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -748,7 +782,8 @@ Query Parameters:   - **all** – 1/True/true or 0/False/false, default false -- **filters** – a JSON encoded value of the filters (a map[string][]string) to process on the images list. +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. Available filters: + - dangling=true @@ -760,16 +795,16 @@ Create an image, either by pull it from the registry or by importing i **Example request**: - POST /images/create?fromImage=base HTTP/1.1 + POST /images/create?fromImage=ubuntu HTTP/1.1 **Example response**: HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -803,7 +838,7 @@ Return low-level information on the image `name` **Example request**: - GET /images/base/json HTTP/1.1 + GET /images/ubuntu/json HTTP/1.1 **Example response**: @@ -811,31 +846,31 @@ Return low-level information on the image `name` Content-Type: application/json { - "Created":"2013-03-23T22:24:18.818426-07:00", - "Container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", + "Created": "2013-03-23T22:24:18.818426-07:00", + "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", "ContainerConfig": { - "Hostname":"", - "User":"", - "Memory":0, - "MemorySwap":0, - "AttachStdin":false, - "AttachStdout":false, - "AttachStderr":false, - "PortSpecs":null, - "Tty":true, - "OpenStdin":true, - "StdinOnce":false, - "Env":null, + "Hostname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "PortSpecs": null, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": null, "Cmd": ["/bin/bash"], - "Dns":null, - "Image":"base", - "Volumes":null, - "VolumesFrom":"", - "WorkingDir":"" + "Dns": null, + "Image": "ubuntu", + "Volumes": null, + "VolumesFrom": "", + "WorkingDir": "" }, - "Id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", - "Parent":"27cf784147099545", + "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "Parent": "27cf784147099545", "Size": 6824592 } @@ -853,7 +888,7 @@ Return the history of the image `name` **Example request**: - GET /images/base/history HTTP/1.1 + GET /images/ubuntu/history HTTP/1.1 **Example response**: @@ -862,14 +897,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -894,9 +929,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... If you wish to push an image on to a private registry, that image must already have been tagged @@ -966,9 +1001,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Query Parameters: @@ -1055,9 +1090,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1071,6 +1106,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** - remove intermediate containers after a successful build (default behavior) @@ -1098,10 +1134,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1130,20 +1166,20 @@ Display system-wide information Content-Type: application/json { - "Containers":11, - "Images":16, - "Driver":"btrfs", - "ExecutionDriver":"native-0.1", - "KernelVersion":"3.12.0-1-amd64" - "Debug":false, + "Containers": 11, + "Images": 16, + "Driver": "btrfs", + "ExecutionDriver": "native-0.1", + "KernelVersion": "3.12.0-1-amd64" + "Debug": false, "NFd": 11, - "NGoroutines":21, - "NEventsListener":0, - "InitPath":"/usr/bin/docker", - "IndexServerAddress":["https://index.docker.io/v1/"], - "MemoryLimit":true, - "SwapLimit":false, - "IPv4Forwarding":true + "NGoroutines": 21, + "NEventsListener": 0, + "InitPath": "/usr/bin/docker", + "IndexServerAddress": ["https://index.docker.io/v1/"], + "MemoryLimit": true, + "SwapLimit": false, + "IPv4Forwarding": true } Status Codes: @@ -1167,10 +1203,10 @@ Show the docker version information Content-Type: application/json { - "ApiVersion":"1.12", - "Version":"0.2.2", - "GitCommit":"5a2a5cc+CHANGES", - "GoVersion":"go1.0.3" + "ApiVersion": "1.12", + "Version": "0.2.2", + "GitCommit": "5a2a5cc+CHANGES", + "GoVersion": "go1.0.3" } Status Codes: @@ -1212,30 +1248,30 @@ Create a new image from a container's changes Content-Type: application/json { - "Hostname":"", + "Hostname": "", "Domainname": "", - "User":"", - "Memory":0, - "MemorySwap":0, + "User": "", + "Memory": 0, + "MemorySwap": 0, "CpuShares": 512, "Cpuset": "0,1", - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "PortSpecs":null, - "Tty":false, - "OpenStdin":false, - "StdinOnce":false, - "Env":null, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ "date" ], - "Volumes":{ + "Volumes": { "/tmp": {} }, - "WorkingDir":"", + "WorkingDir": "", "NetworkDisabled": false, - "ExposedPorts":{ + "ExposedPorts": { "22/tcp": {} } } @@ -1245,7 +1281,7 @@ Create a new image from a container's changes HTTP/1.1 201 Created Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1290,10 +1326,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} Query Parameters: @@ -1369,7 +1405,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` diff --git a/docs/sources/reference/api/docker_remote_api_v1.13.md b/docs/sources/reference/api/docker_remote_api_v1.13.md index f5ca931fe..1590978f0 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.13.md +++ b/docs/sources/reference/api/docker_remote_api_v1.13.md @@ -36,27 +36,27 @@ List containers [ { "Id": "8dfafdbc3a40", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 3333333333333333", "Created": 1367854154, "Status": "Exit 0", @@ -66,13 +66,13 @@ List containers }, { "Id": "4cb07b47f9fb", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -121,7 +121,7 @@ Create a container "Cmd":[ "date" ], - "Image":"base", + "Image":"ubuntu", "Volumes":{ "/tmp": {} }, @@ -198,11 +198,10 @@ Return low-level information on the container `id` "date" ], "Dns": null, - "Image": "base", + "Image": "ubuntu", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -262,7 +261,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -275,7 +274,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -341,16 +340,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -576,7 +575,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](../docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -616,6 +615,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1 +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -631,7 +665,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -679,7 +713,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -739,7 +773,8 @@ Status Codes: Query Parameters: - **all** – 1/True/true or 0/False/false, default false -- **filters** – a json encoded value of the filters (a map[string][string]) to process on the images list. +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. Available filters: + - dangling=true ### Create an image @@ -749,16 +784,16 @@ Create an image, either by pulling it from the registry or by importing it **Example request**: - POST /images/create?fromImage=base HTTP/1.1 + POST /images/create?fromImage=ubuntu HTTP/1.1 **Example response**: HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -792,7 +827,7 @@ Return low-level information on the image `name` **Example request**: - GET /images/base/json HTTP/1.1 + GET /images/ubuntu/json HTTP/1.1 **Example response**: @@ -800,31 +835,31 @@ Return low-level information on the image `name` Content-Type: application/json { - "Created":"2013-03-23T22:24:18.818426-07:00", - "Container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", + "Created": "2013-03-23T22:24:18.818426-07:00", + "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", "ContainerConfig": { - "Hostname":"", - "User":"", - "Memory":0, - "MemorySwap":0, - "AttachStdin":false, - "AttachStdout":false, - "AttachStderr":false, - "PortSpecs":null, - "Tty":true, - "OpenStdin":true, - "StdinOnce":false, - "Env":null, + "Hostname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "PortSpecs": null, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": null, "Cmd": ["/bin/bash"], - "Dns":null, - "Image":"base", - "Volumes":null, - "VolumesFrom":"", - "WorkingDir":"" + "Dns": null, + "Image": "ubuntu", + "Volumes": null, + "VolumesFrom": "", + "WorkingDir": "" }, - "Id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", - "Parent":"27cf784147099545", + "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "Parent": "27cf784147099545", "Size": 6824592 } @@ -842,7 +877,7 @@ Return the history of the image `name` **Example request**: - GET /images/base/history HTTP/1.1 + GET /images/ubuntu/history HTTP/1.1 **Example response**: @@ -851,14 +886,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -883,9 +918,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... If you wish to push an image on to a private registry, that image must already have been tagged @@ -955,9 +990,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Query Parameters: @@ -1044,9 +1079,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1060,6 +1095,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** - remove intermediate containers after a successful build (default behavior) @@ -1087,10 +1123,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1119,20 +1155,20 @@ Display system-wide information Content-Type: application/json { - "Containers":11, - "Images":16, - "Driver":"btrfs", - "ExecutionDriver":"native-0.1", - "KernelVersion":"3.12.0-1-amd64" - "Debug":false, + "Containers": 11, + "Images": 16, + "Driver": "btrfs", + "ExecutionDriver": "native-0.1", + "KernelVersion": "3.12.0-1-amd64" + "Debug": false, "NFd": 11, - "NGoroutines":21, - "NEventsListener":0, - "InitPath":"/usr/bin/docker", - "IndexServerAddress":["https://index.docker.io/v1/"], - "MemoryLimit":true, - "SwapLimit":false, - "IPv4Forwarding":true + "NGoroutines": 21, + "NEventsListener": 0, + "InitPath": "/usr/bin/docker", + "IndexServerAddress": ["https://index.docker.io/v1/"], + "MemoryLimit": true, + "SwapLimit": false, + "IPv4Forwarding": true } Status Codes: @@ -1156,10 +1192,10 @@ Show the docker version information Content-Type: application/json { - "ApiVersion":"1.12", - "Version":"0.2.2", - "GitCommit":"5a2a5cc+CHANGES", - "GoVersion":"go1.0.3" + "ApiVersion": "1.12", + "Version": "0.2.2", + "GitCommit": "5a2a5cc+CHANGES", + "GoVersion": "go1.0.3" } Status Codes: @@ -1201,30 +1237,30 @@ Create a new image from a container's changes Content-Type: application/json { - "Hostname":"", + "Hostname": "", "Domainname": "", - "User":"", - "Memory":0, - "MemorySwap":0, + "User": "", + "Memory": 0, + "MemorySwap": 0, "CpuShares": 512, "Cpuset": "0,1", - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "PortSpecs":null, - "Tty":false, - "OpenStdin":false, - "StdinOnce":false, - "Env":null, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ "date" ], - "Volumes":{ + "Volumes": { "/tmp": {} }, - "WorkingDir":"", + "WorkingDir": "", "NetworkDisabled": false, - "ExposedPorts":{ + "ExposedPorts": { "22/tcp": {} } } @@ -1234,7 +1270,7 @@ Create a new image from a container's changes HTTP/1.1 201 Created Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1279,10 +1315,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} Query Parameters: @@ -1359,7 +1395,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` diff --git a/docs/sources/reference/api/docker_remote_api_v1.14.md b/docs/sources/reference/api/docker_remote_api_v1.14.md index a5392f3bc..f4e1b3edc 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.14.md +++ b/docs/sources/reference/api/docker_remote_api_v1.14.md @@ -36,27 +36,27 @@ List containers [ { "Id": "8dfafdbc3a40", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 3333333333333333", "Created": 1367854154, "Status": "Exit 0", @@ -66,13 +66,13 @@ List containers }, { "Id": "4cb07b47f9fb", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -84,6 +84,9 @@ Query Parameters: - **since** – Show only containers created since Id, include non-running ones. - **before** – Show only containers created before Id, include non-running ones. - **size** – 1/True/true or 0/False/false, Show the containers sizes +- **filters** - a json encoded value of the filters (a map[string][]string) to process on the containers list. Available filters: + - exited=<int> -- containers with exit code of <int> + - status=(restarting|running|paused|exited) Status Codes: @@ -121,7 +124,7 @@ Create a container "Cmd":[ "date" ], - "Image":"base", + "Image":"ubuntu", "Volumes":{ "/tmp": {} }, @@ -151,6 +154,8 @@ Json Parameters: exit code is non-zero. If `on-failure` is used, `MaximumRetryCount` controls the number of times to retry before giving up. The default is not to restart. (optional) + An ever increasing delay (double the previous delay, starting at 100mS) + is added before each restart to prevent flooding the server. - **config** – the container's configuration Query Parameters: @@ -202,11 +207,10 @@ Return low-level information on the container `id` "date" ], "Dns": null, - "Image": "base", + "Image": "ubuntu", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -241,8 +245,8 @@ Return low-level information on the container `id` }, "Links": ["/name:alias"], "PublishAllPorts": false, - "CapAdd: ["NET_ADMIN"], - "CapDrop: ["MKNOD"] + "CapAdd": ["NET_ADMIN"], + "CapDrop": ["MKNOD"] } } @@ -268,7 +272,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -281,7 +285,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -347,16 +351,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -581,7 +585,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](../docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -621,6 +625,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1 +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -636,7 +675,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -684,7 +723,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -744,7 +783,8 @@ Status Codes: Query Parameters: - **all** – 1/True/true or 0/False/false, default false -- **filters** – a json encoded value of the filters (a map[string][string]) to process on the images list. +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. Available filters: + - dangling=true ### Create an image @@ -754,16 +794,16 @@ Create an image, either by pulling it from the registry or by importing it **Example request**: - POST /images/create?fromImage=base HTTP/1.1 + POST /images/create?fromImage=ubuntu HTTP/1.1 **Example response**: HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -797,7 +837,7 @@ Return low-level information on the image `name` **Example request**: - GET /images/base/json HTTP/1.1 + GET /images/ubuntu/json HTTP/1.1 **Example response**: @@ -805,31 +845,31 @@ Return low-level information on the image `name` Content-Type: application/json { - "Created":"2013-03-23T22:24:18.818426-07:00", - "Container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", + "Created": "2013-03-23T22:24:18.818426-07:00", + "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", "ContainerConfig": { - "Hostname":"", - "User":"", - "Memory":0, - "MemorySwap":0, - "AttachStdin":false, - "AttachStdout":false, - "AttachStderr":false, - "PortSpecs":null, - "Tty":true, - "OpenStdin":true, - "StdinOnce":false, - "Env":null, + "Hostname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "PortSpecs": null, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": null, "Cmd": ["/bin/bash"], - "Dns":null, - "Image":"base", - "Volumes":null, - "VolumesFrom":"", - "WorkingDir":"" + "Dns": null, + "Image": "ubuntu", + "Volumes": null, + "VolumesFrom": "", + "WorkingDir": "" }, - "Id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", - "Parent":"27cf784147099545", + "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "Parent": "27cf784147099545", "Size": 6824592 } @@ -847,7 +887,7 @@ Return the history of the image `name` **Example request**: - GET /images/base/history HTTP/1.1 + GET /images/ubuntu/history HTTP/1.1 **Example response**: @@ -856,14 +896,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -888,9 +928,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... If you wish to push an image on to a private registry, that image must already have been tagged @@ -960,9 +1000,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Query Parameters: @@ -1049,9 +1089,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1065,6 +1105,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** - remove intermediate containers after a successful build (default behavior) @@ -1092,10 +1133,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1124,20 +1165,20 @@ Display system-wide information Content-Type: application/json { - "Containers":11, - "Images":16, - "Driver":"btrfs", - "ExecutionDriver":"native-0.1", - "KernelVersion":"3.12.0-1-amd64" - "Debug":false, + "Containers": 11, + "Images": 16, + "Driver": "btrfs", + "ExecutionDriver": "native-0.1", + "KernelVersion": "3.12.0-1-amd64" + "Debug": false, "NFd": 11, - "NGoroutines":21, - "NEventsListener":0, - "InitPath":"/usr/bin/docker", - "IndexServerAddress":["https://index.docker.io/v1/"], - "MemoryLimit":true, - "SwapLimit":false, - "IPv4Forwarding":true + "NGoroutines": 21, + "NEventsListener": 0, + "InitPath": "/usr/bin/docker", + "IndexServerAddress": ["https://index.docker.io/v1/"], + "MemoryLimit": true, + "SwapLimit": false, + "IPv4Forwarding": true } Status Codes: @@ -1161,10 +1202,10 @@ Show the docker version information Content-Type: application/json { - "ApiVersion":"1.12", - "Version":"0.2.2", - "GitCommit":"5a2a5cc+CHANGES", - "GoVersion":"go1.0.3" + "ApiVersion": "1.12", + "Version": "0.2.2", + "GitCommit": "5a2a5cc+CHANGES", + "GoVersion": "go1.0.3" } Status Codes: @@ -1206,30 +1247,30 @@ Create a new image from a container's changes Content-Type: application/json { - "Hostname":"", + "Hostname": "", "Domainname": "", - "User":"", - "Memory":0, - "MemorySwap":0, + "User": "", + "Memory": 0, + "MemorySwap": 0, "CpuShares": 512, "Cpuset": "0,1", - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "PortSpecs":null, - "Tty":false, - "OpenStdin":false, - "StdinOnce":false, - "Env":null, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ "date" ], - "Volumes":{ + "Volumes": { "/tmp": {} }, - "WorkingDir":"", + "WorkingDir": "", "NetworkDisabled": false, - "ExposedPorts":{ + "ExposedPorts": { "22/tcp": {} } } @@ -1239,7 +1280,7 @@ Create a new image from a container's changes HTTP/1.1 201 Created Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1284,10 +1325,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} Query Parameters: @@ -1363,7 +1404,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` diff --git a/docs/sources/reference/api/docker_remote_api_v1.15.md b/docs/sources/reference/api/docker_remote_api_v1.15.md index ae265653a..a956d454a 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.15.md +++ b/docs/sources/reference/api/docker_remote_api_v1.15.md @@ -36,27 +36,27 @@ List containers [ { "Id": "8dfafdbc3a40", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 3333333333333333", "Created": 1367854154, "Status": "Exit 0", @@ -66,13 +66,13 @@ List containers }, { "Id": "4cb07b47f9fb", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -88,6 +88,9 @@ Query Parameters: non-running ones. - **size** – 1/True/true or 0/False/false, Show the containers sizes +- **filters** - a json encoded value of the filters (a map[string][]string) to process on the containers list. Available filters: + - exited=<int> -- containers with exit code of <int> + - status=(restarting|running|paused|exited) Status Codes: @@ -107,44 +110,45 @@ Create a container Content-Type: application/json { - "Hostname":"", + "Hostname": "", "Domainname": "", - "User":"", - "Memory":0, - "MemorySwap":0, + "User": "", + "Memory": 0, + "MemorySwap": 0, "CpuShares": 512, "Cpuset": "0,1", - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "Tty":false, - "OpenStdin":false, - "StdinOnce":false, - "Env":null, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ "date" ], "Entrypoint": "", - "Image":"base", - "Volumes":{ + "Image": "ubuntu", + "Volumes": { "/tmp": {} }, - "WorkingDir":"", + "WorkingDir": "", "NetworkDisabled": false, - "MacAddress":"12:34:56:78:9a:bc", - "ExposedPorts":{ + "MacAddress": "12:34:56:78:9a:bc", + "ExposedPorts": { "22/tcp": {} }, "SecurityOpts": [""], "HostConfig": { - "Binds":["/tmp:/tmp"], - "Links":["redis3:redis"], - "LxcConf":{"lxc.utsname":"docker"}, - "PortBindings":{ "22/tcp": [{ "HostPort": "11022" }] }, - "PublishAllPorts":false, - "Privileged":false, + "Binds": ["/tmp:/tmp"], + "Links": ["redis3:redis"], + "LxcConf": {"lxc.utsname":"docker"}, + "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] }, + "PublishAllPorts": false, + "Privileged": false, "Dns": ["8.8.8.8"], "DnsSearch": [""], + "ExtraHosts": null, "VolumesFrom": ["parent", "other:ro"], "CapAdd": ["NET_ADMIN"], "CapDrop": ["MKNOD"], @@ -160,8 +164,8 @@ Create a container Content-Type: application/json { - "Id":"f91ddc4b01e079c4481a8340bbbeca4dbd33d6e4a10662e499f8eacbb5bf252b" - "Warnings":[] + "Id": "f91ddc4b01e079c4481a8340bbbeca4dbd33d6e4a10662e499f8eacbb5bf252b" + "Warnings": [] } Json Parameters: @@ -217,6 +221,8 @@ Json Parameters: a boolean value. - **Dns** - A list of dns servers for the container to use. - **DnsSearch** - A list of DNS search domains + - **ExtraHosts** - A list of hostnames/IP mappings to be added to the + container's `/etc/hosts` file. Specified in the form `["hostname:IP"]`. - **VolumesFrom** - A list of volumes to inherit from another container. Specified in the form `[:]` - **CapAdd** - A list of kernel capabilties to add to the container. @@ -227,6 +233,8 @@ Json Parameters: exit code is non-zero. If `on-failure` is used, `MaximumRetryCount` controls the number of times to retry before giving up. The default is not to restart. (optional) + An ever increasing delay (double the previous delay, starting at 100mS) + is added before each restart to prevent flooding the server. - **NetworkMode** - Sets the networking mode for the container. Supported values are: `bridge`, `host`, and `container:` - **Devices** - A list of devices to add to the container specified in the @@ -283,11 +291,10 @@ Return low-level information on the container `id` "date" ], "Dns": null, - "Image": "base", + "Image": "ubuntu", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -322,8 +329,8 @@ Return low-level information on the container `id` }, "Links": ["/name:alias"], "PublishAllPorts": false, - "CapAdd: ["NET_ADMIN"], - "CapDrop: ["MKNOD"] + "CapAdd": ["NET_ADMIN"], + "CapDrop": ["MKNOD"] } } @@ -349,7 +356,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -362,7 +369,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -427,16 +434,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -503,12 +510,12 @@ Start the container `id` Content-Type: application/json { - "Binds":["/tmp:/tmp"], - "Links":["redis3:redis"], - "LxcConf":{"lxc.utsname":"docker"}, - "PortBindings":{ "22/tcp": [{ "HostPort": "11022" }] }, - "PublishAllPorts":false, - "Privileged":false, + "Binds": ["/tmp:/tmp"], + "Links": ["redis3:redis"], + "LxcConf": {"lxc.utsname":"docker"}, + "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] }, + "PublishAllPorts": false, + "Privileged": false, "Dns": ["8.8.8.8"], "DnsSearch": [""], "VolumesFrom": ["parent", "other:ro"], @@ -554,6 +561,8 @@ Json Parameters: exit code is non-zero. If `on-failure` is used, `MaximumRetryCount` controls the number of times to retry before giving up. The default is not to restart. (optional) + An ever increasing delay (double the previous delay, starting at 100mS) + is added before each restart to prevent flooding the server. - **NetworkMode** - Sets the networking mode for the container. Supported values are: `bridge`, `host`, and `container:` - **Devices** - A list of devices to add to the container specified in the @@ -721,7 +730,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](../docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -761,6 +770,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1 +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -776,7 +820,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -824,7 +868,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -884,7 +928,8 @@ Status Codes: Query Parameters: - **all** – 1/True/true or 0/False/false, default false -- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. Available filters: + - dangling=true ### Create an image @@ -894,16 +939,16 @@ Create an image, either by pulling it from the registry or by importing it **Example request**: - POST /images/create?fromImage=base HTTP/1.1 + POST /images/create?fromImage=ubuntu HTTP/1.1 **Example response**: HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -938,7 +983,7 @@ Return low-level information on the image `name` **Example request**: - GET /images/base/json HTTP/1.1 + GET /images/ubuntu/json HTTP/1.1 **Example response**: @@ -946,31 +991,31 @@ Return low-level information on the image `name` Content-Type: application/json { - "Created":"2013-03-23T22:24:18.818426-07:00", - "Container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", + "Created": "2013-03-23T22:24:18.818426-07:00", + "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", "ContainerConfig": { - "Hostname":"", - "User":"", - "Memory":0, - "MemorySwap":0, - "AttachStdin":false, - "AttachStdout":false, - "AttachStderr":false, - "PortSpecs":null, - "Tty":true, - "OpenStdin":true, - "StdinOnce":false, - "Env":null, + "Hostname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "PortSpecs": null, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": null, "Cmd": ["/bin/bash"], - "Dns":null, - "Image":"base", - "Volumes":null, - "VolumesFrom":"", - "WorkingDir":"" + "Dns": null, + "Image": "ubuntu", + "Volumes": null, + "VolumesFrom": "", + "WorkingDir": "" }, - "Id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", - "Parent":"27cf784147099545", + "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "Parent": "27cf784147099545", "Size": 6824592 } @@ -988,7 +1033,7 @@ Return the history of the image `name` **Example request**: - GET /images/base/history HTTP/1.1 + GET /images/ubuntu/history HTTP/1.1 **Example response**: @@ -997,14 +1042,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -1029,9 +1074,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... If you wish to push an image on to a private registry, that image must already have been tagged @@ -1102,9 +1147,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Query Parameters: @@ -1191,9 +1236,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1207,6 +1252,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** - remove intermediate containers after a successful build (default behavior) @@ -1234,10 +1280,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1266,20 +1312,20 @@ Display system-wide information Content-Type: application/json { - "Containers":11, - "Images":16, - "Driver":"btrfs", - "ExecutionDriver":"native-0.1", - "KernelVersion":"3.12.0-1-amd64" - "Debug":false, + "Containers": 11, + "Images": 16, + "Driver": "btrfs", + "ExecutionDriver": "native-0.1", + "KernelVersion": "3.12.0-1-amd64" + "Debug": false, "NFd": 11, - "NGoroutines":21, - "NEventsListener":0, - "InitPath":"/usr/bin/docker", - "IndexServerAddress":["https://index.docker.io/v1/"], - "MemoryLimit":true, - "SwapLimit":false, - "IPv4Forwarding":true + "NGoroutines": 21, + "NEventsListener": 0, + "InitPath": "/usr/bin/docker", + "IndexServerAddress": ["https://index.docker.io/v1/"], + "MemoryLimit": true, + "SwapLimit": false, + "IPv4Forwarding": true } Status Codes: @@ -1303,10 +1349,10 @@ Show the docker version information Content-Type: application/json { - "ApiVersion":"1.12", - "Version":"0.2.2", - "GitCommit":"5a2a5cc+CHANGES", - "GoVersion":"go1.0.3" + "ApiVersion": "1.12", + "Version": "0.2.2", + "GitCommit": "5a2a5cc+CHANGES", + "GoVersion": "go1.0.3" } Status Codes: @@ -1348,30 +1394,30 @@ Create a new image from a container's changes Content-Type: application/json { - "Hostname":"", + "Hostname": "", "Domainname": "", - "User":"", - "Memory":0, - "MemorySwap":0, + "User": "", + "Memory": 0, + "MemorySwap": 0, "CpuShares": 512, "Cpuset": "0,1", - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "PortSpecs":null, - "Tty":false, - "OpenStdin":false, - "StdinOnce":false, - "Env":null, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ "date" ], - "Volumes":{ + "Volumes": { "/tmp": {} }, - "WorkingDir":"", + "WorkingDir": "", "NetworkDisabled": false, - "ExposedPorts":{ + "ExposedPorts": { "22/tcp": {} } } @@ -1381,7 +1427,7 @@ Create a new image from a container's changes HTTP/1.1 201 Created Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1426,10 +1472,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} Query Parameters: @@ -1539,7 +1585,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` @@ -1555,11 +1601,11 @@ Sets up an exec instance in a running container `id` Content-Type: application/json { - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "Tty":false, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "Tty": false, + "Cmd": [ "date" ], } @@ -1570,7 +1616,7 @@ Sets up an exec instance in a running container `id` Content-Type: application/json { - "Id":"f90e34656806" + "Id": "f90e34656806" } Json Parameters: @@ -1601,8 +1647,8 @@ interactive session with the `exec` command. Content-Type: application/json { - "Detach":false, - "Tty":false, + "Detach": false, + "Tty": false, } **Example response**: diff --git a/docs/sources/reference/api/docker_remote_api_v1.16.md b/docs/sources/reference/api/docker_remote_api_v1.16.md index 72f5519e1..86df97b71 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.16.md +++ b/docs/sources/reference/api/docker_remote_api_v1.16.md @@ -36,27 +36,27 @@ List containers [ { "Id": "8dfafdbc3a40", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 3333333333333333", "Created": 1367854154, "Status": "Exit 0", @@ -66,13 +66,13 @@ List containers }, { "Id": "4cb07b47f9fb", - "Image": "base:latest", + "Image": "ubuntu:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -88,6 +88,9 @@ Query Parameters: non-running ones. - **size** – 1/True/true or 0/False/false, Show the containers sizes +- **filters** - a json encoded value of the filters (a map[string][]string) to process on the containers list. Available filters: + - exited=<int> -- containers with exit code of <int> + - status=(restarting|running|paused|exited) Status Codes: @@ -107,44 +110,45 @@ Create a container Content-Type: application/json { - "Hostname":"", + "Hostname": "", "Domainname": "", - "User":"", - "Memory":0, - "MemorySwap":0, + "User": "", + "Memory": 0, + "MemorySwap": 0, "CpuShares": 512, "Cpuset": "0,1", - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "Tty":false, - "OpenStdin":false, - "StdinOnce":false, - "Env":null, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ "date" ], "Entrypoint": "", - "Image":"base", - "Volumes":{ + "Image": "ubuntu", + "Volumes": { "/tmp": {} }, - "WorkingDir":"", + "WorkingDir": "", "NetworkDisabled": false, - "MacAddress":"12:34:56:78:9a:bc", - "ExposedPorts":{ + "MacAddress": "12:34:56:78:9a:bc", + "ExposedPorts": { "22/tcp": {} }, "SecurityOpts": [""], "HostConfig": { - "Binds":["/tmp:/tmp"], - "Links":["redis3:redis"], - "LxcConf":{"lxc.utsname":"docker"}, - "PortBindings":{ "22/tcp": [{ "HostPort": "11022" }] }, - "PublishAllPorts":false, - "Privileged":false, + "Binds": ["/tmp:/tmp"], + "Links": ["redis3:redis"], + "LxcConf": {"lxc.utsname":"docker"}, + "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] }, + "PublishAllPorts": false, + "Privileged": false, "Dns": ["8.8.8.8"], "DnsSearch": [""], + "ExtraHosts": null, "VolumesFrom": ["parent", "other:ro"], "CapAdd": ["NET_ADMIN"], "CapDrop": ["MKNOD"], @@ -217,6 +221,8 @@ Json Parameters: a boolean value. - **Dns** - A list of dns servers for the container to use. - **DnsSearch** - A list of DNS search domains + - **ExtraHosts** - A list of hostnames/IP mappings to be added to the + container's `/etc/hosts` file. Specified in the form `["hostname:IP"]`. - **VolumesFrom** - A list of volumes to inherit from another container. Specified in the form `[:]` - **CapAdd** - A list of kernel capabilties to add to the container. @@ -227,6 +233,8 @@ Json Parameters: exit code is non-zero. If `on-failure` is used, `MaximumRetryCount` controls the number of times to retry before giving up. The default is not to restart. (optional) + An ever increasing delay (double the previous delay, starting at 100mS) + is added before each restart to prevent flooding the server. - **NetworkMode** - Sets the networking mode for the container. Supported values are: `bridge`, `host`, and `container:` - **Devices** - A list of devices to add to the container specified in the @@ -283,11 +291,10 @@ Return low-level information on the container `id` "date" ], "Dns": null, - "Image": "base", + "Image": "ubuntu", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -322,8 +329,8 @@ Return low-level information on the container `id` }, "Links": ["/name:alias"], "PublishAllPorts": false, - "CapAdd: ["NET_ADMIN"], - "CapDrop: ["MKNOD"] + "CapAdd": ["NET_ADMIN"], + "CapDrop": ["MKNOD"] } } @@ -349,7 +356,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -362,7 +369,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -427,16 +434,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -669,7 +676,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](../docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -709,6 +716,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1 +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -724,7 +766,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -772,7 +814,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -832,7 +874,8 @@ Status Codes: Query Parameters: - **all** – 1/True/true or 0/False/false, default false -- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. Available filters: + - dangling=true ### Create an image @@ -842,16 +885,16 @@ Create an image, either by pulling it from the registry or by importing it **Example request**: - POST /images/create?fromImage=base HTTP/1.1 + POST /images/create?fromImage=ubuntu HTTP/1.1 **Example response**: HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -886,7 +929,7 @@ Return low-level information on the image `name` **Example request**: - GET /images/base/json HTTP/1.1 + GET /images/ubuntu/json HTTP/1.1 **Example response**: @@ -894,31 +937,31 @@ Return low-level information on the image `name` Content-Type: application/json { - "Created":"2013-03-23T22:24:18.818426-07:00", - "Container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", + "Created": "2013-03-23T22:24:18.818426-07:00", + "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", "ContainerConfig": { - "Hostname":"", - "User":"", - "Memory":0, - "MemorySwap":0, - "AttachStdin":false, - "AttachStdout":false, - "AttachStderr":false, - "PortSpecs":null, - "Tty":true, - "OpenStdin":true, - "StdinOnce":false, - "Env":null, + "Hostname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "PortSpecs": null, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": null, "Cmd": ["/bin/bash"], - "Dns":null, - "Image":"base", - "Volumes":null, - "VolumesFrom":"", - "WorkingDir":"" + "Dns": null, + "Image": "ubuntu", + "Volumes": null, + "VolumesFrom": "", + "WorkingDir": "" }, - "Id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", - "Parent":"27cf784147099545", + "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "Parent": "27cf784147099545", "Size": 6824592 } @@ -936,7 +979,7 @@ Return the history of the image `name` **Example request**: - GET /images/base/history HTTP/1.1 + GET /images/ubuntu/history HTTP/1.1 **Example response**: @@ -945,14 +988,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -977,9 +1020,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... If you wish to push an image on to a private registry, that image must already have been tagged @@ -1050,9 +1093,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Query Parameters: @@ -1139,9 +1182,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1155,6 +1198,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **pull** - attempt to pull the image even if an older image exists locally @@ -1183,10 +1227,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1218,6 +1262,7 @@ Display system-wide information "Containers":11, "Images":16, "Driver":"btrfs", + "DriverStatus": [[""]], "ExecutionDriver":"native-0.1", "KernelVersion":"3.12.0-1-amd64" "NCPU":1, @@ -1229,11 +1274,14 @@ Display system-wide information "NGoroutines":21, "NEventsListener":0, "InitPath":"/usr/bin/docker", + "InitSha1":"", "IndexServerAddress":["https://index.docker.io/v1/"], "MemoryLimit":true, "SwapLimit":false, "IPv4Forwarding":true, - "Labels":["storage=ssd"] + "Labels":["storage=ssd"], + "DockerRootDir": "/var/lib/docker", + "OperatingSystem": "Boot2Docker", } Status Codes: @@ -1257,10 +1305,10 @@ Show the docker version information Content-Type: application/json { - "ApiVersion":"1.12", - "Version":"0.2.2", - "GitCommit":"5a2a5cc+CHANGES", - "GoVersion":"go1.0.3" + "ApiVersion": "1.12", + "Version": "0.2.2", + "GitCommit": "5a2a5cc+CHANGES", + "GoVersion": "go1.0.3" } Status Codes: @@ -1302,30 +1350,30 @@ Create a new image from a container's changes Content-Type: application/json { - "Hostname":"", + "Hostname": "", "Domainname": "", - "User":"", - "Memory":0, - "MemorySwap":0, + "User": "", + "Memory": 0, + "MemorySwap": 0, "CpuShares": 512, "Cpuset": "0,1", - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "PortSpecs":null, - "Tty":false, - "OpenStdin":false, - "StdinOnce":false, - "Env":null, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ "date" ], - "Volumes":{ + "Volumes": { "/tmp": {} }, - "WorkingDir":"", + "WorkingDir": "", "NetworkDisabled": false, - "ExposedPorts":{ + "ExposedPorts": { "22/tcp": {} } } @@ -1335,7 +1383,7 @@ Create a new image from a container's changes HTTP/1.1 201 Created Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1380,16 +1428,19 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} Query Parameters: - **since** – timestamp used for polling - **until** – timestamp used for polling -- **filters** – a json encoded value of the filters (a map[string][]string) to process on the event list. +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the event list. Available filters: + - event=<string> -- event to filter + - image=<string> -- image to filter + - container=<string> -- container to filter Status Codes: @@ -1494,7 +1545,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` @@ -1510,11 +1561,11 @@ Sets up an exec instance in a running container `id` Content-Type: application/json { - "AttachStdin":false, - "AttachStdout":true, - "AttachStderr":true, - "Tty":false, - "Cmd":[ + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "Tty": false, + "Cmd": [ "date" ], } @@ -1525,7 +1576,7 @@ Sets up an exec instance in a running container `id` Content-Type: application/json { - "Id":"f90e34656806" + "Id": "f90e34656806" } Json Parameters: @@ -1556,8 +1607,8 @@ interactive session with the `exec` command. Content-Type: application/json { - "Detach":false, - "Tty":false, + "Detach": false, + "Tty": false, } **Example response**: diff --git a/docs/sources/reference/api/docker_remote_api_v1.17.md b/docs/sources/reference/api/docker_remote_api_v1.17.md new file mode 100644 index 000000000..955ae8fb5 --- /dev/null +++ b/docs/sources/reference/api/docker_remote_api_v1.17.md @@ -0,0 +1,1975 @@ +page_title: Remote API v1.17 +page_description: API Documentation for Docker +page_keywords: API, Docker, rcli, REST, documentation + +# Docker Remote API v1.17 + +## 1. Brief introduction + + - The Remote API has replaced `rcli`. + - The daemon listens on `unix:///var/run/docker.sock` but you can + [Bind Docker to another host/port or a Unix socket]( + /articles/basics/#bind-docker-to-another-hostport-or-a-unix-socket). + - The API tends to be REST, but for some complex commands, like `attach` + or `pull`, the HTTP connection is hijacked to transport `STDOUT`, + `STDIN` and `STDERR`. + +# 2. Endpoints + +## 2.1 Containers + +### List containers + +`GET /containers/json` + +List containers + +**Example request**: + + GET /containers/json?all=1&before=8dfafdbc3a40&size=1 HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "Id": "8dfafdbc3a40", + "Image": "ubuntu:latest", + "Command": "echo 1", + "Created": 1367854155, + "Status": "Exit 0", + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 + }, + { + "Id": "9cd87474be90", + "Image": "ubuntu:latest", + "Command": "echo 222222", + "Created": 1367854155, + "Status": "Exit 0", + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 + }, + { + "Id": "3176a2479c92", + "Image": "ubuntu:latest", + "Command": "echo 3333333333333333", + "Created": 1367854154, + "Status": "Exit 0", + "Ports":[], + "SizeRw":12288, + "SizeRootFs":0 + }, + { + "Id": "4cb07b47f9fb", + "Image": "ubuntu:latest", + "Command": "echo 444444444444444444444444444444444", + "Created": 1367854152, + "Status": "Exit 0", + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 + } + ] + +Query Parameters: + +- **all** – 1/True/true or 0/False/false, Show all containers. + Only running containers are shown by default (i.e., this defaults to false) +- **limit** – Show `limit` last created + containers, include non-running ones. +- **since** – Show only containers created since Id, include + non-running ones. +- **before** – Show only containers created before Id, include + non-running ones. +- **size** – 1/True/true or 0/False/false, Show the containers + sizes +- **filters** - a json encoded value of the filters (a map[string][]string) to process on the containers list. Available filters: + - exited=<int> -- containers with exit code of <int> + - status=(restarting|running|paused|exited) + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **500** – server error + +### Create a container + +`POST /containers/create` + +Create a container + +**Example request**: + + POST /containers/create HTTP/1.1 + Content-Type: application/json + + { + "Hostname": "", + "Domainname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "CpuShares": 512, + "Cpuset": "0,1", + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ + "date" + ], + "Entrypoint": "", + "Image": "ubuntu", + "Volumes": { + "/tmp": {} + }, + "WorkingDir": "", + "NetworkDisabled": false, + "MacAddress": "12:34:56:78:9a:bc", + "ExposedPorts": { + "22/tcp": {} + }, + "SecurityOpts": [""], + "HostConfig": { + "Binds": ["/tmp:/tmp"], + "Links": ["redis3:redis"], + "LxcConf": {"lxc.utsname":"docker"}, + "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] }, + "PublishAllPorts": false, + "Privileged": false, + "ReadonlyRootfs": false, + "Dns": ["8.8.8.8"], + "DnsSearch": [""], + "ExtraHosts": null, + "VolumesFrom": ["parent", "other:ro"], + "CapAdd": ["NET_ADMIN"], + "CapDrop": ["MKNOD"], + "RestartPolicy": { "Name": "", "MaximumRetryCount": 0 }, + "NetworkMode": "bridge", + "Devices": [] + } + } + +**Example response**: + + HTTP/1.1 201 Created + Content-Type: application/json + + { + "Id":"e90e34656806" + "Warnings":[] + } + +Json Parameters: + +- **Hostname** - A string value containing the desired hostname to use for the + container. +- **Domainname** - A string value containing the desired domain name to use + for the container. +- **User** - A string value containg the user to use inside the container. +- **Memory** - Memory limit in bytes. +- **MemorySwap**- Total memory usage (memory + swap); set `-1` to disable swap. +- **CpuShares** - An integer value containing the CPU Shares for container + (ie. the relative weight vs othercontainers). + **CpuSet** - String value containg the cgroups Cpuset to use. +- **AttachStdin** - Boolean value, attaches to stdin. +- **AttachStdout** - Boolean value, attaches to stdout. +- **AttachStderr** - Boolean value, attaches to stderr. +- **Tty** - Boolean value, Attach standard streams to a tty, including stdin if it is not closed. +- **OpenStdin** - Boolean value, opens stdin, +- **StdinOnce** - Boolean value, close stdin after the 1 attached client disconnects. +- **Env** - A list of environment variables in the form of `VAR=value` +- **Cmd** - Command to run specified as a string or an array of strings. +- **Entrypoint** - Set the entrypoint for the container a a string or an array + of strings +- **Image** - String value containing the image name to use for the container +- **Volumes** – An object mapping mountpoint paths (strings) inside the + container to empty objects. +- **WorkingDir** - A string value containing the working dir for commands to + run in. +- **NetworkDisabled** - Boolean value, when true disables neworking for the + container +- **ExposedPorts** - An object mapping ports to an empty object in the form of: + `"ExposedPorts": { "/: {}" }` +- **SecurityOpts**: A list of string values to customize labels for MLS + systems, such as SELinux. +- **HostConfig** + - **Binds** – A list of volume bindings for this container. Each volume + binding is a string of the form `container_path` (to create a new + volume for the container), `host_path:container_path` (to bind-mount + a host path into the container), or `host_path:container_path:ro` + (to make the bind-mount read-only inside the container). + - **Links** - A list of links for the container. Each link entry should be of + of the form "container_name:alias". + - **LxcConf** - LXC specific configurations. These configurations will only + work when using the `lxc` execution driver. + - **PortBindings** - A map of exposed container ports and the host port they + should map to. It should be specified in the form + `{ /: [{ "HostPort": "" }] }` + Take note that `port` is specified as a string and not an integer value. + - **PublishAllPorts** - Allocates a random host port for all of a container's + exposed ports. Specified as a boolean value. + - **Privileged** - Gives the container full access to the host. Specified as + a boolean value. + - **ReadonlyRootfs** - Mount the container's root filesystem as read only. + Specified as a boolean value. + - **Dns** - A list of dns servers for the container to use. + - **DnsSearch** - A list of DNS search domains + - **ExtraHosts** - A list of hostnames/IP mappings to be added to the + container's `/etc/hosts` file. Specified in the form `["hostname:IP"]`. + - **VolumesFrom** - A list of volumes to inherit from another container. + Specified in the form `[:]` + - **CapAdd** - A list of kernel capabilties to add to the container. + - **Capdrop** - A list of kernel capabilties to drop from the container. + - **RestartPolicy** – The behavior to apply when the container exits. The + value is an object with a `Name` property of either `"always"` to + always restart or `"on-failure"` to restart only when the container + exit code is non-zero. If `on-failure` is used, `MaximumRetryCount` + controls the number of times to retry before giving up. + The default is not to restart. (optional) + An ever increasing delay (double the previous delay, starting at 100mS) + is added before each restart to prevent flooding the server. + - **NetworkMode** - Sets the networking mode for the container. Supported + values are: `bridge`, `host`, and `container:` + - **Devices** - A list of devices to add to the container specified in the + form + `{ "PathOnHost": "/dev/deviceName", "PathInContainer": "/dev/deviceName", "CgroupPermissions": "mrw"}` + +Query Parameters: + +- **name** – Assign the specified name to the container. Must + match `/?[a-zA-Z0-9_-]+`. + +Status Codes: + +- **201** – no error +- **404** – no such container +- **406** – impossible to attach (container not running) +- **500** – server error + +### Inspect a container + +`GET /containers/(id)/json` + +Return low-level information on the container `id` + + +**Example request**: + + GET /containers/4fa6e0f0c678/json HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "AppArmorProfile": "", + "Args": [ + "-c", + "exit 9" + ], + "Config": { + "AttachStderr": true, + "AttachStdin": false, + "AttachStdout": true, + "Cmd": [ + "/bin/sh", + "-c", + "exit 9" + ], + "CpuShares": 0, + "Cpuset": "", + "Domainname": "", + "Entrypoint": null, + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "ExposedPorts": null, + "Hostname": "ba033ac44011", + "Image": "ubuntu", + "MacAddress": "", + "Memory": 0, + "MemorySwap": 0, + "NetworkDisabled": false, + "OnBuild": null, + "OpenStdin": false, + "PortSpecs": null, + "StdinOnce": false, + "Tty": false, + "User": "", + "Volumes": null, + "WorkingDir": "" + }, + "Created": "2015-01-06T15:47:31.485331387Z", + "Driver": "devicemapper", + "ExecDriver": "native-0.2", + "ExecIDs": null, + "HostConfig": { + "Binds": null, + "CapAdd": null, + "CapDrop": null, + "ContainerIDFile": "", + "Devices": [], + "Dns": null, + "DnsSearch": null, + "ExtraHosts": null, + "IpcMode": "", + "Links": null, + "LxcConf": [], + "NetworkMode": "bridge", + "PortBindings": {}, + "Privileged": false, + "ReadonlyRootfs": false, + "PublishAllPorts": false, + "RestartPolicy": { + "MaximumRetryCount": 2, + "Name": "on-failure" + }, + "SecurityOpt": null, + "VolumesFrom": null + }, + "HostnamePath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname", + "HostsPath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts", + "Id": "ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39", + "Image": "04c5d3b7b0656168630d3ba35d8889bd0e9caafcaeb3004d2bfbc47e7c5d35d2", + "MountLabel": "", + "Name": "/boring_euclid", + "NetworkSettings": { + "Bridge": "", + "Gateway": "", + "IPAddress": "", + "IPPrefixLen": 0, + "MacAddress": "", + "PortMapping": null, + "Ports": null + }, + "Path": "/bin/sh", + "ProcessLabel": "", + "ResolvConfPath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/resolv.conf", + "RestartCount": 1, + "State": { + "Error": "", + "ExitCode": 9, + "FinishedAt": "2015-01-06T15:47:32.080254511Z", + "OOMKilled": false, + "Paused": false, + "Pid": 0, + "Restarting": false, + "Running": false, + "StartedAt": "2015-01-06T15:47:32.072697474Z" + }, + "Volumes": {}, + "VolumesRW": {} + } + +Status Codes: + +- **200** – no error +- **404** – no such container +- **500** – server error + +### List processes running inside a container + +`GET /containers/(id)/top` + +List processes running inside the container `id` + +**Example request**: + + GET /containers/4fa6e0f0c678/top HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "Titles": [ + "USER", + "PID", + "%CPU", + "%MEM", + "VSZ", + "RSS", + "TTY", + "STAT", + "START", + "TIME", + "COMMAND" + ], + "Processes": [ + ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], + ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] + ] + } + +Query Parameters: + +- **ps_args** – ps arguments to use (e.g., aux) + +Status Codes: + +- **200** – no error +- **404** – no such container +- **500** – server error + +### Get container logs + +`GET /containers/(id)/logs` + +Get stdout and stderr logs from the container ``id`` + +**Example request**: + + GET /containers/4fa6e0f0c678/logs?stderr=1&stdout=1×tamps=1&follow=1&tail=10 HTTP/1.1 + +**Example response**: + + HTTP/1.1 101 UPGRADED + Content-Type: application/vnd.docker.raw-stream + Connection: Upgrade + Upgrade: tcp + + {{ STREAM }} + +Query Parameters: + +- **follow** – 1/True/true or 0/False/false, return stream. Default false +- **stdout** – 1/True/true or 0/False/false, show stdout log. Default false +- **stderr** – 1/True/true or 0/False/false, show stderr log. Default false +- **timestamps** – 1/True/true or 0/False/false, print timestamps for + every log line. Default false +- **tail** – Output specified number of lines at the end of logs: `all` or ``. Default all + +Status Codes: + +- **101** – no error, hints proxy about hijacking +- **200** – no error, no upgrade header found +- **404** – no such container +- **500** – server error + +### Inspect changes on a container's filesystem + +`GET /containers/(id)/changes` + +Inspect changes on container `id`'s filesystem + +**Example request**: + + GET /containers/4fa6e0f0c678/changes HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "Path": "/dev", + "Kind": 0 + }, + { + "Path": "/dev/kmsg", + "Kind": 1 + }, + { + "Path": "/test", + "Kind": 1 + } + ] + +Status Codes: + +- **200** – no error +- **404** – no such container +- **500** – server error + +### Export a container + +`GET /containers/(id)/export` + +Export the contents of container `id` + +**Example request**: + + GET /containers/4fa6e0f0c678/export HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/octet-stream + + {{ TAR STREAM }} + +Status Codes: + +- **200** – no error +- **404** – no such container +- **500** – server error + +### Get container stats based on resource usage + +`GET /containers/(id)/stats` + +This endpoint returns a live stream of a container's resource usage statistics. + +> **Note**: this functionality currently only works when using the *libcontainer* exec-driver. + +**Example request**: + + GET /containers/redis1/stats HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "read" : "2015-01-08T22:57:31.547920715Z", + "network" : { + "rx_dropped" : 0, + "rx_bytes" : 648, + "rx_errors" : 0, + "tx_packets" : 8, + "tx_dropped" : 0, + "rx_packets" : 8, + "tx_errors" : 0, + "tx_bytes" : 648 + }, + "memory_stats" : { + "stats" : { + "total_pgmajfault" : 0, + "cache" : 0, + "mapped_file" : 0, + "total_inactive_file" : 0, + "pgpgout" : 414, + "rss" : 6537216, + "total_mapped_file" : 0, + "writeback" : 0, + "unevictable" : 0, + "pgpgin" : 477, + "total_unevictable" : 0, + "pgmajfault" : 0, + "total_rss" : 6537216, + "total_rss_huge" : 6291456, + "total_writeback" : 0, + "total_inactive_anon" : 0, + "rss_huge" : 6291456, + "hierarchical_memory_limit" : 67108864, + "total_pgfault" : 964, + "total_active_file" : 0, + "active_anon" : 6537216, + "total_active_anon" : 6537216, + "total_pgpgout" : 414, + "total_cache" : 0, + "inactive_anon" : 0, + "active_file" : 0, + "pgfault" : 964, + "inactive_file" : 0, + "total_pgpgin" : 477 + }, + "max_usage" : 6651904, + "usage" : 6537216, + "failcnt" : 0, + "limit" : 67108864 + }, + "blkio_stats" : {}, + "cpu_stats" : { + "cpu_usage" : { + "percpu_usage" : [ + 16970827, + 1839451, + 7107380, + 10571290 + ], + "usage_in_usermode" : 10000000, + "total_usage" : 36488948, + "usage_in_kernelmode" : 20000000 + }, + "system_cpu_usage" : 20091722000000000, + "throttling_data" : {} + } + } + +Status Codes: + +- **200** – no error +- **404** – no such container +- **500** – server error + +### Resize a container TTY + +`POST /containers/(id)/resize?h=&w=` + +Resize the TTY for container with `id`. The container must be restarted for the resize to take effect. + +**Example request**: + + POST /containers/4fa6e0f0c678/resize?h=40&w=80 HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Length: 0 + Content-Type: text/plain; charset=utf-8 + +Status Codes: + +- **200** – no error +- **404** – No such container +- **500** – Cannot resize container + +### Start a container + +`POST /containers/(id)/start` + +Start the container `id` + +**Example request**: + + POST /containers/(id)/start HTTP/1.1 + Content-Type: application/json + +**Example response**: + + HTTP/1.1 204 No Content + +Json Parameters: + +Status Codes: + +- **204** – no error +- **304** – container already started +- **404** – no such container +- **500** – server error + +### Stop a container + +`POST /containers/(id)/stop` + +Stop the container `id` + +**Example request**: + + POST /containers/e90e34656806/stop?t=5 HTTP/1.1 + +**Example response**: + + HTTP/1.1 204 No Content + +Query Parameters: + +- **t** – number of seconds to wait before killing the container + +Status Codes: + +- **204** – no error +- **304** – container already stopped +- **404** – no such container +- **500** – server error + +### Restart a container + +`POST /containers/(id)/restart` + +Restart the container `id` + +**Example request**: + + POST /containers/e90e34656806/restart?t=5 HTTP/1.1 + +**Example response**: + + HTTP/1.1 204 No Content + +Query Parameters: + +- **t** – number of seconds to wait before killing the container + +Status Codes: + +- **204** – no error +- **404** – no such container +- **500** – server error + +### Kill a container + +`POST /containers/(id)/kill` + +Kill the container `id` + +**Example request**: + + POST /containers/e90e34656806/kill HTTP/1.1 + +**Example response**: + + HTTP/1.1 204 No Content + +Query Parameters + +- **signal** - Signal to send to the container: integer or string like "SIGINT". + When not set, SIGKILL is assumed and the call will waits for the container to exit. + +Status Codes: + +- **204** – no error +- **404** – no such container +- **500** – server error + +### Rename a container + +`POST /containers/(id)/rename` + +Rename the container `id` to a `new_name` + +**Example request**: + + POST /containers/e90e34656806/rename?name=new_name HTTP/1.1 + +**Example response**: + + HTTP/1.1 204 No Content + +Query Parameters: + +- **name** – new name for the container + +Status Codes: + +- **204** – no error +- **404** – no such container +- **409** - conflict name already assigned +- **500** – server error + +### Pause a container + +`POST /containers/(id)/pause` + +Pause the container `id` + +**Example request**: + + POST /containers/e90e34656806/pause HTTP/1.1 + +**Example response**: + + HTTP/1.1 204 No Content + +Status Codes: + +- **204** – no error +- **404** – no such container +- **500** – server error + +### Unpause a container + +`POST /containers/(id)/unpause` + +Unpause the container `id` + +**Example request**: + + POST /containers/e90e34656806/unpause HTTP/1.1 + +**Example response**: + + HTTP/1.1 204 No Content + +Status Codes: + +- **204** – no error +- **404** – no such container +- **500** – server error + +### Attach to a container + +`POST /containers/(id)/attach` + +Attach to the container `id` + +**Example request**: + + POST /containers/16253994b7c4/attach?logs=1&stream=0&stdout=1 HTTP/1.1 + +**Example response**: + + HTTP/1.1 101 UPGRADED + Content-Type: application/vnd.docker.raw-stream + Connection: Upgrade + Upgrade: tcp + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **101** – no error, hints proxy about hijacking +- **200** – no error, no upgrade header found +- **400** – bad parameter +- **404** – no such container +- **500** – server error + + **Stream details**: + + When using the TTY setting is enabled in + [`POST /containers/create` + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), + the stream is the raw data from the process PTY and client's stdin. + When the TTY is disabled, then the stream is multiplexed to separate + stdout and stderr. + + The format is a **Header** and a **Payload** (frame). + + **HEADER** + + The header will contain the information on which stream write the + stream (stdout or stderr). It also contain the size of the + associated frame encoded on the last 4 bytes (uint32). + + It is encoded on the first 8 bytes like this: + + header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4} + + `STREAM_TYPE` can be: + +- 0: stdin (will be written on stdout) +- 1: stdout +- 2: stderr + + `SIZE1, SIZE2, SIZE3, SIZE4` are the 4 bytes of + the uint32 size encoded as big endian. + + **PAYLOAD** + + The payload is the raw stream. + + **IMPLEMENTATION** + + The simplest way to implement the Attach protocol is the following: + + 1. Read 8 bytes + 2. chose stdout or stderr depending on the first byte + 3. Extract the frame size from the last 4 byets + 4. Read the extracted size and output it on the correct output + 5. Goto 1 + +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + +### Wait a container + +`POST /containers/(id)/wait` + +Block until container `id` stops, then returns the exit code + +**Example request**: + + POST /containers/16253994b7c4/wait HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + {"StatusCode": 0} + +Status Codes: + +- **200** – no error +- **404** – no such container +- **500** – server error + +### Remove a container + +`DELETE /containers/(id)` + +Remove the container `id` from the filesystem + +**Example request**: + + DELETE /containers/16253994b7c4?v=1 HTTP/1.1 + +**Example response**: + + HTTP/1.1 204 No Content + +Query Parameters: + +- **v** – 1/True/true or 0/False/false, Remove the volumes + associated to the container. Default false +- **force** - 1/True/true or 0/False/false, Kill then remove the container. + Default false + +Status Codes: + +- **204** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + +### Copy files or folders from a container + +`POST /containers/(id)/copy` + +Copy files or folders of container `id` + +**Example request**: + + POST /containers/4fa6e0f0c678/copy HTTP/1.1 + Content-Type: application/json + + { + "Resource": "test.txt" + } + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/x-tar + + {{ TAR STREAM }} + +Status Codes: + +- **200** – no error +- **404** – no such container +- **500** – server error + +## 2.2 Images + +### List Images + +`GET /images/json` + +**Example request**: + + GET /images/json?all=0 HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "RepoTags": [ + "ubuntu:12.04", + "ubuntu:precise", + "ubuntu:latest" + ], + "Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c", + "Created": 1365714795, + "Size": 131506275, + "VirtualSize": 131506275 + }, + { + "RepoTags": [ + "ubuntu:12.10", + "ubuntu:quantal" + ], + "ParentId": "27cf784147099545", + "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "Created": 1364102658, + "Size": 24653, + "VirtualSize": 180116135 + } + ] + + +Query Parameters: + +- **all** – 1/True/true or 0/False/false, default false +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. Available filters: + - dangling=true + +### Build image from a Dockerfile + +`POST /build` + +Build an image from a Dockerfile + +**Example request**: + + POST /build HTTP/1.1 + + {{ TAR STREAM }} + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} + +The input stream must be a tar archive compressed with one of the +following algorithms: identity (no compression), gzip, bzip2, xz. + +The archive must include a build instructions file, typically called +`Dockerfile` at the root of the archive. The `dockerfile` parameter may be +used to specify a different build instructions file by having its value be +the path to the alternate build instructions file to use. + +The archive may include any number of other files, +which will be accessible in the build context (See the [*ADD build +command*](/reference/builder/#dockerbuilder)). + +Query Parameters: + +- **dockerfile** - path within the build context to the Dockerfile +- **t** – repository name (and optionally a tag) to be applied to + the resulting image in case of success +- **remote** – git or HTTP/HTTPS URI build source +- **q** – suppress verbose build output +- **nocache** – do not use the cache when building the image +- **pull** - attempt to pull the image even if an older image exists locally +- **rm** - remove intermediate containers after a successful build (default behavior) +- **forcerm** - always remove intermediate containers (includes rm) + + Request Headers: + +- **Content-type** – should be set to `"application/tar"`. +- **X-Registry-Config** – base64-encoded ConfigFile objec + +Status Codes: + +- **200** – no error +- **500** – server error + +### Create an image + +`POST /images/create` + +Create an image, either by pulling it from the registry or by importing it + +**Example request**: + + POST /images/create?fromImage=ubuntu HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} + ... + + When using this endpoint to pull an image from the registry, the + `X-Registry-Auth` header can be used to include + a base64-encoded AuthConfig object. + +Query Parameters: + +- **fromImage** – name of the image to pull +- **fromSrc** – source to import. The value may be a URL from which the image + can be retrieved or `-` to read the image from the request body. +- **repo** – repository +- **tag** – tag +- **registry** – the registry to pull from + + Request Headers: + +- **X-Registry-Auth** – base64-encoded AuthConfig object + +Status Codes: + +- **200** – no error +- **500** – server error + + + +### Inspect an image + +`GET /images/(name)/json` + +Return low-level information on the image `name` + +**Example request**: + + GET /images/ubuntu/json HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "Created": "2013-03-23T22:24:18.818426-07:00", + "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", + "ContainerConfig": + { + "Hostname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "PortSpecs": null, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": null, + "Cmd": ["/bin/bash"], + "Dns": null, + "Image": "ubuntu", + "Volumes": null, + "VolumesFrom": "", + "WorkingDir": "" + }, + "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "Parent": "27cf784147099545", + "Size": 6824592 + } + +Status Codes: + +- **200** – no error +- **404** – no such image +- **500** – server error + +### Get the history of an image + +`GET /images/(name)/history` + +Return the history of the image `name` + +**Example request**: + + GET /images/ubuntu/history HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" + }, + { + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" + } + ] + +Status Codes: + +- **200** – no error +- **404** – no such image +- **500** – server error + +### Push an image on the registry + +`POST /images/(name)/push` + +Push the image `name` on the registry + +**Example request**: + + POST /images/test/push HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} + ... + + If you wish to push an image on to a private registry, that image must already have been tagged + into a repository which references that registry host name and port. This repository name should + then be used in the URL. This mirrors the flow of the CLI. + +**Example request**: + + POST /images/registry.acme.com:5000/test/push HTTP/1.1 + + +Query Parameters: + +- **tag** – the tag to associate with the image on the registry, optional + +Request Headers: + +- **X-Registry-Auth** – include a base64-encoded AuthConfig + object. + +Status Codes: + +- **200** – no error +- **404** – no such image +- **500** – server error + +### Tag an image into a repository + +`POST /images/(name)/tag` + +Tag the image `name` into a repository + +**Example request**: + + POST /images/test/tag?repo=myrepo&force=0&tag=v42 HTTP/1.1 + +**Example response**: + + HTTP/1.1 201 OK + +Query Parameters: + +- **repo** – The repository to tag in +- **force** – 1/True/true or 0/False/false, default false +- **tag** - The new tag name + +Status Codes: + +- **201** – no error +- **400** – bad parameter +- **404** – no such image +- **409** – conflict +- **500** – server error + +### Remove an image + +`DELETE /images/(name)` + +Remove the image `name` from the filesystem + +**Example request**: + + DELETE /images/test HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-type: application/json + + [ + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} + ] + +Query Parameters: + +- **force** – 1/True/true or 0/False/false, default false +- **noprune** – 1/True/true or 0/False/false, default false + +Status Codes: + +- **200** – no error +- **404** – no such image +- **409** – conflict +- **500** – server error + +### Search images + +`GET /images/search` + +Search for an image on [Docker Hub](https://hub.docker.com). + +> **Note**: +> The response keys have changed from API v1.6 to reflect the JSON +> sent by the registry server to the docker daemon's request. + +**Example request**: + + GET /images/search?term=sshd HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + [ + { + "description": "", + "is_official": false, + "is_automated": false, + "name": "wma55/u1210sshd", + "star_count": 0 + }, + { + "description": "", + "is_official": false, + "is_automated": false, + "name": "jdswinbank/sshd", + "star_count": 0 + }, + { + "description": "", + "is_official": false, + "is_automated": false, + "name": "vgauthier/sshd", + "star_count": 0 + } + ... + ] + +Query Parameters: + +- **term** – term to search + +Status Codes: + +- **200** – no error +- **500** – server error + +## 2.3 Misc + +### Check auth configuration + +`POST /auth` + +Get the default username and email + +**Example request**: + + POST /auth HTTP/1.1 + Content-Type: application/json + + { + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" + } + +**Example response**: + + HTTP/1.1 200 OK + +Status Codes: + +- **200** – no error +- **204** – no error +- **500** – server error + +### Display system-wide information + +`GET /info` + +Display system-wide information + +**Example request**: + + GET /info HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "Containers":11, + "Images":16, + "Driver":"btrfs", + "DriverStatus": [[""]], + "ExecutionDriver":"native-0.1", + "KernelVersion":"3.12.0-1-amd64" + "NCPU":1, + "MemTotal":2099236864, + "Name":"prod-server-42", + "ID":"7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS", + "Debug":false, + "NFd": 11, + "NGoroutines":21, + "NEventsListener":0, + "InitPath":"/usr/bin/docker", + "InitSha1":"", + "IndexServerAddress":["https://index.docker.io/v1/"], + "MemoryLimit":true, + "SwapLimit":false, + "IPv4Forwarding":true, + "Labels":["storage=ssd"], + "DockerRootDir": "/var/lib/docker", + "OperatingSystem": "Boot2Docker", + } + +Status Codes: + +- **200** – no error +- **500** – server error + +### Show the docker version information + +`GET /version` + +Show the docker version information + +**Example request**: + + GET /version HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "ApiVersion": "1.12", + "Version": "0.2.2", + "GitCommit": "5a2a5cc+CHANGES", + "GoVersion": "go1.0.3" + } + +Status Codes: + +- **200** – no error +- **500** – server error + +### Ping the docker server + +`GET /_ping` + +Ping the docker server + +**Example request**: + + GET /_ping HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: text/plain + + OK + +Status Codes: + +- **200** - no error +- **500** - server error + +### Create a new image from a container's changes + +`POST /commit` + +Create a new image from a container's changes + +**Example request**: + + POST /commit?container=44c004db4b17&comment=message&repo=myrepo HTTP/1.1 + Content-Type: application/json + + { + "Hostname": "", + "Domainname": "", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "CpuShares": 512, + "Cpuset": "0,1", + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ + "date" + ], + "Volumes": { + "/tmp": {} + }, + "WorkingDir": "", + "NetworkDisabled": false, + "ExposedPorts": { + "22/tcp": {} + } + } + +**Example response**: + + HTTP/1.1 201 Created + Content-Type: application/vnd.docker.raw-stream + + {"Id": "596069db4bf5"} + +Json Parameters: + +- **config** - the container's configuration + +Query Parameters: + +- **container** – source container +- **repo** – repository +- **tag** – tag +- **comment** – commit message +- **author** – author (e.g., "John Hannibal Smith + <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") + +Status Codes: + +- **201** – no error +- **404** – no such container +- **500** – server error + +### Monitor Docker's events + +`GET /events` + +Get container events from docker, either in real time via streaming, or via +polling (using since). + +Docker containers will report the following events: + + create, destroy, die, exec_create, exec_start, export, kill, oom, pause, restart, start, stop, unpause + +and Docker images will report: + + untag, delete + +**Example request**: + + GET /events?since=1374067924 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/json + + {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} + +Query Parameters: + +- **since** – timestamp used for polling +- **until** – timestamp used for polling +- **filters** – a json encoded value of the filters (a map[string][]string) to process on the event list. Available filters: + - event=<string> -- event to filter + - image=<string> -- image to filter + - container=<string> -- container to filter + +Status Codes: + +- **200** – no error +- **500** – server error + +### Get a tarball containing all images in a repository + +`GET /images/(name)/get` + +Get a tarball containing all images and metadata for the repository specified +by `name`. + +If `name` is a specific name and tag (e.g. ubuntu:latest), then only that image +(and its parents) are returned. If `name` is an image ID, similarly only tha +image (and its parents) are returned, but with the exclusion of the +'repositories' file in the tarball, as there were no image names referenced. + +See the [image tarball format](#image-tarball-format) for more details. + +**Example request** + + GET /images/ubuntu/get + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/x-tar + + Binary data stream + +Status Codes: + +- **200** – no error +- **500** – server error + +### Get a tarball containing all images. + +`GET /images/get` + +Get a tarball containing all images and metadata for one or more repositories. + +For each value of the `names` parameter: if it is a specific name and tag (e.g. +ubuntu:latest), then only that image (and its parents) are returned; if it is +an image ID, similarly only that image (and its parents) are returned and there +would be no names referenced in the 'repositories' file for this image ID. + +See the [image tarball format](#image-tarball-format) for more details. + +**Example request** + + GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: application/x-tar + + Binary data stream + +Status Codes: + +- **200** – no error +- **500** – server error + +### Load a tarball with a set of images and tags into docker + +`POST /images/load` + +Load a set of images and tags into the docker repository. +See the [image tarball format](#image-tarball-format) for more details. + +**Example request** + + POST /images/load + + Tarball in body + +**Example response**: + + HTTP/1.1 200 OK + +Status Codes: + +- **200** – no error +- **500** – server error + +### Image tarball format + +An image tarball contains one directory per image layer (named using its long ID), +each containing three files: + +1. `VERSION`: currently `1.0` - the file format version +2. `json`: detailed layer information, similar to `docker inspect layer_id` +3. `layer.tar`: A tarfile containing the filesystem changes in this layer + +The `layer.tar` file will contain `aufs` style `.wh..wh.aufs` files and directories +for storing attribute changes and deletions. + +If the tarball defines a repository, there will also be a `repositories` file at +the root that contains a list of repository and tag names mapped to layer IDs. + +``` +{"hello-world": + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} +} +``` + +### Exec Create + +`POST /containers/(id)/exec` + +Sets up an exec instance in a running container `id` + +**Example request**: + + POST /containers/e90e34656806/exec HTTP/1.1 + Content-Type: application/json + + { + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "Tty": false, + "Cmd": [ + "date" + ], + } + +**Example response**: + + HTTP/1.1 201 OK + Content-Type: application/json + + { + "Id": "f90e34656806" + } + +Json Parameters: + +- **AttachStdin** - Boolean value, attaches to stdin of the exec command. +- **AttachStdout** - Boolean value, attaches to stdout of the exec command. +- **AttachStderr** - Boolean value, attaches to stderr of the exec command. +- **Tty** - Boolean value to allocate a pseudo-TTY +- **Cmd** - Command to run specified as a string or an array of strings. + + +Status Codes: + +- **201** – no error +- **404** – no such container + +### Exec Start + +`POST /exec/(id)/start` + +Starts a previously set up exec instance `id`. If `detach` is true, this API +returns after starting the `exec` command. Otherwise, this API sets up an +interactive session with the `exec` command. + +**Example request**: + + POST /exec/e90e34656806/start HTTP/1.1 + Content-Type: application/json + + { + "Detach": false, + "Tty": false, + } + +**Example response**: + + HTTP/1.1 201 OK + Content-Type: application/json + + {{ STREAM }} + +Json Parameters: + +- **Detach** - Detach from the exec command +- **Tty** - Boolean value to allocate a pseudo-TTY + +Status Codes: + +- **201** – no error +- **404** – no such exec instance + + **Stream details**: + Similar to the stream behavior of `POST /container/(id)/attach` API + +### Exec Resize + +`POST /exec/(id)/resize` + +Resizes the tty session used by the exec command `id`. +This API is valid only if `tty` was specified as part of creating and starting the exec command. + +**Example request**: + + POST /exec/e90e34656806/resize HTTP/1.1 + Content-Type: text/plain + +**Example response**: + + HTTP/1.1 201 OK + Content-Type: text/plain + +Query Parameters: + +- **h** – height of tty session +- **w** – width + +Status Codes: + +- **201** – no error +- **404** – no such exec instance + +### Exec Inspect + +`GET /exec/(id)/json` + +Return low-level information about the exec command `id`. + +**Example request**: + + GET /exec/11fb006128e8ceb3942e7c58d77750f24210e35f879dd204ac975c184b820b39/json HTTP/1.1 + +**Example response**: + + HTTP/1.1 200 OK + Content-Type: plain/text + + { + "ID" : "11fb006128e8ceb3942e7c58d77750f24210e35f879dd204ac975c184b820b39", + "Running" : false, + "ExitCode" : 2, + "ProcessConfig" : { + "privileged" : false, + "user" : "", + "tty" : false, + "entrypoint" : "sh", + "arguments" : [ + "-c", + "exit 2" + ] + }, + "OpenStdin" : false, + "OpenStderr" : false, + "OpenStdout" : false, + "Container" : { + "State" : { + "Running" : true, + "Paused" : false, + "Restarting" : false, + "OOMKilled" : false, + "Pid" : 3650, + "ExitCode" : 0, + "Error" : "", + "StartedAt" : "2014-11-17T22:26:03.717657531Z", + "FinishedAt" : "0001-01-01T00:00:00Z" + }, + "ID" : "8f177a186b977fb451136e0fdf182abff5599a08b3c7f6ef0d36a55aaf89634c", + "Created" : "2014-11-17T22:26:03.626304998Z", + "Path" : "date", + "Args" : [], + "Config" : { + "Hostname" : "8f177a186b97", + "Domainname" : "", + "User" : "", + "Memory" : 0, + "MemorySwap" : 0, + "CpuShares" : 0, + "Cpuset" : "", + "AttachStdin" : false, + "AttachStdout" : false, + "AttachStderr" : false, + "PortSpecs" : null, + "ExposedPorts" : null, + "Tty" : false, + "OpenStdin" : false, + "StdinOnce" : false, + "Env" : [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], + "Cmd" : [ + "date" + ], + "Image" : "ubuntu", + "Volumes" : null, + "WorkingDir" : "", + "Entrypoint" : null, + "NetworkDisabled" : false, + "MacAddress" : "", + "OnBuild" : null, + "SecurityOpt" : null + }, + "Image" : "5506de2b643be1e6febbf3b8a240760c6843244c41e12aa2f60ccbb7153d17f5", + "NetworkSettings" : { + "IPAddress" : "172.17.0.2", + "IPPrefixLen" : 16, + "MacAddress" : "02:42:ac:11:00:02", + "Gateway" : "172.17.42.1", + "Bridge" : "docker0", + "PortMapping" : null, + "Ports" : {} + }, + "ResolvConfPath" : "/var/lib/docker/containers/8f177a186b977fb451136e0fdf182abff5599a08b3c7f6ef0d36a55aaf89634c/resolv.conf", + "HostnamePath" : "/var/lib/docker/containers/8f177a186b977fb451136e0fdf182abff5599a08b3c7f6ef0d36a55aaf89634c/hostname", + "HostsPath" : "/var/lib/docker/containers/8f177a186b977fb451136e0fdf182abff5599a08b3c7f6ef0d36a55aaf89634c/hosts", + "Name" : "/test", + "Driver" : "aufs", + "ExecDriver" : "native-0.2", + "MountLabel" : "", + "ProcessLabel" : "", + "AppArmorProfile" : "", + "RestartCount" : 0, + "Volumes" : {}, + "VolumesRW" : {} + } + } + +Status Codes: + +- **200** – no error +- **404** – no such exec instance +- **500** - server error + +# 3. Going further + +## 3.1 Inside `docker run` + +As an example, the `docker run` command line makes the following API calls: + +- Create the container + +- If the status code is 404, it means the image doesn't exist: + - Try to pull it + - Then retry to create the container + +- Start the container + +- If you are not in detached mode: +- Attach to the container, using logs=1 (to have stdout and + stderr from the container's start) and stream=1 + +- If in detached mode or only stdin is attached: +- Display the container's id + +## 3.2 Hijacking + +In this version of the API, /attach, uses hijacking to transport stdin, +stdout and stderr on the same socket. + +To hint potential proxies about connection hijacking, Docker client sends +connection upgrade headers similarly to websocket. + + Upgrade: tcp + Connection: Upgrade + +When Docker daemon detects the `Upgrade` header, it will switch its status code +from **200 OK** to **101 UPGRADED** and resend the same headers. + +This might change in the future. + +## 3.3 CORS Requests + +To enable cross origin requests to the remote api add the flag +"--api-enable-cors" when running docker in daemon mode. + + $ docker -d -H="192.168.1.9:2375" --api-enable-cors diff --git a/docs/sources/reference/api/docker_remote_api_v1.2.md b/docs/sources/reference/api/docker_remote_api_v1.2.md index 4a518aea9..3438eab2d 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.2.md +++ b/docs/sources/reference/api/docker_remote_api_v1.2.md @@ -230,16 +230,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -397,6 +397,41 @@ Status Codes: - **404** – no such container - **500** – server error +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -412,7 +447,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -738,9 +773,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Status Codes: @@ -930,7 +965,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.3.md b/docs/sources/reference/api/docker_remote_api_v1.3.md index 7ae7462bf..5a88d8276 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.3.md +++ b/docs/sources/reference/api/docker_remote_api_v1.3.md @@ -266,16 +266,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -445,6 +445,41 @@ Status Codes: - **404** – no such container - **500** – server error +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -460,7 +495,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -697,14 +732,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -785,9 +820,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Status Codes: @@ -863,6 +898,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – build source URI (git or HTTPS/HTTP) - **q** – suppress verbose build output Status Codes: @@ -978,7 +1014,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.4.md b/docs/sources/reference/api/docker_remote_api_v1.4.md index 5c0a015cc..790c97d07 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.4.md +++ b/docs/sources/reference/api/docker_remote_api_v1.4.md @@ -189,8 +189,7 @@ Return low-level information on the container `id` "Image": "ubuntu", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -235,7 +234,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -248,7 +247,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -281,16 +280,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -461,6 +460,41 @@ Status Codes: - **404** – no such container - **500** – server error +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -476,7 +510,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -522,7 +556,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -743,14 +777,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -828,9 +862,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Status Codes: @@ -906,6 +940,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – build source URI (git or HTTPS/HTTP) - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image @@ -926,10 +961,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1022,7 +1057,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.5.md b/docs/sources/reference/api/docker_remote_api_v1.5.md index 56245c303..c2f0a7add 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.5.md +++ b/docs/sources/reference/api/docker_remote_api_v1.5.md @@ -458,6 +458,41 @@ Status Codes: - **404** – no such container - **500** – server error +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -473,7 +508,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -916,6 +951,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – build source URI (git or HTTPS/HTTP) - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** – remove intermediate containers after a successful build @@ -1032,7 +1068,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.6.md b/docs/sources/reference/api/docker_remote_api_v1.6.md index 9055b2471..d0f9661e5 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.6.md +++ b/docs/sources/reference/api/docker_remote_api_v1.6.md @@ -39,9 +39,9 @@ List containers "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", @@ -49,9 +49,9 @@ List containers "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", @@ -69,9 +69,9 @@ List containers "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -237,8 +237,7 @@ Return low-level information on the container `id` "Image": "base", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -282,7 +281,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -295,7 +294,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -328,16 +327,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -525,7 +524,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](/api/docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -565,6 +564,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1) +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -580,7 +614,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -626,7 +660,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -850,14 +884,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -937,9 +971,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Status Codes: @@ -1015,6 +1049,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – build source URI (git or HTTPS/HTTP) - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image @@ -1035,10 +1070,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1130,7 +1165,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: @@ -1171,10 +1206,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "base:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "base:latest", "time":1374067970} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.7.md b/docs/sources/reference/api/docker_remote_api_v1.7.md index 2f07b2b69..6cdd60374 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.7.md +++ b/docs/sources/reference/api/docker_remote_api_v1.7.md @@ -39,9 +39,9 @@ List containers "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", @@ -49,9 +49,9 @@ List containers "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", @@ -69,9 +69,9 @@ List containers "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -191,8 +191,7 @@ Return low-level information on the container `id` "Image": "base", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -236,7 +235,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -249,7 +248,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -282,16 +281,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -470,7 +469,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](/api/docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.7/#create-a-container), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -510,6 +509,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1) +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -525,7 +559,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -571,7 +605,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -765,14 +799,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -859,9 +893,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Status Codes: @@ -957,6 +991,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – build source URI (git or HTTPS/HTTP) - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image @@ -984,10 +1019,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1073,7 +1108,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: @@ -1116,10 +1151,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "base:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "base:latest", "time":1374067970} Query Parameters: diff --git a/docs/sources/reference/api/docker_remote_api_v1.8.md b/docs/sources/reference/api/docker_remote_api_v1.8.md index faaa71397..409e63a16 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.8.md +++ b/docs/sources/reference/api/docker_remote_api_v1.8.md @@ -39,9 +39,9 @@ List containers "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", @@ -49,9 +49,9 @@ List containers "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", @@ -69,9 +69,9 @@ List containers "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -215,8 +215,7 @@ Return low-level information on the container `id` "Image": "base", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -276,7 +275,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -289,7 +288,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -322,16 +321,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -518,7 +517,7 @@ Status Codes: When using the TTY setting is enabled in [`POST /containers/create` - ](/api/docker_remote_api_v1.9/#post--containers-create "POST /containers/create"), + ](/reference/api/docker_remote_api_v1.9/#create-a-container "POST /containers/create"), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -558,6 +557,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1) +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -573,7 +607,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -619,7 +653,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -690,9 +724,9 @@ Create an image, either by pull it from the registry or by importing i HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -813,14 +847,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -845,9 +879,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... Request Headers: @@ -907,9 +941,9 @@ Remove the image `name` from the filesystem Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Status Codes: @@ -991,9 +1025,9 @@ Build an image from Dockerfile via stdin HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1007,6 +1041,7 @@ Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – build source URI (git or HTTPS/HTTP) - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image @@ -1035,10 +1070,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1124,7 +1159,7 @@ Create a new image from a container's changes HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Query Parameters: @@ -1167,10 +1202,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "base:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "base:latest", "time":1374067970} Query Parameters: @@ -1245,7 +1280,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` diff --git a/docs/sources/reference/api/docker_remote_api_v1.9.md b/docs/sources/reference/api/docker_remote_api_v1.9.md index 4c7301ee1..7ea3fc9ab 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.9.md +++ b/docs/sources/reference/api/docker_remote_api_v1.9.md @@ -39,9 +39,9 @@ List containers. "Command": "echo 1", "Created": 1367854155, "Status": "Exit 0", - "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "9cd87474be90", @@ -49,9 +49,9 @@ List containers. "Command": "echo 222222", "Created": 1367854155, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 }, { "Id": "3176a2479c92", @@ -69,9 +69,9 @@ List containers. "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, "Status": "Exit 0", - "Ports":[], - "SizeRw":12288, - "SizeRootFs":0 + "Ports": [], + "SizeRw": 12288, + "SizeRootFs": 0 } ] @@ -215,8 +215,7 @@ Return low-level information on the container `id` "Image": "base", "Volumes": {}, "VolumesFrom": "", - "WorkingDir":"" - + "WorkingDir": "" }, "State": { "Running": false, @@ -276,7 +275,7 @@ List processes running inside the container `id` Content-Type: application/json { - "Titles":[ + "Titles": [ "USER", "PID", "%CPU", @@ -289,7 +288,7 @@ List processes running inside the container `id` "TIME", "COMMAND" ], - "Processes":[ + "Processes": [ ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"], ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"] ] @@ -322,16 +321,16 @@ Inspect changes on container `id`'s filesystem [ { - "Path":"/dev", - "Kind":0 + "Path": "/dev", + "Kind": 0 }, { - "Path":"/dev/kmsg", - "Kind":1 + "Path": "/dev/kmsg", + "Kind": 1 }, { - "Path":"/test", - "Kind":1 + "Path": "/test", + "Kind": 1 } ] @@ -522,7 +521,7 @@ Status Codes: **Stream details**: When using the TTY setting is enabled in - [`POST /containers/create`](#post--containers-create), the + [`POST /containers/create`](#create-a-container), the stream is the raw data from the process PTY and client's stdin. When the TTY is disabled, then the stream is multiplexed to separate stdout and stderr. @@ -562,6 +561,41 @@ Status Codes: 4. Read the extracted size and output it on the correct output 5. Goto 1) +### Attach to a container (websocket) + +`GET /containers/(id)/attach/ws` + +Attach to the container `id` via websocket + +Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455) + +**Example request** + + GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 + +**Example response** + + {{ STREAM }} + +Query Parameters: + +- **logs** – 1/True/true or 0/False/false, return logs. Default false +- **stream** – 1/True/true or 0/False/false, return stream. + Default false +- **stdin** – 1/True/true or 0/False/false, if stream=true, attach + to stdin. Default false +- **stdout** – 1/True/true or 0/False/false, if logs=true, return + stdout log, if stream=true, attach to stdout. Default false +- **stderr** – 1/True/true or 0/False/false, if logs=true, return + stderr log, if stream=true, attach to stderr. Default false + +Status Codes: + +- **200** – no error +- **400** – bad parameter +- **404** – no such container +- **500** – server error + ### Wait a container `POST /containers/(id)/wait` @@ -577,7 +611,7 @@ Block until container `id` stops, then returns the exit code HTTP/1.1 200 OK Content-Type: application/json - {"StatusCode":0} + {"StatusCode": 0} Status Codes: @@ -623,7 +657,7 @@ Copy files or folders of container `id` Content-Type: application/json { - "Resource":"test.txt" + "Resource": "test.txt" } **Example response**: @@ -694,9 +728,9 @@ Create an image, either by pull it from the registry or by importing i HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pulling..."} - {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}} - {"error":"Invalid..."} + {"status": "Pulling..."} + {"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}} + {"error": "Invalid..."} ... When using this endpoint to pull an image from the registry, the @@ -817,14 +851,14 @@ Return the history of the image `name` [ { - "Id":"b750fe79269d", - "Created":1364102658, - "CreatedBy":"/bin/bash" + "Id": "b750fe79269d", + "Created": 1364102658, + "CreatedBy": "/bin/bash" }, { - "Id":"27cf78414709", - "Created":1364068391, - "CreatedBy":"" + "Id": "27cf78414709", + "Created": 1364068391, + "CreatedBy": "" } ] @@ -849,9 +883,9 @@ Push the image `name` on the registry HTTP/1.1 200 OK Content-Type: application/json - {"status":"Pushing..."} - {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}} - {"error":"Invalid..."} + {"status": "Pushing..."} + {"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}} + {"error": "Invalid..."} ... Request Headers: @@ -910,9 +944,9 @@ Status Codes: Content-type: application/json [ - {"Untagged":"3e2f21a89f"}, - {"Deleted":"3e2f21a89f"}, - {"Deleted":"53b4f83ac9"} + {"Untagged": "3e2f21a89f"}, + {"Deleted": "3e2f21a89f"}, + {"Deleted": "53b4f83ac9"} ] Status Codes: @@ -994,9 +1028,9 @@ Build an image from Dockerfile using a POST body. HTTP/1.1 200 OK Content-Type: application/json - {"stream":"Step 1..."} - {"stream":"..."} - {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}} + {"stream": "Step 1..."} + {"stream": "..."} + {"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}} The stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. @@ -1004,12 +1038,13 @@ Build an image from Dockerfile using a POST body. The archive must include a file called `Dockerfile` at its root. It may include any number of other files, which will be accessible in the build context (See the [*ADD build - command*](/reference/builder/#dockerbuilder)). + command*](/reference/builder/#add)). Query Parameters: - **t** – repository name (and optionally a tag) to be applied to the resulting image in case of success +- **remote** – build source URI (git or HTTPS/HTTP) - **q** – suppress verbose build output - **nocache** – do not use the cache when building the image - **rm** – Remove intermediate containers after a successful build @@ -1036,10 +1071,10 @@ Get the default username and email Content-Type: application/json { - "username":"hannibal", - "password:"xxxx", - "email":"hannibal@a-team.com", - "serveraddress":"https://index.docker.io/v1/" + "username":" hannibal", + "password: "xxxx", + "email": "hannibal@a-team.com", + "serveraddress": "https://index.docker.io/v1/" } **Example response**: @@ -1152,7 +1187,7 @@ Create a new image from a container's changes HTTP/1.1 201 Created Content-Type: application/vnd.docker.raw-stream - {"Id":"596069db4bf5"} + {"Id": "596069db4bf5"} Json Parameters: @@ -1197,10 +1232,10 @@ and Docker images will report: HTTP/1.1 200 OK Content-Type: application/json - {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924} - {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966} - {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970} + {"status": "create", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "start", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924} + {"status": "stop", "id": "dfdf82bd3881","from": "base:latest", "time":1374067966} + {"status": "destroy", "id": "dfdf82bd3881","from": "base:latest", "time":1374067970} Query Parameters: @@ -1275,7 +1310,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. ``` {"hello-world": - {"latest":"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} + {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"} } ``` diff --git a/docs/sources/reference/api/registry_api.md b/docs/sources/reference/api/registry_api.md index 43a463cd5..54a158934 100644 --- a/docs/sources/reference/api/registry_api.md +++ b/docs/sources/reference/api/registry_api.md @@ -514,28 +514,41 @@ Search the Index given a search term. It accepts **Example request**: - GET /v1/search?q=search_term HTTP/1.1 + GET /v1/search?q=search_term&page=1&n=25 HTTP/1.1 Host: index.docker.io Accept: application/json +Query Parameters: + +- **q** – what you want to search for +- **n** - number of results you want returned per page (default: 25, min:1, max:100) +- **page** - page number of results + **Example response**: HTTP/1.1 200 OK Vary: Accept Content-Type: application/json - {"query":"search_term", + {"num_pages": 1, "num_results": 3, "results" : [ {"name": "ubuntu", "description": "An ubuntu image..."}, {"name": "centos", "description": "A centos image..."}, {"name": "fedora", "description": "A fedora image..."} - ] + ], + "page_size": 25, + "query":"search_term", + "page": 1 } -Query Parameters: - -- **q** – what you want to search for +Response Items: +- **num_pages** - Total number of pages returned by query +- **num_results** - Total number of results returned by query +- **results** - List of results for the current page +- **page_size** - How many results returned per page +- **query** - Your search term +- **page** - Current page number Status Codes: diff --git a/docs/sources/reference/api/remote_api_client_libraries.md b/docs/sources/reference/api/remote_api_client_libraries.md index bff2fa30c..d79bbd89a 100644 --- a/docs/sources/reference/api/remote_api_client_libraries.md +++ b/docs/sources/reference/api/remote_api_client_libraries.md @@ -30,6 +30,12 @@ will add the libraries here. + + + + + + diff --git a/docs/sources/reference/builder.md b/docs/sources/reference/builder.md index adc308c9d..d0c928188 100644 --- a/docs/sources/reference/builder.md +++ b/docs/sources/reference/builder.md @@ -79,7 +79,7 @@ guide](/articles/dockerfile_best-practices/#build-cache) for more information): Successfully built 1a5ffc17324d When you're done with your build, you're ready to look into [*Pushing a -repository to its registry*]( /userguide/dockerrepos/#image-push). +repository to its registry*]( /userguide/dockerrepos/#contributing-to-docker-hub). ## Format @@ -93,7 +93,7 @@ be UPPERCASE in order to distinguish them from arguments more easily. Docker runs the instructions in a `Dockerfile` in order. **The first instruction must be \`FROM\`** in order to specify the [*Base -Image*](/terms/image/#base-image-def) from which you are building. +Image*](/terms/image/#base-image) from which you are building. Docker will treat lines that *begin* with `#` as a comment. A `#` marker anywhere else in the line will @@ -113,7 +113,7 @@ was no formal definition on as to which instructions handled environment replacement at the time. After 1.3 this behavior will be preserved and canonical. -Environment variables (declared with the `ENV` statement) can also be used in +Environment variables (declared with [the `ENV` statement](#env)) can also be used in certain instructions as variables to be interpreted by the `Dockerfile`. Escapes are also handled for including variable-like syntax into a statement literally. @@ -154,6 +154,12 @@ Exclusion patterns match files or directories relative to the source repository that will be excluded from the context. Globbing is done using Go's [filepath.Match](http://golang.org/pkg/path/filepath#Match) rules. +> **Note**: +> The `.dockerignore` file can even be used to ignore the `Dockerfile` and +> `.dockerignore` files. This might be useful if you are copying files from +> the root of the build context into your new containter but do not want to +> include the `Dockerfile` or `.dockerignore` files (e.g. `ADD . /someDir/`). + The following example shows the use of the `.dockerignore` file to exclude the `.git` directory from the context. Its effect can be seen in the changed size of the uploaded context. @@ -186,11 +192,11 @@ Or FROM : -The `FROM` instruction sets the [*Base Image*](/terms/image/#base-image-def) +The `FROM` instruction sets the [*Base Image*](/terms/image/#base-image) for subsequent instructions. As such, a valid `Dockerfile` must have `FROM` as its first instruction. The image can be any valid image – it is especially easy to start by **pulling an image** from the [*Public Repositories*]( -/userguide/dockerrepos/#using-public-repositories). +/userguide/dockerrepos). `FROM` must be the first non-comment instruction in the `Dockerfile`. @@ -343,8 +349,8 @@ accessible from the host by default. To expose ports to the host, at runtime, ENV = ... The `ENV` instruction sets the environment variable `` to the value -``. This value will be passed to all future `RUN` instructions. This is -functionally equivalent to prefixing the command with `=` +``. This value will be in the environment of all "descendent" `Dockerfile` +commands and can be [replaced inline](#environment-replacement) in many as well. The `ENV` instruction has two forms. The first form, `ENV `, will set a single variable to a value. The entire string after the first @@ -375,13 +381,18 @@ from the resulting image. You can view the values using `docker inspect`, and change them using `docker run --env =`. > **Note**: -> One example where this can cause unexpected consequences, is setting -> `ENV DEBIAN_FRONTEND noninteractive`. Which will persist when the container -> is run interactively; for example: `docker run -t -i image bash` +> Environment persistence can cause unexpected effects. For example, +> setting `ENV DEBIAN_FRONTEND noninteractive` may confuse apt-get +> users on a Debian-based image. To set a value for a single command, use +> `RUN = `. ## ADD - ADD ... +ADD has two forms: + +- `ADD ... ` +- `ADD [""... ""]` (this form is required for paths containing +whitespace) The `ADD` instruction copies new files, directories or remote file URLs from `` and adds them to the filesystem of the container at the path ``. @@ -397,8 +408,10 @@ For most command line uses this should act as expected, for example: ADD hom* /mydir/ # adds all files starting with "hom" ADD hom?.txt /mydir/ # ? is replaced with any single character -The `` is the absolute path to which the source will be copied inside the -destination container. +The `` is an absolute path, or a path relative to `WORKDIR`, into which +the source will be copied inside the destination container. + + ADD test aDir/ # adds "test" to `WORKDIR`/aDir/ All new files and directories are created with a UID and GID of 0. @@ -479,7 +492,11 @@ The copy obeys the following rules: ## COPY - COPY ... +COPY has two forms: + +- `COPY ... ` +- `COPY [""... ""]` (this form is required for paths containing +whitespace) The `COPY` instruction copies new files or directories from `` and adds them to the filesystem of the container at the path ``. @@ -494,8 +511,10 @@ For most command line uses this should act as expected, for example: COPY hom* /mydir/ # adds all files starting with "hom" COPY hom?.txt /mydir/ # ? is replaced with any single character -The `` is the absolute path to which the source will be copied inside the -destination container. +The `` is an absolute path, or a path relative to `WORKDIR`, into which +the source will be copied inside the destination container. + + COPY test aDir/ # adds "test" to `WORKDIR`/aDir/ All new files and directories are created with a UID and GID of 0. @@ -763,7 +782,7 @@ and mark it as holding externally mounted volumes from native host or other containers. The value can be a JSON array, `VOLUME ["/var/log/"]`, or a plain string with multiple arguments, such as `VOLUME /var/log` or `VOLUME /var/log /var/db`. For more information/examples and mounting instructions via the -Docker client, refer to [*Share Directories via Volumes*](/userguide/dockervolumes/#volume-def) +Docker client, refer to [*Share Directories via Volumes*](/userguide/dockervolumes/#volume) documentation. > **Note**: @@ -782,8 +801,8 @@ and for any `RUN`, `CMD` and `ENTRYPOINT` instructions that follow it in the WORKDIR /path/to/workdir -The `WORKDIR` instruction sets the working directory for any `RUN`, `CMD` and -`ENTRYPOINT` instructions that follow it in the `Dockerfile`. +The `WORKDIR` instruction sets the working directory for any `RUN`, `CMD`, +`ENTRYPOINT`, `COPY` and `ADD` instructions that follow it in the `Dockerfile`. It can be used multiple times in the one `Dockerfile`. If a relative path is provided, it will be relative to the path of the previous `WORKDIR` diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 577a4c68c..9c9bd1d3c 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -4,6 +4,8 @@ page_keywords: Docker, Docker documentation, CLI, command line # Command Line +{{ include "no-remote-sudo.md" }} + To list available commands, either run `docker` with no parameters or execute `docker help`: @@ -15,21 +17,39 @@ or execute `docker help`: ... +## Help +To list the help on any command just execute the command, followed by the `--help` option. + + $ sudo docker run --help + + Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] + + Run a command in a new container + + -a, --attach=[] Attach to STDIN, STDOUT or STDERR. + -c, --cpu-shares=0 CPU shares (relative weight) + ... + ## Option types -Single character commandline options can be combined, so rather than +Single character command line options can be combined, so rather than typing `docker run -t -i --name test busybox sh`, you can write `docker run -ti --name test busybox sh`. ### Boolean -Boolean options look like `-d=false`. The value you -see is the default value which gets set if you do **not** use the -boolean flag. If you do call `run -d`, that sets the -opposite boolean value, so in this case, `true`, and -so `docker run -d` **will** run in "detached" mode, -in the background. Other boolean options are similar – specifying them -will set the value to the opposite of the default value. +Boolean options take the form `-d=false`. The value you see in the help text is the +default value which is set if you do **not** specify that flag. If you specify +a Boolean flag without a value, this will set the flag to `true`, irrespective +of the default value. + +For example, running `docker run -d` will set the value to `true`, so +your container **will** run in "detached" mode, in the background. + +Options which default to `true` (e.g., `docker build --rm=true`) can only +be set to the non-default value by explicitly setting them to `false`: + + $ docker build --rm=false . ### Multi @@ -63,8 +83,9 @@ expect an integer, and they can only be specified once. --dns=[] Force Docker to use specific DNS servers --dns-search=[] Force Docker to use specific DNS search domains -e, --exec-driver="native" Force the Docker runtime to use a specific exec driver - --fixed-cidr="" IPv4 subnet for fixed IPs (ex: 10.20.0.0/16) + --fixed-cidr="" IPv4 subnet for fixed IPs (e.g.: 10.20.0.0/16) this subnet must be nested in the bridge subnet (which is defined by -b or --bip) + --fixed-cidr-v6="" IPv6 subnet for global IPs (e.g.: 2a00:1450::/64) -G, --group="docker" Group to assign the unix socket specified by -H when running in daemon mode use '' (the empty string) to disable setting of a group -g, --graph="/var/lib/docker" Path to use as the root of the Docker runtime @@ -72,10 +93,11 @@ expect an integer, and they can only be specified once. --icc=true Allow unrestricted inter-container and Docker daemon host communication --insecure-registry=[] Enable insecure communication with specified registries (disables certificate verification for HTTPS and enables HTTP fallback) (e.g., localhost:5000 or 10.20.0.0/16) --ip=0.0.0.0 Default IP address to use when binding container ports - --ip-forward=true Enable net.ipv4.ip_forward + --ip-forward=true Enable net.ipv4.ip_forward and IPv6 forwarding if --fixed-cidr-v6 is defined. IPv6 forwarding may interfere with your existing IPv6 configuration when using Router Advertisement. --ip-masq=true Enable IP masquerading for bridge's IP range --iptables=true Enable Docker's addition of iptables rules - -l, --log-level="info" Set the logging level + --ipv6=false Enable Docker IPv6 support + -l, --log-level="info" Set the logging level (debug, info, warn, error, fatal) --label=[] Set key=value labels to the daemon (displayed in `docker info`) --mtu=0 Set the containers network MTU if no value is provided: default to the default route MTU or 1500 if no default route is available @@ -122,7 +144,7 @@ for un-encrypted, and port `2376` for encrypted communication with the daemon. > for security reasons. On Systemd based systems, you can communicate with the daemon via -[systemd socket activation](http://0pointer.de/blog/projects/socket-activation.html), use +[Systemd socket activation](http://0pointer.de/blog/projects/socket-activation.html), use `docker -d -H fd://`. Using `fd://` will work perfectly for most setups but you can also specify individual sockets: `docker -d -H fd://3`. If the specified socket activated files aren't found, then Docker will exit. You @@ -153,6 +175,14 @@ string is equivalent to setting the `--tlsverify` flag. The following are equiva $ export DOCKER_TLS_VERIFY=1 $ sudo docker ps +The Docker client will honor the `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` +environment variables (or the lowercase versions thereof). `HTTPS_PROXY` takes +precedence over `HTTP_PROXY`. If you happen to have a proxy configured with the +`HTTP_PROXY` or `HTTPS_PROXY` environment variables but still want to +communicate with the Docker daemon over its default `unix` domain socket, +setting the `NO_PROXY` environment variable to the path of the socket +(`/var/run/docker.sock`) is required. + ### Daemon storage-driver option The Docker daemon has support for several different image layer storage drivers: `aufs`, @@ -304,7 +334,7 @@ Currently supported options are: Enables or disables the use of blkdiscard when removing devicemapper devices. This is enabled by default (only) if using loopback devices and is - required to res-parsify the loopback file on image/container removal. + required to resparsify the loopback file on image/container removal. Disabling this on loopback can lead to *much* faster container removal times, but will make the space used in `/var/lib/docker` directory not be @@ -364,6 +394,22 @@ flag to the Docker daemon as described above. Local registries, whose IP address falls in the 127.0.0.0/8 range, are automatically marked as insecure as of Docker 1.3.2. It is not recommended to rely on this, as it may change in the future. +### Running a Docker daemon behind a HTTPS_PROXY + +When running inside a LAN that uses a `HTTPS` proxy, the Docker Hub certificates +will be replaced by the proxy's certificates. These certificates need to be added +to your Docker host's configuration: + +1. Install the `ca-certificates` package for your distribution +2. Ask your network admin for the proxy's CA certificate and append them to + `/etc/pki/tls/certs/ca-bundle.crt` +3. Then start your Docker daemon with `HTTPS_PROXY=http://username:password@proxy:port/ docker -d`. + The `username:` and `password@` are optional - and are only needed if your proxy + is set up to require authentication. + +This will only add the proxy and authentication to the Docker daemon's requests - +your `docker build`s and running containers will need extra configuration to use +the proxy ### Miscellaneous options @@ -389,29 +435,24 @@ Docker supports softlinks for the Docker data directory --no-stdin=false Do not attach STDIN --sig-proxy=true Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied. -The `attach` command lets you view or interact with any running container's -primary process (`pid 1`). +The `docker attach` command allows you to attach to a running container using +the container's ID or name, either to view its ongoing output or to control it +interactively. You can attach to the same contained process multiple times +simultaneously, screen sharing style, or quickly view the progress of your +daemonized process. -You can attach to the same contained process multiple times simultaneously, screen -sharing style, or quickly view the progress of your daemonized process. +You can detach from the container (and leave it running) with `CTRL-p CTRL-q` +(for a quiet exit) or `CTRL-c` which will send a `SIGKILL` to the container. +When you are attached to a container, and exit its main process, the process's +exit code will be returned to the client. -> **Note:** This command is not for running a new process in a container. -> See: [`docker exec`](#exec). - -You can detach from the container again (and leave it running) with -`CTRL-p CTRL-q` (for a quiet exit), or `CTRL-c` which will send a -SIGKILL to the container, or `CTRL-\` to get a stacktrace of the -Docker client when it quits. When you detach from the container's -process the exit code will be returned to the client. - -To stop a container, use `docker stop`. - -To kill the container, use `docker kill`. +It is forbidden to redirect the standard input of a `docker attach` command while +attaching to a tty-enabled container (i.e.: launched with `-t`). #### Examples - $ ID=$(sudo docker run -d ubuntu /usr/bin/top -b) - $ sudo docker attach $ID + $ sudo docker run -d --name topdemo ubuntu /usr/bin/top -b) + $ sudo docker attach topdemo top - 02:05:52 up 3:05, 0 users, load average: 0.01, 0.02, 0.05 Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st @@ -440,7 +481,23 @@ To kill the container, use `docker kill`. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top ^C$ - $ sudo docker stop $ID + $ echo $? + 0 + $ docker ps -a | grep topdemo + 7998ac8581f9 ubuntu:14.04 "/usr/bin/top -b" 38 seconds ago Exited (0) 21 seconds ago topdemo + +And in this second example, you can see the exit code returned by the `bash` process +is returned by the `docker attach` command to its caller too: + + $ sudo docker run --name test -d -it debian + 275c44472aebd77c926d4527885bb09f2f6db21d878c75f0a1c212c03d3bcfab + $ sudo docker attach test + $$ exit 13 + exit + $ echo $? + 13 + $ sudo docker ps -a | grep test + 275c44472aeb debian:7 "/bin/bash" 26 seconds ago Exited (13) 17 seconds ago test ## build @@ -448,18 +505,19 @@ To kill the container, use `docker kill`. Build a new image from the source code at PATH - --force-rm=false Always remove intermediate containers, even after unsuccessful builds - --no-cache=false Do not use cache when building the image - -q, --quiet=false Suppress the verbose output generated by the containers - --rm=true Remove intermediate containers after a successful build - -t, --tag="" Repository name (and optionally a tag) to be applied to the resulting image in case of success + --force-rm=false Always remove intermediate containers, even after unsuccessful builds + --no-cache=false Do not use cache when building the image + --pull=false Always attempt to pull a newer version of the image + -q, --quiet=false Suppress the verbose output generated by the containers + --rm=true Remove intermediate containers after a successful build + -t, --tag="" Repository name (and optionally a tag) to be applied to the resulting image in case of success Use this command to build Docker images from a Dockerfile and a "context". The files at `PATH` or `URL` are called the "context" of the build. The build process may refer to any of the files in the context, for example -when using an [*ADD*](/reference/builder/#dockerfile-add) instruction. +when using an [*ADD*](/reference/builder/#add) instruction. When a single Dockerfile is given as `URL` or is piped through `STDIN` (`docker build - < Dockerfile`), then no context is set. @@ -497,6 +555,13 @@ For example, the files `tempa`, `tempb` are ignored from the root directory. Currently there is no support for regular expressions. Formats like `[^temp*]` are ignored. +By default the `docker build` command will look for a `Dockerfile` at the +root of the build context. The `-f`, `--file`, option lets you specify +the path to an alternative file to use instead. This is useful +in cases where the same set of files are used for multiple builds. The path +must be to a file within the build context. If a relative path is specified +then it must to be relative to the current directory. + See also: @@ -539,7 +604,7 @@ machine and that no parsing of the Dockerfile happens at the client side (where you're running `docker build`). That means that *all* the files at `PATH` get sent, not just the ones listed to -[*ADD*](/reference/builder/#dockerfile-add) in the Dockerfile. +[*ADD*](/reference/builder/#add) in the Dockerfile. The transfer of context from the local machine to the Docker daemon is what the `docker` client means when you see the @@ -599,6 +664,28 @@ repository is used as Dockerfile. Note that you can specify an arbitrary Git repository by using the `git://` or `git@` schema. + $ sudo docker build -f Dockerfile.debug . + +This will use a file called `Dockerfile.debug` for the build +instructions instead of `Dockerfile`. + + $ sudo docker build -f dockerfiles/Dockerfile.debug -t myapp_debug . + $ sudo docker build -f dockerfiles/Dockerfile.prod -t myapp_prod . + +The above commands will build the current build context (as specified by +the `.`) twice, once using a debug version of a `Dockerfile` and once using +a production version. + + $ cd /home/me/myapp/some/dir/really/deep + $ sudo docker build -f /home/me/myapp/dockerfiles/debug /home/me/myapp + $ sudo docker build -f ../../../../dockerfiles/debug /home/me/myapp + +These two `docker build` commands do the exact same thing. They both +use the contents of the `debug` file instead of looking for a `Dockerfile` +and will use `/home/me/myapp` as the root of the build context. Note that +`debug` is in the directory structure of the build context, regardless of how +you refer to it on the command line. + > **Note:** `docker build` will return a `no such file or directory` error > if the file or directory does not exist in the uploaded context. This may > happen if there is no context, or if you specify a file that is elsewhere @@ -675,7 +762,7 @@ Creates a new container. --ipc="" Default is to create a private IPC namespace (POSIX SysV IPC) for the container 'container:': reuses another container shared memory, semaphores and message queues 'host': use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. - --link=[] Add link to another container in the form of name:alias + --link=[] Add link to another container in the form of :alias --lxc-conf=[] (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" -m, --memory="" Memory limit (format: , where unit = b, k, m or g) --mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33) @@ -685,11 +772,14 @@ Creates a new container. 'none': no networking for this container 'container:': reuses another container network stack 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. - -P, --publish-all=false Publish all exposed ports to the host interfaces - -p, --publish=[] Publish a container's port to the host + -P, --publish-all=false Publish all exposed ports to random ports on the host interfaces + -p, --publish=[] Publish a container's port, or a range of ports (e.g., `-p 3300-3310`), to the host format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort + Both hostPort and containerPort can be specified as a range of ports. + When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. (e.g., `-p 1234-1236:1234-1236/tcp`) (use 'docker port' to see the actual mapping) --privileged=false Give extended privileges to this container + --read-only=false Mount the container's root filesystem as read only --restart="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always) --security-opt=[] Security Options -t, --tty=false Allocate a pseudo-TTY @@ -708,15 +798,47 @@ container at any point. This is useful when you want to set up a container configuration ahead of time so that it is ready to start when you need it. +Note that volumes set by `create` may be over-ridden by options set with +`start`. + Please see the [run command](#run) section for more details. -#### Example +#### Examples $ sudo docker create -t -i fedora bash 6d8af538ec541dd581ebc2a24153a28329acb5268abe5ef868c1f1a261221752 $ sudo docker start -a -i 6d8af538ec5 bash-4.2# +As of v1.4.0 container volumes are initialized during the `docker create` +phase (i.e., `docker run` too). For example, this allows you to `create` the +`data` volume container, and then use it from another container: + + $ docker create -v /data --name data ubuntu + 240633dfbb98128fa77473d3d9018f6123b99c454b3251427ae190a7d951ad57 + $ docker run --rm --volumes-from data ubuntu ls -la /data + total 8 + drwxr-xr-x 2 root root 4096 Dec 5 04:10 . + drwxr-xr-x 48 root root 4096 Dec 5 04:11 .. + +Similarly, `create` a host directory bind mounted volume container, which +can then be used from the subsequent container: + + $ docker create -v /home/docker:/docker --name docker ubuntu + 9aa88c08f319cd1e4515c3c46b0de7cc9aa75e878357b1e96f91e2c773029f03 + $ docker run --rm --volumes-from docker ubuntu ls -la /docker + total 20 + drwxr-sr-x 5 1000 staff 180 Dec 5 04:00 . + drwxr-xr-x 48 root root 4096 Dec 5 04:13 .. + -rw-rw-r-- 1 1000 staff 3833 Dec 5 04:01 .ash_history + -rw-r--r-- 1 1000 staff 446 Nov 28 11:51 .ashrc + -rw-r--r-- 1 1000 staff 25 Dec 5 04:00 .gitconfig + drwxr-sr-x 3 1000 staff 60 Dec 1 03:28 .local + -rw-r--r-- 1 1000 staff 920 Nov 28 11:51 .profile + drwx--S--- 2 1000 staff 460 Dec 5 00:51 .ssh + drwxr-xr-x 32 1000 staff 1140 Dec 5 04:01 docker + + ## diff List the changed files and directories in a container᾿s filesystem @@ -753,12 +875,13 @@ For example: Get real time events from the server + -f, --filter=[] Provide filter values (i.e., 'event=stop') --since="" Show all events created since timestamp --until="" Stream events until this timestamp Docker containers will report the following events: - create, destroy, die, export, kill, pause, restart, start, stop, unpause + create, destroy, die, export, kill, oom, pause, restart, start, stop, unpause and Docker images will report: @@ -819,7 +942,7 @@ You'll need two shells for this example. 2014-05-10T17:42:14.999999999Z07:00 7805c1d35632: (from redis:2.8) die 2014-09-03T17:42:14.999999999Z07:00 7805c1d35632: (from redis:2.8) stop - $ sudo docker events --since '2013-09-03 15:49:29 +0200 CEST' + $ sudo docker events --since '2013-09-03T15:49:29' 2014-09-03T15:49:29.999999999Z07:00 4386fb97867d: (from ubuntu-1:14.04) die 2014-05-10T17:42:14.999999999Z07:00 4386fb97867d: (from ubuntu-1:14.04) stop 2014-05-10T17:42:14.999999999Z07:00 7805c1d35632: (from redis:2.8) die @@ -864,8 +987,17 @@ The `docker exec` command runs a new command in a running container. The command started using `docker exec` will only run while the container's primary process (`PID 1`) is running, and will not be restarted if the container is restarted. -If the container is paused, then the `docker exec` command will wait until the -container is unpaused, and then run. +If the container is paused, then the `docker exec` command will fail with an error: + + $ docker pause test + test + $ docker ps + CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + 1ae3b36715d2 ubuntu:latest "bash" 17 seconds ago Up 16 seconds (Paused) test + $ docker exec test ls + FATA[0000] Error response from daemon: Container test is paused, unpause the container before exec + $ echo $? + 1 #### Examples @@ -892,6 +1024,15 @@ For example: $ sudo docker export red_panda > latest.tar +> **Note:** +> `docker export` does not export the contents of volumes associated with the +> container. If a volume is mounted on top of an existing directory in the +> container, `docker export` will export the contents of the *underlying* +> directory, not the contents of the volume. +> +> Refer to [Backup, restore, or migrate data volumes](/userguide/dockervolumes/#backup-restore-or-migrate-data-volumes) +> in the user guide for examples on exporting data in a volume. + ## history Usage: docker history [OPTIONS] IMAGE @@ -919,7 +1060,7 @@ To see how the `docker:latest` image was built: List images -a, --all=false Show all images (by default filter out the intermediate image layers) - -f, --filter=[] Provide filter values (i.e. 'dangling=true') + -f, --filter=[] Provide filter values (i.e., 'dangling=true') --no-trunc=false Don't truncate output -q, --quiet=false Only show numeric IDs @@ -1055,6 +1196,7 @@ For example: Images: 52 Storage Driver: aufs Root Dir: /var/lib/docker/aufs + Backing Filesystem: extfs Dirs: 545 Execution Driver: native-0.2 Kernel Version: 3.13.0-24-generic @@ -1224,6 +1366,22 @@ timestamp, for example `2014-09-16T06:17:46.000000000Z`, to each log entry. To ensure that the timestamps for are aligned the nano-second part of the timestamp will be padded with zero when necessary. +## pause + + Usage: docker pause CONTAINER + + Pause all processes within a container + +The `docker pause` command uses the cgroups freezer to suspend all processes in +a container. Traditionally, when suspending a process the `SIGSTOP` signal is +used, which is observable by the process being suspended. With the cgroups freezer +the process is unaware, and unable to capture, that it is being suspended, +and subsequently resumed. + +See the +[cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) +for further details. + ## port Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]] @@ -1262,6 +1420,14 @@ See the [cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for further details. +## rename + + Usage: docker rename OLD_NAME NEW_NAME + + rename a existing container to a NEW_NAME + +The `docker rename` command allows the container to be renamed to a different name. + ## ps Usage: docker ps [OPTIONS] @@ -1280,12 +1446,12 @@ for further details. -s, --size=false Display total file sizes --since="" Show only containers created since Id or Name, include non-running ones. -Running `docker ps` showing 2 linked containers. +Running `docker ps --no-trunc` showing 2 linked containers. $ sudo docker ps - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - 4c01db0b339c ubuntu:12.04 bash 17 seconds ago Up 16 seconds webapp - d7886598dbe2 crosbymichael/redis:latest /redis-server --dir 33 minutes ago Up 33 minutes 6379/tcp redis,webapp/db + CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + f7ee772232194fcc088c6bdec6ea09f7b3f6c54d53934658164b8602d7cd4744 ubuntu:12.04 bash 17 seconds ago Up 16 seconds webapp + d0963715a061c7c7b7cc80b2646da913a959fbf13e80a971d4a60f6997a2f595 crosbymichael/redis:latest /redis-server --dir 33 minutes ago Up 33 minutes 6379/tcp redis,webapp/db `docker ps` will show only running containers by default. To see all containers: `docker ps -a` @@ -1463,6 +1629,7 @@ removed before the image is removed. --link=[] Add link to another container in the form of name:alias --lxc-conf=[] (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" -m, --memory="" Memory limit (format: , where unit = b, k, m or g) + -memory-swap="" Total memory usage (memory + swap), set '-1' to disable swap (format: , where unit = b, k, m or g) --mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33) --name="" Assign a name to the container --net="bridge" Set the Network mode for the container @@ -1470,11 +1637,15 @@ removed before the image is removed. 'none': no networking for this container 'container:': reuses another container network stack 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. - -P, --publish-all=false Publish all exposed ports to the host interfaces + -P, --publish-all=false Publish all exposed ports to random ports on the host interfaces -p, --publish=[] Publish a container's port to the host format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort + Both hostPort and containerPort can be specified as a range of ports. + When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. (e.g., `-p 1234-1236:1234-1236/tcp`) (use 'docker port' to see the actual mapping) + --pid=host 'host': use the host PID namespace inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. --privileged=false Give extended privileges to this container + --read-only=false Mount the container's root filesystem as read only --restart="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always) --rm=false Automatically remove the container when it exits (incompatible with -d) --security-opt=[] Security Options @@ -1504,6 +1675,19 @@ and linking containers. #### Examples + $ sudo docker run --name test -it debian + $$ exit 13 + exit + $ echo $? + 13 + $ sudo docker ps -a | grep test + 275c44472aeb debian:7 "/bin/bash" 26 seconds ago Exited (13) 17 seconds ago test + +In this example, we are running `bash` interactively in the `debian:latest` image, and giving +the container the name `test`. We then quit `bash` by running `exit 13`, which means `bash` +will have an exit code of `13`. This is then passed on to the caller of `docker run`, and +is recorded in the `test` container metadata. + $ sudo docker run --cidfile /tmp/docker_test.cid ubuntu echo "test" This will create a container and print `test` to the console. The `cidfile` @@ -1550,6 +1734,13 @@ will automatically create this directory on the host for you. In the example above, Docker will create the `/doesnt/exist` folder before starting your container. + $ sudo docker run --read-only -v /icanwrite busybox touch /icanwrite here + +Volumes can be used in combination with `--read-only` to control where +a container writes files. The `--read-only` flag mounts the container's root +filesystem as read only prohibiting writes to locations other than the +specified volumes for the container. + $ sudo docker run -t -i -v /var/run/docker.sock:/var/run/docker.sock -v ./static-docker:/usr/bin/docker busybox sh By bind-mounting the docker unix socket and statically linked docker @@ -1574,9 +1765,12 @@ ports in Docker. This sets environmental variables in the container. For illustration all three flags are shown here. Where `-e`, `--env` take an environment variable and -value, or if no "=" is provided, then that variable's current value is passed -through (i.e. `$MYVAR1` from the host is set to `$MYVAR1` in the container). All -three flags, `-e`, `--env` and `--env-file` can be repeated. +value, or if no `=` is provided, then that variable's current value is passed +through (i.e. `$MYVAR1` from the host is set to `$MYVAR1` in the container). +When no `=` is provided and that variable is not defined in the client's +environment then that variable will be removed from the container's list of +environment variables. +All three flags, `-e`, `--env` and `--env-file` can be repeated. Regardless of the order of these three flags, the `--env-file` are processed first, and then `-e`, `--env` flags. This way, the `-e` or `--env` will @@ -1727,6 +1921,16 @@ application change: Using the `--restart` flag on Docker run you can specify a restart policy for how a container should or should not be restarted on exit. +An ever increasing delay (double the previous delay, starting at 100 milliseconds) +is added before each restart to prevent flooding the server. This means the daemaon +will wait for 100 mS, then 200 mS, 400, 800, 1600, and so on until either the +`on-failure` limit is hit, or when you `docker stop` or even `docker rm -f` +the container. + +When a restart policy is active on a container, it will be shown in `docker ps` +as either `Up` or `Restarting` in `docker ps`. It can also be useful to use +`docker events` to see the restart policy in effect. + ** no ** - Do not restart the container when it exits. ** on-failure ** - Restart the container only if it exits with a non zero exit status. @@ -1814,9 +2018,12 @@ Search [Docker Hub](https://hub.docker.com) for images -s, --stars=0 Only displays with at least x stars See [*Find Public Images on Docker Hub*]( -/userguide/dockerrepos/#find-public-images-on-docker-hub) for +/userguide/dockerrepos/#searching-for-images) for more details on finding shared images from the command line. +> **Note:** +> Search queries will only return up to 25 results + ## start Usage: docker start [OPTIONS] CONTAINER [CONTAINER...] @@ -1826,8 +2033,29 @@ more details on finding shared images from the command line. -a, --attach=false Attach container's STDOUT and STDERR and forward all signals to the process -i, --interactive=false Attach container's STDIN -When run on a container that has already been started, -takes no action and succeeds unconditionally. +## stats + + Usage: docker stats [CONTAINERS] + + Display a live stream of one or more containers' resource usage statistics + + --help=false Print usage + +> **Note**: this functionality currently only works when using the *libcontainer* exec-driver. + +Running `docker stats` on multiple containers + + $ sudo docker stats redis1 redis2 + CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O + redis1 0.07% 796 KiB/64 MiB 1.21% 788 B/648 B + redis2 0.07% 2.746 MiB/64 MiB 4.29% 1.266 KiB/648 B + + +The `docker stats` command will only return a live stream of data for running +containers. Stopped containers will not return any data. + +> **Note:** +> If you want more detailed information about a container's resource usage, use the API endpoint. ## stop @@ -1850,7 +2078,7 @@ grace period, `SIGKILL`. You can group your images together using names and tags, and then upload them to [*Share Images via Repositories*]( -/userguide/dockerrepos/#working-with-the-repository). +/userguide/dockerrepos/#contributing-to-docker-hub). ## top diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index e9ecfff44..ca7480beb 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -7,7 +7,7 @@ page_keywords: docker, run, configure, runtime **Docker runs processes in isolated containers**. When an operator executes `docker run`, she starts a process with its own file system, its own networking, and its own isolated process tree. The -[*Image*](/terms/image/#image-def) which starts the process may define +[*Image*](/terms/image/#image) which starts the process may define defaults related to the binary to run, the networking to expose, and more, but `docker run` gives final control to the operator who starts the container from the image. That's the main reason @@ -114,7 +114,7 @@ The UUID identifiers come from the Docker daemon, and if you do not assign a name to the container with `--name` then the daemon will also generate a random string name too. The name can become a handy way to add meaning to a container since you can use this name when defining -[*links*](/userguide/dockerlinks/#working-with-links-names) (or any +[*links*](/userguide/dockerlinks) (or any other place you need to identify a container). This works for both background and foreground Docker containers. @@ -133,11 +133,31 @@ While not strictly a means of identifying a container, you can specify a version image you'd like to run the container with by adding `image[:tag]` to the command. For example, `docker run ubuntu:14.04`. +## PID Settings + --pid="" : Set the PID (Process) Namespace mode for the container, + 'host': use the host's PID namespace inside the container +By default, all containers have the PID namespace enabled. + +PID namespace provides separation of processes. The PID Namespace removes the +view of the system processes, and allows process ids to be reused including +pid 1. + +In certain cases you want your container to share the host's process namespace, +basically allowing processes within the container to see all of the processes +on the system. For example, you could build a container with debugging tools +like `strace` or `gdb`, but want to use these tools when debugging processes +within the container. + + $ sudo docker run --pid=host rhel7 strace -p 1234 + +This command would allow you to use `strace` inside the container on pid 1234 on +the host. + ## IPC Settings --ipc="" : Set the IPC mode for the container, 'container:': reuses another container's IPC namespace 'host': use the host's IPC namespace inside the container -By default, all containers have the IPC namespace enabled +By default, all containers have the IPC namespace enabled. IPC (POSIX/SysV IPC) namespace provides separation of named shared memory segments, semaphores and message queues. @@ -254,7 +274,7 @@ the container exits**, you can add the `--rm` flag: --security-opt="label:type:TYPE" : Set the label type for the container --security-opt="label:level:LEVEL" : Set the label level for the container --security-opt="label:disable" : Turn off label confinement for the container - --secutity-opt="apparmor:PROFILE" : Set the apparmor profile to be applied + --security-opt="apparmor:PROFILE" : Set the apparmor profile to be applied to the container You can override the default labeling scheme for each container by specifying @@ -420,7 +440,7 @@ familiar with using LXC directly. ## Overriding Dockerfile image defaults -When a developer builds an image from a [*Dockerfile*](/reference/builder/#dockerbuilder) +When a developer builds an image from a [*Dockerfile*](/reference/builder) or when she commits it, the developer can set a number of default parameters that take effect when the image starts up as a container. @@ -487,11 +507,12 @@ or override the Dockerfile's exposed defaults: --expose=[]: Expose a port or a range of ports from the container without publishing it to your host -P=false : Publish all exposed ports to the host interfaces - -p=[] : Publish a container᾿s port to the host (format: - ip:hostPort:containerPort | ip::containerPort | - hostPort:containerPort | containerPort) - (use 'docker port' to see the actual mapping) - --link="" : Add link to another container (name:alias) + -p=[] : Publish a container᾿s port or a range of ports to the host + format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort + Both hostPort and containerPort can be specified as a range of ports. + When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. (e.g., `-p 1234-1236:1234-1236/tcp`) + (use 'docker port' to see the actual mapping) + --link="" : Add link to another container (:alias) As mentioned previously, `EXPOSE` (and `--expose`) makes ports available **in** a container for incoming connections. The port number on the @@ -574,7 +595,7 @@ above, or already defined by the developer with a Dockerfile `ENV`: Similarly the operator can set the **hostname** with `-h`. -`--link name:alias` also sets environment variables, using the *alias* string to +`--link :alias` also sets environment variables, using the *alias* string to define environment variables within the container that give the IP and PORT information for connecting to the service container. Let's imagine we have a container running Redis: @@ -626,6 +647,12 @@ mechanism to communicate with a linked container by its alias: If you restart the source container (`servicename` in this case), the recipient container's `/etc/hosts` entry will be automatically updated. +> **Note**: +> Unlike host entries in the `/ets/hosts` file, IP addresses stored in the +> environment variables are not automatically updated if the source container is +> restarted. We recommend using the host entries in `/etc/hosts` to resolve the +> IP address of linked containers. + ## VOLUME (shared filesystems) -v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. @@ -634,7 +661,7 @@ container's `/etc/hosts` entry will be automatically updated. The volumes commands are complex enough to have their own documentation in section [*Managing data in -containers*](/userguide/dockervolumes/#volume-def). A developer can define +containers*](/userguide/dockervolumes). A developer can define one or more `VOLUME`'s associated with an image, but only the operator can give access from one container to another (or from a container to a volume mounted on the host). diff --git a/docs/sources/release-notes.md b/docs/sources/release-notes.md index 7ec08b1a8..e6c0ec5d4 100644 --- a/docs/sources/release-notes.md +++ b/docs/sources/release-notes.md @@ -2,356 +2,64 @@ page_title: Docker 1.x Series Release Notes page_description: Release Notes for Docker 1.x. page_keywords: docker, documentation, about, technology, understanding, release -#Release Notes - -##Version 1.3.3 -(2014-12-11) - -This release fixes several security issues. In order to encourage immediate -upgrading, this release also patches some critical bugs. All users are highly -encouraged to upgrade as soon as possible. - -*Security fixes* - -Patches and changes were made to address the following vulnerabilities: - -* CVE-2014-9356: Path traversal during processing of absolute symlinks. -Absolute symlinks were not adequately checked for traversal which created a -vulnerability via image extraction and/or volume mounts. -* CVE-2014-9357: Escalation of privileges during decompression of LZMA (.xz) -archives. Docker 1.3.2 added `chroot` for archive extraction. This created a -vulnerability that could allow malicious images or builds to write files to the -host system and escape containerization, leading to privilege escalation. -* CVE-2014-9358: Path traversal and spoofing opportunities via image -identifiers. Image IDs passed either via `docker load` or registry communications -were not sufficiently validated. This created a vulnerability to path traversal -attacks wherein malicious images or repository spoofing could lead to graph -corruption and manipulation. - -*Runtime fixes* - -* Fixed an issue that cause image archives to be read slowly. - -*Client fixes* - -* Fixed a regression related to STDIN redirection. -* Fixed a regression involving `docker cp` when the current directory is the -destination. - -##Version 1.3.2 -(2014-11-24) - -This release fixes some bugs and addresses some security issues. We have also -made improvements to aspects of `docker run`. - -*Security fixes* - -Patches and changes were made to address CVE-2014-6407 and CVE-2014-6408. -Specifically, changes were made in order to: - -* Prevent host privilege escalation from an image extraction vulnerability (CVE-2014-6407). - -* Prevent container escalation from malicious security options applied to images (CVE-2014-6408). - -*Daemon fixes* - -The `--insecure-registry` flag of the `docker run` command has undergone -several refinements and additions. For details, please see the -[command-line reference](http://docs.docker.com/reference/commandline/cli/#run). - -* You can now specify a sub-net in order to set a range of registries which the Docker daemon will consider insecure. - -* By default, Docker now defines `localhost` as an insecure registry. - -* Registries can now be referenced using the Classless Inter-Domain Routing (CIDR) format. - -* When mirroring is enabled, the experimental registry v2 API is skipped. - -##Version 1.3.1 -(2014-10-28) - -This release fixes some bugs and addresses some security issues. - -*Security fixes* - -Patches and changes were made to address [CVE-2014-5277 and CVE-2014-3566](https://groups.google.com/forum/#!topic/docker-user/oYm0i3xShJU). -Specifically, changes were made to: - -* Prevent fallback to SSL protocols < TLS 1.0 for client, daemon and registry -* Secure HTTPS connection to registries with certificate verification and without HTTP fallback unless [`--insecure-registry`](/reference/commandline/cli/#run) is specified. - -*Runtime fixes* - -* Fixed issue where volumes would not be shared. - -*Client fixes* - -* Fixed issue with `--iptables=false` not automatically setting -`--ip-masq=false`. -* Fixed docker run output to non-TTY stdout. - -*Builder fixes* - -* Fixed escaping `$` for environment variables. -* Fixed issue with lowercase `onbuild` instruction in a `Dockerfile`. -* Restricted environment variable expansion to `ENV`, `ADD`, `COPY`, `WORKDIR`, -`EXPOSE`, `VOLUME`, and `USER` - -##Version 1.3.0 - -This version fixes a number of bugs and issues and adds new functions and other -improvements. The [GitHub 1.3milestone](https://github.com/docker/docker/issues?q=milestone%3A1.3.0+) has -more detailed information. Major additions and changes include: - -###New Features - -*New command: `docker exec`* - -The new `docker exec` command lets you run a process in an existing, active -container. The command has APIs for both the daemon and the client. With `docker -exec`, you'll be able to do things like add or remove devices from running -containers, debug running containers, and run commands that are not part of the -container's static specification. Details in the [command line reference](/reference/commandline/cli/#exec). - -*New command: `docker create`* - -Traditionally, the `docker run` command has been used to both create a container -and spawn a process to run it. The new `docker create` command breaks this -apart, letting you set up a container without actually starting it. This -provides more control over management of the container lifecycle, giving you the -ability to configure things like volumes or port mappings before the container -is started. For example, in a rapid-response scaling situation, you could use -`create` to prepare and stage ten containers in anticipation of heavy loads. -Details in the [command line reference](/reference/commandline/cli/#create). - -*Tech preview of new provenance features* - -This release offers a sneak peek at new image signing capabilities that are -currently under development. Soon, these capabilities will allow any image -author to sign their images to certify they have not been tampered with. For -this release, Official images are now signed by Docker, Inc. Not only does this -demonstrate the new functionality, we hope it will improve your confidence in -the security of Official images. Look for the blue ribbons denoting signed -images on the [Docker Hub](https://hub.docker.com/). The Docker Engine has been -updated to automatically verify that a given Official Repo has a current, valid -signature. When pulling a signed image, you'll see a message stating `the image -you are pulling has been verified`. If no valid signature is detected, Docker -Engine will fall back to pulling a regular, unsigned image. - -###Other improvements & changes* - -* We've added a new security options flag to the `docker run` command, -`--security-opt`, that lets you set SELinux and AppArmor labels and profiles. -This means you'll no longer have to use `docker run --privileged` on kernels -that support SE Linux or AppArmor. For more information, see the [command line -reference](/reference/commandline/cli/#run). - -* A new flag, `--add-host`, has been added to `docker run` that lets you add -lines to `/etc/hosts`. This allows you to specify different name resolution for -the container than it would get via DNS. For more information, see the [command -line reference](/reference/commandline/cli/#run). - -* You can now set a `DOCKER_TLS_VERIFY` environment variable to secure -connections by default (rather than having to pass the `--tlsverify` flag on -every call). For more information, see the [https guide](/articles/https). - -* Three security issues have been addressed in this release: [CVE-2014-5280, -CVE-2014-5270, and -CVE-2014-5282](https://groups.google.com/forum/#!msg/docker-announce/aQoVmQlcE0A/smPuBNYf8VwJ). - -##Version 1.2.0 - -This version fixes a number of bugs and issues and adds new functions and other -improvements. These include: - -###New Features - -*New restart policies* - -We added a `--restart flag` to `docker run` to specify a restart policy for your -container. Currently, there are three policies available: - -* `no` – Do not restart the container if it dies. (default) * `on-failure` – -Restart the container if it exits with a non-zero exit code. This can also -accept an optional maximum restart count (e.g. `on-failure:5`). * `always` – -Always restart the container no matter what exit code is returned. This -deprecates the `--restart` flag on the Docker daemon. - -*New flags for `docker run`: `--cap-add` and `--cap-drop`* - -In previous releases, Docker containers could either be given complete -capabilities or they could all follow a whitelist of allowed capabilities while -dropping all others. Further, using `--privileged` would grant all capabilities -inside a container, rather than applying a whitelist. This was not recommended -for production use because it’s really unsafe; it’s as if you were directly in -the host. - -This release introduces two new flags for `docker run`, `--cap-add` and -`--cap-drop`, that give you fine-grain control over the specific capabilities -you want grant to a particular container. - -*New `--device` flag for `docker run`* - -Previously, you could only use devices inside your containers by bind mounting -them (with `-v`) in a `--privileged` container. With this release, we introduce -the `--device flag` to `docker run` which lets you use a device without -requiring a privileged container. - -*Writable `/etc/hosts`, `/etc/hostname` and `/etc/resolv.conf`* - -You can now edit `/etc/hosts`, `/etc/hostname` and `/etc/resolve.conf` in a -running container. This is useful if you need to install BIND or other services -that might override one of those files. - -Note, however, that changes to these files are not saved when running `docker -build` and so will not be preserved in the resulting image. The changes will -only “stick” in a running container. - -*Docker proxy in a separate process* - -The Docker userland proxy that routes outbound traffic to your containers now -has its own separate process (one process per connection). This greatly reduces -the load on the daemon, which increases stability and efficiency. - -###Other improvements & changes - -* When using `docker rm -f`, Docker now kills the container (instead of stopping -it) before removing it . If you intend to stop the container cleanly, you can -use `docker stop`. - -* Added support for IPv6 addresses in `--dns` - -* Added search capability in private registries - -##Version 1.1.0 - -###New Features - -*`.dockerignore` support* - -You can now add a `.dockerignore` file next to your `Dockerfile` and Docker will -ignore files and directories specified in that file when sending the build -context to the daemon. Example: -https://github.com/docker/docker/blob/master/.dockerignore - -*Pause containers during commit* - -Doing a commit on a running container was not recommended because you could end -up with files in an inconsistent state (for example, if they were being written -during the commit). Containers are now paused when a commit is made to them. You -can disable this feature by doing a `docker commit --pause=false ` - -*Tailing logs* - -You can now tail the logs of a container. For example, you can get the last ten -lines of a log by using `docker logs --tail 10 `. You can also -follow the logs of a container without having to read the whole log file with -`docker logs --tail 0 -f `. - -*Allow a tar file as context for docker build* - -You can now pass a tar archive to `docker build` as context. This can be used to -automate docker builds, for example: `cat context.tar | docker build -` or -`docker run builder_image | docker build -` - -*Bind mounting your whole filesystem in a container* - -`/` is now allowed as source of `--volumes`. This means you can bind-mount your -whole system in a container if you need to. For example: `docker run -v -/:/my_host ubuntu:ro ls /my_host`. However, it is now forbidden to mount to /. - - -###Other Improvements & Changes - -* Port allocation has been improved. In the previous release, Docker could -prevent you from starting a container with previously allocated ports which -seemed to be in use when in fact they were not. This has been fixed. - -* A bug in `docker save` was introduced in the last release. The `docker save` -command could produce images with invalid metadata. The command now produces -images with correct metadata. - -* Running `docker inspect` in a container now returns which containers it is -linked to. - -* Parsing of the `docker commit` flag has improved validation, to better prevent -you from committing an image with a name such as `-m`. Image names with dashes -in them potentially conflict with command line flags. - -* The API now has Improved status codes for `start` and `stop`. Trying to start -a running container will now return a 304 error. - -* Performance has been improved overall. Starting the daemon is faster than in -previous releases. The daemon’s performance has also been improved when it is -working with large numbers of images and containers. - -* Fixed an issue with white-spaces and multi-lines in Dockerfiles. - -##Version 1.1.0 - -###New Features - -*`.dockerignore` support* - -You can now add a `.dockerignore` file next to your `Dockerfile` and Docker will -ignore files and directories specified in that file when sending the build -context to the daemon. Example: -https://github.com/dotcloud/docker/blob/master/.dockerignore - -*Pause containers during commit* - -Doing a commit on a running container was not recommended because you could end -up with files in an inconsistent state (for example, if they were being written -during the commit). Containers are now paused when a commit is made to them. You -can disable this feature by doing a `docker commit --pause=false ` - -*Tailing logs* - -You can now tail the logs of a container. For example, you can get the last ten -lines of a log by using `docker logs --tail 10 `. You can also -follow the logs of a container without having to read the whole log file with -`docker logs --tail 0 -f `. - -*Allow a tar file as context for docker build* - -You can now pass a tar archive to `docker build` as context. This can be used to -automate docker builds, for example: `cat context.tar | docker build -` or -`docker run builder_image | docker build -` - -*Bind mounting your whole filesystem in a container* - -`/` is now allowed as source of `--volumes`. This means you can bind-mount your -whole system in a container if you need to. For example: `docker run -v -/:/my_host ubuntu:ro ls /my_host`. However, it is now forbidden to mount to /. - - -###Other Improvements & Changes - -* Port allocation has been improved. In the previous release, Docker could -prevent you from starting a container with previously allocated ports which -seemed to be in use when in fact they were not. This has been fixed. - -* A bug in `docker save` was introduced in the last release. The `docker save` -command could produce images with invalid metadata. The command now produces -images with correct metadata. - -* Running `docker inspect` in a container now returns which containers it is -linked to. - -* Parsing of the `docker commit` flag has improved validation, to better prevent -you from committing an image with a name such as `-m`. Image names with dashes -in them potentially conflict with command line flags. - -* The API now has Improved status codes for `start` and `stop`. Trying to start -a running container will now return a 304 error. - -* Performance has been improved overall. Starting the daemon is faster than in -previous releases. The daemon’s performance has also been improved when it is -working with large numbers of images and containers. - -* Fixed an issue with white-spaces and multi-lines in Dockerfiles. - -##Version 1.0.0 - -First production-ready release. Prior development history can be found by -searching in [GitHub](https://github.com/docker/docker). +# Release Notes + +You can view release notes for earlier version of Docker by selecting the +desired version from the drop-down list at the top right of this page. + +## Version 1.5.0 +(2015-02-03) + +For a complete list of patches, fixes, and other improvements, see the +[merge PR on GitHub](https://github.com/docker/docker/pull/10286). + +*New Features* + +* The Docker daemon has now supports for IPv6 networking between containers + and on the `docker0` bridge. For more information see the + [IPv6 networking reference](/articles/networking/#ipv6). +* Docker container filesystems can now be set to`--read-only`, restricting your + container to writing to volumes [PR# 10093](https://github.com/docker/docker/pull/10093). +* A new `docker stats CONTAINERID` command has been added to allow users to view a + continuously updating stream of container resource usage statistics. See the + [`stats` command line reference](/reference/commandline/cli/#stats) and the + [container `stats` API reference](/reference/api/docker_remote_api_v1.17/#get-container-stats-based-on-resource-usage). + **Note**: this feature is only enabled for the `libcontainer` exec-driver at this point. +* Users can now specify the file to use as the `Dockerfile` by running + `docker build -f alternate.dockerfile .`. This will allow the definition of multiple + `Dockerfile`s for a single project. See the [`docker build` command reference]( +/reference/commandline/cli/#build) for more information. +* The v1 Open Image specification has been created to document the current Docker image + format and metadata. Please see [the Open Image specification document]( +https://github.com/docker/docker/blob/master/image/spec/v1.md) for more details. +* This release also includes a number of significant performance improvements in + build and image management ([PR #9720](https://github.com/docker/docker/pull/9720), + [PR #8827](https://github.com/docker/docker/pull/8827)) +* The `docker inspect` command now lists ExecIDs generated for each `docker exec` process. + See [PR #9800](https://github.com/docker/docker/pull/9800)) for more details. +* The `docker inspect` command now shows the number of container restarts when there + is a restart policy ([PR #9621](https://github.com/docker/docker/pull/9621)) +* This version of Docker is built using Go 1.4 + +> **Note:** +> Development history prior to version 1.0 can be found by +> searching in the [Docker GitHub repo](https://github.com/docker/docker). + +## Known Issues + +This section lists significant known issues present in Docker as of release +date. It is not exhaustive; it lists only issues with potentially significant +impact on users. This list will be updated as issues are resolved. + +* **Unexpected File Permissions in Containers** +An idiosyncrasy in AUFS prevents permissions from propagating predictably +between upper and lower layers. This can cause issues with accessing private +keys, database instances, etc. For complete information and workarounds see +[Github Issue 783](https://github.com/docker/docker/issues/783). + +* **Docker Hub incompatible with Safari 8** +Docker Hub has multiple issues displaying on Safari 8, the default browser +for OS X 10.10 (Yosemite). Users should access the hub using a different +browser. Most notably, changes in the way Safari handles cookies means that the +user is repeatedly logged out. For more information, see the [Docker +forum post](https://forums.docker.com/t/new-safari-in-yosemite-issue/300). diff --git a/docs/sources/terms/image.md b/docs/sources/terms/image.md index 40438be63..e42a6cfa1 100644 --- a/docs/sources/terms/image.md +++ b/docs/sources/terms/image.md @@ -8,10 +8,10 @@ page_keywords: containers, lxc, concepts, explanation, image, container ![](/terms/images/docker-filesystems-debian.png) -In Docker terminology, a read-only [*Layer*](/terms/layer/#layer-def) is +In Docker terminology, a read-only [*Layer*](/terms/layer/#layer) is called an **image**. An image never changes. -Since Docker uses a [*Union File System*](/terms/layer/#ufs-def), the +Since Docker uses a [*Union File System*](/terms/layer/#union-file-system), the processes think the whole file system is mounted read-write. But all the changes go to the top-most writeable layer, and underneath, the original file in the read-only image is unchanged. Since images don't change, diff --git a/docs/sources/terms/layer.md b/docs/sources/terms/layer.md index 561807fc4..3e8704cd0 100644 --- a/docs/sources/terms/layer.md +++ b/docs/sources/terms/layer.md @@ -7,7 +7,7 @@ page_keywords: containers, lxc, concepts, explanation, image, container ## Introduction In a traditional Linux boot, the kernel first mounts the root [*File -System*](/terms/filesystem/#filesystem-def) as read-only, checks its +System*](/terms/filesystem) as read-only, checks its integrity, and then switches the whole rootfs volume to read-write mode. ## Layer diff --git a/docs/sources/userguide/dockerimages.md b/docs/sources/userguide/dockerimages.md index ead6d82db..6224479fb 100644 --- a/docs/sources/userguide/dockerimages.md +++ b/docs/sources/userguide/dockerimages.md @@ -4,7 +4,7 @@ page_keywords: documentation, docs, the docker guide, docker guide, docker, dock # Working with Docker Images -In the [introduction](/introduction/) we've discovered that Docker +In the [introduction](/introduction/understanding-docker/) we've discovered that Docker images are the basis of containers. In the [previous](/userguide/dockerizing/) [sections](/userguide/usingdocker/) we've used Docker images that already exist, for example the `ubuntu` @@ -192,7 +192,7 @@ Now we have a container with the change we want to make. We can then commit a copy of this container to an image using the `docker commit` command. - $ sudo docker commit -m="Added json gem" -a="Kate Smith" \ + $ sudo docker commit -m "Added json gem" -a "Kate Smith" \ 0b2616b0e5a8 ouruser/sinatra:v2 4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c @@ -263,7 +263,7 @@ this case we're basing our new image on an Ubuntu 14.04 image. Next we use the `MAINTAINER` instruction to specify who maintains our new image. -Lastly, we've specified three `RUN` instructions. A `RUN` instruction executes +Lastly, we've specified two `RUN` instructions. A `RUN` instruction executes a command inside the image, for example installing a package. Here we're updating our APT cache, installing Ruby and RubyGems and then installing the Sinatra gem. @@ -273,7 +273,7 @@ Sinatra gem. Now let's take our `Dockerfile` and use the `docker build` command to build an image. - $ sudo docker build -t="ouruser/sinatra:v2" . + $ sudo docker build -t ouruser/sinatra:v2 . Sending build context to Docker daemon 2.048 kB Sending build context to Docker daemon Step 0 : FROM ubuntu:14.04 diff --git a/docs/sources/userguide/dockerizing.md b/docs/sources/userguide/dockerizing.md index 238316098..6f56a5695 100644 --- a/docs/sources/userguide/dockerizing.md +++ b/docs/sources/userguide/dockerizing.md @@ -9,6 +9,8 @@ page_keywords: docker guide, docker, docker platform, virtualization framework, Docker allows you to run applications inside containers. Running an application inside a container takes a single command: `docker run`. +{{ include "no-remote-sudo.md" }} + ## Hello world Let's try it now. diff --git a/docs/sources/userguide/dockerlinks.md b/docs/sources/userguide/dockerlinks.md index e2228cef0..f35f61ecf 100644 --- a/docs/sources/userguide/dockerlinks.md +++ b/docs/sources/userguide/dockerlinks.md @@ -146,7 +146,7 @@ Now, create a new `web` container and link it with your `db` container. This will link the new `web` container with the `db` container you created earlier. The `--link` flag takes the form: - --link name:alias + --link :alias Where `name` is the name of the container we're linking to and `alias` is an alias for the link name. You'll see how that alias gets used shortly. @@ -232,6 +232,12 @@ command to list the specified container's environment variables. > container. Similarly, some daemons (such as `sshd`) > will scrub them when spawning shells for connection. +> **Note**: +> Unlike host entries in the [`/etc/hosts` file](#updating-the-etchosts-file), +> IP addresses stored in the environment variables are not automatically updated +> if the source container is restarted. We recommend using the host entries in +> `/etc/hosts` to resolve the IP address of linked containers. + You can see that Docker has created a series of environment variables with useful information about the source `db` container. Each variable is prefixed with `DB_`, which is populated from the `alias` you specified above. If the `alias` @@ -282,6 +288,8 @@ will be automatically updated with the source container's new IP address, allowing linked communication to continue. $ sudo docker restart db + db + $ sudo docker run -t -i --rm --link db:db training/webapp /bin/bash root@aed84ee21bde:/opt/webapp# cat /etc/hosts 172.17.0.7 aed84ee21bde . . . diff --git a/docs/sources/userguide/dockerrepos.md b/docs/sources/userguide/dockerrepos.md index 9b5f9783e..d8dc44e69 100644 --- a/docs/sources/userguide/dockerrepos.md +++ b/docs/sources/userguide/dockerrepos.md @@ -36,8 +36,8 @@ e-mail address. It will then automatically log you in. You can now commit and push your own images up to your repos on Docker Hub. > **Note:** -> Your authentication credentials will be stored in the [`.dockercfg` -> authentication file](#authentication-file) in your home directory. +> Your authentication credentials will be stored in the `.dockercfg` +> authentication file in your home directory. ## Searching for images diff --git a/docs/sources/userguide/dockervolumes.md b/docs/sources/userguide/dockervolumes.md index 6f94b6dbd..4d5bd7247 100644 --- a/docs/sources/userguide/dockervolumes.md +++ b/docs/sources/userguide/dockervolumes.md @@ -21,9 +21,10 @@ Docker. A *data volume* is a specially-designated directory within one or more containers that bypasses the [*Union File -System*](/terms/layer/#ufs-def) to provide several useful features for +System*](/terms/layer/#union-file-system) to provide several useful features for persistent or shared data: +- Volumes are initialized when a container is created - Data volumes can be shared and reused between containers - Changes to a data volume are made directly - Changes to a data volume will not be included when you update an image @@ -32,9 +33,9 @@ persistent or shared data: ### Adding a data volume You can add a data volume to a container using the `-v` flag with the -`docker run` command. You can use the `-v` multiple times in a single -`docker run` to mount multiple data volumes. Let's mount a single volume -now in our web application container. +`docker create` and `docker run` command. You can use the `-v` multiple times +to mount multiple data volumes. Let's mount a single volume now in our web +application container. $ sudo docker run -d -P --name web -v /webapp training/webapp python app.py @@ -47,7 +48,15 @@ This will create a new volume inside a container at `/webapp`. ### Mount a Host Directory as a Data Volume In addition to creating a volume using the `-v` flag you can also mount a -directory from your own host into a container. +directory from your Docker daemon's host into a container. + +> **Note:** +> If you are using Boot2Docker, your Docker daemon only has limited access to +> your OSX/Windows filesystem. Boot2Docker tries to auto-share your `/Users` +> (OSX) or `C:\Users` (Windows) directory - and so you can mount files or directories +> using `docker run -v /Users/:/ ...` (OSX) or +> `docker run -v /c/Users/:/ come from the Boot2Docker virtual machine's filesystem. $ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py @@ -55,7 +64,7 @@ This will mount the host directory, `/src/webapp`, into the container at `/opt/webapp`. > **Note:** -> If the path `/opt/webapp` already exists inside the container's image, it's +> If the path `/opt/webapp` already exists inside the container's image, its > contents will be replaced by the contents of `/src/webapp` on the host to stay > consistent with the expected behavior of `mount` @@ -67,8 +76,8 @@ create it for you. > **Note:** > This is not available from a `Dockerfile` due to the portability -> and sharing purpose of it. As the host directory is, by its nature, -> host-dependent, a host directory specified in a `Dockerfile` probably +> and sharing purpose of built images. The host directory is, by its nature, +> host-dependent, so a host directory specified in a `Dockerfile` probably > wouldn't work on all hosts. Docker defaults to a read-write volume but we can also mount a directory @@ -105,8 +114,10 @@ create a named Data Volume Container, and then to mount the data from it. Let's create a new named container with a volume to share. +While this container doesn't run an application, it reuses the `training/postgres` +image so that all containers are using layers in common, saving disk space. - $ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres + $ sudo docker create -v /dbdata --name dbdata training/postgres You can then use the `--volumes-from` flag to mount the `/dbdata` volume in another container. diff --git a/docs/sources/userguide/level1.md b/docs/sources/userguide/level1.md index 56048bfcc..cca77dc36 100644 --- a/docs/sources/userguide/level1.md +++ b/docs/sources/userguide/level1.md @@ -29,7 +29,7 @@ page_keywords: documentation, docs, the docker guide, docker guide, docker, dock

@@ -69,4 +69,4 @@ Tell the world! Back -Go to the next level \ No newline at end of file +Go to the next level diff --git a/docs/sources/userguide/level2.md b/docs/sources/userguide/level2.md index 4ff76be07..fe6654e71 100644 --- a/docs/sources/userguide/level2.md +++ b/docs/sources/userguide/level2.md @@ -39,7 +39,7 @@ What is the Dockerfile instruction to specify the base image?
@@ -93,4 +93,4 @@ Thanks for going through our tutorial! We will be posting Level 3 in the future. To improve your Dockerfile writing skills even further, visit the Dockerfile best practices page. -Back to the Docs! \ No newline at end of file +Back to the Docs! diff --git a/docs/sources/userguide/usingdocker.md b/docs/sources/userguide/usingdocker.md index 865f446bd..12a6b6fb2 100644 --- a/docs/sources/userguide/usingdocker.md +++ b/docs/sources/userguide/usingdocker.md @@ -167,8 +167,9 @@ host. You might be asking about now: why wouldn't we just want to always use 1:1 port mappings in Docker containers rather than mapping to high ports? Well 1:1 mappings have the constraint of only being able to map one of each port on your local host. Let's say you want to test two -Python applications: both bound to port 5000 inside your container. -Without Docker's port mapping you could only access one at a time. +Python applications: both bound to port 5000 inside their own containers. +Without Docker's port mapping you could only access one at a time on the +Docker host. So let's now browse to port 49155 in a web browser to see the application. diff --git a/docs/test.sh b/docs/test.sh new file mode 100755 index 000000000..351236844 --- /dev/null +++ b/docs/test.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +mkdocs serve & +echo "Waiting for 5 seconds to allow mkdocs server to be ready" +sleep 5 +./docvalidate.py diff --git a/docs/theme/mkdocs/css/docs.css b/docs/theme/mkdocs/css/docs.css index 068a0003e..767aa1f8e 100644 --- a/docs/theme/mkdocs/css/docs.css +++ b/docs/theme/mkdocs/css/docs.css @@ -22,22 +22,39 @@ #leftnav { height: 100%; -} - -#leftnav h3 { - font-size: 10px; - font-weight: 700; - color: #394d54; - line-height: 1; - margin: 10px 0 10px 0; - padding-left: 20px; - white-space: nowrap; overflow: hidden; - text-overflow: ellipsis; } -#leftnav li.active { - margin-bottom: 10px; +#leftnav .nav ul { + line-height: 1; + margin: 10px 10px 0px 16px; + padding: 0; + list-style: none; +} +#leftnav .nav li ul a, +#leftnav .nav li ul a:hover { + margin: 0 !important; + padding: 0 !important; + font-size: 13px; + font-weight: 400; + color: #394d54; +} +#leftnav .nav li ul a:hover { + color: #24b8eb; +} + +#leftnav .nav.nav-tabs li a, +#leftnav .nav.nav-tabs li li { + line-height: 1.1 !important; +} + +#leftnav li { + margin-top: 20px; + // text-indent: -16px; + padding-left: 10px; +} +#leftnav .nav-tabs.nav ul li { + margin-top: 5px; } .content-body { @@ -60,6 +77,7 @@ pre { /* Main Navigation */ #nav_menu > #docsnav { max-width: 940px; + width: 940px; margin: 0 auto; } #nav_menu > #docsnav > #nav_search { @@ -112,7 +130,7 @@ pre { box-sizing: border-box; } #nav_menu #docsnav #main-nav > li { - font-size: 14px; + font-size: 15px; font-weight: 400; color: #253237; line-height: 2em; @@ -177,13 +195,13 @@ pre { display: block; } .dd_menu li a { - font-size: 14px; + font-size: 15px; font-weight: 400; color: #005976; } .dd_menu li a:hover { text-decoration: none; - font-size: 14px; + font-size: 15px; font-weight: 400; color: #24b8eb; } @@ -321,13 +339,6 @@ pre { font-weight: bold; } -#leftnav .nav.nav-tabs li a { - line-height: 20px !important; - padding-top: 15px !important; - padding-right: 8px; - padding-bottom: 15px !important; -} - /* Logged-in/out header */ .topmostnav_loggedin { display: none; diff --git a/docs/theme/mkdocs/css/main.css b/docs/theme/mkdocs/css/main.css index ed7c189a0..270c220fd 100644 --- a/docs/theme/mkdocs/css/main.css +++ b/docs/theme/mkdocs/css/main.css @@ -801,10 +801,6 @@ div + .form-inline { transition: box-shadow linear 0.2s, background linear 0.3s, width linear 0.3s; width: 140px; } -#topmostnav .navbar-index-search .search-query:focus, -#topmostnav .navbar-index-search .search-query.focused { - width: 200px; -} #topmostnav.public { border-bottom: none; height: 80px; @@ -995,7 +991,7 @@ div + .form-inline { #leftnav .nav.nav-tabs.nav-stacked > li > a { border: 0; } -#leftnav .nav.nav-tabs li.active a { +Killwithfire #leftnav .nav.nav-tabs li.active a { font-size: 16px; font-weight: 500; color: #394d54; @@ -1005,14 +1001,14 @@ div + .form-inline { border-left: 10px solid #ade5f9; padding-left: 9px; } -#leftnav .nav.nav-tabs li.active a:hover { +Killwithfire #leftnav .nav.nav-tabs li.active a:hover { font-size: 16px; font-weight: 500; color: #24b8eb; text-decoration: none; cursor: pointer; } -#leftnav .nav.nav-tabs li.active a:focus { +Killwithfire #leftnav .nav.nav-tabs li.active a:focus { outline: none; } #leftnav .nav.nav-tabs > li > a { diff --git a/docs/theme/mkdocs/footer.html b/docs/theme/mkdocs/footer.html index 69a4e6367..923ace519 100644 --- a/docs/theme/mkdocs/footer.html +++ b/docs/theme/mkdocs/footer.html @@ -101,7 +101,7 @@
- \ No newline at end of file + diff --git a/docs/theme/mkdocs/header.html b/docs/theme/mkdocs/header.html index a3b1d9bd7..6622f9330 100644 --- a/docs/theme/mkdocs/header.html +++ b/docs/theme/mkdocs/header.html @@ -1,13 +1,14 @@ -
https://github.com/ahmetalpbalkan/Docker.DotNet Active
C++lasote/docker_clienthttp://www.biicode.com/lasote/docker_client (Biicode C++ dependency manager)Active
Erlang erldocker