Initial commit
554
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/dockerimages.md
generated
vendored
Normal file
@@ -0,0 +1,554 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
aliases = ["/engine/userguide/dockerimages/"]
|
||||
title = "Build your own images"
|
||||
description = "How to work with Docker images."
|
||||
keywords = ["documentation, docs, the docker guide, docker guide, docker, docker platform, docker.io, Docker images, Docker image, image management, Docker repos, Docker repositories, docker, docker tag, docker tags, Docker Hub, collaboration"]
|
||||
[menu.main]
|
||||
parent = "engine_learn"
|
||||
weight = -4
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Build your own images
|
||||
|
||||
Docker images are the basis of containers. Each time you've used `docker run`
|
||||
you told it which image you wanted. In the previous sections of the guide you
|
||||
used Docker images that already exist, for example the `ubuntu` image and the
|
||||
`training/webapp` image.
|
||||
|
||||
You also discovered that Docker stores downloaded images on the Docker host. If
|
||||
an image isn't already present on the host then it'll be downloaded from a
|
||||
registry: by default the [Docker Hub Registry](https://registry.hub.docker.com).
|
||||
|
||||
In this section you're going to explore Docker images a bit more
|
||||
including:
|
||||
|
||||
* Managing and working with images locally on your Docker host.
|
||||
* Creating basic images.
|
||||
* Uploading images to [Docker Hub Registry](https://registry.hub.docker.com).
|
||||
|
||||
## Listing images on the host
|
||||
|
||||
Let's start with listing the images you have locally on our host. You can
|
||||
do this using the `docker images` command like so:
|
||||
|
||||
$ docker images
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
ubuntu 14.04 1d073211c498 3 days ago 187.9 MB
|
||||
busybox latest 2c5ac3f849df 5 days ago 1.113 MB
|
||||
training/webapp latest 54bb4e8718e8 5 months ago 348.7 MB
|
||||
|
||||
You can see the images you've previously used in the user guide.
|
||||
Each has been downloaded from [Docker Hub](https://hub.docker.com) when you
|
||||
launched a container using that image. When you list images, you get three crucial pieces of information in the listing.
|
||||
|
||||
* What repository they came from, for example `ubuntu`.
|
||||
* The tags for each image, for example `14.04`.
|
||||
* The image ID of each image.
|
||||
|
||||
> **Tip:**
|
||||
> You can use [a third-party dockviz tool](https://github.com/justone/dockviz)
|
||||
> or the [Image layers site](https://imagelayers.io/) to display
|
||||
> visualizations of image data.
|
||||
|
||||
A repository potentially holds multiple variants of an image. In the case of
|
||||
our `ubuntu` image you can see multiple variants covering Ubuntu 10.04, 12.04,
|
||||
12.10, 13.04, 13.10 and 14.04. Each variant is identified by a tag and you can
|
||||
refer to a tagged image like so:
|
||||
|
||||
ubuntu:14.04
|
||||
|
||||
So when you run a container you refer to a tagged image like so:
|
||||
|
||||
$ docker run -t -i ubuntu:14.04 /bin/bash
|
||||
|
||||
If instead you wanted to run an Ubuntu 12.04 image you'd use:
|
||||
|
||||
$ docker run -t -i ubuntu:12.04 /bin/bash
|
||||
|
||||
If you don't specify a variant, for example you just use `ubuntu`, then Docker
|
||||
will default to using the `ubuntu:latest` image.
|
||||
|
||||
> **Tip:**
|
||||
> You should always specify an image tag, for example `ubuntu:14.04`.
|
||||
> That way, you always know exactly what variant of an image you are using.
|
||||
> This is useful for troubleshooting and debugging.
|
||||
|
||||
## Getting a new image
|
||||
|
||||
So how do you get new images? Well Docker will automatically download any image
|
||||
you use that isn't already present on the Docker host. But this can potentially
|
||||
add some time to the launch of a container. If you want to pre-load an image you
|
||||
can download it using the `docker pull` command. Suppose you'd like to
|
||||
download the `centos` image.
|
||||
|
||||
$ docker pull centos
|
||||
Pulling repository centos
|
||||
b7de3133ff98: Pulling dependent layers
|
||||
5cc9e91966f7: Pulling fs layer
|
||||
511136ea3c5a: Download complete
|
||||
ef52fb1fe610: Download complete
|
||||
. . .
|
||||
|
||||
Status: Downloaded newer image for centos
|
||||
|
||||
You can see that each layer of the image has been pulled down and now you
|
||||
can run a container from this image and you won't have to wait to
|
||||
download the image.
|
||||
|
||||
$ docker run -t -i centos /bin/bash
|
||||
bash-4.1#
|
||||
|
||||
## Finding images
|
||||
|
||||
One of the features of Docker is that a lot of people have created Docker
|
||||
images for a variety of purposes. Many of these have been uploaded to
|
||||
[Docker Hub](https://hub.docker.com). You can search these images on the
|
||||
[Docker Hub](https://hub.docker.com) website.
|
||||
|
||||

|
||||
|
||||
You can also search for images on the command line using the `docker search`
|
||||
command. Suppose your team wants an image with Ruby and Sinatra installed on
|
||||
which to do our web application development. You can search for a suitable image
|
||||
by using the `docker search` command to find all the images that contain the
|
||||
term `sinatra`.
|
||||
|
||||
$ docker search sinatra
|
||||
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
|
||||
training/sinatra Sinatra training image 0 [OK]
|
||||
marceldegraaf/sinatra Sinatra test app 0
|
||||
mattwarren/docker-sinatra-demo 0 [OK]
|
||||
luisbebop/docker-sinatra-hello-world 0 [OK]
|
||||
bmorearty/handson-sinatra handson-ruby + Sinatra for Hands on with D... 0
|
||||
subwiz/sinatra 0
|
||||
bmorearty/sinatra 0
|
||||
. . .
|
||||
|
||||
You can see the command returns a lot of images that use the term `sinatra`.
|
||||
You've received a list of image names, descriptions, Stars (which measure the
|
||||
social popularity of images - if a user likes an image then they can "star" it),
|
||||
and the Official and Automated build statuses. [Official
|
||||
Repositories](https://docs.docker.com/docker-hub/official_repos) are a carefully
|
||||
curated set of Docker repositories supported by Docker, Inc. Automated
|
||||
repositories are [Automated Builds](dockerrepos.md#automated-builds) that allow
|
||||
you to validate the source and content of an image.
|
||||
|
||||
You've reviewed the images available to use and you decided to use the
|
||||
`training/sinatra` image. So far you've seen two types of images repositories,
|
||||
images like `ubuntu`, which are called base or root images. These base images
|
||||
are provided by Docker Inc and are built, validated and supported. These can be
|
||||
identified by their single word names.
|
||||
|
||||
You've also seen user images, for example the `training/sinatra` image you've
|
||||
chosen. A user image belongs to a member of the Docker community and is built
|
||||
and maintained by them. You can identify user images as they are always
|
||||
prefixed with the user name, here `training`, of the user that created them.
|
||||
|
||||
## Pulling our image
|
||||
|
||||
You've identified a suitable image, `training/sinatra`, and now you can download it using the `docker pull` command.
|
||||
|
||||
$ docker pull training/sinatra
|
||||
|
||||
The team can now use this image by running their own containers.
|
||||
|
||||
$ docker run -t -i training/sinatra /bin/bash
|
||||
root@a8cb6ce02d85:/#
|
||||
|
||||
## Creating our own images
|
||||
|
||||
The team has found the `training/sinatra` image pretty useful but it's not quite
|
||||
what they need and you need to make some changes to it. There are two ways you
|
||||
can update and create images.
|
||||
|
||||
1. You can update a container created from an image and commit the results to an image.
|
||||
2. You can use a `Dockerfile` to specify instructions to create an image.
|
||||
|
||||
|
||||
### Updating and committing an image
|
||||
|
||||
To update an image you first need to create a container from the image
|
||||
you'd like to update.
|
||||
|
||||
$ docker run -t -i training/sinatra /bin/bash
|
||||
root@0b2616b0e5a8:/#
|
||||
|
||||
> **Note:**
|
||||
> Take note of the container ID that has been created, `0b2616b0e5a8`, as you'll
|
||||
> need it in a moment.
|
||||
|
||||
Inside our running container let's add the `json` gem.
|
||||
|
||||
root@0b2616b0e5a8:/# gem install json
|
||||
|
||||
Once this has completed let's exit our container using the `exit`
|
||||
command.
|
||||
|
||||
Now you have a container with the change you want to make. You can then
|
||||
commit a copy of this container to an image using the `docker commit`
|
||||
command.
|
||||
|
||||
$ docker commit -m "Added json gem" -a "Kate Smith" \
|
||||
0b2616b0e5a8 ouruser/sinatra:v2
|
||||
4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c
|
||||
|
||||
Here you've used the `docker commit` command. You've specified two flags: `-m`
|
||||
and `-a`. The `-m` flag allows us to specify a commit message, much like you
|
||||
would with a commit on a version control system. The `-a` flag allows us to
|
||||
specify an author for our update.
|
||||
|
||||
You've also specified the container you want to create this new image from,
|
||||
`0b2616b0e5a8` (the ID you recorded earlier) and you've specified a target for
|
||||
the image:
|
||||
|
||||
ouruser/sinatra:v2
|
||||
|
||||
Break this target down. It consists of a new user, `ouruser`, that you're
|
||||
writing this image to. You've also specified the name of the image, here you're
|
||||
keeping the original image name `sinatra`. Finally you're specifying a tag for
|
||||
the image: `v2`.
|
||||
|
||||
You can then look at our new `ouruser/sinatra` image using the `docker images`
|
||||
command.
|
||||
|
||||
$ docker images
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
training/sinatra latest 5bc342fa0b91 10 hours ago 446.7 MB
|
||||
ouruser/sinatra v2 3c59e02ddd1a 10 hours ago 446.7 MB
|
||||
ouruser/sinatra latest 5db5f8471261 10 hours ago 446.7 MB
|
||||
|
||||
To use our new image to create a container you can then:
|
||||
|
||||
$ docker run -t -i ouruser/sinatra:v2 /bin/bash
|
||||
root@78e82f680994:/#
|
||||
|
||||
### Building an image from a `Dockerfile`
|
||||
|
||||
Using the `docker commit` command is a pretty simple way of extending an image
|
||||
but it's a bit cumbersome and it's not easy to share a development process for
|
||||
images amongst a team. Instead you can use a new command, `docker build`, to
|
||||
build new images from scratch.
|
||||
|
||||
To do this you create a `Dockerfile` that contains a set of instructions that
|
||||
tell Docker how to build our image.
|
||||
|
||||
First, create a directory and a `Dockerfile`.
|
||||
|
||||
$ mkdir sinatra
|
||||
$ cd sinatra
|
||||
$ touch Dockerfile
|
||||
|
||||
If you are using Docker Machine on Windows, you may access your host
|
||||
directory by `cd` to `/c/Users/your_user_name`.
|
||||
|
||||
Each instruction creates a new layer of the image. Try a simple example now for
|
||||
building your own Sinatra image for your fictitious development team.
|
||||
|
||||
# This is a comment
|
||||
FROM ubuntu:14.04
|
||||
MAINTAINER Kate Smith <ksmith@example.com>
|
||||
RUN apt-get update && apt-get install -y ruby ruby-dev
|
||||
RUN gem install sinatra
|
||||
|
||||
Examine what your `Dockerfile` does. Each instruction prefixes a statement and
|
||||
is capitalized.
|
||||
|
||||
INSTRUCTION statement
|
||||
|
||||
> **Note:** You use `#` to indicate a comment
|
||||
|
||||
The first instruction `FROM` tells Docker what the source of our image is, in
|
||||
this case you're basing our new image on an Ubuntu 14.04 image. The instruction uses the `MAINTAINER` instruction to specify who maintains the new image.
|
||||
|
||||
Lastly, you've specified two `RUN` instructions. A `RUN` instruction executes
|
||||
a command inside the image, for example installing a package. Here you're
|
||||
updating our APT cache, installing Ruby and RubyGems and then installing the
|
||||
Sinatra gem.
|
||||
|
||||
|
||||
|
||||
Now let's take our `Dockerfile` and use the `docker build` command to build an image.
|
||||
|
||||
$ docker build -t ouruser/sinatra:v2 .
|
||||
Sending build context to Docker daemon 2.048 kB
|
||||
Sending build context to Docker daemon
|
||||
Step 1 : FROM ubuntu:14.04
|
||||
---> e54ca5efa2e9
|
||||
Step 2 : MAINTAINER Kate Smith <ksmith@example.com>
|
||||
---> Using cache
|
||||
---> 851baf55332b
|
||||
Step 3 : RUN apt-get update && apt-get install -y ruby ruby-dev
|
||||
---> Running in 3a2558904e9b
|
||||
Selecting previously unselected package libasan0:amd64.
|
||||
(Reading database ... 11518 files and directories currently installed.)
|
||||
Preparing to unpack .../libasan0_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking libasan0:amd64 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package libatomic1:amd64.
|
||||
Preparing to unpack .../libatomic1_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking libatomic1:amd64 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package libgmp10:amd64.
|
||||
Preparing to unpack .../libgmp10_2%3a5.1.3+dfsg-1ubuntu1_amd64.deb ...
|
||||
Unpacking libgmp10:amd64 (2:5.1.3+dfsg-1ubuntu1) ...
|
||||
Selecting previously unselected package libisl10:amd64.
|
||||
Preparing to unpack .../libisl10_0.12.2-1_amd64.deb ...
|
||||
Unpacking libisl10:amd64 (0.12.2-1) ...
|
||||
Selecting previously unselected package libcloog-isl4:amd64.
|
||||
Preparing to unpack .../libcloog-isl4_0.18.2-1_amd64.deb ...
|
||||
Unpacking libcloog-isl4:amd64 (0.18.2-1) ...
|
||||
Selecting previously unselected package libgomp1:amd64.
|
||||
Preparing to unpack .../libgomp1_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking libgomp1:amd64 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package libitm1:amd64.
|
||||
Preparing to unpack .../libitm1_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking libitm1:amd64 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package libmpfr4:amd64.
|
||||
Preparing to unpack .../libmpfr4_3.1.2-1_amd64.deb ...
|
||||
Unpacking libmpfr4:amd64 (3.1.2-1) ...
|
||||
Selecting previously unselected package libquadmath0:amd64.
|
||||
Preparing to unpack .../libquadmath0_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking libquadmath0:amd64 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package libtsan0:amd64.
|
||||
Preparing to unpack .../libtsan0_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking libtsan0:amd64 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package libyaml-0-2:amd64.
|
||||
Preparing to unpack .../libyaml-0-2_0.1.4-3ubuntu3_amd64.deb ...
|
||||
Unpacking libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
|
||||
Selecting previously unselected package libmpc3:amd64.
|
||||
Preparing to unpack .../libmpc3_1.0.1-1ubuntu1_amd64.deb ...
|
||||
Unpacking libmpc3:amd64 (1.0.1-1ubuntu1) ...
|
||||
Selecting previously unselected package openssl.
|
||||
Preparing to unpack .../openssl_1.0.1f-1ubuntu2.4_amd64.deb ...
|
||||
Unpacking openssl (1.0.1f-1ubuntu2.4) ...
|
||||
Selecting previously unselected package ca-certificates.
|
||||
Preparing to unpack .../ca-certificates_20130906ubuntu2_all.deb ...
|
||||
Unpacking ca-certificates (20130906ubuntu2) ...
|
||||
Selecting previously unselected package manpages.
|
||||
Preparing to unpack .../manpages_3.54-1ubuntu1_all.deb ...
|
||||
Unpacking manpages (3.54-1ubuntu1) ...
|
||||
Selecting previously unselected package binutils.
|
||||
Preparing to unpack .../binutils_2.24-5ubuntu3_amd64.deb ...
|
||||
Unpacking binutils (2.24-5ubuntu3) ...
|
||||
Selecting previously unselected package cpp-4.8.
|
||||
Preparing to unpack .../cpp-4.8_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking cpp-4.8 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package cpp.
|
||||
Preparing to unpack .../cpp_4%3a4.8.2-1ubuntu6_amd64.deb ...
|
||||
Unpacking cpp (4:4.8.2-1ubuntu6) ...
|
||||
Selecting previously unselected package libgcc-4.8-dev:amd64.
|
||||
Preparing to unpack .../libgcc-4.8-dev_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking libgcc-4.8-dev:amd64 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package gcc-4.8.
|
||||
Preparing to unpack .../gcc-4.8_4.8.2-19ubuntu1_amd64.deb ...
|
||||
Unpacking gcc-4.8 (4.8.2-19ubuntu1) ...
|
||||
Selecting previously unselected package gcc.
|
||||
Preparing to unpack .../gcc_4%3a4.8.2-1ubuntu6_amd64.deb ...
|
||||
Unpacking gcc (4:4.8.2-1ubuntu6) ...
|
||||
Selecting previously unselected package libc-dev-bin.
|
||||
Preparing to unpack .../libc-dev-bin_2.19-0ubuntu6_amd64.deb ...
|
||||
Unpacking libc-dev-bin (2.19-0ubuntu6) ...
|
||||
Selecting previously unselected package linux-libc-dev:amd64.
|
||||
Preparing to unpack .../linux-libc-dev_3.13.0-30.55_amd64.deb ...
|
||||
Unpacking linux-libc-dev:amd64 (3.13.0-30.55) ...
|
||||
Selecting previously unselected package libc6-dev:amd64.
|
||||
Preparing to unpack .../libc6-dev_2.19-0ubuntu6_amd64.deb ...
|
||||
Unpacking libc6-dev:amd64 (2.19-0ubuntu6) ...
|
||||
Selecting previously unselected package ruby.
|
||||
Preparing to unpack .../ruby_1%3a1.9.3.4_all.deb ...
|
||||
Unpacking ruby (1:1.9.3.4) ...
|
||||
Selecting previously unselected package ruby1.9.1.
|
||||
Preparing to unpack .../ruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
|
||||
Unpacking ruby1.9.1 (1.9.3.484-2ubuntu1) ...
|
||||
Selecting previously unselected package libruby1.9.1.
|
||||
Preparing to unpack .../libruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
|
||||
Unpacking libruby1.9.1 (1.9.3.484-2ubuntu1) ...
|
||||
Selecting previously unselected package manpages-dev.
|
||||
Preparing to unpack .../manpages-dev_3.54-1ubuntu1_all.deb ...
|
||||
Unpacking manpages-dev (3.54-1ubuntu1) ...
|
||||
Selecting previously unselected package ruby1.9.1-dev.
|
||||
Preparing to unpack .../ruby1.9.1-dev_1.9.3.484-2ubuntu1_amd64.deb ...
|
||||
Unpacking ruby1.9.1-dev (1.9.3.484-2ubuntu1) ...
|
||||
Selecting previously unselected package ruby-dev.
|
||||
Preparing to unpack .../ruby-dev_1%3a1.9.3.4_all.deb ...
|
||||
Unpacking ruby-dev (1:1.9.3.4) ...
|
||||
Setting up libasan0:amd64 (4.8.2-19ubuntu1) ...
|
||||
Setting up libatomic1:amd64 (4.8.2-19ubuntu1) ...
|
||||
Setting up libgmp10:amd64 (2:5.1.3+dfsg-1ubuntu1) ...
|
||||
Setting up libisl10:amd64 (0.12.2-1) ...
|
||||
Setting up libcloog-isl4:amd64 (0.18.2-1) ...
|
||||
Setting up libgomp1:amd64 (4.8.2-19ubuntu1) ...
|
||||
Setting up libitm1:amd64 (4.8.2-19ubuntu1) ...
|
||||
Setting up libmpfr4:amd64 (3.1.2-1) ...
|
||||
Setting up libquadmath0:amd64 (4.8.2-19ubuntu1) ...
|
||||
Setting up libtsan0:amd64 (4.8.2-19ubuntu1) ...
|
||||
Setting up libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
|
||||
Setting up libmpc3:amd64 (1.0.1-1ubuntu1) ...
|
||||
Setting up openssl (1.0.1f-1ubuntu2.4) ...
|
||||
Setting up ca-certificates (20130906ubuntu2) ...
|
||||
debconf: unable to initialize frontend: Dialog
|
||||
debconf: (TERM is not set, so the dialog frontend is not usable.)
|
||||
debconf: falling back to frontend: Readline
|
||||
debconf: unable to initialize frontend: Readline
|
||||
debconf: (This frontend requires a controlling tty.)
|
||||
debconf: falling back to frontend: Teletype
|
||||
Setting up manpages (3.54-1ubuntu1) ...
|
||||
Setting up binutils (2.24-5ubuntu3) ...
|
||||
Setting up cpp-4.8 (4.8.2-19ubuntu1) ...
|
||||
Setting up cpp (4:4.8.2-1ubuntu6) ...
|
||||
Setting up libgcc-4.8-dev:amd64 (4.8.2-19ubuntu1) ...
|
||||
Setting up gcc-4.8 (4.8.2-19ubuntu1) ...
|
||||
Setting up gcc (4:4.8.2-1ubuntu6) ...
|
||||
Setting up libc-dev-bin (2.19-0ubuntu6) ...
|
||||
Setting up linux-libc-dev:amd64 (3.13.0-30.55) ...
|
||||
Setting up libc6-dev:amd64 (2.19-0ubuntu6) ...
|
||||
Setting up manpages-dev (3.54-1ubuntu1) ...
|
||||
Setting up libruby1.9.1 (1.9.3.484-2ubuntu1) ...
|
||||
Setting up ruby1.9.1-dev (1.9.3.484-2ubuntu1) ...
|
||||
Setting up ruby-dev (1:1.9.3.4) ...
|
||||
Setting up ruby (1:1.9.3.4) ...
|
||||
Setting up ruby1.9.1 (1.9.3.484-2ubuntu1) ...
|
||||
Processing triggers for libc-bin (2.19-0ubuntu6) ...
|
||||
Processing triggers for ca-certificates (20130906ubuntu2) ...
|
||||
Updating certificates in /etc/ssl/certs... 164 added, 0 removed; done.
|
||||
Running hooks in /etc/ca-certificates/update.d....done.
|
||||
---> c55c31703134
|
||||
Removing intermediate container 3a2558904e9b
|
||||
Step 4 : RUN gem install sinatra
|
||||
---> Running in 6b81cb6313e5
|
||||
unable to convert "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to US-ASCII for README.rdoc, skipping
|
||||
unable to convert "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to US-ASCII for README.rdoc, skipping
|
||||
Successfully installed rack-1.5.2
|
||||
Successfully installed tilt-1.4.1
|
||||
Successfully installed rack-protection-1.5.3
|
||||
Successfully installed sinatra-1.4.5
|
||||
4 gems installed
|
||||
Installing ri documentation for rack-1.5.2...
|
||||
Installing ri documentation for tilt-1.4.1...
|
||||
Installing ri documentation for rack-protection-1.5.3...
|
||||
Installing ri documentation for sinatra-1.4.5...
|
||||
Installing RDoc documentation for rack-1.5.2...
|
||||
Installing RDoc documentation for tilt-1.4.1...
|
||||
Installing RDoc documentation for rack-protection-1.5.3...
|
||||
Installing RDoc documentation for sinatra-1.4.5...
|
||||
---> 97feabe5d2ed
|
||||
Removing intermediate container 6b81cb6313e5
|
||||
Successfully built 97feabe5d2ed
|
||||
|
||||
You've specified our `docker build` command and used the `-t` flag to identify
|
||||
our new image as belonging to the user `ouruser`, the repository name `sinatra`
|
||||
and given it the tag `v2`.
|
||||
|
||||
You've also specified the location of our `Dockerfile` using the `.` to
|
||||
indicate a `Dockerfile` in the current directory.
|
||||
|
||||
> **Note:**
|
||||
> You can also specify a path to a `Dockerfile`.
|
||||
|
||||
Now you can see the build process at work. The first thing Docker does is
|
||||
upload the build context: basically the contents of the directory you're
|
||||
building in. This is done because the Docker daemon does the actual
|
||||
build of the image and it needs the local context to do it.
|
||||
|
||||
Next you can see each instruction in the `Dockerfile` being executed
|
||||
step-by-step. You can see that each step creates a new container, runs
|
||||
the instruction inside that container and then commits that change -
|
||||
just like the `docker commit` work flow you saw earlier. When all the
|
||||
instructions have executed you're left with the `97feabe5d2ed` image
|
||||
(also helpfully tagged as `ouruser/sinatra:v2`) and all intermediate
|
||||
containers will get removed to clean things up.
|
||||
|
||||
> **Note:**
|
||||
> An image can't have more than 127 layers regardless of the storage driver.
|
||||
> This limitation is set globally to encourage optimization of the overall
|
||||
> size of images.
|
||||
|
||||
You can then create a container from our new image.
|
||||
|
||||
$ docker run -t -i ouruser/sinatra:v2 /bin/bash
|
||||
root@8196968dac35:/#
|
||||
|
||||
> **Note:**
|
||||
> This is just a brief introduction to creating images. We've
|
||||
> skipped a whole bunch of other instructions that you can use. We'll see more of
|
||||
> those instructions in later sections of the Guide or you can refer to the
|
||||
> [`Dockerfile`](../../reference/builder.md) reference for a
|
||||
> detailed description and examples of every instruction.
|
||||
> To help you write a clear, readable, maintainable `Dockerfile`, we've also
|
||||
> written a [`Dockerfile` Best Practices guide](../eng-image/dockerfile_best-practices.md).
|
||||
|
||||
|
||||
## Setting tags on an image
|
||||
|
||||
You can also add a tag to an existing image after you commit or build it. We
|
||||
can do this using the `docker tag` command. Now, add a new tag to your
|
||||
`ouruser/sinatra` image.
|
||||
|
||||
$ docker tag 5db5f8471261 ouruser/sinatra:devel
|
||||
|
||||
The `docker tag` command takes the ID of the image, here `5db5f8471261`, and our
|
||||
user name, the repository name and the new tag.
|
||||
|
||||
Now, see your new tag using the `docker images` command.
|
||||
|
||||
$ docker images ouruser/sinatra
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
ouruser/sinatra latest 5db5f8471261 11 hours ago 446.7 MB
|
||||
ouruser/sinatra devel 5db5f8471261 11 hours ago 446.7 MB
|
||||
ouruser/sinatra v2 5db5f8471261 11 hours ago 446.7 MB
|
||||
|
||||
## Image Digests
|
||||
|
||||
Images that use the v2 or later format have a content-addressable identifier
|
||||
called a `digest`. As long as the input used to generate the image is
|
||||
unchanged, the digest value is predictable. To list image digest values, use
|
||||
the `--digests` flag:
|
||||
|
||||
$ docker images --digests | head
|
||||
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
|
||||
ouruser/sinatra latest sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf 5db5f8471261 11 hours ago 446.7 MB
|
||||
|
||||
When pushing or pulling to a 2.0 registry, the `push` or `pull` command
|
||||
output includes the image digest. You can `pull` using a digest value.
|
||||
|
||||
$ docker pull ouruser/sinatra@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
|
||||
|
||||
You can also reference by digest in `create`, `run`, and `rmi` commands, as well as the
|
||||
`FROM` image reference in a Dockerfile.
|
||||
|
||||
## Push an image to Docker Hub
|
||||
|
||||
Once you've built or created a new image you can push it to [Docker
|
||||
Hub](https://hub.docker.com) using the `docker push` command. This
|
||||
allows you to share it with others, either publicly, or push it into [a
|
||||
private repository](https://registry.hub.docker.com/plans/).
|
||||
|
||||
$ docker push ouruser/sinatra
|
||||
The push refers to a repository [ouruser/sinatra] (len: 1)
|
||||
Sending image list
|
||||
Pushing repository ouruser/sinatra (3 tags)
|
||||
. . .
|
||||
|
||||
## Remove an image from the host
|
||||
|
||||
You can also remove images on your Docker host in a way [similar to
|
||||
containers](usingdocker.md) using the `docker rmi` command.
|
||||
|
||||
Delete the `training/sinatra` image as you don't need it anymore.
|
||||
|
||||
$ docker rmi training/sinatra
|
||||
Untagged: training/sinatra:latest
|
||||
Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d
|
||||
Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f
|
||||
Deleted: 5c58979d73ae448df5af1d8142436d81116187a7633082650549c52c3a2418f0
|
||||
|
||||
> **Note:** To remove an image from the host, please make sure
|
||||
> that there are no containers actively based on it.
|
||||
|
||||
# Next steps
|
||||
|
||||
Until now you've seen how to build individual applications inside Docker
|
||||
containers. Now learn how to build whole application stacks with Docker
|
||||
by networking together multiple Docker containers.
|
||||
|
||||
Go to [Network containers](networkingcontainers.md).
|
||||
212
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/dockerizing.md
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
aliases = ["/engine/userguide/dockerizing/"]
|
||||
title = "Hello world in a container"
|
||||
description = "A simple 'Hello world' exercise that introduced you to Docker."
|
||||
keywords = ["docker guide, docker, docker platform, how to, dockerize, dockerizing apps, dockerizing applications, container, containers"]
|
||||
[menu.main]
|
||||
parent="engine_learn"
|
||||
weight=-6
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Hello world in a container
|
||||
|
||||
*So what's this Docker thing all about?*
|
||||
|
||||
Docker allows you to run applications, worlds you create, inside containers.
|
||||
Running an application inside a container takes a single command: `docker run`.
|
||||
|
||||
>**Note**: Depending on your Docker system configuration, you may be required to
|
||||
>preface each `docker` command on this page with `sudo`. To avoid this behavior,
|
||||
>your system administrator can create a Unix group called `docker` and add users
|
||||
>to it.
|
||||
|
||||
## Run a Hello world
|
||||
|
||||
Let's try it now.
|
||||
|
||||
$ docker run ubuntu /bin/echo 'Hello world'
|
||||
Hello world
|
||||
|
||||
And you just launched your first container!
|
||||
|
||||
So what just happened? Let's step through what the `docker run` command
|
||||
did.
|
||||
|
||||
First we specified the `docker` binary and the command we wanted to
|
||||
execute, `run`. The `docker run` combination *runs* containers.
|
||||
|
||||
Next we specified an image: `ubuntu`. This is the source of the container
|
||||
we ran. Docker calls this an image. In this case we used the Ubuntu
|
||||
operating system image.
|
||||
|
||||
When you specify an image, Docker looks first for the image on your
|
||||
Docker host. If it can't find it then it downloads the image from the public
|
||||
image registry: [Docker Hub](https://hub.docker.com).
|
||||
|
||||
Next we told Docker what command to run inside our new container:
|
||||
|
||||
/bin/echo 'Hello world'
|
||||
|
||||
When our container was launched Docker created a new Ubuntu
|
||||
environment and then executed the `/bin/echo` command inside it. We saw
|
||||
the result on the command line:
|
||||
|
||||
Hello world
|
||||
|
||||
So what happened to our container after that? Well Docker containers
|
||||
only run as long as the command you specify is active. Here, as soon as
|
||||
`Hello world` was echoed, the container stopped.
|
||||
|
||||
## An interactive container
|
||||
|
||||
Let's try the `docker run` command again, this time specifying a new
|
||||
command to run in our container.
|
||||
|
||||
$ docker run -t -i ubuntu /bin/bash
|
||||
root@af8bae53bdd3:/#
|
||||
|
||||
Here we've again specified the `docker run` command and launched an
|
||||
`ubuntu` image. But we've also passed in two flags: `-t` and `-i`.
|
||||
The `-t` flag assigns a pseudo-tty or terminal inside our new container
|
||||
and the `-i` flag allows us to make an interactive connection by
|
||||
grabbing the standard in (`STDIN`) of the container.
|
||||
|
||||
We've also specified a new command for our container to run:
|
||||
`/bin/bash`. This will launch a Bash shell inside our container.
|
||||
|
||||
So now when our container is launched we can see that we've got a
|
||||
command prompt inside it:
|
||||
|
||||
root@af8bae53bdd3:/#
|
||||
|
||||
Let's try running some commands inside our container:
|
||||
|
||||
root@af8bae53bdd3:/# pwd
|
||||
/
|
||||
root@af8bae53bdd3:/# ls
|
||||
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
|
||||
|
||||
You can see we've run the `pwd` to show our current directory and can
|
||||
see we're in the `/` root directory. We've also done a directory listing
|
||||
of the root directory which shows us what looks like a typical Linux
|
||||
file system.
|
||||
|
||||
You can play around inside this container and when you're done you can
|
||||
use the `exit` command or enter Ctrl-D to finish.
|
||||
|
||||
root@af8bae53bdd3:/# exit
|
||||
|
||||
As with our previous container, once the Bash shell process has
|
||||
finished, the container is stopped.
|
||||
|
||||
## A daemonized Hello world
|
||||
|
||||
Now a container that runs a command and then exits has some uses but
|
||||
it's not overly helpful. Let's create a container that runs as a daemon,
|
||||
like most of the applications we're probably going to run with Docker.
|
||||
|
||||
Again we can do this with the `docker run` command:
|
||||
|
||||
$ docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
|
||||
1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147
|
||||
|
||||
Wait, what? Where's our "hello world" output? Let's look at what we've run here.
|
||||
It should look pretty familiar. We ran `docker run` but this time we
|
||||
specified a flag: `-d`. The `-d` flag tells Docker to run the container
|
||||
and put it in the background, to daemonize it.
|
||||
|
||||
We also specified the same image: `ubuntu`.
|
||||
|
||||
Finally, we specified a command to run:
|
||||
|
||||
/bin/sh -c "while true; do echo hello world; sleep 1; done"
|
||||
|
||||
This is the (hello) world's silliest daemon: a shell script that echoes
|
||||
`hello world` forever.
|
||||
|
||||
So why aren't we seeing any `hello world`'s? Instead Docker has returned
|
||||
a really long string:
|
||||
|
||||
1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147
|
||||
|
||||
This really long string is called a *container ID*. It uniquely
|
||||
identifies a container so we can work with it.
|
||||
|
||||
> **Note:**
|
||||
> The container ID is a bit long and unwieldy. A bit later,
|
||||
> we'll see a shorter ID and ways to name our containers to make
|
||||
> working with them easier.
|
||||
|
||||
We can use this container ID to see what's happening with our `hello world` daemon.
|
||||
|
||||
Firstly let's make sure our container is running. We can
|
||||
do that with the `docker ps` command. The `docker ps` command queries
|
||||
the Docker daemon for information about all the containers it knows
|
||||
about.
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
1e5535038e28 ubuntu /bin/sh -c 'while tr 2 minutes ago Up 1 minute insane_babbage
|
||||
|
||||
Here we can see our daemonized container. The `docker ps` has returned some useful
|
||||
information about it, starting with a shorter variant of its container ID:
|
||||
`1e5535038e28`.
|
||||
|
||||
We can also see the image we used to build it, `ubuntu`, the command it
|
||||
is running, its status and an automatically assigned name,
|
||||
`insane_babbage`.
|
||||
|
||||
> **Note:**
|
||||
> Docker automatically generates names for any containers started.
|
||||
> We'll see how to specify your own names a bit later.
|
||||
|
||||
Okay, so we now know it's running. But is it doing what we asked it to do? To
|
||||
see this we're going to look inside the container using the `docker logs`
|
||||
command. Let's use the container name Docker assigned.
|
||||
|
||||
$ docker logs insane_babbage
|
||||
hello world
|
||||
hello world
|
||||
hello world
|
||||
. . .
|
||||
|
||||
The `docker logs` command looks inside the container and returns its standard
|
||||
output: in this case the output of our command `hello world`.
|
||||
|
||||
Awesome! Our daemon is working and we've just created our first
|
||||
Dockerized application!
|
||||
|
||||
Now we've established we can create our own containers let's tidy up
|
||||
after ourselves and stop our detached container. To do this we use the
|
||||
`docker stop` command.
|
||||
|
||||
$ docker stop insane_babbage
|
||||
insane_babbage
|
||||
|
||||
The `docker stop` command tells Docker to politely stop the running
|
||||
container. If it succeeds it will return the name of the container it
|
||||
has just stopped.
|
||||
|
||||
Let's check it worked with the `docker ps` command.
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
|
||||
Excellent. Our container has been stopped.
|
||||
|
||||
# Next steps
|
||||
|
||||
So far, you launched your first containers using the `docker run` command. You
|
||||
ran an *interactive container* that ran in the foreground. You also ran a
|
||||
*detached container* that ran in the background. In the process you learned
|
||||
about several Docker commands:
|
||||
|
||||
* `docker ps` - Lists containers.
|
||||
* `docker logs` - Shows us the standard output of a container.
|
||||
* `docker stop` - Stops running containers.
|
||||
|
||||
Now, you have the basis learn more about Docker and how to do some more advanced
|
||||
tasks. Go to ["*Run a simple application*"](usingdocker.md) to actually build a
|
||||
web application with the Docker client.
|
||||
187
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/dockerrepos.md
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
aliases = ["/engine/userguide/dockerrepos/"]
|
||||
title = "Store images on Docker Hub"
|
||||
description = "Learn how to use the Docker Hub to manage Docker images and work flow"
|
||||
keywords = ["repo, Docker Hub, Docker Hub, registry, index, repositories, usage, pull image, push image, image, documentation"]
|
||||
[menu.main]
|
||||
parent = "engine_learn"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Store images on Docker Hub
|
||||
|
||||
So far you've learned how to use the command line to run Docker on your local
|
||||
host. You've learned how to [pull down images](usingdocker.md) to build
|
||||
containers from existing images and you've learned how to [create your own
|
||||
images](dockerimages.md).
|
||||
|
||||
Next, you're going to learn how to use the [Docker Hub](https://hub.docker.com)
|
||||
to simplify and enhance your Docker workflows.
|
||||
|
||||
The [Docker Hub](https://hub.docker.com) is a public registry maintained by
|
||||
Docker, Inc. It contains images you can download and use to build
|
||||
containers. It also provides authentication, work group structure, workflow
|
||||
tools like webhooks and build triggers, and privacy tools like private
|
||||
repositories for storing images you don't want to share publicly.
|
||||
|
||||
## Docker commands and Docker Hub
|
||||
|
||||
Docker itself provides access to Docker Hub services via the `docker search`,
|
||||
`pull`, `login`, and `push` commands. This page will show you how these commands work.
|
||||
|
||||
### Account creation and login
|
||||
Typically, you'll want to start by creating an account on Docker Hub (if you haven't
|
||||
already) and logging in. You can create your account directly on
|
||||
[Docker Hub](https://hub.docker.com/account/signup/), or by running:
|
||||
|
||||
$ docker login
|
||||
|
||||
This will prompt you for a user name, which will become the public namespace for your
|
||||
public repositories.
|
||||
If your user name is available, Docker will prompt you to enter a password and your
|
||||
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 `~/.docker/config.json`
|
||||
> authentication file in your home directory.
|
||||
|
||||
## Searching for images
|
||||
|
||||
You can search the [Docker Hub](https://hub.docker.com) registry via its search
|
||||
interface or by using the command line interface. Searching can find images by image
|
||||
name, user name, or description:
|
||||
|
||||
$ docker search centos
|
||||
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
|
||||
centos The official build of CentOS 1223 [OK]
|
||||
tianon/centos CentOS 5 and 6, created using rinse instea... 33
|
||||
...
|
||||
|
||||
There you can see two example results: `centos` and `tianon/centos`. The second
|
||||
result shows that it comes from the public repository of a user, named
|
||||
`tianon/`, while the first result, `centos`, doesn't explicitly list a
|
||||
repository which means that it comes from the trusted top-level namespace for
|
||||
[Official Repositories](https://docs.docker.com/docker-hub/official_repos/). The `/` character separates
|
||||
a user's repository from the image name.
|
||||
|
||||
Once you've found the image you want, you can download it with `docker pull <imagename>`:
|
||||
|
||||
$ docker pull centos
|
||||
Using default tag: latest
|
||||
latest: Pulling from library/centos
|
||||
f1b10cd84249: Pull complete
|
||||
c852f6d61e65: Pull complete
|
||||
7322fbe74aa5: Pull complete
|
||||
Digest: sha256:90305c9112250c7e3746425477f1c4ef112b03b4abe78c612e092037bfecc3b7
|
||||
Status: Downloaded newer image for centos:latest
|
||||
|
||||
You now have an image from which you can run containers.
|
||||
|
||||
### Specific Versions or Latest
|
||||
Using `docker pull centos` is equivalent to using `docker pull centos:latest`.
|
||||
To pull an image that is not the default latest image you can be more precise
|
||||
with the image that you want.
|
||||
|
||||
For example, to pull version 5 of `centos` use `docker pull centos:centos5`.
|
||||
In this example, `centos5` is the tag labeling an image in the `centos`
|
||||
repository for a version of `centos`.
|
||||
|
||||
To find a list of tags pointing to currently available versions of a repository
|
||||
see the [Docker Hub](https://hub.docker.com) registry.
|
||||
|
||||
## Contributing to Docker Hub
|
||||
|
||||
Anyone can pull public images from the [Docker Hub](https://hub.docker.com)
|
||||
registry, but if you would like to share your own images, then you must
|
||||
[register first](https://docs.docker.com/docker-hub/accounts).
|
||||
|
||||
## Pushing a repository to Docker Hub
|
||||
|
||||
In order to push a repository to its registry, you need to have named an image
|
||||
or committed your container to a named image as we saw
|
||||
[here](dockerimages.md).
|
||||
|
||||
Now you can push this repository to the registry designated by its name or tag.
|
||||
|
||||
$ docker push yourname/newimage
|
||||
|
||||
The image will then be uploaded and available for use by your team-mates and/or the
|
||||
community.
|
||||
|
||||
## Features of Docker Hub
|
||||
|
||||
Let's take a closer look at some of the features of Docker Hub. You can find more
|
||||
information [here](https://docs.docker.com/docker-hub/).
|
||||
|
||||
* Private repositories
|
||||
* Organizations and teams
|
||||
* Automated Builds
|
||||
* Webhooks
|
||||
|
||||
### Private repositories
|
||||
|
||||
Sometimes you have images you don't want to make public and share with
|
||||
everyone. So Docker Hub allows you to have private repositories. You can
|
||||
sign up for a plan [here](https://registry.hub.docker.com/plans/).
|
||||
|
||||
### Organizations and teams
|
||||
|
||||
One of the useful aspects of private repositories is that you can share
|
||||
them only with members of your organization or team. Docker Hub lets you
|
||||
create organizations where you can collaborate with your colleagues and
|
||||
manage private repositories. You can learn how to create and manage an organization
|
||||
[here](https://registry.hub.docker.com/account/organizations/).
|
||||
|
||||
### Automated Builds
|
||||
|
||||
Automated Builds automate the building and updating of images from
|
||||
[GitHub](https://www.github.com) or [Bitbucket](http://bitbucket.com), directly on Docker
|
||||
Hub. It works by adding a commit hook to your selected GitHub or Bitbucket repository,
|
||||
triggering a build and update when you push a commit.
|
||||
|
||||
#### To setup an Automated Build
|
||||
|
||||
1. Create a [Docker Hub account](https://hub.docker.com/) and login.
|
||||
2. Link your GitHub or Bitbucket account through the ["Link Accounts"](https://registry.hub.docker.com/account/accounts/) menu.
|
||||
3. [Configure an Automated Build](https://registry.hub.docker.com/builds/add/).
|
||||
4. Pick a GitHub or Bitbucket project that has a `Dockerfile` that you want to build.
|
||||
5. Pick the branch you want to build (the default is the `master` branch).
|
||||
6. Give the Automated Build a name.
|
||||
7. Assign an optional Docker tag to the Build.
|
||||
8. Specify where the `Dockerfile` is located. The default is `/`.
|
||||
|
||||
Once the Automated Build is configured it will automatically trigger a
|
||||
build and, in a few minutes, you should see your new Automated Build on the [Docker Hub](https://hub.docker.com)
|
||||
Registry. It will stay in sync with your GitHub and Bitbucket repository until you
|
||||
deactivate the Automated Build.
|
||||
|
||||
To check the output and status of your Automated Build repositories, click on a repository name within the ["Your Repositories" page](https://registry.hub.docker.com/repos/). Automated Builds are indicated by a check-mark icon next to the repository name. Within the repository details page, you may click on the "Build Details" tab to view the status and output of all builds triggered by the Docker Hub.
|
||||
|
||||
Once you've created an Automated Build you can deactivate or delete it. You
|
||||
cannot, however, push to an Automated Build with the `docker push` command.
|
||||
You can only manage it by committing code to your GitHub or Bitbucket
|
||||
repository.
|
||||
|
||||
You can create multiple Automated Builds per repository and configure them
|
||||
to point to specific `Dockerfile`'s or Git branches.
|
||||
|
||||
#### Build triggers
|
||||
|
||||
Automated Builds can also be triggered via a URL on Docker Hub. This
|
||||
allows you to rebuild an Automated build image on demand.
|
||||
|
||||
### Webhooks
|
||||
|
||||
Webhooks are attached to your repositories and allow you to trigger an
|
||||
event when an image or updated image is pushed to the repository. With
|
||||
a webhook you can specify a target URL and a JSON payload that will be
|
||||
delivered when the image is pushed.
|
||||
|
||||
See the Docker Hub documentation for [more information on
|
||||
webhooks](https://docs.docker.com/docker-hub/repos/#webhooks)
|
||||
|
||||
## Next steps
|
||||
|
||||
Go and use Docker!
|
||||
286
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/dockervolumes.md
generated
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
aliases = ["/engine/userguide/dockervolumes/"]
|
||||
title = "Manage data in containers"
|
||||
description = "How to manage data inside your Docker containers."
|
||||
keywords = ["Examples, Usage, volume, docker, documentation, user guide, data, volumes"]
|
||||
[menu.main]
|
||||
parent = "engine_learn"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Manage data in containers
|
||||
|
||||
So far we've been introduced to some [basic Docker concepts](../containers/usingdocker.md),
|
||||
seen how to work with [Docker images](../containers/dockerimages.md) as well as learned about
|
||||
[networking and links between containers](../networking/default_network/dockerlinks.md). In this section we're
|
||||
going to discuss how you can manage data inside and between your Docker
|
||||
containers.
|
||||
|
||||
We're going to look at the two primary ways you can manage data in
|
||||
Docker.
|
||||
|
||||
* Data volumes, and
|
||||
* Data volume containers.
|
||||
|
||||
## Data volumes
|
||||
|
||||
A *data volume* is a specially-designated directory within one or more
|
||||
containers that bypasses the [*Union File System*](../../reference/glossary.md#union-file-system). Data volumes provide several useful features for persistent or shared data:
|
||||
|
||||
- Volumes are initialized when a container is created. If the container's
|
||||
base image contains data at the specified mount point, that existing data is
|
||||
copied into the new volume upon volume initialization. (Note that this does
|
||||
not apply when [mounting a host directory](#mount-a-host-directory-as-a-data-volume).)
|
||||
- Data volumes can be shared and reused among containers.
|
||||
- Changes to a data volume are made directly.
|
||||
- Changes to a data volume will not be included when you update an image.
|
||||
- Data volumes persist even if the container itself is deleted.
|
||||
|
||||
Data volumes are designed to persist data, independent of the container's life
|
||||
cycle. Docker therefore *never* automatically deletes volumes when you remove
|
||||
a container, nor will it "garbage collect" volumes that are no longer
|
||||
referenced by a container.
|
||||
|
||||
### Adding a data volume
|
||||
|
||||
You can add a data volume to a container using the `-v` flag with the
|
||||
`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.
|
||||
|
||||
$ docker run -d -P --name web -v /webapp training/webapp python app.py
|
||||
|
||||
This will create a new volume inside a container at `/webapp`.
|
||||
|
||||
> **Note:**
|
||||
> You can also use the `VOLUME` instruction in a `Dockerfile` to add one or
|
||||
> more new volumes to any container created from that image.
|
||||
|
||||
### Locating a volume
|
||||
|
||||
You can locate the volume on the host by utilizing the `docker inspect` command.
|
||||
|
||||
$ docker inspect web
|
||||
|
||||
The output will provide details on the container configurations including the
|
||||
volumes. The output should look something similar to the following:
|
||||
|
||||
...
|
||||
Mounts": [
|
||||
{
|
||||
"Name": "fac362...80535",
|
||||
"Source": "/var/lib/docker/volumes/fac362...80535/_data",
|
||||
"Destination": "/webapp",
|
||||
"Driver": "local",
|
||||
"Mode": "",
|
||||
"RW": true,
|
||||
"Propagation": ""
|
||||
}
|
||||
]
|
||||
...
|
||||
|
||||
You will notice in the above `Source` is specifying the location on the host and
|
||||
`Destination` is specifying the volume location inside the container. `RW` shows
|
||||
if the volume is read/write.
|
||||
|
||||
### 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 Docker daemon's host into a container.
|
||||
|
||||
```
|
||||
$ docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
|
||||
```
|
||||
|
||||
This command mounts the host directory, `/src/webapp`, into the container at
|
||||
`/opt/webapp`. If the path `/opt/webapp` already exists inside the container's
|
||||
image, the `/src/webapp` mount overlays but does not remove the pre-existing
|
||||
content. Once the mount is removed, the content is accessible again. This is
|
||||
consistent with the expected behavior of the `mount` command.
|
||||
|
||||
The `container-dir` must always be an absolute path such as `/src/docs`.
|
||||
The `host-dir` can either be an absolute path or a `name` value. If you
|
||||
supply an absolute path for the `host-dir`, Docker bind-mounts to the path
|
||||
you specify. If you supply a `name`, Docker creates a named volume by that `name`.
|
||||
|
||||
A `name` value must start with an alphanumeric character,
|
||||
followed by `a-z0-9`, `_` (underscore), `.` (period) or `-` (hyphen).
|
||||
An absolute path starts with a `/` (forward slash).
|
||||
|
||||
For example, you can specify either `/foo` or `foo` for a `host-dir` value.
|
||||
If you supply the `/foo` value, Docker creates a bind-mount. If you supply
|
||||
the `foo` specification, Docker creates a named volume.
|
||||
|
||||
If you are using Docker Machine on Mac or Windows, your Docker daemon has only limited access to your OS X or Windows filesystem. Docker Machine tries
|
||||
to auto-share your `/Users` (OS X) or `C:\Users` (Windows) directory. So,
|
||||
you can mount files or directories on OS X using.
|
||||
|
||||
```
|
||||
docker run -v /Users/<path>:/<container path> ...
|
||||
```
|
||||
|
||||
On Windows, mount directories using:
|
||||
|
||||
```
|
||||
docker run -v /c/Users/<path>:/<container path> ...`
|
||||
```
|
||||
|
||||
All other paths come from your virtual machine's filesystem. For example, if
|
||||
you are using VirtualBox some other folder available for sharing, you need to do
|
||||
additional work. In the case of VirtualBox you need to make the host folder
|
||||
available as a shared folder in VirtualBox. Then, you can mount it using the
|
||||
Docker `-v` flag.
|
||||
|
||||
Mounting a host directory can be useful for testing. For example, you can mount
|
||||
source code inside a container. Then, change the source code and see its effect
|
||||
on the application in real time. The directory on the host must be specified as
|
||||
an absolute path and if the directory doesn't exist Docker will automatically
|
||||
create it for you. This auto-creation of the host path has been [*deprecated*](#auto-creating-missing-host-paths-for-bind-mounts).
|
||||
|
||||
Docker volumes default to mount in read-write mode, but you can also set it to
|
||||
be mounted read-only.
|
||||
|
||||
```
|
||||
$ docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
|
||||
```
|
||||
|
||||
Here we've mounted the same `/src/webapp` directory but we've added the `ro`
|
||||
option to specify that the mount should be read-only.
|
||||
|
||||
Because of [limitations in the `mount`
|
||||
function](http://lists.linuxfoundation.org/pipermail/containers/2015-April/035788.html),
|
||||
moving subdirectories within the host's source directory can give
|
||||
access from the container to the host's file system. This requires a malicious
|
||||
user with access to host and its mounted directory.
|
||||
|
||||
>**Note**: The host directory is, by its nature, host-dependent. For this
|
||||
>reason, you can't mount a host directory from `Dockerfile` because built images
|
||||
>should be portable. A host directory wouldn't be available on all potential
|
||||
>hosts.
|
||||
|
||||
### Volume labels
|
||||
|
||||
Labeling systems like SELinux require that proper labels are placed on volume
|
||||
content mounted into a container. Without a label, the security system might
|
||||
prevent the processes running inside the container from using the content. By
|
||||
default, Docker does not change the labels set by the OS.
|
||||
|
||||
To change a label in the container context, you can add either of two suffixes
|
||||
`:z` or `:Z` to the volume mount. These suffixes tell Docker to relabel file
|
||||
objects on the shared volumes. The `z` option tells Docker that two containers
|
||||
share the volume content. As a result, Docker labels the content with a shared
|
||||
content label. Shared volume labels allow all containers to read/write content.
|
||||
The `Z` option tells Docker to label the content with a private unshared label.
|
||||
Only the current container can use a private volume.
|
||||
|
||||
### Mount a host file as a data volume
|
||||
|
||||
The `-v` flag can also be used to mount a single file - instead of *just*
|
||||
directories - from the host machine.
|
||||
|
||||
$ docker run --rm -it -v ~/.bash_history:/root/.bash_history ubuntu /bin/bash
|
||||
|
||||
This will drop you into a bash shell in a new container, you will have your bash
|
||||
history from the host and when you exit the container, the host will have the
|
||||
history of the commands typed while in the container.
|
||||
|
||||
> **Note:**
|
||||
> Many tools used to edit files including `vi` and `sed --in-place` may result
|
||||
> in an inode change. Since Docker v1.1.0, this will produce an error such as
|
||||
> "*sed: cannot rename ./sedKdJ9Dy: Device or resource busy*". In the case where
|
||||
> you want to edit the mounted file, it is often easiest to instead mount the
|
||||
> parent directory.
|
||||
|
||||
## Creating and mounting a data volume container
|
||||
|
||||
If you have some persistent data that you want to share between
|
||||
containers, or want to use from non-persistent containers, it's best to
|
||||
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.
|
||||
|
||||
$ docker create -v /dbdata --name dbstore training/postgres /bin/true
|
||||
|
||||
You can then use the `--volumes-from` flag to mount the `/dbdata` volume in another container.
|
||||
|
||||
$ docker run -d --volumes-from dbstore --name db1 training/postgres
|
||||
|
||||
And another:
|
||||
|
||||
$ docker run -d --volumes-from dbstore --name db2 training/postgres
|
||||
|
||||
In this case, if the `postgres` image contained a directory called `/dbdata`
|
||||
then mounting the volumes from the `dbstore` container hides the
|
||||
`/dbdata` files from the `postgres` image. The result is only the files
|
||||
from the `dbstore` container are visible.
|
||||
|
||||
You can use multiple `--volumes-from` parameters to combine data volumes from
|
||||
several containers. To find detailed information about `--volumes-from` see the
|
||||
[Mount volumes from container](../../reference/commandline/run.md#mount-volumes-from-container-volumes-from)
|
||||
in the `run` command reference.
|
||||
|
||||
You can also extend the chain by mounting the volume that came from the
|
||||
`dbstore` container in yet another container via the `db1` or `db2` containers.
|
||||
|
||||
$ docker run -d --name db3 --volumes-from db1 training/postgres
|
||||
|
||||
If you remove containers that mount volumes, including the initial `dbstore`
|
||||
container, or the subsequent containers `db1` and `db2`, the volumes will not
|
||||
be deleted. To delete the volume from disk, you must explicitly call
|
||||
`docker rm -v` against the last container with a reference to the volume. This
|
||||
allows you to upgrade, or effectively migrate data volumes between containers.
|
||||
|
||||
> **Note:** Docker will not warn you when removing a container *without*
|
||||
> providing the `-v` option to delete its volumes. If you remove containers
|
||||
> without using the `-v` option, you may end up with "dangling" volumes;
|
||||
> volumes that are no longer referenced by a container.
|
||||
> You can use `docker volume ls -f dangling=true` to find dangling volumes,
|
||||
> and use `docker volume rm <volume name>` to remove a volume that's
|
||||
> no longer needed.
|
||||
|
||||
## Backup, restore, or migrate data volumes
|
||||
|
||||
Another useful function we can perform with volumes is use them for
|
||||
backups, restores or migrations. We do this by using the
|
||||
`--volumes-from` flag to create a new container that mounts that volume,
|
||||
like so:
|
||||
|
||||
$ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
|
||||
|
||||
Here we've launched a new container and mounted the volume from the
|
||||
`dbstore` container. We've then mounted a local host directory as
|
||||
`/backup`. Finally, we've passed a command that uses `tar` to backup the
|
||||
contents of the `dbdata` volume to a `backup.tar` file inside our
|
||||
`/backup` directory. When the command completes and the container stops
|
||||
we'll be left with a backup of our `dbdata` volume.
|
||||
|
||||
You could then restore it to the same container, or another that you've made
|
||||
elsewhere. Create a new container.
|
||||
|
||||
$ docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
|
||||
|
||||
Then un-tar the backup file in the new container's data volume.
|
||||
|
||||
$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"
|
||||
|
||||
You can use the techniques above to automate backup, migration and
|
||||
restore testing using your preferred tools.
|
||||
|
||||
## Important tips on using shared volumes
|
||||
|
||||
Multiple containers can also share one or more data volumes. However, multiple containers writing to a single shared volume can cause data corruption. Make sure your applications are designed to write to shared data stores.
|
||||
|
||||
Data volumes are directly accessible from the Docker host. This means you can read and write to them with normal Linux tools. In most cases you should not do this as it can cause data corruption if your containers and applications are unaware of your direct access.
|
||||
|
||||
# Next steps
|
||||
|
||||
Now we've learned a bit more about how to use Docker we're going to see how to
|
||||
combine Docker with the services available on
|
||||
[Docker Hub](https://hub.docker.com) including Automated Builds and private
|
||||
repositories.
|
||||
|
||||
Go to [Working with Docker Hub](../containers/dockerrepos.md).
|
||||
19
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/index.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Learn by example"
|
||||
description = "Explains how to work with containers"
|
||||
keywords = ["docker, introduction, documentation, about, technology, docker.io, user, guide, user's, manual, platform, framework, home, intro"]
|
||||
[menu.main]
|
||||
identifier="engine_learn"
|
||||
parent = "engine_guide"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Learn by example
|
||||
|
||||
* [Hello world in a container](dockerizing.md)
|
||||
* [Run a simple application](usingdocker.md)
|
||||
* [Build your own images](dockerimages.md)
|
||||
* [Network containers](networkingcontainers.md)
|
||||
* [Manage data in containers](dockervolumes.md)
|
||||
* [Store images on Docker Hub](dockerrepos.md)
|
||||
247
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/networkingcontainers.md
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
aliases = ["/engine/userguide/networkigncontainers/"]
|
||||
title = "Network containers"
|
||||
description = "How to network Docker containers."
|
||||
keywords = ["Examples, Usage, volume, docker, documentation, user guide, data, volumes"]
|
||||
[menu.main]
|
||||
parent = "engine_learn"
|
||||
weight = -3
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
|
||||
# Network containers
|
||||
|
||||
If you are working your way through the user guide, you just built and ran a
|
||||
simple application. You've also built in your own images. This section teaches
|
||||
you how to network your containers.
|
||||
|
||||
## Name a container
|
||||
|
||||
You've already seen that each container you create has an automatically
|
||||
created name; indeed you've become familiar with our old friend
|
||||
`nostalgic_morse` during this guide. You can also name containers
|
||||
yourself. This naming provides two useful functions:
|
||||
|
||||
* You can name containers that do specific functions in a way
|
||||
that makes it easier for you to remember them, for example naming a
|
||||
container containing a web application `web`.
|
||||
|
||||
* Names provide Docker with a reference point that allows it to refer to other
|
||||
containers. There are several commands that support this and you'll use one in an exercise later.
|
||||
|
||||
You name your container by using the `--name` flag, for example launch a new container called web:
|
||||
|
||||
$ docker run -d -P --name web training/webapp python app.py
|
||||
|
||||
Use the `docker ps` command to see check the name:
|
||||
|
||||
$ docker ps -l
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
aed84ee21bde training/webapp:latest python app.py 12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web
|
||||
|
||||
You can also use `docker inspect` with the container's name.
|
||||
|
||||
$ docker inspect web
|
||||
[
|
||||
{
|
||||
"Id": "3ce51710b34f5d6da95e0a340d32aa2e6cf64857fb8cdb2a6c38f7c56f448143",
|
||||
"Created": "2015-10-25T22:44:17.854367116Z",
|
||||
"Path": "python",
|
||||
"Args": [
|
||||
"app.py"
|
||||
],
|
||||
"State": {
|
||||
"Status": "running",
|
||||
"Running": true,
|
||||
"Paused": false,
|
||||
"Restarting": false,
|
||||
"OOMKilled": false,
|
||||
...
|
||||
|
||||
Container names must be unique. That means you can only call one container
|
||||
`web`. If you want to re-use a container name you must delete the old container
|
||||
(with `docker rm`) before you can reuse the name with a new container. Go ahead and stop and remove your old `web` container.
|
||||
|
||||
$ docker stop web
|
||||
web
|
||||
$ docker rm web
|
||||
web
|
||||
|
||||
|
||||
## Launch a container on the default network
|
||||
|
||||
Docker includes support for networking containers through the use of **network
|
||||
drivers**. By default, Docker provides two network drivers for you, the
|
||||
`bridge` and the `overlay` drivers. You can also write a network driver plugin so
|
||||
that you can create your own drivers but that is an advanced task.
|
||||
|
||||
Every installation of the Docker Engine automatically includes three default networks. You can list them:
|
||||
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
18a2866682b8 none null
|
||||
c288470c46f6 host host
|
||||
7b369448dccb bridge bridge
|
||||
|
||||
The network named `bridge` is a special network. Unless you tell it otherwise, Docker always launches your containers in this network. Try this now:
|
||||
|
||||
$ docker run -itd --name=networktest ubuntu
|
||||
74695c9cea6d9810718fddadc01a727a5dd3ce6a69d09752239736c030599741
|
||||
|
||||
Inspecting the network is an easy way to find out the container's IP address.
|
||||
|
||||
```bash
|
||||
$ docker network inspect bridge
|
||||
[
|
||||
{
|
||||
"Name": "bridge",
|
||||
"Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.17.0.1/16",
|
||||
"Gateway": "172.17.0.1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {
|
||||
"3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c": {
|
||||
"EndpointID": "647c12443e91faf0fd508b6edfe59c30b642abb60dfab890b4bdccee38750bc1",
|
||||
"MacAddress": "02:42:ac:11:00:02",
|
||||
"IPv4Address": "172.17.0.2/16",
|
||||
"IPv6Address": ""
|
||||
},
|
||||
"94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c": {
|
||||
"EndpointID": "b047d090f446ac49747d3c37d63e4307be745876db7f0ceef7b311cbba615f48",
|
||||
"MacAddress": "02:42:ac:11:00:03",
|
||||
"IPv4Address": "172.17.0.3/16",
|
||||
"IPv6Address": ""
|
||||
}
|
||||
},
|
||||
"Options": {
|
||||
"com.docker.network.bridge.default_bridge": "true",
|
||||
"com.docker.network.bridge.enable_icc": "true",
|
||||
"com.docker.network.bridge.enable_ip_masquerade": "true",
|
||||
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
|
||||
"com.docker.network.bridge.name": "docker0",
|
||||
"com.docker.network.driver.mtu": "9001"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
You can remove a container from a network by disconnecting the container. To do this, you supply both the network name and the container name. You can also use the container id. In this example, though, the name is faster.
|
||||
|
||||
$ docker network disconnect bridge networktest
|
||||
|
||||
While you can disconnect a container from a network, you cannot remove the builtin `bridge` network named `bridge`. Networks are natural ways to isolate containers from other containers or other networks. So, as you get more experienced with Docker, you'll want to create your own networks.
|
||||
|
||||
## Create your own bridge network
|
||||
|
||||
Docker Engine natively supports both bridge networks and overlay networks. A bridge network is limited to a single host running Docker Engine. An overlay network can include multiple hosts and is a more advanced topic. For this example, you'll create a bridge network:
|
||||
|
||||
$ docker network create -d bridge my-bridge-network
|
||||
|
||||
The `-d` flag tells Docker to use the `bridge` driver for the new network. You could have left this flag off as `bridge` is the default value for this flag. Go ahead and list the networks on your machine:
|
||||
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
7b369448dccb bridge bridge
|
||||
615d565d498c my-bridge-network bridge
|
||||
18a2866682b8 none null
|
||||
c288470c46f6 host host
|
||||
|
||||
If you inspect the network, you'll find that it has nothing in it.
|
||||
|
||||
$ docker network inspect my-bridge-network
|
||||
[
|
||||
{
|
||||
"Name": "my-bridge-network",
|
||||
"Id": "5a8afc6364bccb199540e133e63adb76a557906dd9ff82b94183fc48c40857ac",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.18.0.0/16",
|
||||
"Gateway": "172.18.0.1/16"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {},
|
||||
"Options": {}
|
||||
}
|
||||
]
|
||||
|
||||
## Add containers to a network
|
||||
|
||||
To build web applications that act in concert but do so securely, create a
|
||||
network. Networks, by definition, provide complete isolation for containers. You
|
||||
can add containers to a network when you first run a container.
|
||||
|
||||
Launch a container running a PostgreSQL database and pass it the `--net=my-bridge-network` flag to connect it to your new network:
|
||||
|
||||
$ docker run -d --net=my-bridge-network --name db training/postgres
|
||||
|
||||
If you inspect your `my-bridge-network` you'll see it has a container attached.
|
||||
You can also inspect your container to see where it is connected:
|
||||
|
||||
$ docker inspect --format='{{json .NetworkSettings.Networks}}' db
|
||||
{"my-bridge-network":{"NetworkID":"7d86d31b1478e7cca9ebed7e73aa0fdeec46c5ca29497431d3007d2d9e15ed99",
|
||||
"EndpointID":"508b170d56b2ac9e4ef86694b0a76a22dd3df1983404f7321da5649645bf7043","Gateway":"172.18.0.1","IPAddress":"172.18.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}
|
||||
|
||||
Now, go ahead and start your by now familiar web application. This time leave off the `-P` flag and also don't specify a network.
|
||||
|
||||
$ docker run -d --name web training/webapp python app.py
|
||||
|
||||
Which network is your `web` application running under? Inspect the application and you'll find it is running in the default `bridge` network.
|
||||
|
||||
$ docker inspect --format='{{json .NetworkSettings.Networks}}' web
|
||||
{"bridge":{"NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812",
|
||||
"EndpointID":"508b170d56b2ac9e4ef86694b0a76a22dd3df1983404f7321da5649645bf7043","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}
|
||||
|
||||
Then, get the IP address of your `web`
|
||||
|
||||
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
|
||||
172.17.0.2
|
||||
|
||||
Now, open a shell to your running `db` container:
|
||||
|
||||
$ docker exec -it db bash
|
||||
root@a205f0dd33b2:/# ping 172.17.0.2
|
||||
ping 172.17.0.2
|
||||
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
|
||||
^C
|
||||
--- 172.17.0.2 ping statistics ---
|
||||
44 packets transmitted, 0 received, 100% packet loss, time 43185ms
|
||||
|
||||
After a bit, use `CTRL-C` to end the `ping` and you'll find the ping failed. That is because the two containers are running on different networks. You can fix that. Then, use the `exit` command to close the container.
|
||||
|
||||
Docker networking allows you to attach a container to as many networks as you like. You can also attach an already running container. Go ahead and attach your running `web` app to the `my-bridge-network`.
|
||||
|
||||
$ docker network connect my-bridge-network web
|
||||
|
||||
Open a shell into the `db` application again and try the ping command. This time just use the container name `web` rather than the IP Address.
|
||||
|
||||
$ docker exec -it db bash
|
||||
root@a205f0dd33b2:/# ping web
|
||||
PING web (172.18.0.3) 56(84) bytes of data.
|
||||
64 bytes from web (172.18.0.3): icmp_seq=1 ttl=64 time=0.095 ms
|
||||
64 bytes from web (172.18.0.3): icmp_seq=2 ttl=64 time=0.060 ms
|
||||
64 bytes from web (172.18.0.3): icmp_seq=3 ttl=64 time=0.066 ms
|
||||
^C
|
||||
--- web ping statistics ---
|
||||
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
|
||||
rtt min/avg/max/mdev = 0.060/0.073/0.095/0.018 ms
|
||||
|
||||
The `ping` shows it is contacting a different IP address, the address on the `my-bridge-network` which is different from its address on the `bridge` network.
|
||||
|
||||
## Next steps
|
||||
|
||||
Now that you know how to network containers, see [how to manage data in containers](dockervolumes.md).
|
||||
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/search.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 18 KiB |
306
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/usingdocker.md
generated
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Run a simple application"
|
||||
description = "Learn how to manage and operate Docker containers."
|
||||
keywords = ["docker, the docker guide, documentation, docker.io, monitoring containers, docker top, docker inspect, docker port, ports, docker logs, log, Logs"]
|
||||
[menu.main]
|
||||
parent="engine_learn"
|
||||
weight=-5
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Run a simple application
|
||||
|
||||
In the ["*Hello world in a container*"](dockerizing.md) you launched your
|
||||
first containers using the `docker run` command. You ran an *interactive container* that ran in the foreground. You also ran a *detached container* that ran in the background. In the process you learned about several Docker commands:
|
||||
|
||||
* `docker ps` - Lists containers.
|
||||
* `docker logs` - Shows us the standard output of a container.
|
||||
* `docker stop` - Stops running containers.
|
||||
|
||||
## Learn about the Docker client
|
||||
|
||||
If you didn't realize it yet, you've been using the Docker client each time you
|
||||
typed `docker` in your Bash terminal. The client is a simple command line client
|
||||
also known as a command-line interface (CLI). Each action you can take with
|
||||
the client is a command and each command can take a series of flags and arguments.
|
||||
|
||||
# Usage: [sudo] docker [subcommand] [flags] [arguments] ..
|
||||
# Example:
|
||||
$ docker run -i -t ubuntu /bin/bash
|
||||
|
||||
You can see this in action by using the `docker version` command to return
|
||||
version information on the currently installed Docker client and daemon.
|
||||
|
||||
$ docker version
|
||||
|
||||
This command will not only provide you the version of Docker client and
|
||||
daemon you are using, but also the version of Go (the programming
|
||||
language powering Docker).
|
||||
|
||||
Client:
|
||||
Version: 1.8.1
|
||||
API version: 1.20
|
||||
Go version: go1.4.2
|
||||
Git commit: d12ea79
|
||||
Built: Thu Aug 13 02:35:49 UTC 2015
|
||||
OS/Arch: linux/amd64
|
||||
|
||||
Server:
|
||||
Version: 1.8.1
|
||||
API version: 1.20
|
||||
Go version: go1.4.2
|
||||
Git commit: d12ea79
|
||||
Built: Thu Aug 13 02:35:49 UTC 2015
|
||||
OS/Arch: linux/amd64
|
||||
|
||||
## Get Docker command help
|
||||
|
||||
You can display the help for specific Docker commands. The help details the
|
||||
options and their usage. To see a list of all the possible commands, use the
|
||||
following:
|
||||
|
||||
$ docker --help
|
||||
|
||||
To see usage for a specific command, specify the command with the `--help` flag:
|
||||
|
||||
$ docker attach --help
|
||||
|
||||
Usage: docker attach [OPTIONS] CONTAINER
|
||||
|
||||
Attach to a running container
|
||||
|
||||
--help Print usage
|
||||
--no-stdin Do not attach stdin
|
||||
--sig-proxy=true Proxy all received signals to the process
|
||||
|
||||
> **Note:**
|
||||
> For further details and examples of each command, see the
|
||||
> [command reference](../../reference/commandline/cli.md) in this guide.
|
||||
|
||||
## Running a web application in Docker
|
||||
|
||||
So now you've learned a bit more about the `docker` client you can move onto
|
||||
the important stuff: running more containers. So far none of the
|
||||
containers you've run did anything particularly useful, so you can
|
||||
change that by running an example web application in Docker.
|
||||
|
||||
For our web application we're going to run a Python Flask application.
|
||||
Start with a `docker run` command.
|
||||
|
||||
$ docker run -d -P training/webapp python app.py
|
||||
|
||||
Review what the command did. You've specified two flags: `-d` and
|
||||
`-P`. You've already seen the `-d` flag which tells Docker to run the
|
||||
container in the background. The `-P` flag is new and tells Docker to
|
||||
map any required network ports inside our container to our host. This
|
||||
lets us view our web application.
|
||||
|
||||
You've specified an image: `training/webapp`. This image is a
|
||||
pre-built image you've created that contains a simple Python Flask web
|
||||
application.
|
||||
|
||||
Lastly, you've specified a command for our container to run: `python app.py`. This launches our web application.
|
||||
|
||||
> **Note:**
|
||||
> You can see more detail on the `docker run` command in the [command
|
||||
> reference](../../reference/commandline/run.md) and the [Docker Run
|
||||
> Reference](../../reference/run.md).
|
||||
|
||||
## Viewing our web application container
|
||||
|
||||
Now you can see your running container using the `docker ps` command.
|
||||
|
||||
$ docker ps -l
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
|
||||
|
||||
You can see you've specified a new flag, `-l`, for the `docker ps`
|
||||
command. This tells the `docker ps` command to return the details of the
|
||||
*last* container started.
|
||||
|
||||
> **Note:**
|
||||
> By default, the `docker ps` command only shows information about running
|
||||
> containers. If you want to see stopped containers too use the `-a` flag.
|
||||
|
||||
We can see the same details we saw [when we first Dockerized a
|
||||
container](dockerizing.md) with one important addition in the `PORTS`
|
||||
column.
|
||||
|
||||
PORTS
|
||||
0.0.0.0:49155->5000/tcp
|
||||
|
||||
When we passed the `-P` flag to the `docker run` command Docker mapped any
|
||||
ports exposed in our image to our host.
|
||||
|
||||
> **Note:**
|
||||
> We'll learn more about how to expose ports in Docker images when
|
||||
> [we learn how to build images](dockerimages.md).
|
||||
|
||||
In this case Docker has exposed port 5000 (the default Python Flask
|
||||
port) on port 49155.
|
||||
|
||||
Network port bindings are very configurable in Docker. In our last example the
|
||||
`-P` flag is a shortcut for `-p 5000` that maps port 5000 inside the container
|
||||
to a high port (from *ephemeral port range* which typically ranges from 32768
|
||||
to 61000) on the local Docker host. We can also bind Docker containers to
|
||||
specific ports using the `-p` flag, for example:
|
||||
|
||||
$ docker run -d -p 80:5000 training/webapp python app.py
|
||||
|
||||
This would map port 5000 inside our container to port 80 on our local
|
||||
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.
|
||||
|
||||
Suppose you want to test two 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 you can now browse to port 49155 in a web browser to
|
||||
see the application.
|
||||
|
||||
.
|
||||
|
||||
Our Python application is live!
|
||||
|
||||
> **Note:**
|
||||
> If you have been using a virtual machine on OS X, Windows or Linux,
|
||||
> you'll need to get the IP of the virtual host instead of using localhost.
|
||||
> You can do this by running the `docker-machine ip your_vm_name` from your command line or terminal application, for example:
|
||||
>
|
||||
> $ docker-machine ip my-docker-vm
|
||||
> 192.168.99.100
|
||||
>
|
||||
> In this case you'd browse to `http://192.168.99.100:49155` for the above example.
|
||||
|
||||
## A network port shortcut
|
||||
|
||||
Using the `docker ps` command to return the mapped port is a bit clumsy so
|
||||
Docker has a useful shortcut we can use: `docker port`. To use `docker port` we
|
||||
specify the ID or name of our container and then the port for which we need the
|
||||
corresponding public-facing port.
|
||||
|
||||
$ docker port nostalgic_morse 5000
|
||||
0.0.0.0:49155
|
||||
|
||||
In this case you've looked up what port is mapped externally to port 5000 inside
|
||||
the container.
|
||||
|
||||
## Viewing the web application's logs
|
||||
|
||||
You can also find out a bit more about what's happening with our application and
|
||||
use another of the commands you've learned, `docker logs`.
|
||||
|
||||
$ docker logs -f nostalgic_morse
|
||||
* Running on http://0.0.0.0:5000/
|
||||
10.0.2.2 - - [23/May/2014 20:16:31] "GET / HTTP/1.1" 200 -
|
||||
10.0.2.2 - - [23/May/2014 20:16:31] "GET /favicon.ico HTTP/1.1" 404 -
|
||||
|
||||
This time though you've added a new flag, `-f`. This causes the `docker
|
||||
logs` command to act like the `tail -f` command and watch the
|
||||
container's standard out. We can see here the logs from Flask showing
|
||||
the application running on port 5000 and the access log entries for it.
|
||||
|
||||
## Looking at our web application container's processes
|
||||
|
||||
In addition to the container's logs we can also examine the processes
|
||||
running inside it using the `docker top` command.
|
||||
|
||||
$ docker top nostalgic_morse
|
||||
PID USER COMMAND
|
||||
854 root python app.py
|
||||
|
||||
Here we can see our `python app.py` command is the only process running inside
|
||||
the container.
|
||||
|
||||
## Inspecting our web application container
|
||||
|
||||
Lastly, we can take a low-level dive into our Docker container using the
|
||||
`docker inspect` command. It returns a JSON document containing useful
|
||||
configuration and status information for the specified container.
|
||||
|
||||
$ docker inspect nostalgic_morse
|
||||
|
||||
You can see a sample of that JSON output.
|
||||
|
||||
[{
|
||||
"ID": "bc533791f3f500b280a9626688bc79e342e3ea0d528efe3a86a51ecb28ea20",
|
||||
"Created": "2014-05-26T05:52:40.808952951Z",
|
||||
"Path": "python",
|
||||
"Args": [
|
||||
"app.py"
|
||||
],
|
||||
"Config": {
|
||||
"Hostname": "bc533791f3f5",
|
||||
"Domainname": "",
|
||||
"User": "",
|
||||
. . .
|
||||
|
||||
We can also narrow down the information we want to return by requesting a
|
||||
specific element, for example to return the container's IP address we would:
|
||||
|
||||
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nostalgic_morse
|
||||
172.17.0.5
|
||||
|
||||
## Stopping our web application container
|
||||
|
||||
Okay you've seen web application working. Now you can stop it using the
|
||||
`docker stop` command and the name of our container: `nostalgic_morse`.
|
||||
|
||||
$ docker stop nostalgic_morse
|
||||
nostalgic_morse
|
||||
|
||||
We can now use the `docker ps` command to check if the container has
|
||||
been stopped.
|
||||
|
||||
$ docker ps -l
|
||||
|
||||
## Restarting our web application container
|
||||
|
||||
Oops! Just after you stopped the container you get a call to say another
|
||||
developer needs the container back. From here you have two choices: you
|
||||
can create a new container or restart the old one. Look at
|
||||
starting your previous container back up.
|
||||
|
||||
$ docker start nostalgic_morse
|
||||
nostalgic_morse
|
||||
|
||||
Now quickly run `docker ps -l` again to see the running container is
|
||||
back up or browse to the container's URL to see if the application
|
||||
responds.
|
||||
|
||||
> **Note:**
|
||||
> Also available is the `docker restart` command that runs a stop and
|
||||
> then start on the container.
|
||||
|
||||
## Removing our web application container
|
||||
|
||||
Your colleague has let you know that they've now finished with the container
|
||||
and won't need it again. Now, you can remove it using the `docker rm` command.
|
||||
|
||||
$ docker rm nostalgic_morse
|
||||
Error: Impossible to remove a running container, please stop it first or use -f
|
||||
2014/05/24 08:12:56 Error: failed to remove one or more containers
|
||||
|
||||
What happened? We can't actually remove a running container. This protects
|
||||
you from accidentally removing a running container you might need. You can try
|
||||
this again by stopping the container first.
|
||||
|
||||
$ docker stop nostalgic_morse
|
||||
nostalgic_morse
|
||||
$ docker rm nostalgic_morse
|
||||
nostalgic_morse
|
||||
|
||||
And now our container is stopped and deleted.
|
||||
|
||||
> **Note:**
|
||||
> Always remember that removing a container is final!
|
||||
|
||||
# Next steps
|
||||
|
||||
Until now you've only used images that you've downloaded from Docker Hub. Next,
|
||||
you can get introduced to building and sharing our own images.
|
||||
|
||||
Go to [Working with Docker Images](dockerimages.md).
|
||||
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/containers/webapp1.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
71
vendor/github.com/hyperhq/hypercli/docs/userguide/eng-image/baseimages.md
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
aliases = ["/engine/articles/baseimages/"]
|
||||
title = "Create a base image"
|
||||
description = "How to create base images"
|
||||
keywords = ["Examples, Usage, base image, docker, documentation, examples"]
|
||||
[menu.main]
|
||||
parent = "engine_images"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Create a base image
|
||||
|
||||
So you want to create your own [*Base Image*](../../reference/glossary.md#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
|
||||
submit pull requests to contribute new ones.
|
||||
|
||||
## Create a full image using tar
|
||||
|
||||
In general, you'll want to start with a working machine that is running
|
||||
the distribution you'd like to package as a base image, though that is
|
||||
not required for some tools like Debian's
|
||||
[Debootstrap](https://wiki.debian.org/Debootstrap), which you can also
|
||||
use to build Ubuntu images.
|
||||
|
||||
It can be as simple as this to create an Ubuntu base image:
|
||||
|
||||
$ sudo debootstrap raring raring > /dev/null
|
||||
$ sudo tar -C raring -c . | docker import - raring
|
||||
a29c15f1bf7a
|
||||
$ docker run raring cat /etc/lsb-release
|
||||
DISTRIB_ID=Ubuntu
|
||||
DISTRIB_RELEASE=13.04
|
||||
DISTRIB_CODENAME=raring
|
||||
DISTRIB_DESCRIPTION="Ubuntu 13.04"
|
||||
|
||||
There are more example scripts for creating base images in the Docker
|
||||
GitHub Repo:
|
||||
|
||||
- [BusyBox](https://github.com/docker/docker/blob/master/contrib/mkimage-busybox.sh)
|
||||
- CentOS / Scientific Linux CERN (SLC) [on Debian/Ubuntu](
|
||||
https://github.com/docker/docker/blob/master/contrib/mkimage-rinse.sh) or
|
||||
[on CentOS/RHEL/SLC/etc.](
|
||||
https://github.com/docker/docker/blob/master/contrib/mkimage-yum.sh)
|
||||
- [Debian / Ubuntu](
|
||||
https://github.com/docker/docker/blob/master/contrib/mkimage-debootstrap.sh)
|
||||
|
||||
## Creating a simple base image using scratch
|
||||
|
||||
You can use Docker's reserved, minimal image, `scratch`, as a starting point for building containers. Using the `scratch` "image" signals to the build process that you want the next command in the `Dockerfile` to be the first filesystem layer in your image.
|
||||
|
||||
While `scratch` appears in Docker's repository on the hub, you can't pull it, run it, or tag any image with the name `scratch`. Instead, you can refer to it in your `Dockerfile`. For example, to create a minimal container using `scratch`:
|
||||
|
||||
FROM scratch
|
||||
ADD hello /
|
||||
CMD ["/hello"]
|
||||
|
||||
This example creates the hello-world image used in the tutorials.
|
||||
If you want to test it out, you can clone [the image repo](https://github.com/docker-library/hello-world)
|
||||
|
||||
|
||||
## More resources
|
||||
|
||||
There are lots more resources available to help you write your 'Dockerfile`.
|
||||
|
||||
* There's a [complete guide to all the instructions](../../reference/builder.md) available for use in a `Dockerfile` in the reference section.
|
||||
* To help you write a clear, readable, maintainable `Dockerfile`, we've also
|
||||
written a [`Dockerfile` Best Practices guide](dockerfile_best-practices.md).
|
||||
* If your goal is to create a new Official Repository, be sure to read up on Docker's [Official Repositories](https://docs.docker.com/docker-hub/official_repos/).
|
||||
495
vendor/github.com/hyperhq/hypercli/docs/userguide/eng-image/dockerfile_best-practices.md
generated
vendored
Normal file
@@ -0,0 +1,495 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
aliases = ["/engine/articles/dockerfile_best-practices/"]
|
||||
title = "Best practices for writing Dockerfiles"
|
||||
description = "Hints, tips and guidelines for writing clean, reliable Dockerfiles"
|
||||
keywords = ["Examples, Usage, base image, docker, documentation, dockerfile, best practices, hub, official repo"]
|
||||
[menu.main]
|
||||
parent = "engine_images"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Best practices for writing Dockerfiles
|
||||
|
||||
Docker can build images automatically by reading the instructions from a
|
||||
`Dockerfile`, a text file that contains all the commands, in order, needed to
|
||||
build a given image. `Dockerfile`s adhere to a specific format and use a
|
||||
specific set of instructions. You can learn the basics on the
|
||||
[Dockerfile Reference](../../reference/builder.md) page. If
|
||||
you’re new to writing `Dockerfile`s, you should start there.
|
||||
|
||||
This document covers the best practices and methods recommended by Docker,
|
||||
Inc. and the Docker community for creating easy-to-use, effective
|
||||
`Dockerfile`s. We strongly suggest you follow these recommendations (in fact,
|
||||
if you’re creating an Official Image, you *must* adhere to these practices).
|
||||
|
||||
You can see many of these practices and recommendations in action in the [buildpack-deps `Dockerfile`](https://github.com/docker-library/buildpack-deps/blob/master/jessie/Dockerfile).
|
||||
|
||||
> Note: for more detailed explanations of any of the Dockerfile commands
|
||||
>mentioned here, visit the [Dockerfile Reference](../../reference/builder.md) page.
|
||||
|
||||
## General guidelines and recommendations
|
||||
|
||||
### Containers should be ephemeral
|
||||
|
||||
The container produced by the image your `Dockerfile` defines should be as
|
||||
ephemeral as possible. By “ephemeral,” we mean that it can be stopped and
|
||||
destroyed and a new one built and put in place with an absolute minimum of
|
||||
set-up and configuration.
|
||||
|
||||
### Use a .dockerignore file
|
||||
|
||||
In most cases, it's best to put each Dockerfile in an empty directory. Then,
|
||||
add to that directory only the files needed for building the Dockerfile. To
|
||||
increase the build's performance, you can exclude files and directories by
|
||||
adding a `.dockerignore` file to that directory as well. This file supports
|
||||
exclusion patterns similar to `.gitignore` files. For information on creating one,
|
||||
see the [.dockerignore file](../../reference/builder.md#dockerignore-file).
|
||||
|
||||
### Avoid installing unnecessary packages
|
||||
|
||||
In order to reduce complexity, dependencies, file sizes, and build times, you
|
||||
should avoid installing extra or unnecessary packages just because they
|
||||
might be “nice to have.” For example, you don’t need to include a text editor
|
||||
in a database image.
|
||||
|
||||
### Run only one process per container
|
||||
|
||||
In almost all cases, you should only run a single process in a single
|
||||
container. Decoupling applications into multiple containers makes it much
|
||||
easier to scale horizontally and reuse containers. If that service depends on
|
||||
another service, make use of [container linking](../../userguide/networking/default_network/dockerlinks.md).
|
||||
|
||||
### Minimize the number of layers
|
||||
|
||||
You need to find the balance between readability (and thus long-term
|
||||
maintainability) of the `Dockerfile` and minimizing the number of layers it
|
||||
uses. Be strategic and cautious about the number of layers you use.
|
||||
|
||||
### Sort multi-line arguments
|
||||
|
||||
Whenever possible, ease later changes by sorting multi-line arguments
|
||||
alphanumerically. This will help you avoid duplication of packages and make the
|
||||
list much easier to update. This also makes PRs a lot easier to read and
|
||||
review. Adding a space before a backslash (`\`) helps as well.
|
||||
|
||||
Here’s an example from the [`buildpack-deps` image](https://github.com/docker-library/buildpack-deps):
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
bzr \
|
||||
cvs \
|
||||
git \
|
||||
mercurial \
|
||||
subversion
|
||||
|
||||
### Build cache
|
||||
|
||||
During the process of building an image Docker will step through the
|
||||
instructions in your `Dockerfile` executing each in the order specified.
|
||||
As each instruction is examined Docker will look for an existing image in its
|
||||
cache that it can reuse, rather than creating a new (duplicate) image.
|
||||
If you do not want to use the cache at all you can use the ` --no-cache=true`
|
||||
option on the `docker build` command.
|
||||
|
||||
However, if you do let Docker use its cache then it is very important to
|
||||
understand when it will, and will not, find a matching image. The basic rules
|
||||
that Docker will follow are outlined below:
|
||||
|
||||
* Starting with a base image that is already in the cache, the next
|
||||
instruction is compared against all child images derived from that base
|
||||
image to see if one of them was built using the exact same instruction. If
|
||||
not, the cache is invalidated.
|
||||
|
||||
* In most cases simply comparing the instruction in the `Dockerfile` with one
|
||||
of the child images is sufficient. However, certain instructions require
|
||||
a little more examination and explanation.
|
||||
|
||||
* For the `ADD` and `COPY` instructions, the contents of the file(s)
|
||||
in the image are examined and a checksum is calculated for each file.
|
||||
The last-modified and last-accessed times of the file(s) are not considered in
|
||||
these checksums. During the cache lookup, the checksum is compared against the
|
||||
checksum in the existing images. If anything has changed in the file(s), such
|
||||
as the contents and metadata, then the cache is invalidated.
|
||||
|
||||
* Aside from the `ADD` and `COPY` commands, cache checking will not look at the
|
||||
files in the container to determine a cache match. For example, when processing
|
||||
a `RUN apt-get -y update` command the files updated in the container
|
||||
will not be examined to determine if a cache hit exists. In that case just
|
||||
the command string itself will be used to find a match.
|
||||
|
||||
Once the cache is invalidated, all subsequent `Dockerfile` commands will
|
||||
generate new images and the cache will not be used.
|
||||
|
||||
## The Dockerfile instructions
|
||||
|
||||
Below you'll find recommendations for the best way to write the
|
||||
various instructions available for use in a `Dockerfile`.
|
||||
|
||||
### FROM
|
||||
|
||||
[Dockerfile reference for the FROM instruction](../../reference/builder.md#from)
|
||||
|
||||
Whenever possible, use current Official Repositories as the basis for your
|
||||
image. We recommend the [Debian image](https://registry.hub.docker.com/_/debian/)
|
||||
since it’s very tightly controlled and kept extremely minimal (currently under
|
||||
100 mb), while still being a full distribution.
|
||||
|
||||
### RUN
|
||||
|
||||
[Dockerfile reference for the RUN instruction](../../reference/builder.md#run)
|
||||
|
||||
As always, to make your `Dockerfile` more readable, understandable, and
|
||||
maintainable, split long or complex `RUN` statements on multiple lines separated
|
||||
with backslashes.
|
||||
|
||||
### apt-get
|
||||
|
||||
Probably the most common use-case for `RUN` is an application of `apt-get`. The
|
||||
`RUN apt-get` command, because it installs packages, has several gotchas to look
|
||||
out for.
|
||||
|
||||
You should avoid `RUN apt-get upgrade` or `dist-upgrade`, as many of the
|
||||
“essential” packages from the base images won't upgrade inside an unprivileged
|
||||
container. If a package contained in the base image is out-of-date, you should
|
||||
contact its maintainers.
|
||||
If you know there’s a particular package, `foo`, that needs to be updated, use
|
||||
`apt-get install -y foo` to update automatically.
|
||||
|
||||
Always combine `RUN apt-get update` with `apt-get install` in the same `RUN`
|
||||
statement, for example:
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
package-bar \
|
||||
package-baz \
|
||||
package-foo
|
||||
|
||||
|
||||
Using `apt-get update` alone in a `RUN` statement causes caching issues and
|
||||
subsequent `apt-get install` instructions fail.
|
||||
For example, say you have a Dockerfile:
|
||||
|
||||
FROM ubuntu:14.04
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl
|
||||
|
||||
After building the image, all layers are in the Docker cache. Suppose you later
|
||||
modify `apt-get install` by adding extra package:
|
||||
|
||||
FROM ubuntu:14.04
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl nginx
|
||||
|
||||
Docker sees the initial and modified instructions as identical and reuses the
|
||||
cache from previous steps. As a result the `apt-get update` is *NOT* executed
|
||||
because the build uses the cached version. Because the `apt-get update` is not
|
||||
run, your build can potentially get an outdated version of the `curl` and `nginx`
|
||||
packages.
|
||||
|
||||
Using `RUN apt-get update && apt-get install -y` ensures your Dockerfile
|
||||
installs the latest package versions with no further coding or manual
|
||||
intervention. This technique is known as "cache busting". You can also achieve
|
||||
cache-busting by specifying a package version. This is known as version pinning,
|
||||
for example:
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
package-bar \
|
||||
package-baz \
|
||||
package-foo=1.3.*
|
||||
|
||||
Version pinning forces the build to retrieve a particular version regardless of
|
||||
what’s in the cache. This technique can also reduce failures due to unanticipated changes
|
||||
in required packages.
|
||||
|
||||
Below is a well-formed `RUN` instruction that demonstrates all the `apt-get`
|
||||
recommendations.
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
aufs-tools \
|
||||
automake \
|
||||
build-essential \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
libcap-dev \
|
||||
libsqlite3-dev \
|
||||
mercurial \
|
||||
reprepro \
|
||||
ruby1.9.1 \
|
||||
ruby1.9.1-dev \
|
||||
s3cmd=1.1.* \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
The `s3cmd` instructions specifies a version `1.1.0*`. If the image previously
|
||||
used an older version, specifying the new one causes a cache bust of `apt-get
|
||||
update` and ensure the installation of the new version. Listing packages on
|
||||
each line can also prevent mistakes in package duplication.
|
||||
|
||||
In addition, cleaning up the apt cache and removing `/var/lib/apt/lists` helps
|
||||
keep the image size down. Since the `RUN` statement starts with
|
||||
`apt-get update`, the package cache will always be refreshed prior to
|
||||
`apt-get install`.
|
||||
|
||||
> **Note**: The official Debian and Ubuntu images [automatically run `apt-get clean`](https://github.com/docker/docker/blob/03e2923e42446dbb830c654d0eec323a0b4ef02a/contrib/mkimage/debootstrap#L82-L105),
|
||||
> so explicit invocation is not required.
|
||||
|
||||
### CMD
|
||||
|
||||
[Dockerfile reference for the CMD instruction](../../reference/builder.md#cmd)
|
||||
|
||||
The `CMD` instruction should be used to run the software contained by your
|
||||
image, along with any arguments. `CMD` should almost always be used in the
|
||||
form of `CMD [“executable”, “param1”, “param2”…]`. Thus, if the image is for a
|
||||
service (Apache, Rails, etc.), you would run something like
|
||||
`CMD ["apache2","-DFOREGROUND"]`. Indeed, this form of the instruction is
|
||||
recommended for any service-based image.
|
||||
|
||||
In most other cases, `CMD` should be given an interactive shell (bash, python,
|
||||
perl, etc), for example, `CMD ["perl", "-de0"]`, `CMD ["python"]`, or
|
||||
`CMD [“php”, “-a”]`. Using this form means that when you execute something like
|
||||
`docker run -it python`, you’ll get dropped into a usable shell, ready to go.
|
||||
`CMD` should rarely be used in the manner of `CMD [“param”, “param”]` in
|
||||
conjunction with [`ENTRYPOINT`](../../reference/builder.md#entrypoint), unless
|
||||
you and your expected users are already quite familiar with how `ENTRYPOINT`
|
||||
works.
|
||||
|
||||
### EXPOSE
|
||||
|
||||
[Dockerfile reference for the EXPOSE instruction](../../reference/builder.md#expose)
|
||||
|
||||
The `EXPOSE` instruction indicates the ports on which a container will listen
|
||||
for connections. Consequently, you should use the common, traditional port for
|
||||
your application. For example, an image containing the Apache web server would
|
||||
use `EXPOSE 80`, while an image containing MongoDB would use `EXPOSE 27017` and
|
||||
so on.
|
||||
|
||||
For external access, your users can execute `docker run` with a flag indicating
|
||||
how to map the specified port to the port of their choice.
|
||||
For container linking, Docker provides environment variables for the path from
|
||||
the recipient container back to the source (ie, `MYSQL_PORT_3306_TCP`).
|
||||
|
||||
### ENV
|
||||
|
||||
[Dockerfile reference for the ENV instruction](../../reference/builder.md#env)
|
||||
|
||||
In order to make new software easier to run, you can use `ENV` to update the
|
||||
`PATH` environment variable for the software your container installs. For
|
||||
example, `ENV PATH /usr/local/nginx/bin:$PATH` will ensure that `CMD [“nginx”]`
|
||||
just works.
|
||||
|
||||
The `ENV` instruction is also useful for providing required environment
|
||||
variables specific to services you wish to containerize, such as Postgres’s
|
||||
`PGDATA`.
|
||||
|
||||
Lastly, `ENV` can also be used to set commonly used version numbers so that
|
||||
version bumps are easier to maintain, as seen in the following example:
|
||||
|
||||
ENV PG_MAJOR 9.3
|
||||
ENV PG_VERSION 9.3.4
|
||||
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
|
||||
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
|
||||
|
||||
Similar to having constant variables in a program (as opposed to hard-coding
|
||||
values), this approach lets you change a single `ENV` instruction to
|
||||
auto-magically bump the version of the software in your container.
|
||||
|
||||
### ADD or COPY
|
||||
|
||||
[Dockerfile reference for the ADD instruction](../../reference/builder.md#add)<br/>
|
||||
[Dockerfile reference for the COPY instruction](../../reference/builder.md#copy)
|
||||
|
||||
Although `ADD` and `COPY` are functionally similar, generally speaking, `COPY`
|
||||
is preferred. That’s because it’s more transparent than `ADD`. `COPY` only
|
||||
supports the basic copying of local files into the container, while `ADD` has
|
||||
some features (like local-only tar extraction and remote URL support) that are
|
||||
not immediately obvious. Consequently, the best use for `ADD` is local tar file
|
||||
auto-extraction into the image, as in `ADD rootfs.tar.xz /`.
|
||||
|
||||
If you have multiple `Dockerfile` steps that use different files from your
|
||||
context, `COPY` them individually, rather than all at once. This will ensure that
|
||||
each step's build cache is only invalidated (forcing the step to be re-run) if the
|
||||
specifically required files change.
|
||||
|
||||
For example:
|
||||
|
||||
COPY requirements.txt /tmp/
|
||||
RUN pip install --requirement /tmp/requirements.txt
|
||||
COPY . /tmp/
|
||||
|
||||
Results in fewer cache invalidations for the `RUN` step, than if you put the
|
||||
`COPY . /tmp/` before it.
|
||||
|
||||
Because image size matters, using `ADD` to fetch packages from remote URLs is
|
||||
strongly discouraged; you should use `curl` or `wget` instead. That way you can
|
||||
delete the files you no longer need after they've been extracted and you won't
|
||||
have to add another layer in your image. For example, you should avoid doing
|
||||
things like:
|
||||
|
||||
ADD http://example.com/big.tar.xz /usr/src/things/
|
||||
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
|
||||
RUN make -C /usr/src/things all
|
||||
|
||||
And instead, do something like:
|
||||
|
||||
RUN mkdir -p /usr/src/things \
|
||||
&& curl -SL http://example.com/big.tar.xz \
|
||||
| tar -xJC /usr/src/things \
|
||||
&& make -C /usr/src/things all
|
||||
|
||||
For other items (files, directories) that do not require `ADD`’s tar
|
||||
auto-extraction capability, you should always use `COPY`.
|
||||
|
||||
### ENTRYPOINT
|
||||
|
||||
[Dockerfile reference for the ENTRYPOINT instruction](../../reference/builder.md#entrypoint)
|
||||
|
||||
The best use for `ENTRYPOINT` is to set the image's main command, allowing that
|
||||
image to be run as though it was that command (and then use `CMD` as the
|
||||
default flags).
|
||||
|
||||
Let's start with an example of an image for the command line tool `s3cmd`:
|
||||
|
||||
ENTRYPOINT ["s3cmd"]
|
||||
CMD ["--help"]
|
||||
|
||||
Now the image can be run like this to show the command's help:
|
||||
|
||||
$ docker run s3cmd
|
||||
|
||||
Or using the right parameters to execute a command:
|
||||
|
||||
$ docker run s3cmd ls s3://mybucket
|
||||
|
||||
This is useful because the image name can double as a reference to the binary as
|
||||
shown in the command above.
|
||||
|
||||
The `ENTRYPOINT` instruction can also be used in combination with a helper
|
||||
script, allowing it to function in a similar way to the command above, even
|
||||
when starting the tool may require more than one step.
|
||||
|
||||
For example, the [Postgres Official Image](https://registry.hub.docker.com/_/postgres/)
|
||||
uses the following script as its `ENTRYPOINT`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ "$1" = 'postgres' ]; then
|
||||
chown -R postgres "$PGDATA"
|
||||
|
||||
if [ -z "$(ls -A "$PGDATA")" ]; then
|
||||
gosu postgres initdb
|
||||
fi
|
||||
|
||||
exec gosu postgres "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
```
|
||||
|
||||
> **Note**:
|
||||
> This script uses [the `exec` Bash command](http://wiki.bash-hackers.org/commands/builtin/exec)
|
||||
> so that the final running application becomes the container's PID 1. This allows
|
||||
> the application to receive any Unix signals sent to the container.
|
||||
> See the [`ENTRYPOINT`](../../reference/builder.md#entrypoint)
|
||||
> help for more details.
|
||||
|
||||
|
||||
The helper script is copied into the container and run via `ENTRYPOINT` on
|
||||
container start:
|
||||
|
||||
COPY ./docker-entrypoint.sh /
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
|
||||
This script allows the user to interact with Postgres in several ways.
|
||||
|
||||
It can simply start Postgres:
|
||||
|
||||
$ docker run postgres
|
||||
|
||||
Or, it can be used to run Postgres and pass parameters to the server:
|
||||
|
||||
$ docker run postgres postgres --help
|
||||
|
||||
Lastly, it could also be used to start a totally different tool, such as Bash:
|
||||
|
||||
$ docker run --rm -it postgres bash
|
||||
|
||||
### VOLUME
|
||||
|
||||
[Dockerfile reference for the VOLUME instruction](../../reference/builder.md#volume)
|
||||
|
||||
The `VOLUME` instruction should be used to expose any database storage area,
|
||||
configuration storage, or files/folders created by your docker container. You
|
||||
are strongly encouraged to use `VOLUME` for any mutable and/or user-serviceable
|
||||
parts of your image.
|
||||
|
||||
### USER
|
||||
|
||||
[Dockerfile reference for the USER instruction](../../reference/builder.md#user)
|
||||
|
||||
If a service can run without privileges, use `USER` to change to a non-root
|
||||
user. Start by creating the user and group in the `Dockerfile` with something
|
||||
like `RUN groupadd -r postgres && useradd -r -g postgres postgres`.
|
||||
|
||||
> **Note:** Users and groups in an image get a non-deterministic
|
||||
> UID/GID in that the “next” UID/GID gets assigned regardless of image
|
||||
> 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 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).
|
||||
|
||||
Lastly, to reduce layers and complexity, avoid switching `USER` back
|
||||
and forth frequently.
|
||||
|
||||
### WORKDIR
|
||||
|
||||
[Dockerfile reference for the WORKDIR instruction](../../reference/builder.md#workdir)
|
||||
|
||||
For clarity and reliability, you should always use absolute paths for your
|
||||
`WORKDIR`. Also, you should use `WORKDIR` instead of proliferating
|
||||
instructions like `RUN cd … && do-something`, which are hard to read,
|
||||
troubleshoot, and maintain.
|
||||
|
||||
### ONBUILD
|
||||
|
||||
[Dockerfile reference for the ONBUILD instruction](../../reference/builder.md#onbuild)
|
||||
|
||||
An `ONBUILD` command executes after the current `Dockerfile` build completes.
|
||||
`ONBUILD` executes in any child image derived `FROM` the current image. Think
|
||||
of the `ONBUILD` command as an instruction the parent `Dockerfile` gives
|
||||
to the child `Dockerfile`.
|
||||
|
||||
A Docker build executes `ONBUILD` commands before any command in a child
|
||||
`Dockerfile`.
|
||||
|
||||
`ONBUILD` is useful for images that are going to be built `FROM` a given
|
||||
image. For example, you would use `ONBUILD` for a language stack image that
|
||||
builds arbitrary user software written in that language within the
|
||||
`Dockerfile`, as you can see in [Ruby’s `ONBUILD` variants](https://github.com/docker-library/ruby/blob/master/2.1/onbuild/Dockerfile).
|
||||
|
||||
Images built from `ONBUILD` should get a separate tag, for example:
|
||||
`ruby:1.9-onbuild` or `ruby:2.0-onbuild`.
|
||||
|
||||
Be careful when putting `ADD` or `COPY` in `ONBUILD`. The “onbuild” image will
|
||||
fail catastrophically if the new build's context is missing the resource being
|
||||
added. Adding a separate tag, as recommended above, will help mitigate this by
|
||||
allowing the `Dockerfile` author to make a choice.
|
||||
|
||||
## Examples for Official Repositories
|
||||
|
||||
These Official Repositories have exemplary `Dockerfile`s:
|
||||
|
||||
* [Go](https://registry.hub.docker.com/_/golang/)
|
||||
* [Perl](https://registry.hub.docker.com/_/perl/)
|
||||
* [Hy](https://registry.hub.docker.com/_/hylang/)
|
||||
* [Rails](https://registry.hub.docker.com/_/rails)
|
||||
|
||||
## Additional resources:
|
||||
|
||||
* [Dockerfile Reference](../../reference/builder.md)
|
||||
* [More about Base Images](baseimages.md)
|
||||
* [More about Automated Builds](https://docs.docker.com/docker-hub/builds/)
|
||||
* [Guidelines for Creating Official
|
||||
Repositories](https://docs.docker.com/docker-hub/official_repos/)
|
||||
53
vendor/github.com/hyperhq/hypercli/docs/userguide/eng-image/image_management.md
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
alias = [ "/reference/api/hub_registry_spec/", "/userguide/image_management/"]
|
||||
title = "Image management"
|
||||
description = "Documentation for docker Registry and Registry API"
|
||||
keywords = ["docker, registry, api, hub"]
|
||||
[menu.main]
|
||||
parent="engine_images"
|
||||
weight=90
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Image management
|
||||
|
||||
The Docker Engine provides a client which you can use to create images on the command line or through a build process. You can run these images in a container or publish them for others to use. Storing the images you create, searching for images you might want, or publishing images others might use are all elements of image management.
|
||||
|
||||
This section provides an overview of the major features and products Docker provides for image management.
|
||||
|
||||
|
||||
## Docker Hub
|
||||
|
||||
The [Docker Hub](https://docs.docker.com/docker-hub/) is responsible for centralizing information about user accounts, images, and public name spaces. It has different components:
|
||||
|
||||
- Web UI
|
||||
- Meta-data store (comments, stars, list public repositories)
|
||||
- Authentication service
|
||||
- Tokenization
|
||||
|
||||
There is only one instance of the Docker Hub, run and managed by Docker Inc. This public Hub is useful for most individuals and smaller companies.
|
||||
|
||||
## Docker Registry and the Docker Trusted Registry
|
||||
|
||||
The Docker Registry is a component of Docker's ecosystem. A registry is a
|
||||
storage and content delivery system, holding named Docker images, available in
|
||||
different tagged versions. For example, the image `distribution/registry`, with
|
||||
tags `2.0` and `latest`. Users interact with a registry by using docker push and
|
||||
pull commands such as, `docker pull myregistry.com/stevvooe/batman:voice`.
|
||||
|
||||
The Docker Hub has its own registry which, like the Hub itself, is run and managed by Docker. However, there are other ways to obtain a registry. You can purchase the [Docker Trusted Registry](https://docs.docker.com/docker-trusted-registry) product to run on your company's network. Alternatively, you can use the Docker Registry component to build a private registry. For information about using a registry, see overview for the [Docker Registry](https://docs.docker.com/registry).
|
||||
|
||||
|
||||
## Content Trust
|
||||
|
||||
When transferring data among networked systems, *trust* is a central concern. In
|
||||
particular, when communicating over an untrusted medium such as the internet, it
|
||||
is critical to ensure the integrity and publisher of all of the data a system
|
||||
operates on. You use Docker to push and pull images (data) to a registry.
|
||||
Content trust gives you the ability to both verify the integrity and the
|
||||
publisher of all the data received from a registry over any channel.
|
||||
|
||||
[Content trust](../../security/trust/index.md) is currently only available for users of the
|
||||
public Docker Hub. It is currently not available for the Docker Trusted Registry
|
||||
or for private registries.
|
||||
16
vendor/github.com/hyperhq/hypercli/docs/userguide/eng-image/index.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Work with images"
|
||||
description = "The Docker user guide home page"
|
||||
keywords = ["docker, introduction, documentation, about, technology, docker.io, user, guide, user's, manual, platform, framework, home, intro"]
|
||||
[menu.main]
|
||||
identifier="engine_images"
|
||||
parent = "engine_guide"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Work with images
|
||||
|
||||
* [Create a base image](baseimages.md)
|
||||
* [Best practices for writing Dockerfiles](dockerfile_best-practices.md)
|
||||
* [Image management](image_management.md)
|
||||
13
vendor/github.com/hyperhq/hypercli/docs/userguide/index.md
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "User guide"
|
||||
description = "Welcome to the user guide"
|
||||
keywords = ["docker, introduction, documentation, about, technology, docker.io, user, guide, user's, manual, platform, framework, home, intro"]
|
||||
[menu.main]
|
||||
parent="engine_use"
|
||||
identifier = "engine_guide"
|
||||
weight="-80"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# User guide
|
||||
119
vendor/github.com/hyperhq/hypercli/docs/userguide/intro.md
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Introduction"
|
||||
description = "Introduction to user guide"
|
||||
keywords = ["docker, introduction, documentation, about, technology, docker.io, user, guide, user's, manual, platform, framework, home, intro"]
|
||||
[menu.main]
|
||||
parent="engine_guide"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Introduction to Engine user guide
|
||||
|
||||
This guide takes you through the fundamentals of using Docker Engine and
|
||||
integrating it into your environment. You'll learn how to use Engine to:
|
||||
|
||||
* Dockerize your applications.
|
||||
* Run your own containers.
|
||||
* Build Docker images.
|
||||
* Share your Docker images with others.
|
||||
* And a whole lot more!
|
||||
|
||||
This guide is broken into major sections that take you through learning the basics of Docker Engine and the other Docker products that support it.
|
||||
|
||||
## Dockerizing applications: A "Hello world"
|
||||
|
||||
*How do I run applications inside containers?*
|
||||
|
||||
Docker Engine offers a containerization platform to power your applications. To
|
||||
learn how to Dockerize applications and run them:
|
||||
|
||||
Go to [Dockerizing Applications](containers/dockerizing.md).
|
||||
|
||||
|
||||
## Working with containers
|
||||
|
||||
*How do I manage my containers?*
|
||||
|
||||
Once you get a grip on running your applications in Docker containers, you'll learn how to manage those containers. To find out
|
||||
about how to inspect, monitor and manage containers:
|
||||
|
||||
Go to [Working With Containers](containers/usingdocker.md).
|
||||
|
||||
## Working with Docker images
|
||||
|
||||
*How can I access, share and build my own images?*
|
||||
|
||||
Once you've learnt how to use Docker it's time to take the next step and
|
||||
learn how to build your own application images with Docker.
|
||||
|
||||
Go to [Working with Docker Images](containers/dockerimages.md).
|
||||
|
||||
## Networking containers
|
||||
|
||||
Until now we've seen how to build individual applications inside Docker
|
||||
containers. Now learn how to build whole application stacks with Docker
|
||||
networking.
|
||||
|
||||
Go to [Networking Containers](containers/networkingcontainers.md).
|
||||
|
||||
## Managing data in containers
|
||||
|
||||
Now we know how to link Docker containers together the next step is
|
||||
learning how to manage data, volumes and mounts inside our containers.
|
||||
|
||||
Go to [Managing Data in Containers](containers/dockervolumes.md).
|
||||
|
||||
## Docker products that complement Engine
|
||||
|
||||
Often, one powerful technology spawns many other inventions that make that easier to get to, easier to use, and more powerful. These spawned things share one common characteristic: they augment the central technology. The following Docker products expand on the core Docker Engine functions.
|
||||
|
||||
### Docker Hub
|
||||
|
||||
Docker Hub is the central hub for Docker. It hosts public Docker images
|
||||
and provides services to help you build and manage your Docker
|
||||
environment. To learn more:
|
||||
|
||||
Go to [Using Docker Hub](https://docs.docker.com/docker-hub).
|
||||
|
||||
### Docker Machine
|
||||
|
||||
Docker Machine helps you get Docker Engines up and running quickly. Machine
|
||||
can set up hosts for Docker Engines on your computer, on cloud providers,
|
||||
and/or in your data center, and then configure your Docker client to securely
|
||||
talk to them.
|
||||
|
||||
Go to [Docker Machine user guide](https://docs.docker.com/machine/).
|
||||
|
||||
### Docker Compose
|
||||
|
||||
Docker Compose allows you to define a application's components -- their containers,
|
||||
configuration, links and volumes -- in a single file. Then a single command
|
||||
will set everything up and start your application running.
|
||||
|
||||
Go to [Docker Compose user guide](https://docs.docker.com/compose/).
|
||||
|
||||
|
||||
### Docker Swarm
|
||||
|
||||
Docker Swarm pools several Docker Engines together and exposes them as a single
|
||||
virtual Docker Engine. It serves the standard Docker API, so any tool that already
|
||||
works with Docker can now transparently scale up to multiple hosts.
|
||||
|
||||
Go to [Docker Swarm user guide](https://docs.docker.com/swarm/).
|
||||
|
||||
## Getting help
|
||||
|
||||
* [Docker homepage](https://www.docker.com/)
|
||||
* [Docker Hub](https://hub.docker.com)
|
||||
* [Docker blog](https://blog.docker.com/)
|
||||
* [Docker documentation](https://docs.docker.com/)
|
||||
* [Docker Getting Started Guide](https://docs.docker.com/mac/started/)
|
||||
* [Docker code on GitHub](https://github.com/docker/docker)
|
||||
* [Docker mailing
|
||||
list](https://groups.google.com/forum/#!forum/docker-user)
|
||||
* Docker on IRC: irc.freenode.net and channel #docker
|
||||
* [Docker on Twitter](https://twitter.com/docker)
|
||||
* Get [Docker help](https://stackoverflow.com/search?q=docker) on
|
||||
StackOverflow
|
||||
* [Docker.com](https://www.docker.com/)
|
||||
229
vendor/github.com/hyperhq/hypercli/docs/userguide/labels-custom-metadata.md
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Apply custom metadata"
|
||||
description = "Learn how to work with custom metadata in Docker, using labels."
|
||||
keywords = ["Usage, user guide, labels, metadata, docker, documentation, examples, annotating"]
|
||||
[menu.main]
|
||||
parent = "engine_guide"
|
||||
weight=90
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Apply custom metadata
|
||||
|
||||
You can apply metadata to your images, containers, or daemons via
|
||||
labels. Labels serve a wide range of uses, such as adding notes or licensing
|
||||
information to an image, or to identify a host.
|
||||
|
||||
A label is a `<key>` / `<value>` pair. Docker stores the label values as
|
||||
*strings*. You can specify multiple labels but each `<key>` must be
|
||||
unique or the value will be overwritten. If you specify the same `key` several
|
||||
times but with different values, newer labels overwrite previous labels. Docker
|
||||
uses the last `key=value` you supply.
|
||||
|
||||
>**Note:** Support for daemon-labels was added in Docker 1.4.1. Labels on
|
||||
>containers and images are new in Docker 1.6.0
|
||||
|
||||
## Label keys (namespaces)
|
||||
|
||||
Docker puts no hard restrictions on the `key` used for a label. However, using
|
||||
simple keys can easily lead to conflicts. For example, you have chosen to
|
||||
categorize your images by CPU architecture using "architecture" labels in
|
||||
your Dockerfiles:
|
||||
|
||||
LABEL architecture="amd64"
|
||||
|
||||
LABEL architecture="ARMv7"
|
||||
|
||||
Another user may apply the same label based on a building's "architecture":
|
||||
|
||||
LABEL architecture="Art Nouveau"
|
||||
|
||||
To prevent naming conflicts, Docker recommends using namespaces to label keys
|
||||
using reverse domain notation. Use the following guidelines to name your keys:
|
||||
|
||||
- All (third-party) tools should prefix their keys with the
|
||||
reverse DNS notation of a domain controlled by the author. For
|
||||
example, `com.example.some-label`.
|
||||
|
||||
- The `com.docker.*`, `io.docker.*` and `org.dockerproject.*` namespaces are
|
||||
reserved for Docker's internal use.
|
||||
|
||||
- Keys should only consist of lower-cased alphanumeric characters,
|
||||
dots and dashes (for example, `[a-z0-9-.]`).
|
||||
|
||||
- Keys should start *and* end with an alpha numeric character.
|
||||
|
||||
- Keys may not contain consecutive dots or dashes.
|
||||
|
||||
- Keys *without* namespace (dots) are reserved for CLI use. This allows end-
|
||||
users to add metadata to their containers and images without having to type
|
||||
cumbersome namespaces on the command-line.
|
||||
|
||||
|
||||
These are simply guidelines and Docker does not *enforce* them. However, for
|
||||
the benefit of the community, you *should* use namespaces for your label keys.
|
||||
|
||||
|
||||
## Store structured data in labels
|
||||
|
||||
Label values can contain any data type as long as it can be represented as a
|
||||
string. For example, consider this JSON document:
|
||||
|
||||
|
||||
{
|
||||
"Description": "A containerized foobar",
|
||||
"Usage": "docker run --rm example/foobar [args]",
|
||||
"License": "GPL",
|
||||
"Version": "0.0.1-beta",
|
||||
"aBoolean": true,
|
||||
"aNumber" : 0.01234,
|
||||
"aNestedArray": ["a", "b", "c"]
|
||||
}
|
||||
|
||||
You can store this struct in a label by serializing it to a string first:
|
||||
|
||||
LABEL com.example.image-specs="{\"Description\":\"A containerized foobar\",\"Usage\":\"docker run --rm example\\/foobar [args]\",\"License\":\"GPL\",\"Version\":\"0.0.1-beta\",\"aBoolean\":true,\"aNumber\":0.01234,\"aNestedArray\":[\"a\",\"b\",\"c\"]}"
|
||||
|
||||
While it is *possible* to store structured data in label values, Docker treats
|
||||
this data as a 'regular' string. This means that Docker doesn't offer ways to
|
||||
query (filter) based on nested properties. If your tool needs to filter on
|
||||
nested properties, the tool itself needs to implement this functionality.
|
||||
|
||||
|
||||
## Add labels to images
|
||||
|
||||
To add labels to an image, use the `LABEL` instruction in your Dockerfile:
|
||||
|
||||
|
||||
LABEL [<namespace>.]<key>=<value> ...
|
||||
|
||||
The `LABEL` instruction adds a label to your image. A `LABEL` consists of a `<key>`
|
||||
and a `<value>`.
|
||||
Use an empty string for labels that don't have a `<value>`,
|
||||
Use surrounding quotes or backslashes for labels that contain
|
||||
white space characters in the `<value>`:
|
||||
|
||||
LABEL vendor=ACME\ Incorporated
|
||||
LABEL com.example.version.is-beta=
|
||||
LABEL com.example.version.is-production=""
|
||||
LABEL com.example.version="0.0.1-beta"
|
||||
LABEL com.example.release-date="2015-02-12"
|
||||
|
||||
The `LABEL` instruction also supports setting multiple `<key>` / `<value>` pairs
|
||||
in a single instruction:
|
||||
|
||||
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
|
||||
|
||||
Long lines can be split up by using a backslash (`\`) as continuation marker:
|
||||
|
||||
LABEL vendor=ACME\ Incorporated \
|
||||
com.example.is-beta= \
|
||||
com.example.is-production="" \
|
||||
com.example.version="0.0.1-beta" \
|
||||
com.example.release-date="2015-02-12"
|
||||
|
||||
Docker recommends you add multiple labels in a single `LABEL` instruction. Using
|
||||
individual instructions for each label can result in an inefficient image. This
|
||||
is because each `LABEL` instruction in a Dockerfile produces a new IMAGE layer.
|
||||
|
||||
You can view the labels via the `docker inspect` command:
|
||||
|
||||
$ docker inspect 4fa6e0f0c678
|
||||
|
||||
...
|
||||
"Labels": {
|
||||
"vendor": "ACME Incorporated",
|
||||
"com.example.is-beta": "",
|
||||
"com.example.is-production": "",
|
||||
"com.example.version": "0.0.1-beta",
|
||||
"com.example.release-date": "2015-02-12"
|
||||
}
|
||||
...
|
||||
|
||||
# Inspect labels on container
|
||||
$ docker inspect -f "{{json .Config.Labels }}" 4fa6e0f0c678
|
||||
|
||||
{"Vendor":"ACME Incorporated","com.example.is-beta":"", "com.example.is-production":"", "com.example.version":"0.0.1-beta","com.example.release-date":"2015-02-12"}
|
||||
|
||||
# Inspect labels on images
|
||||
$ docker inspect -f "{{json .ContainerConfig.Labels }}" myimage
|
||||
|
||||
|
||||
## Query labels
|
||||
|
||||
Besides storing metadata, you can filter images and containers by label. To list all
|
||||
running containers that have the `com.example.is-beta` label:
|
||||
|
||||
# List all running containers that have a `com.example.is-beta` label
|
||||
$ docker ps --filter "label=com.example.is-beta"
|
||||
|
||||
List all running containers with the label `color` that have a value `blue`:
|
||||
|
||||
$ docker ps --filter "label=color=blue"
|
||||
|
||||
List all images with the label `vendor` that have the value `ACME`:
|
||||
|
||||
$ docker images --filter "label=vendor=ACME"
|
||||
|
||||
|
||||
## Container labels
|
||||
|
||||
docker run \
|
||||
-d \
|
||||
--label com.example.group="webservers" \
|
||||
--label com.example.environment="production" \
|
||||
busybox \
|
||||
top
|
||||
|
||||
Please refer to the [Query labels](#query-labels) section above for information
|
||||
on how to query labels set on a container.
|
||||
|
||||
|
||||
## Daemon labels
|
||||
|
||||
docker daemon \
|
||||
--dns 8.8.8.8 \
|
||||
--dns 8.8.4.4 \
|
||||
-H unix:///var/run/docker.sock \
|
||||
--label com.example.environment="production" \
|
||||
--label com.example.storage="ssd"
|
||||
|
||||
These labels appear as part of the `docker info` output for the daemon:
|
||||
|
||||
$ docker -D info
|
||||
Containers: 12
|
||||
Running: 5
|
||||
Paused: 2
|
||||
Stopped: 5
|
||||
Images: 672
|
||||
Server Version: 1.9.0
|
||||
Storage Driver: aufs
|
||||
Root Dir: /var/lib/docker/aufs
|
||||
Backing Filesystem: extfs
|
||||
Dirs: 697
|
||||
Dirperm1 Supported: true
|
||||
Execution Driver: native-0.2
|
||||
Logging Driver: json-file
|
||||
Kernel Version: 3.19.0-22-generic
|
||||
Operating System: Ubuntu 15.04
|
||||
CPUs: 24
|
||||
Total Memory: 62.86 GiB
|
||||
Name: docker
|
||||
ID: I54V:OLXT:HVMM:TPKO:JPHQ:CQCD:JNLC:O3BZ:4ZVJ:43XJ:PFHZ:6N2S
|
||||
Debug mode (server): true
|
||||
File Descriptors: 59
|
||||
Goroutines: 159
|
||||
System Time: 2015-09-23T14:04:20.699842089+08:00
|
||||
EventsListeners: 0
|
||||
Init SHA1:
|
||||
Init Path: /usr/bin/docker
|
||||
Docker Root Dir: /var/lib/docker
|
||||
Http Proxy: http://test:test@localhost:8080
|
||||
Https Proxy: https://test:test@localhost:8080
|
||||
WARNING: No swap limit support
|
||||
Username: svendowideit
|
||||
Registry: [https://index.docker.io/v1/]
|
||||
Labels:
|
||||
com.example.environment=production
|
||||
com.example.storage=ssd
|
||||
138
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/configure-dns.md
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Configure container DNS in user-defined networks"
|
||||
description = "Learn how to configure DNS in user-defined networks"
|
||||
keywords = ["docker, DNS, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Embedded DNS server in user-defined networks
|
||||
|
||||
The information in this section covers the embedded DNS server operation for
|
||||
containers in user-defined networks. DNS lookup for containers connected to
|
||||
user-defined networks works differently compared to the containers connected
|
||||
to `default bridge` network.
|
||||
|
||||
> **Note**: In order to maintain backward compatibility, the DNS configuration
|
||||
> in `default bridge` network is retained with no behaviorial change.
|
||||
> Please refer to the [DNS in default bridge network](default_network/configure-dns.md)
|
||||
> for more information on DNS configuration in the `default bridge` network.
|
||||
|
||||
As of Docker 1.10, the docker daemon implements an embedded DNS server which
|
||||
provides built-in service discovery for any container created with a valid
|
||||
`name` or `net-alias` or aliased by `link`. The exact details of how Docker
|
||||
manages the DNS configurations inside the container can change from one Docker
|
||||
version to the next. So you should not assume the way the files such as
|
||||
`/etc/hosts`, `/etc/resolv.conf` are managed inside the containers and leave
|
||||
the files alone and use the following Docker options instead.
|
||||
|
||||
Various container options that affect container domain name services.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<p>
|
||||
<code>--name=CONTAINER-NAME</code>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
Container name configured using <code>--name</code> is used to discover a container within
|
||||
an user-defined docker network. The embedded DNS server maintains the mapping between
|
||||
the container name and its IP address (on the network the container is connected to).
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p>
|
||||
<code>--net-alias=ALIAS</code>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
In addition to <code>--name</code> as described above, a container is discovered by one or more
|
||||
of its configured <code>--net-alias</code> (or <code>--alias</code> in <code>docker network connect</code> command)
|
||||
within the user-defined network. The embedded DNS server maintains the mapping between
|
||||
all of the container aliases and its IP address on a specific user-defined network.
|
||||
A container can have different aliases in different networks by using the <code>--alias</code>
|
||||
option in <code>docker network connect</code> command.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p>
|
||||
<code>--link=CONTAINER_NAME:ALIAS</code>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
Using this option as you <code>run</code> a container gives the embedded DNS
|
||||
an extra entry named <code>ALIAS</code> that points to the IP address
|
||||
of the container identified by <code>CONTAINER_NAME</code>. When using <code>--link</code>
|
||||
the embedded DNS will guarantee that localized lookup result only on that
|
||||
container where the <code>--link</code> is used. This lets processes inside the new container
|
||||
connect to container without without having to know its name or IP.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p>
|
||||
<code>--dns=[IP_ADDRESS...]</code>
|
||||
</p></td>
|
||||
<td><p>
|
||||
The IP addresses passed via the <code>--dns</code> option is used by the embedded DNS
|
||||
server to forward the DNS query if embedded DNS server is unable to resolve a name
|
||||
resolution request from the containers.
|
||||
These <code>--dns</code> IP addresses are managed by the embedded DNS server and
|
||||
will not be updated in the container's <code>/etc/resolv.conf</code> file.
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p>
|
||||
<code>--dns-search=DOMAIN...</code>
|
||||
</p></td>
|
||||
<td><p>
|
||||
Sets the domain names that are searched when a bare unqualified hostname is
|
||||
used inside of the container. These <code>--dns-search</code> options are managed by the
|
||||
embedded DNS server and will not be updated in the container's <code>/etc/resolv.conf</code> file.
|
||||
When a container process attempts to access <code>host</code> and the search
|
||||
domain <code>example.com</code> is set, for instance, the DNS logic will not only
|
||||
look up <code>host</code> but also <code>host.example.com</code>.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p>
|
||||
<code>--dns-opt=OPTION...</code>
|
||||
</p></td>
|
||||
<td><p>
|
||||
Sets the options used by DNS resolvers. These options are managed by the embedded
|
||||
DNS server and will not be updated in the container's <code>/etc/resolv.conf</code> file.
|
||||
</p>
|
||||
<p>
|
||||
See documentation for <code>resolv.conf</code> for a list of valid options
|
||||
</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
In the absence of the `--dns=IP_ADDRESS...`, `--dns-search=DOMAIN...`, or
|
||||
`--dns-opt=OPTION...` options, Docker uses the `/etc/resolv.conf` of the
|
||||
host machine (where the `docker` daemon runs). While doing so the daemon
|
||||
filters out all localhost IP address `nameserver` entries from the host's
|
||||
original file.
|
||||
|
||||
Filtering is necessary because all localhost addresses on the host are
|
||||
unreachable from the container's network. After this filtering, if there are
|
||||
no more `nameserver` entries left in the container's `/etc/resolv.conf` file,
|
||||
the daemon adds public Google DNS nameservers (8.8.8.8 and 8.8.4.4) to the
|
||||
container's DNS configuration. If IPv6 is enabled on the daemon, the public
|
||||
IPv6 Google DNS nameservers will also be added (2001:4860:4860::8888 and
|
||||
2001:4860:4860::8844).
|
||||
|
||||
> **Note**: If you need access to a host's localhost resolver, you must modify
|
||||
> your DNS service on the host to listen on a non-localhost address that is
|
||||
> reachable from within the container.
|
||||
103
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/binding.md
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Bind container ports to the host"
|
||||
description = "expose, port, docker, bind publish"
|
||||
keywords = ["Examples, Usage, network, docker, documentation, user guide, multihost, cluster"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Bind container ports to the host
|
||||
|
||||
The information in this section explains binding container ports within the Docker default bridge. This is a `bridge` network named `bridge` created automatically when you install Docker.
|
||||
|
||||
> **Note**: The [Docker networks feature](../dockernetworks.md) allows you to
|
||||
create user-defined networks in addition to the default bridge network.
|
||||
|
||||
By default Docker containers can make connections to the outside world, but the
|
||||
outside world cannot connect to containers. Each outgoing connection will
|
||||
appear to originate from one of the host machine's own IP addresses thanks to an
|
||||
`iptables` masquerading rule on the host machine that the Docker server creates
|
||||
when it starts:
|
||||
|
||||
```
|
||||
$ sudo iptables -t nat -L -n
|
||||
...
|
||||
Chain POSTROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
|
||||
...
|
||||
```
|
||||
The Docker server creates a masquerade rule that let containers connect to IP
|
||||
addresses in the outside world.
|
||||
|
||||
If you want containers to accept incoming connections, you will need to provide
|
||||
special options when invoking `docker run`. There are two approaches.
|
||||
|
||||
First, you can supply `-P` or `--publish-all=true|false` to `docker run` which
|
||||
is a blanket operation that identifies every port with an `EXPOSE` line in the
|
||||
image's `Dockerfile` or `--expose <port>` commandline flag and maps it to a host
|
||||
port somewhere within an _ephemeral port range_. The `docker port` command then
|
||||
needs to be used to inspect created mapping. The _ephemeral port range_ is
|
||||
configured by `/proc/sys/net/ipv4/ip_local_port_range` kernel parameter,
|
||||
typically ranging from 32768 to 61000.
|
||||
|
||||
Mapping can be specified explicitly using `-p SPEC` or `--publish=SPEC` option.
|
||||
It allows you to particularize which port on docker server - which can be any
|
||||
port at all, not just one within the _ephemeral port range_ -- you want mapped
|
||||
to which port in the container.
|
||||
|
||||
Either way, you should be able to peek at what Docker has accomplished in your
|
||||
network stack by examining your NAT tables.
|
||||
|
||||
```
|
||||
# What your NAT rules might look like when Docker
|
||||
# is finished setting up a -P forward:
|
||||
|
||||
$ iptables -t nat -L -n
|
||||
...
|
||||
Chain DOCKER (2 references)
|
||||
target prot opt source destination
|
||||
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80
|
||||
|
||||
# What your NAT rules might look like when Docker
|
||||
# is finished setting up a -p 80:80 forward:
|
||||
|
||||
Chain DOCKER (2 references)
|
||||
target prot opt source destination
|
||||
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
|
||||
```
|
||||
|
||||
You can see that Docker has exposed these container ports on `0.0.0.0`, the
|
||||
wildcard IP address that will match any possible incoming port on the host
|
||||
machine. If you want to be more restrictive and only allow container services to
|
||||
be contacted through a specific external interface on the host machine, you have
|
||||
two choices. When you invoke `docker run` you can use either `-p
|
||||
IP:host_port:container_port` or `-p IP::port` to specify the external interface
|
||||
for one particular binding.
|
||||
|
||||
Or if you always want Docker port forwards to bind to one specific IP address,
|
||||
you can edit your system-wide Docker server settings and add the option
|
||||
`--ip=IP_ADDRESS`. Remember to restart your Docker server after editing this
|
||||
setting.
|
||||
|
||||
> **Note**: With hairpin NAT enabled (`--userland-proxy=false`), containers port
|
||||
exposure is achieved purely through iptables rules, and no attempt to bind the
|
||||
exposed port is ever made. This means that nothing prevents shadowing a
|
||||
previously listening service outside of Docker through exposing the same port
|
||||
for a container. In such conflicting situation, Docker created iptables rules
|
||||
will take precedence and route to the container.
|
||||
|
||||
The `--userland-proxy` parameter, true by default, provides a userland
|
||||
implementation for inter-container and outside-to-container communication. When
|
||||
disabled, Docker uses both an additional `MASQUERADE` iptable rule and the
|
||||
`net.ipv4.route_localnet` kernel parameter which allow the host machine to
|
||||
connect to a local container exposed port through the commonly used loopback
|
||||
address: this alternative is preferred for performance reasons.
|
||||
|
||||
## Related information
|
||||
|
||||
- [Understand Docker container networks](../dockernetworks.md)
|
||||
- [Work with network commands](../work-with-networks.md)
|
||||
- [Legacy container links](dockerlinks.md)
|
||||
78
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/build-bridges.md
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Build your own bridge"
|
||||
description = "Learn how to build your own bridge interface"
|
||||
keywords = ["docker, bridge, docker0, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Build your own bridge
|
||||
|
||||
This section explains how to build your own bridge to replace the Docker default
|
||||
bridge. This is a `bridge` network named `bridge` created automatically when you
|
||||
install Docker.
|
||||
|
||||
> **Note**: The [Docker networks feature](../dockernetworks.md) allows you to
|
||||
create user-defined networks in addition to the default bridge network.
|
||||
|
||||
You can set up your own bridge before starting Docker and use `-b BRIDGE` or
|
||||
`--bridge=BRIDGE` to tell Docker to use your bridge instead. If you already
|
||||
have Docker up and running with its default `docker0` still configured,
|
||||
you can directly create your bridge and restart Docker with it or want to begin by
|
||||
stopping the service and removing the interface:
|
||||
|
||||
```
|
||||
# Stopping Docker and removing docker0
|
||||
|
||||
$ 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 enough bridge
|
||||
that we really could just have used the options in the previous section to
|
||||
customize `docker0`, but it will be enough to illustrate the technique.
|
||||
|
||||
```
|
||||
# Create our own bridge
|
||||
|
||||
$ sudo brctl addbr bridge0
|
||||
$ sudo ip addr add 192.168.5.1/24 dev bridge0
|
||||
$ sudo ip link set dev bridge0 up
|
||||
|
||||
# Confirming that our bridge is up and running
|
||||
|
||||
$ ip addr show bridge0
|
||||
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
|
||||
link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.5.1/24 scope global bridge0
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
# Tell Docker about it and restart (on Ubuntu)
|
||||
|
||||
$ 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 see that its IP
|
||||
address is in your new IP address range, which Docker will have auto-detected.
|
||||
|
||||
You can use the `brctl show` command to see Docker add and remove interfaces
|
||||
from the bridge as you start and stop containers, and can run `ip addr` and `ip
|
||||
route` inside a container to see that it has been given an address in the
|
||||
bridge's IP address range and has been told to use the Docker host's IP address
|
||||
on the bridge as its default gateway to the rest of the Internet.
|
||||
132
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/configure-dns.md
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Configure container DNS"
|
||||
description = "Learn how to configure DNS in Docker"
|
||||
keywords = ["docker, bridge, docker0, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Configure container DNS
|
||||
|
||||
The information in this section explains configuring container DNS within
|
||||
the Docker default bridge. This is a `bridge` network named `bridge` created
|
||||
automatically when you install Docker.
|
||||
|
||||
> **Note**: The [Docker networks feature](../dockernetworks.md) allows you to create user-defined networks in addition to the default bridge network. Please refer to the [Docker Embedded DNS](../configure-dns.md) section for more information on DNS configurations in user-defined networks.
|
||||
|
||||
How can Docker supply each container with a hostname and DNS configuration, without having to build a custom image with the hostname written inside? Its trick is to overlay three crucial `/etc` files inside the container with virtual files where it can write fresh information. You can see this by running `mount` inside a container:
|
||||
|
||||
```
|
||||
$$ mount
|
||||
...
|
||||
/dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ...
|
||||
/dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ...
|
||||
/dev/disk/by-uuid/1fec...ebdf on /etc/resolv.conf type ext4 ...
|
||||
...
|
||||
```
|
||||
|
||||
This arrangement allows Docker to do clever things like keep `resolv.conf` up to date across all containers when the host machine receives new configuration over DHCP later. The exact details of how Docker maintains these files inside the container can change from one Docker version to the next, so you should leave the files themselves alone and use the following Docker options instead.
|
||||
|
||||
Four different options affect container domain name services.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<p>
|
||||
<code>-h HOSTNAME</code> or <code>--hostname=HOSTNAME</code>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
Sets the hostname by which the container knows itself. This is written
|
||||
into <code>/etc/hostname</code>, into <code>/etc/hosts</code> as the name
|
||||
of the container's host-facing IP address, and is the name that
|
||||
<code>/bin/bash</code> inside the container will display inside its
|
||||
prompt. But the hostname is not easy to see from outside the container.
|
||||
It will not appear in <code>docker ps</code> nor in the
|
||||
<code>/etc/hosts</code> file of any other container.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p>
|
||||
<code>--link=CONTAINER_NAME</code> or <code>ID:ALIAS</code>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
Using this option as you <code>run</code> a container gives the new
|
||||
container's <code>/etc/hosts</code> an extra entry named
|
||||
<code>ALIAS</code> that points to the IP address of the container
|
||||
identified by <code>CONTAINER_NAME_or_ID<c/ode>. This lets processes
|
||||
inside the new container connect to the hostname <code>ALIAS</code>
|
||||
without having to know its IP. The <code>--link=</code> option is
|
||||
discussed in more detail below. Because Docker may assign a different IP
|
||||
address to the linked containers on restart, Docker updates the
|
||||
<code>ALIAS</code> entry in the <code>/etc/hosts</code> file of the
|
||||
recipient containers.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p>
|
||||
<code>--dns=IP_ADDRESS...</code>
|
||||
</p></td>
|
||||
<td><p>
|
||||
Sets the IP addresses added as <code>server</code> lines to the container's
|
||||
<code>/etc/resolv.conf</code> file. Processes in the container, when
|
||||
confronted with a hostname not in <code>/etc/hosts</code>, will connect to
|
||||
these IP addresses on port 53 looking for name resolution services. </p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p>
|
||||
<code>--dns-search=DOMAIN...</code>
|
||||
</p></td>
|
||||
<td><p>
|
||||
Sets the domain names that are searched when a bare unqualified hostname is
|
||||
used inside of the container, by writing <code>search</code> lines into the
|
||||
container's <code>/etc/resolv.conf</code>. When a container process attempts
|
||||
to access <code>host</code> and the search domain <code>example.com</code>
|
||||
is set, for instance, the DNS logic will not only look up <code>host</code>
|
||||
but also <code>host.example.com</code>.
|
||||
</p>
|
||||
<p>
|
||||
Use <code>--dns-search=.</code> if you don't wish to set the search domain.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p>
|
||||
<code>--dns-opt=OPTION...</code>
|
||||
</p></td>
|
||||
<td><p>
|
||||
Sets the options used by DNS resolvers by writing an <code>options<code>
|
||||
line into the container's <code>/etc/resolv.conf<code>.
|
||||
</p>
|
||||
<p>
|
||||
See documentation for <code>resolv.conf<code> for a list of valid options
|
||||
</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p></p></td>
|
||||
<td><p></p></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
Regarding DNS settings, in the absence of the `--dns=IP_ADDRESS...`, `--dns-search=DOMAIN...`, or `--dns-opt=OPTION...` options, Docker makes each container's `/etc/resolv.conf` look like the `/etc/resolv.conf` of the host machine (where the `docker` daemon runs). When creating the container's `/etc/resolv.conf`, the daemon filters out all localhost IP address `nameserver` entries from the host's original file.
|
||||
|
||||
Filtering is necessary because all localhost addresses on the host are unreachable from the container's network. After this filtering, if there are no more `nameserver` entries left in the container's `/etc/resolv.conf` file, the daemon adds public Google DNS nameservers (8.8.8.8 and 8.8.4.4) to the container's DNS configuration. If IPv6 is enabled on the daemon, the public IPv6 Google DNS nameservers will also be added (2001:4860:4860::8888 and 2001:4860:4860::8844).
|
||||
|
||||
> **Note**: If you need access to a host's localhost resolver, you must modify your DNS service on the host to listen on a non-localhost address that is reachable from within the container.
|
||||
|
||||
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.
|
||||
|
||||
> **Note**: The file change notifier relies on the Linux kernel's inotify feature. Because this feature is currently incompatible with the overlay filesystem driver, a Docker daemon using "overlay" will not be able to take advantage of the `/etc/resolv.conf` auto-update feature.
|
||||
|
||||
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`, `--dns-search`, or `--dns-opt`) 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.
|
||||
123
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/container-communication.md
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Understand container communication"
|
||||
description = "Understand container communication"
|
||||
keywords = ["docker, container, communication, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Understand container communication
|
||||
|
||||
The information in this section explains container communication within the
|
||||
Docker default bridge. This is a `bridge` network named `bridge` created
|
||||
automatically when you install Docker.
|
||||
|
||||
**Note**: The [Docker networks feature](../dockernetworks.md) allows you to create user-defined networks in addition to the default bridge network.
|
||||
|
||||
## Communicating to the outside world
|
||||
|
||||
Whether a container can talk to the world is governed by two factors. The first
|
||||
factor is whether the host machine is forwarding its IP packets. The second is
|
||||
whether the host's `iptables` allow this particular connection.
|
||||
|
||||
IP packet forwarding 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. If you
|
||||
set `--ip-forward=false` and your system's kernel has it enabled, the
|
||||
`--ip-forward=false` option has no effect. To check the setting on your kernel
|
||||
or to turn it on manually:
|
||||
```
|
||||
$ sysctl net.ipv4.conf.all.forwarding
|
||||
net.ipv4.conf.all.forwarding = 0
|
||||
$ sysctl net.ipv4.conf.all.forwarding=1
|
||||
$ sysctl net.ipv4.conf.all.forwarding
|
||||
net.ipv4.conf.all.forwarding = 1
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
Whether two containers can communicate is governed, at the operating system level, by two factors.
|
||||
|
||||
- Does the network topology even connect the containers' network interfaces? By default Docker will attach all containers to a single `docker0` bridge, providing a path for packets to travel between them. See the later sections of this document for other possible topologies.
|
||||
|
||||
- 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` so that `iptables` will protect other containers -- and the main
|
||||
host -- from having arbitrary ports probed or accessed by a container that gets
|
||||
compromised.
|
||||
|
||||
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_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 `--link=` option, the Docker
|
||||
server will insert a pair of `iptables` `ACCEPT` rules so that the new
|
||||
container can connect to the ports exposed by the other container -- the ports
|
||||
that it mentioned in the `EXPOSE` lines of its `Dockerfile`.
|
||||
|
||||
> **Note**: The value `CONTAINER_NAME` in `--link=` must either be an
|
||||
auto-assigned Docker name like `stupefied_pare` or else the name you assigned
|
||||
with `--name=` when you ran `docker run`. It cannot be a hostname, which Docker
|
||||
will not recognize in the context of the `--link=` option.
|
||||
|
||||
You can run the `iptables` command on your Docker host to see whether the `FORWARD` chain has a default policy of `ACCEPT` or `DROP`:
|
||||
|
||||
```
|
||||
# When --icc=false, you should see a DROP rule:
|
||||
|
||||
$ sudo iptables -L -n
|
||||
...
|
||||
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
|
||||
...
|
||||
|
||||
# When a --link= has been created under --icc=false,
|
||||
# you should see port-specific ACCEPT rules overriding
|
||||
# the subsequent DROP policy for all other packets:
|
||||
|
||||
$ sudo iptables -L -n
|
||||
...
|
||||
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
|
||||
```
|
||||
|
||||
> **Note**: Docker is careful that its host-wide `iptables` rules fully expose
|
||||
containers to each other's raw IP addresses, so connections from one container
|
||||
to another should always appear to be originating from the first container's own
|
||||
IP address.
|
||||
62
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/custom-docker0.md
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Customize the docker0 bridge"
|
||||
description = "Customizing docker0"
|
||||
keywords = ["docker, bridge, docker0, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Customize the docker0 bridge
|
||||
|
||||
The information in this section explains how to customize the Docker default bridge. This is a `bridge` network named `bridge` created automatically when you install Docker.
|
||||
|
||||
**Note**: The [Docker networks feature](../dockernetworks.md) allows you to create user-defined networks in addition to the default bridge network.
|
||||
|
||||
By default, the Docker server creates and configures the host system's `docker0` interface as an _Ethernet bridge_ inside the Linux kernel that can pass packets back and forth between other physical or virtual network interfaces so that they behave as a single Ethernet network.
|
||||
|
||||
Docker configures `docker0` with an IP address, netmask and IP allocation range. The host machine can both receive and send packets to containers connected to the bridge, and gives it an MTU -- the _maximum transmission unit_ or largest packet length that the interface will allow -- of 1,500 bytes. These options are configurable at server startup:
|
||||
|
||||
- `--bip=CIDR` -- supply a specific IP address and netmask for the `docker0` bridge, using standard CIDR notation like `192.168.1.5/24`.
|
||||
|
||||
- `--fixed-cidr=CIDR` -- restrict the IP range from the `docker0` subnet, using the standard CIDR notation like `172.167.1.0/28`. This range must be an IPv4 range for fixed IPs (ex: 10.20.0.0/16) and must be a subset of the bridge IP range (`docker0` or set using `--bridge`). For example with `--fixed-cidr=192.168.1.0/25`, IPs for your containers will be chosen from the first half of `192.168.1.0/24` subnet.
|
||||
|
||||
- `--mtu=BYTES` -- override the maximum packet length on `docker0`.
|
||||
|
||||
Once you have one or more containers up and running, you can confirm that Docker has properly connected them to the `docker0` bridge by running the `brctl` command on the host machine and looking at the `interfaces` column of the output. Here is a host with two different containers connected:
|
||||
|
||||
```
|
||||
# Display bridge info
|
||||
|
||||
$ sudo brctl show
|
||||
bridge name bridge id STP enabled interfaces
|
||||
docker0 8000.3a1d7362b4ee no veth65f9
|
||||
vethdda6
|
||||
```
|
||||
|
||||
If the `brctl` command is not installed on your Docker host, then on Ubuntu you should be able to run `sudo apt-get install bridge-utils` to install it.
|
||||
|
||||
Finally, the `docker0` Ethernet bridge settings are used every time you create a new container. Docker selects a free IP address from the range available on the bridge each time you `docker run` a new container, and configures the container's `eth0` interface with that IP address and the bridge's netmask. The Docker host's own IP address on the bridge is used as the default gateway by which each container reaches the rest of the Internet.
|
||||
|
||||
```
|
||||
# The network, as seen from a container
|
||||
|
||||
$ docker run -i -t --rm base /bin/bash
|
||||
|
||||
$$ ip addr show eth0
|
||||
24: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
|
||||
link/ether 32:6f:e0:35:57:91 brd ff:ff:ff:ff:ff:ff
|
||||
inet 172.17.0.3/16 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::306f:e0ff:fe35:5791/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
$$ ip route
|
||||
default via 172.17.42.1 dev eth0
|
||||
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
|
||||
|
||||
$$ exit
|
||||
```
|
||||
|
||||
Remember that the Docker host will not be willing to forward container packets out on to the Internet unless its `ip_forward` system setting is `1` -- see the section on [Communicating to the outside world](container-communication.md#communicating-to-the-outside-world) for details.
|
||||
358
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/dockerlinks.md
generated
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Legacy container links"
|
||||
description = "Learn how to connect Docker containers together."
|
||||
keywords = ["Examples, Usage, user guide, links, linking, docker, documentation, examples, names, name, container naming, port, map, network port, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
weight=-2
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Legacy container links
|
||||
|
||||
The information in this section explains legacy container links within the Docker default bridge. This is a `bridge` network named `bridge` created automatically when you install Docker.
|
||||
|
||||
Before the [Docker networks feature](../dockernetworks.md), you could use the
|
||||
Docker link feature to allow containers to discover each other and securely
|
||||
transfer information about one container to another container. With the
|
||||
introduction of the Docker networks feature, you can still create links but they
|
||||
behave differently between default `bridge` network and
|
||||
[user defined networks](../work-with-networks.md#linking-containers-in-user-defined-networks)
|
||||
|
||||
This section briefly discusses connecting via a network port and then goes into
|
||||
detail on container linking in default `bridge` network.
|
||||
|
||||
## Connect using network port mapping
|
||||
|
||||
In [the Using Docker section](../../containers/usingdocker.md), you created a
|
||||
container that ran a Python Flask application:
|
||||
|
||||
$ docker run -d -P training/webapp python app.py
|
||||
|
||||
> **Note:**
|
||||
> Containers have an internal network and an IP address
|
||||
> (as we saw when we used the `docker inspect` command to show the container's
|
||||
> IP address in the [Using Docker](../../containers/usingdocker.md) section).
|
||||
> Docker can have a variety of network configurations. You can see more
|
||||
> information on Docker networking [here](../index.md).
|
||||
|
||||
When that container was created, the `-P` flag was used to automatically map
|
||||
any network port inside it to a random high port within an *ephemeral port
|
||||
range* on your Docker host. Next, when `docker ps` was run, you saw that port
|
||||
5000 in the container was bound to port 49155 on the host.
|
||||
|
||||
$ docker ps nostalgic_morse
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
|
||||
|
||||
You also saw how you can bind a container's ports to a specific port using
|
||||
the `-p` flag. Here port 80 of the host is mapped to port 5000 of the
|
||||
container:
|
||||
|
||||
$ docker run -d -p 80:5000 training/webapp python app.py
|
||||
|
||||
And you saw why this isn't such a great idea because it constrains you to
|
||||
only one container on that specific port.
|
||||
|
||||
Instead, you may specify a range of host ports to bind a container port to
|
||||
that is different than the default *ephemeral port range*:
|
||||
|
||||
$ docker run -d -p 8000-9000:5000 training/webapp python app.py
|
||||
|
||||
This would bind port 5000 in the container to a randomly available port
|
||||
between 8000 and 9000 on the host.
|
||||
|
||||
There are also a few other ways you can configure the `-p` flag. By
|
||||
default the `-p` flag will bind the specified port to all interfaces on
|
||||
the host machine. But you can also specify a binding to a specific
|
||||
interface, for example only to the `localhost`.
|
||||
|
||||
$ docker run -d -p 127.0.0.1:80:5000 training/webapp python app.py
|
||||
|
||||
This would bind port 5000 inside the container to port 80 on the
|
||||
`localhost` or `127.0.0.1` interface on the host machine.
|
||||
|
||||
Or, to bind port 5000 of the container to a dynamic port but only on the
|
||||
`localhost`, you could use:
|
||||
|
||||
$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py
|
||||
|
||||
You can also bind UDP ports by adding a trailing `/udp`. For example:
|
||||
|
||||
$ docker run -d -p 127.0.0.1:80:5000/udp training/webapp python app.py
|
||||
|
||||
You also learned about the useful `docker port` shortcut which showed us the
|
||||
current port bindings. This is also useful for showing you specific port
|
||||
configurations. For example, if you've bound the container port to the
|
||||
`localhost` on the host machine, then the `docker port` output will reflect that.
|
||||
|
||||
$ docker port nostalgic_morse 5000
|
||||
127.0.0.1:49155
|
||||
|
||||
> **Note:**
|
||||
> The `-p` flag can be used multiple times to configure multiple ports.
|
||||
|
||||
## Connect with the linking system
|
||||
|
||||
> **Note**:
|
||||
> This section covers the legacy link feature in the default `bridge` network.
|
||||
> Please refer to [linking containers in user-defined networks]
|
||||
> (../work-with-networks.md#linking-containers-in-user-defined-networks)
|
||||
> for more information on links in user-defined networks.
|
||||
|
||||
Network port mappings are not the only way Docker containers can connect to one
|
||||
another. Docker also has a linking system that allows you to link multiple
|
||||
containers together and send connection information from one to another. When
|
||||
containers are linked, information about a source container can be sent to a
|
||||
recipient container. This allows the recipient to see selected data describing
|
||||
aspects of the source container.
|
||||
|
||||
### The importance of naming
|
||||
|
||||
To establish links, Docker relies on the names of your containers.
|
||||
You've already seen that each container you create has an automatically
|
||||
created name; indeed you've become familiar with our old friend
|
||||
`nostalgic_morse` during this guide. You can also name containers
|
||||
yourself. This naming provides two useful functions:
|
||||
|
||||
1. It can be useful to name containers that do specific functions in a way
|
||||
that makes it easier for you to remember them, for example naming a
|
||||
container containing a web application `web`.
|
||||
|
||||
2. It provides Docker with a reference point that allows it to refer to other
|
||||
containers, for example, you can specify to link the container `web` to container `db`.
|
||||
|
||||
You can name your container by using the `--name` flag, for example:
|
||||
|
||||
$ docker run -d -P --name web training/webapp python app.py
|
||||
|
||||
This launches a new container and uses the `--name` flag to
|
||||
name the container `web`. You can see the container's name using the
|
||||
`docker ps` command.
|
||||
|
||||
$ docker ps -l
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
aed84ee21bde training/webapp:latest python app.py 12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web
|
||||
|
||||
You can also use `docker inspect` to return the container's name.
|
||||
|
||||
|
||||
> **Note:**
|
||||
> Container names have to be unique. That means you can only call
|
||||
> one container `web`. If you want to re-use a container name you must delete
|
||||
> the old container (with `docker rm`) before you can create a new
|
||||
> container with the same name. As an alternative you can use the `--rm`
|
||||
> flag with the `docker run` command. This will delete the container
|
||||
> immediately after it is stopped.
|
||||
|
||||
## Communication across links
|
||||
|
||||
Links allow containers to discover each other and securely transfer information
|
||||
about one container to another container. When you set up a link, you create a
|
||||
conduit between a source container and a recipient container. The recipient can
|
||||
then access select data about the source. To create a link, you use the `--link`
|
||||
flag. First, create a new container, this time one containing a database.
|
||||
|
||||
$ docker run -d --name db training/postgres
|
||||
|
||||
This creates a new container called `db` from the `training/postgres`
|
||||
image, which contains a PostgreSQL database.
|
||||
|
||||
Now, you need to delete the `web` container you created previously so you can replace it
|
||||
with a linked one:
|
||||
|
||||
$ docker rm -f web
|
||||
|
||||
Now, create a new `web` container and link it with your `db` container.
|
||||
|
||||
$ docker run -d -P --name web --link db:db training/webapp python app.py
|
||||
|
||||
This will link the new `web` container with the `db` container you created
|
||||
earlier. The `--link` flag takes the form:
|
||||
|
||||
--link <name or id>: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.
|
||||
The `--link` flag also takes the form:
|
||||
|
||||
--link <name or id>
|
||||
|
||||
In which case the alias will match the name. You could have written the previous
|
||||
example as:
|
||||
|
||||
$ docker run -d -P --name web --link db training/webapp python app.py
|
||||
|
||||
Next, inspect your linked containers with `docker inspect`:
|
||||
|
||||
$ docker inspect -f "{{ .HostConfig.Links }}" web
|
||||
[/db:/web/db]
|
||||
|
||||
You can see that the `web` container is now linked to the `db` container
|
||||
`web/db`. Which allows it to access information about the `db` container.
|
||||
|
||||
So what does linking the containers actually do? You've learned that a link allows a
|
||||
source container to provide information about itself to a recipient container. In
|
||||
our example, the recipient, `web`, can access information about the source `db`. To do
|
||||
this, Docker creates a secure tunnel between the containers that doesn't need to
|
||||
expose any ports externally on the container; you'll note when we started the
|
||||
`db` container we did not use either the `-P` or `-p` flags. That's a big benefit of
|
||||
linking: we don't need to expose the source container, here the PostgreSQL database, to
|
||||
the network.
|
||||
|
||||
Docker exposes connectivity information for the source container to the
|
||||
recipient container in two ways:
|
||||
|
||||
* Environment variables,
|
||||
* Updating the `/etc/hosts` file.
|
||||
|
||||
### Environment variables
|
||||
|
||||
Docker creates several environment variables when you link containers. Docker
|
||||
automatically creates environment variables in the target container based on
|
||||
the `--link` parameters. It will also expose all environment variables
|
||||
originating from Docker from the source container. These include variables from:
|
||||
|
||||
* the `ENV` commands in the source container's Dockerfile
|
||||
* the `-e`, `--env` and `--env-file` options on the `docker run`
|
||||
command when the source container is started
|
||||
|
||||
These environment variables enable programmatic discovery from within the
|
||||
target container of information related to the source container.
|
||||
|
||||
> **Warning**:
|
||||
> It is important to understand that *all* environment variables originating
|
||||
> from Docker within a container are made available to *any* container
|
||||
> that links to it. This could have serious security implications if sensitive
|
||||
> data is stored in them.
|
||||
|
||||
Docker sets an `<alias>_NAME` environment variable for each target container
|
||||
listed in the `--link` parameter. For example, if a new container called
|
||||
`web` is linked to a database container called `db` via `--link db:webdb`,
|
||||
then Docker creates a `WEBDB_NAME=/web/webdb` variable in the `web` container.
|
||||
|
||||
Docker also defines a set of environment variables for each port exposed by the
|
||||
source container. Each variable has a unique prefix in the form:
|
||||
|
||||
`<name>_PORT_<port>_<protocol>`
|
||||
|
||||
The components in this prefix are:
|
||||
|
||||
* the alias `<name>` specified in the `--link` parameter (for example, `webdb`)
|
||||
* the `<port>` number exposed
|
||||
* a `<protocol>` which is either TCP or UDP
|
||||
|
||||
Docker uses this prefix format to define three distinct environment variables:
|
||||
|
||||
* The `prefix_ADDR` variable contains the IP Address from the URL, for
|
||||
example `WEBDB_PORT_5432_TCP_ADDR=172.17.0.82`.
|
||||
* The `prefix_PORT` variable contains just the port number from the URL for
|
||||
example `WEBDB_PORT_5432_TCP_PORT=5432`.
|
||||
* The `prefix_PROTO` variable contains just the protocol from the URL for
|
||||
example `WEBDB_PORT_5432_TCP_PROTO=tcp`.
|
||||
|
||||
If the container exposes multiple ports, an environment variable set is
|
||||
defined for each one. This means, for example, if a container exposes 4 ports
|
||||
that Docker creates 12 environment variables, 3 for each port.
|
||||
|
||||
Additionally, Docker creates an environment variable called `<alias>_PORT`.
|
||||
This variable contains the URL of the source container's first exposed port.
|
||||
The 'first' port is defined as the exposed port with the lowest number.
|
||||
For example, consider the `WEBDB_PORT=tcp://172.17.0.82:5432` variable. If
|
||||
that port is used for both tcp and udp, then the tcp one is specified.
|
||||
|
||||
Finally, Docker also exposes each Docker originated environment variable
|
||||
from the source container as an environment variable in the target. For each
|
||||
variable Docker creates an `<alias>_ENV_<name>` variable in the target
|
||||
container. The variable's value is set to the value Docker used when it
|
||||
started the source container.
|
||||
|
||||
Returning back to our database example, you can run the `env`
|
||||
command to list the specified container's environment variables.
|
||||
|
||||
```
|
||||
$ docker run --rm --name web2 --link db:db training/webapp env
|
||||
. . .
|
||||
DB_NAME=/web2/db
|
||||
DB_PORT=tcp://172.17.0.5:5432
|
||||
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
|
||||
DB_PORT_5432_TCP_PROTO=tcp
|
||||
DB_PORT_5432_TCP_PORT=5432
|
||||
DB_PORT_5432_TCP_ADDR=172.17.0.5
|
||||
. . .
|
||||
```
|
||||
|
||||
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`
|
||||
were `db1`, the variables would be prefixed with `DB1_`. You can use these
|
||||
environment variables to configure your applications to connect to the database
|
||||
on the `db` container. The connection will be secure and private; only the
|
||||
linked `web` container will be able to talk to the `db` container.
|
||||
|
||||
### Important notes on Docker environment variables
|
||||
|
||||
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.
|
||||
|
||||
These environment variables are only set for the first process in the
|
||||
container. Some daemons, such as `sshd`, will scrub them when spawning shells
|
||||
for connection.
|
||||
|
||||
### Updating the `/etc/hosts` file
|
||||
|
||||
In addition to the environment variables, Docker adds a host entry for the
|
||||
source container to the `/etc/hosts` file. Here's an entry for the `web`
|
||||
container:
|
||||
|
||||
$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash
|
||||
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
|
||||
172.17.0.7 aed84ee21bde
|
||||
. . .
|
||||
172.17.0.5 webdb 6e5cdeb2d300 db
|
||||
|
||||
You can see two relevant host entries. The first is an entry for the `web`
|
||||
container that uses the Container ID as a host name. The second entry uses the
|
||||
link alias to reference the IP address of the `db` container. In addition to
|
||||
the alias you provide, the linked container's name--if unique from the alias
|
||||
provided to the `--link` parameter--and the linked container's hostname will
|
||||
also be added in `/etc/hosts` for the linked container's IP address. You can ping
|
||||
that host now via any of these entries:
|
||||
|
||||
root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
|
||||
root@aed84ee21bde:/opt/webapp# ping webdb
|
||||
PING webdb (172.17.0.5): 48 data bytes
|
||||
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
|
||||
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
|
||||
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms
|
||||
|
||||
> **Note:**
|
||||
> In the example, you'll note you had to install `ping` because it was not included
|
||||
> in the container initially.
|
||||
|
||||
Here, you used the `ping` command to ping the `db` container using its host entry,
|
||||
which resolves to `172.17.0.5`. You can use this host entry to configure an application
|
||||
to make use of your `db` container.
|
||||
|
||||
> **Note:**
|
||||
> You can link multiple recipient containers to a single source. For
|
||||
> example, you could have multiple (differently named) web containers attached to your
|
||||
>`db` container.
|
||||
|
||||
If you restart the source container, the linked containers `/etc/hosts` files
|
||||
will be automatically updated with the source container's new IP address,
|
||||
allowing linked communication to continue.
|
||||
|
||||
$ docker restart db
|
||||
db
|
||||
$ docker run -t -i --rm --link db:db training/webapp /bin/bash
|
||||
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
|
||||
172.17.0.7 aed84ee21bde
|
||||
. . .
|
||||
172.17.0.9 db
|
||||
|
||||
# Related information
|
||||
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_basic_host_config.gliffy
generated
vendored
Normal file
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_basic_host_config.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_ndp_proxying.gliffy
generated
vendored
Normal file
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_ndp_proxying.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 66 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_routed_network_example.gliffy
generated
vendored
Normal file
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_routed_network_example.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 96 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_slash64_subnet_config.gliffy
generated
vendored
Normal file
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_slash64_subnet_config.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 74 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_switched_network_example.gliffy
generated
vendored
Normal file
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/images/ipv6_switched_network_example.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 175 KiB |
25
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/index.md
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Default bridge network"
|
||||
description = "Docker networking"
|
||||
keywords = ["network, networking, bridge, docker, documentation"]
|
||||
[menu.main]
|
||||
identifier="smn_networking_def"
|
||||
parent= "smn_networking"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Docker default bridge network
|
||||
|
||||
With the introduction of the Docker networks feature, you can create your own
|
||||
user-defined networks. The Docker default bridge is created when you install
|
||||
Docker Engine. It is a `bridge` network and is also named `bridge`. The topics
|
||||
in this section are related to interacting with that default bridge network.
|
||||
|
||||
- [Understand container communication](container-communication.md)
|
||||
- [Legacy container links](dockerlinks.md)
|
||||
- [Binding container ports to the host](binding.md)
|
||||
- [Build your own bridge](build-bridges.md)
|
||||
- [Configure container DNS](configure-dns.md)
|
||||
- [Customize the docker0 bridge](custom-docker0.md)
|
||||
- [IPv6 with Docker](ipv6.md)
|
||||
259
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/ipv6.md
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "IPv6 with Docker"
|
||||
description = "How do we connect docker containers within and across hosts ?"
|
||||
keywords = ["docker, network, IPv6"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
weight = 3
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# IPv6 with Docker
|
||||
|
||||
The information in this section explains IPv6 with the Docker default bridge.
|
||||
This is a `bridge` network named `bridge` created automatically when you install
|
||||
Docker.
|
||||
|
||||
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).
|
||||
|
||||
## How IPv6 works on 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 daemon --ipv6 --fixed-cidr-v6="2001:db8:1::/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`):
|
||||
|
||||
```
|
||||
$ ip -6 route add 2001:db8:1::/64 dev docker0
|
||||
$ sysctl net.ipv6.conf.default.forwarding=1
|
||||
$ sysctl net.ipv6.conf.all.forwarding=1
|
||||
```
|
||||
|
||||
All traffic to the subnet `2001:db8:1::/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:
|
||||
|
||||
```
|
||||
$ sysctl net.ipv6.conf.eth0.accept_ra=2
|
||||
```
|
||||
|
||||

|
||||
|
||||
Every new container will get an IPv6 address from the defined subnet. Further a
|
||||
default route will be added on `eth0` in the container via the address specified
|
||||
by the daemon option `--default-gateway-v6` if present, otherwise via `fe80::1`:
|
||||
```
|
||||
docker run -it ubuntu bash -c "ip -6 addr show dev eth0; ip -6 route show"
|
||||
|
||||
15: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500
|
||||
inet6 2001:db8:1:0:0:242:ac11:3/64 scope global
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::42:acff:fe11:3/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
2001:db8:1::/64 dev eth0 proto kernel metric 256
|
||||
fe80::/64 dev eth0 proto kernel metric 256
|
||||
default via fe80::1 dev eth0 metric 1024
|
||||
```
|
||||
|
||||
In this example the Docker container is assigned a link-local address with the
|
||||
network suffix `/64` (here: `fe80::42:acff:fe11:3/64`) and a globally routable
|
||||
IPv6 address (here: `2001:db8:1:0:0:242:ac11:3/64`). The container will create
|
||||
connections to addresses outside of the `2001:db8:1::/64` network via the
|
||||
link-local gateway at `fe80::1` on `eth0`.
|
||||
|
||||
Often servers or virtual machines get a `/64` IPv6 subnet assigned (e.g.
|
||||
`2001:db8:23:42::/64`). 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:
|
||||
|
||||

|
||||
|
||||
In this setup the subnet `2001:db8:23:42::/80` with a range from
|
||||
`2001:db8:23:42:0:0:0:0` to `2001:db8:23:42:0:ffff:ffff:ffff` is attached to
|
||||
`eth0`, with the host listening at `2001:db8:23:42::1`. The subnet
|
||||
`2001:db8:23:42:1::/80` with an address range from `2001:db8:23:42:1:0:0:0` to
|
||||
`2001:db8:23:42:1:ffff:ffff:ffff` is attached to `docker0` and will be used by
|
||||
containers.
|
||||
|
||||
### Using NDP proxying
|
||||
|
||||
If your Docker host is only part of an IPv6 subnet but has not got an IPv6
|
||||
subnet assigned you can use NDP proxying to connect your containers via IPv6 to
|
||||
the internet. For example your host has the IPv6 address `2001:db8::c001`, is
|
||||
part of the subnet `2001:db8::/64` and your IaaS provider allows you to
|
||||
configure the IPv6 addresses `2001:db8::c000` to `2001:db8::c00f`:
|
||||
|
||||
```
|
||||
$ ip -6 addr show
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536
|
||||
inet6 ::1/128 scope host
|
||||
valid_lft forever preferred_lft forever
|
||||
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
|
||||
inet6 2001:db8::c001/64 scope global
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::601:3fff:fea1:9c01/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
```
|
||||
|
||||
Let's split up the configurable address range into two subnets
|
||||
`2001:db8::c000/125` and `2001:db8::c008/125`. The first one can be used by the
|
||||
host itself, the latter by Docker:
|
||||
|
||||
```
|
||||
docker daemon --ipv6 --fixed-cidr-v6 2001:db8::c008/125
|
||||
```
|
||||
|
||||
You notice the Docker subnet is within the subnet managed by your router that is
|
||||
connected to `eth0`. This means all devices (containers) with the addresses from
|
||||
the Docker subnet are expected to be found within the router subnet. Therefore
|
||||
the router thinks it can talk to these containers directly.
|
||||
|
||||

|
||||
|
||||
As soon as the router wants to send an IPv6 packet to the first container it
|
||||
will transmit a neighbor solicitation request, asking, who has `2001:db8::c009`?
|
||||
But it will get no answer because no one on this subnet has this address. The
|
||||
container with this address is hidden behind the Docker host. The Docker host
|
||||
has to listen to neighbor solicitation requests for the container address and
|
||||
send a response that itself is the device that is responsible for the address.
|
||||
This is done by a Kernel feature called `NDP Proxy`. You can enable it by
|
||||
executing
|
||||
|
||||
```
|
||||
$ sysctl net.ipv6.conf.eth0.proxy_ndp=1
|
||||
```
|
||||
|
||||
Now you can add the container's IPv6 address to the NDP proxy table:
|
||||
|
||||
```
|
||||
$ ip -6 neigh add proxy 2001:db8::c009 dev eth0
|
||||
```
|
||||
|
||||
This command tells the Kernel to answer to incoming neighbor solicitation
|
||||
requests regarding the IPv6 address `2001:db8::c009` on the device `eth0`. As a
|
||||
consequence of this all traffic to this IPv6 address will go into the Docker
|
||||
host and it will forward it according to its routing table via the `docker0`
|
||||
device to the container network:
|
||||
|
||||
```
|
||||
$ ip -6 route show
|
||||
2001:db8::c008/125 dev docker0 metric 1
|
||||
2001:db8::/64 dev eth0 proto kernel metric 256
|
||||
```
|
||||
|
||||
You have to execute the `ip -6 neigh add proxy ...` command for every IPv6
|
||||
address in your Docker subnet. Unfortunately there is no functionality for
|
||||
adding a whole subnet by executing one command. An alternative approach would be
|
||||
to use an NDP proxy daemon such as
|
||||
[ndppd](https://github.com/DanielAdolfsson/ndppd).
|
||||
|
||||
## 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:
|
||||
|
||||

|
||||
|
||||
The Docker hosts are in the `2001:db8:0::/64` subnet. Host1 is configured to
|
||||
provide addresses from the `2001:db8:1::/64` subnet to its containers. It has
|
||||
three routes configured:
|
||||
|
||||
- Route all traffic to `2001:db8:0::/64` via `eth0`
|
||||
- Route all traffic to `2001:db8:1::/64` via `docker0`
|
||||
- Route all traffic to `2001:db8:2::/64` via Host2 with IP `2001:db8::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:
|
||||
`2001:db8::/64`, `2001:db8:1::/64` and `2001:db8:2::/64`.
|
||||
|
||||
On Host2 we have nearly the same configuration. Host2's containers will get IPv6
|
||||
addresses from `2001:db8:2::/64`. Host2 has three routes configured:
|
||||
|
||||
- Route all traffic to `2001:db8:0::/64` via `eth0`
|
||||
- Route all traffic to `2001:db8:2::/64` via `docker0`
|
||||
- Route all traffic to `2001:db8:1::/64` via Host1 with IP `2001:db8:0::1`
|
||||
|
||||
The difference to Host1 is that the network `2001:db8:2::/64` is directly
|
||||
attached to the host via its `docker0` interface whereas it reaches
|
||||
`2001:db8:1::/64` via Host1's IPv6 address `2001:db8::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 layer 2 switch with a layer 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.
|
||||
|
||||

|
||||
|
||||
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 `/78` 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.
|
||||
141
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/options.md
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
draft=true
|
||||
title = "Tools and Examples"
|
||||
keywords = ["docker, bridge, docker0, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
<!--[metadata]>
|
||||
We may want to add it back in later under another form. Labeled DRAFT for now. Won't be built.
|
||||
<![end-metadata]-->
|
||||
|
||||
# Quick guide to the options
|
||||
Here is a quick list of the networking-related Docker command-line options, in case it helps you find the section below that you are looking for.
|
||||
|
||||
Some networking command-line options can only be supplied to the Docker server when it starts up, and cannot be changed once it is running:
|
||||
- `-b BRIDGE` or `--bridge=BRIDGE` -- see
|
||||
|
||||
[Building your own bridge](#bridge-building)
|
||||
|
||||
- `--bip=CIDR` -- see
|
||||
|
||||
[Customizing docker0](#docker0)
|
||||
|
||||
- `--default-gateway=IP_ADDRESS` -- see
|
||||
|
||||
[How Docker networks a container](#container-networking)
|
||||
|
||||
- `--default-gateway-v6=IP_ADDRESS` -- see
|
||||
|
||||
[IPv6](#ipv6)
|
||||
|
||||
- `--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:
|
||||
|
||||
it tells the Docker server over what channels
|
||||
|
||||
it should be willing to receive commands
|
||||
|
||||
like "run container" and "stop container."
|
||||
|
||||
- `--icc=true|false` -- see
|
||||
|
||||
[Communication between containers](#between-containers)
|
||||
|
||||
- `--ip=IP_ADDRESS` -- see
|
||||
|
||||
[Binding container ports](#binding-ports)
|
||||
|
||||
- `--ipv6=true|false` -- see
|
||||
|
||||
[IPv6](#ipv6)
|
||||
|
||||
- `--ip-forward=true|false` -- see
|
||||
|
||||
[Communication between containers and the wider world](#the-world)
|
||||
|
||||
- `--iptables=true|false` -- see
|
||||
|
||||
[Communication between containers](#between-containers)
|
||||
|
||||
- `--mtu=BYTES` -- see
|
||||
|
||||
[Customizing docker0](#docker0)
|
||||
|
||||
- `--userland-proxy=true|false` -- see
|
||||
|
||||
[Binding container ports](#binding-ports)
|
||||
|
||||
There are three networking options that can be supplied either at startup or when `docker run` is invoked. When provided at startup, set the default value that `docker run` will later use if the options are not specified:
|
||||
- `--dns=IP_ADDRESS...` -- see
|
||||
|
||||
[Configuring DNS](#dns)
|
||||
|
||||
- `--dns-search=DOMAIN...` -- see
|
||||
|
||||
[Configuring DNS](#dns)
|
||||
|
||||
- `--dns-opt=OPTION...` -- see
|
||||
|
||||
[Configuring DNS](#dns)
|
||||
|
||||
Finally, several networking options can only be provided when calling `docker run` because they specify something specific to one container:
|
||||
- `-h HOSTNAME` or `--hostname=HOSTNAME` -- see
|
||||
|
||||
[Configuring DNS](#dns) and
|
||||
|
||||
[How Docker networks a container](#container-networking)
|
||||
|
||||
- `--link=CONTAINER_NAME_or_ID:ALIAS` -- see
|
||||
|
||||
[Configuring DNS](#dns) and
|
||||
|
||||
[Communication between containers](#between-containers)
|
||||
|
||||
- `--net=bridge|none|container:NAME_or_ID|host` -- see
|
||||
|
||||
[How Docker networks a container](#container-networking)
|
||||
|
||||
- `--mac-address=MACADDRESS...` -- see
|
||||
|
||||
[How Docker networks a container](#container-networking)
|
||||
|
||||
- `-p SPEC` or `--publish=SPEC` -- see
|
||||
|
||||
[Binding container ports](#binding-ports)
|
||||
|
||||
- `-P` or `--publish-all=true|false` -- see
|
||||
|
||||
[Binding container ports](#binding-ports)
|
||||
|
||||
To supply networking options to the Docker server at startup, use the `DOCKER_OPTS` variable in the Docker upstart configuration file. For Ubuntu, edit the variable in `/etc/default/docker` or `/etc/sysconfig/docker` for CentOS.
|
||||
|
||||
The following example illustrates how to configure Docker on Ubuntu to recognize a newly built bridge.
|
||||
|
||||
Edit the `/etc/default/docker` file:
|
||||
|
||||
```
|
||||
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
|
||||
```
|
||||
|
||||
Then restart the Docker server.
|
||||
|
||||
```
|
||||
$ sudo service docker start
|
||||
```
|
||||
|
||||
For additional information on bridges, see [building your own bridge](#building-your-own-bridge) later on this page.
|
||||
28
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/saveme.md
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
draft=true
|
||||
title = "Saved text"
|
||||
keywords = ["docker, bridge, docker0, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
<!--[metadata]>
|
||||
This content was extracted from the original introduction. We may want to add it back in later under another form. Labeled DRAFT for now. Won't be built.
|
||||
<![end-metadata]-->
|
||||
|
||||
|
||||
## A Brief introduction to networking and docker
|
||||
When Docker starts, it creates a virtual interface named `docker0` on the host machine. It randomly chooses an address and subnet from the 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. 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 and options for Docker. In most cases you won't need this information. If you're looking to get started with a simpler explanation of Docker networking and an introduction to the concept of container linking see the [Docker User Guide](dockerlinks.md).
|
||||
|
||||
But `docker0` is no ordinary interface. It is a virtual _Ethernet bridge_ that automatically forwards packets between any other network interfaces that are attached to it. This lets containers communicate both with the host machine and with each other. Every time Docker creates a container, it creates a pair of "peer" interfaces that are like opposite ends of a pipe -- a packet sent on one will be received on the other. It gives one of the peers to the container to become its `eth0` interface and keeps the other peer, with a unique name like `vethAQI2QT`, out in the namespace of the host machine. By binding every `veth*` interface to the `docker0` bridge, Docker creates a virtual subnet shared between the host machine and every Docker container.
|
||||
|
||||
The remaining sections of this document explain all of the ways that you can use Docker options and -- in advanced cases -- raw Linux networking commands to tweak, supplement, or entirely replace Docker's default networking configuration.
|
||||
|
||||
## Editing networking config files
|
||||
Starting with Docker v.1.2.0, 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 will not be saved by `docker commit`, nor will they be saved during `docker run`. That means they won't be saved in the image, nor will they persist when a container is restarted; they will only "stick" in a running container.
|
||||
83
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/default_network/tools.md
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
draft=true
|
||||
title = "Tools and Examples"
|
||||
keywords = ["docker, bridge, docker0, network"]
|
||||
[menu.main]
|
||||
parent = "smn_networking_def"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
<!--[metadata]>
|
||||
Dave Tucker instructed remove this. We may want to add it back in later under another form. Labeled DRAFT for now. Won't be built.
|
||||
<![end-metadata]-->
|
||||
|
||||
# Tools and examples
|
||||
Before diving into the following sections on custom network topologies, you might be interested in glancing at a few external tools or examples of the same kinds of configuration. Here are two:
|
||||
- Jérôme Petazzoni has created a `pipework` shell script to help you
|
||||
|
||||
connect together containers in arbitrarily complex scenarios:
|
||||
|
||||
[https://github.com/jpetazzo/pipework](https://github.com/jpetazzo/pipework)
|
||||
|
||||
- Brandon Rhodes has created a whole network topology of Docker
|
||||
|
||||
containers for the next edition of Foundations of Python Network
|
||||
|
||||
Programming that includes routing, NAT'd firewalls, and servers that
|
||||
|
||||
offer HTTP, SMTP, POP, IMAP, Telnet, SSH, and FTP:
|
||||
|
||||
[https://github.com/brandon-rhodes/fopnp/tree/m/playground](https://github.com/brandon-rhodes/fopnp/tree/m/playground)
|
||||
|
||||
Both tools use networking commands very much like the ones you saw in the previous section, and will see in the following sections.
|
||||
|
||||
# Building a point-to-point connection
|
||||
<a name="point-to-point"></a>
|
||||
|
||||
By default, Docker attaches all containers to the virtual subnet implemented by `docker0`. You can create containers that are each connected to some different virtual subnet by creating your own bridge as shown in [Building your own bridge](#bridge-building), starting each container with `docker run --net=none`, and then attaching the containers to your bridge with the shell commands shown in [How Docker networks a container](#container-networking).
|
||||
|
||||
But sometimes you want two particular containers to be able to communicate directly without the added complexity of both being bound to a host-wide Ethernet bridge.
|
||||
|
||||
The solution is simple: when you create your pair of peer interfaces, simply throw _both_ of them into containers, and configure them as classic point-to-point links. The two containers will then be able to communicate directly (provided you manage to tell each container the other's IP address, of course). You might adjust the instructions of the previous section to go something like this:
|
||||
|
||||
```
|
||||
# Start up two containers in two terminal windows
|
||||
|
||||
$ docker run -i -t --rm --net=none base /bin/bash
|
||||
root@1f1f4c1f931a:/#
|
||||
|
||||
$ docker run -i -t --rm --net=none base /bin/bash
|
||||
root@12e343489d2f:/#
|
||||
|
||||
# Learn the container process IDs
|
||||
# and create their namespace entries
|
||||
|
||||
$ docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a
|
||||
2989
|
||||
$ docker inspect -f '{{.State.Pid}}' 12e343489d2f
|
||||
3004
|
||||
$ sudo mkdir -p /var/run/netns
|
||||
$ sudo ln -s /proc/2989/ns/net /var/run/netns/2989
|
||||
$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004
|
||||
|
||||
# Create the "peer" interfaces and hand them out
|
||||
|
||||
$ sudo ip link add A type veth peer name B
|
||||
|
||||
$ sudo ip link set A netns 2989
|
||||
$ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A
|
||||
$ sudo ip netns exec 2989 ip link set A up
|
||||
$ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A
|
||||
|
||||
$ sudo ip link set B netns 3004
|
||||
$ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B
|
||||
$ sudo ip netns exec 3004 ip link set B up
|
||||
$ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B
|
||||
```
|
||||
|
||||
The two containers should now be able to ping each other and make connections successfully. Point-to-point links like this do not depend on a subnet nor a netmask, but on the bare assertion made by `ip route` that some other single IP address is connected to a particular network interface.
|
||||
|
||||
Note that point-to-point links can be safely combined with other kinds of network connectivity -- there is no need to start the containers with `--net=none` if you want point-to-point links to be an addition to the container's normal networking instead of a replacement.
|
||||
|
||||
A final permutation of this pattern is to create the point-to-point link between the Docker host and one container, which would allow the host to communicate with that one container on some single IP address and thus communicate "out-of-band" of the bridge that connects the other, more usual containers. But unless you have very specific networking needs that drive you to such a solution, it is probably far preferable to use `--icc=false` to lock down inter-container communication, as we explored earlier.
|
||||
522
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/dockernetworks.md
generated
vendored
Normal file
@@ -0,0 +1,522 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Docker container networking"
|
||||
description = "How do we connect docker containers within and across hosts ?"
|
||||
keywords = ["Examples, Usage, network, docker, documentation, user guide, multihost, cluster"]
|
||||
[menu.main]
|
||||
parent = "smn_networking"
|
||||
weight = -5
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Understand Docker container networks
|
||||
|
||||
To build web applications that act in concert but do so securely, use the Docker
|
||||
networks feature. Networks, by definition, provide complete isolation for
|
||||
containers. So, it is important to have control over the networks your
|
||||
applications run on. Docker container networks give you that control.
|
||||
|
||||
This section provides an overview of the default networking behavior that Docker
|
||||
Engine delivers natively. It describes the type of networks created by default
|
||||
and how to create your own, user--defined networks. It also describes the
|
||||
resources required to create networks on a single host or across a cluster of
|
||||
hosts.
|
||||
|
||||
## Default Networks
|
||||
|
||||
When you install Docker, it creates three networks automatically. You can list
|
||||
these networks using the `docker network ls` command:
|
||||
|
||||
```
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
7fca4eb8c647 bridge bridge
|
||||
9f904ee27bf5 none null
|
||||
cf03ee007fb4 host host
|
||||
```
|
||||
|
||||
Historically, these three networks are part of Docker's implementation. When
|
||||
you run a container you can use the `--net` flag to specify which network you
|
||||
want to run a container on. These three networks are still available to you.
|
||||
|
||||
The `bridge` network represents the `docker0` network present in all Docker
|
||||
installations. Unless you specify otherwise with the `docker run
|
||||
--net=<NETWORK>` option, the Docker daemon connects containers to this network
|
||||
by default. You can see this bridge as part of a host's network stack by using
|
||||
the `ifconfig` command on the host.
|
||||
|
||||
```
|
||||
ubuntu@ip-172-31-36-118:~$ ifconfig
|
||||
docker0 Link encap:Ethernet HWaddr 02:42:47:bc:3a:eb
|
||||
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
|
||||
inet6 addr: fe80::42:47ff:febc:3aeb/64 Scope:Link
|
||||
UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1
|
||||
RX packets:17 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:1100 (1.1 KB) TX bytes:648 (648.0 B)
|
||||
```
|
||||
|
||||
The `none` network adds a container to a container-specific network stack. That container lacks a network interface. Attaching to such a container and looking at it's stack you see this:
|
||||
|
||||
```
|
||||
ubuntu@ip-172-31-36-118:~$ docker attach nonenetcontainer
|
||||
|
||||
/ # cat /etc/hosts
|
||||
127.0.0.1 localhost
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
fe00::0 ip6-localnet
|
||||
ff00::0 ip6-mcastprefix
|
||||
ff02::1 ip6-allnodes
|
||||
ff02::2 ip6-allrouters
|
||||
/ # ifconfig
|
||||
lo Link encap:Local Loopback
|
||||
inet addr:127.0.0.1 Mask:255.0.0.0
|
||||
inet6 addr: ::1/128 Scope:Host
|
||||
UP LOOPBACK RUNNING MTU:65536 Metric:1
|
||||
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
|
||||
|
||||
/ #
|
||||
```
|
||||
>**Note**: You can detach from the container and leave it running with `CTRL-p CTRL-q`.
|
||||
|
||||
The `host` network adds a container on the hosts network stack. You'll find the
|
||||
network configuration inside the container is identical to the host.
|
||||
|
||||
With the exception of the the `bridge` network, you really don't need to
|
||||
interact with these default networks. While you can list and inspect them, you
|
||||
cannot remove them. They are required by your Docker installation. However, you
|
||||
can add your own user-defined networks and these you can remove when you no
|
||||
longer need them. Before you learn more about creating your own networks, it is
|
||||
worth looking at the `default` network a bit.
|
||||
|
||||
|
||||
### The default bridge network in detail
|
||||
The default bridge network is present on all Docker hosts. The `docker network inspect`
|
||||
|
||||
```
|
||||
$ docker network inspect bridge
|
||||
[
|
||||
{
|
||||
"Name": "bridge",
|
||||
"Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.17.0.1/16",
|
||||
"Gateway": "172.17.0.1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {},
|
||||
"Options": {
|
||||
"com.docker.network.bridge.default_bridge": "true",
|
||||
"com.docker.network.bridge.enable_icc": "true",
|
||||
"com.docker.network.bridge.enable_ip_masquerade": "true",
|
||||
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
|
||||
"com.docker.network.bridge.name": "docker0",
|
||||
"com.docker.network.driver.mtu": "9001"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
The Engine automatically creates a `Subnet` and `Gateway` to the network.
|
||||
The `docker run` command automatically adds new containers to this network.
|
||||
|
||||
```
|
||||
$ docker run -itd --name=container1 busybox
|
||||
3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c
|
||||
|
||||
$ docker run -itd --name=container2 busybox
|
||||
94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c
|
||||
```
|
||||
|
||||
Inspecting the `bridge` network again after starting two containers shows both newly launched containers in the network. Their ids show up in the container
|
||||
|
||||
```
|
||||
$ docker network inspect bridge
|
||||
{[
|
||||
{
|
||||
"Name": "bridge",
|
||||
"Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.17.0.1/16",
|
||||
"Gateway": "172.17.0.1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {
|
||||
"3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c": {
|
||||
"EndpointID": "647c12443e91faf0fd508b6edfe59c30b642abb60dfab890b4bdccee38750bc1",
|
||||
"MacAddress": "02:42:ac:11:00:02",
|
||||
"IPv4Address": "172.17.0.2/16",
|
||||
"IPv6Address": ""
|
||||
},
|
||||
"94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c": {
|
||||
"EndpointID": "b047d090f446ac49747d3c37d63e4307be745876db7f0ceef7b311cbba615f48",
|
||||
"MacAddress": "02:42:ac:11:00:03",
|
||||
"IPv4Address": "172.17.0.3/16",
|
||||
"IPv6Address": ""
|
||||
}
|
||||
},
|
||||
"Options": {
|
||||
"com.docker.network.bridge.default_bridge": "true",
|
||||
"com.docker.network.bridge.enable_icc": "true",
|
||||
"com.docker.network.bridge.enable_ip_masquerade": "true",
|
||||
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
|
||||
"com.docker.network.bridge.name": "docker0",
|
||||
"com.docker.network.driver.mtu": "9001"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The `docker network inspect` command above shows all the connected containers and their network resources on a given network. Containers in this default network are able to communicate with each other using IP addresses. Docker does not support automatic service discovery on the default bridge network. If you want to communicate with container names in this default bridge network, you must connect the containers via the legacy `docker run --link` option.
|
||||
|
||||
You can `attach` to a running `container` and investigate its configuration:
|
||||
|
||||
```
|
||||
$ docker attach container1
|
||||
|
||||
/ # ifconfig
|
||||
ifconfig
|
||||
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: fe80::42:acff:fe11:2/64 Scope:Link
|
||||
UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1
|
||||
RX packets:16 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:1296 (1.2 KiB) TX bytes:648 (648.0 B)
|
||||
|
||||
lo Link encap:Local Loopback
|
||||
inet addr:127.0.0.1 Mask:255.0.0.0
|
||||
inet6 addr: ::1/128 Scope:Host
|
||||
UP LOOPBACK RUNNING MTU:65536 Metric:1
|
||||
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
|
||||
```
|
||||
|
||||
Then use `ping` for about 3 seconds to test the connectivity of the containers on this `bridge` network.
|
||||
|
||||
```
|
||||
/ # ping -w3 172.17.0.3
|
||||
PING 172.17.0.3 (172.17.0.3): 56 data bytes
|
||||
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.096 ms
|
||||
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.074 ms
|
||||
|
||||
--- 172.17.0.3 ping statistics ---
|
||||
3 packets transmitted, 3 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.074/0.083/0.096 ms
|
||||
```
|
||||
|
||||
Finally, use the `cat` command to check the `container1` network configuration:
|
||||
|
||||
```
|
||||
/ # cat /etc/hosts
|
||||
172.17.0.2 3386a527aa08
|
||||
127.0.0.1 localhost
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
fe00::0 ip6-localnet
|
||||
ff00::0 ip6-mcastprefix
|
||||
ff02::1 ip6-allnodes
|
||||
ff02::2 ip6-allrouters
|
||||
```
|
||||
To detach from a `container1` and leave it running use `CTRL-p CTRL-q`.Then, attach to `container2` and repeat these three commands.
|
||||
|
||||
```
|
||||
$ docker attach container2
|
||||
|
||||
/ # ifconfig
|
||||
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
|
||||
inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
|
||||
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
|
||||
UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1
|
||||
RX packets:15 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:1166 (1.1 KiB) TX bytes:1026 (1.0 KiB)
|
||||
|
||||
lo Link encap:Local Loopback
|
||||
inet addr:127.0.0.1 Mask:255.0.0.0
|
||||
inet6 addr: ::1/128 Scope:Host
|
||||
UP LOOPBACK RUNNING MTU:65536 Metric:1
|
||||
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
|
||||
|
||||
/ # ping -w3 172.17.0.2
|
||||
PING 172.17.0.2 (172.17.0.2): 56 data bytes
|
||||
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.067 ms
|
||||
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms
|
||||
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.072 ms
|
||||
|
||||
--- 172.17.0.2 ping statistics ---
|
||||
3 packets transmitted, 3 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.067/0.071/0.075 ms
|
||||
/ # cat /etc/hosts
|
||||
172.17.0.3 94447ca47985
|
||||
127.0.0.1 localhost
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
fe00::0 ip6-localnet
|
||||
ff00::0 ip6-mcastprefix
|
||||
ff02::1 ip6-allnodes
|
||||
ff02::2 ip6-allrouters
|
||||
```
|
||||
|
||||
The default `docker0` bridge network supports the use of port mapping and `docker run --link` to allow communications between containers in the `docker0` network. These techniques are cumbersome to set up and prone to error. While they are still available to you as techniques, it is better to avoid them and define your own bridge networks instead.
|
||||
|
||||
## User-defined networks
|
||||
|
||||
You can create your own user-defined networks that better isolate containers.
|
||||
Docker provides some default **network drivers** for creating these
|
||||
networks. You can create a new **bridge network** or **overlay network**. You
|
||||
can also create a **network plugin** or **remote network** written to your own
|
||||
specifications.
|
||||
|
||||
You can create multiple networks. You can add containers to more than one
|
||||
network. Containers can only communicate within networks but not across
|
||||
networks. A container attached to two networks can communicate with member
|
||||
containers in either network.
|
||||
|
||||
The next few sections describe each of Docker's built-in network drivers in
|
||||
greater detail.
|
||||
|
||||
### A bridge network
|
||||
|
||||
The easiest user-defined network to create is a `bridge` network. This network
|
||||
is similar to the historical, default `docker0` network. There are some added
|
||||
features and some old features that aren't available.
|
||||
|
||||
```
|
||||
$ docker network create --driver bridge isolated_nw
|
||||
1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b
|
||||
|
||||
$ docker network inspect isolated_nw
|
||||
[
|
||||
{
|
||||
"Name": "isolated_nw",
|
||||
"Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.21.0.0/16",
|
||||
"Gateway": "172.21.0.1/16"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {},
|
||||
"Options": {}
|
||||
}
|
||||
]
|
||||
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
9f904ee27bf5 none null
|
||||
cf03ee007fb4 host host
|
||||
7fca4eb8c647 bridge bridge
|
||||
c5ee82f76de3 isolated_nw bridge
|
||||
|
||||
```
|
||||
|
||||
After you create the network, you can launch containers on it using the `docker run --net=<NETWORK>` option.
|
||||
|
||||
```
|
||||
$ docker run --net=isolated_nw -itd --name=container3 busybox
|
||||
8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c
|
||||
|
||||
$ docker network inspect isolated_nw
|
||||
[
|
||||
{
|
||||
"Name": "isolated_nw",
|
||||
"Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{}
|
||||
]
|
||||
},
|
||||
"Containers": {
|
||||
"8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c": {
|
||||
"EndpointID": "93b2db4a9b9a997beb912d28bcfc117f7b0eb924ff91d48cfa251d473e6a9b08",
|
||||
"MacAddress": "02:42:ac:15:00:02",
|
||||
"IPv4Address": "172.21.0.2/16",
|
||||
"IPv6Address": ""
|
||||
}
|
||||
},
|
||||
"Options": {}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The containers you launch into this network must reside on the same Docker host.
|
||||
Each container in the network can immediately communicate with other containers
|
||||
in the network. Though, the network itself isolates the containers from external
|
||||
networks.
|
||||
|
||||

|
||||
|
||||
Within a user-defined bridge network, linking is not supported. You can
|
||||
expose and publish container ports on containers in this network. This is useful
|
||||
if you want to make a portion of the `bridge` network available to an outside
|
||||
network.
|
||||
|
||||

|
||||
|
||||
A bridge network is useful in cases where you want to run a relatively small
|
||||
network on a single host. You can, however, create significantly larger networks
|
||||
by creating an `overlay` network.
|
||||
|
||||
|
||||
### An overlay network
|
||||
|
||||
Docker's `overlay` network driver supports multi-host networking natively
|
||||
out-of-the-box. This support is accomplished with the help of `libnetwork`, a
|
||||
built-in VXLAN-based overlay network driver, and Docker's `libkv` library.
|
||||
|
||||
The `overlay` network requires a valid key-value store service. Currently,
|
||||
Docker's `libkv` supports Consul, Etcd, and ZooKeeper (Distributed store). Before
|
||||
creating a network you must install and configure your chosen key-value store
|
||||
service. The Docker hosts that you intend to network and the service must be
|
||||
able to communicate.
|
||||
|
||||

|
||||
|
||||
Each host in the network must run a Docker Engine instance. The easiest way to
|
||||
provision the hosts are with Docker Machine.
|
||||
|
||||

|
||||
|
||||
You should open the following ports between each of your hosts.
|
||||
|
||||
| Protocol | Port | Description |
|
||||
|----------|------|-----------------------|
|
||||
| udp | 4789 | Data plane (VXLAN) |
|
||||
| tcp/udp | 7946 | Control plane |
|
||||
|
||||
Your key-value store service may require additional ports.
|
||||
Check your vendor's documentation and open any required ports.
|
||||
|
||||
Once you have several machines provisioned, you can use Docker Swarm to quickly
|
||||
form them into a swarm which includes a discovery service as well.
|
||||
|
||||
To create an overlay network, you configure options on the `daemon` on each
|
||||
Docker Engine for use with `overlay` network. There are two options to set:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><pre>--cluster-store=PROVIDER://URL</pre></td>
|
||||
<td>Describes the location of the KV service.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><pre>--cluster-advertise=HOST_IP|HOST_IFACE:PORT</pre></td>
|
||||
<td>The IP address or interface of the HOST used for clustering.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><pre>--cluster-store-opt=KEY-VALUE OPTIONS</pre></td>
|
||||
<td>Options such as TLS certificate or tuning discovery Timers</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Create an `overlay` network on one of the machines in the Swarm.
|
||||
|
||||
$ docker network create --driver overlay my-multi-host-network
|
||||
|
||||
This results in a single network spanning multiple hosts. An `overlay` network
|
||||
provides complete isolation for the containers.
|
||||
|
||||

|
||||
|
||||
Then, on each host, launch containers making sure to specify the network name.
|
||||
|
||||
$ docker run -itd --net=my-multi-host-network busybox
|
||||
|
||||
Once connected, each container has access to all the containers in the network
|
||||
regardless of which Docker host the container was launched on.
|
||||
|
||||

|
||||
|
||||
If you would like to try this for yourself, see the [Getting started for
|
||||
overlay](get-started-overlay.md).
|
||||
|
||||
### Custom network plugin
|
||||
|
||||
If you like, you can write your own network driver plugin. A network
|
||||
driver plugin makes use of Docker's plugin infrastructure. In this
|
||||
infrastructure, a plugin is a process running on the same Docker host as the
|
||||
Docker `daemon`.
|
||||
|
||||
Network plugins follow the same restrictions and installation rules as other
|
||||
plugins. All plugins make use of the plugin API. They have a lifecycle that
|
||||
encompasses installation, starting, stopping and activation.
|
||||
|
||||
Once you have created and installed a custom network driver, you use it like the
|
||||
built-in network drivers. For example:
|
||||
|
||||
$ docker network create --driver weave mynet
|
||||
|
||||
You can inspect it, add containers too and from it, and so forth. Of course,
|
||||
different plugins may make use of different technologies or frameworks. Custom
|
||||
networks can include features not present in Docker's default networks. For more
|
||||
information on writing plugins, see [Extending Docker](../../extend/index.md) and
|
||||
[Writing a network driver plugin](../../extend/plugins_network.md).
|
||||
|
||||
### Docker embedded DNS server
|
||||
|
||||
Docker daemon runs an embedded DNS server to provide automatic service discovery
|
||||
for containers connected to user defined networks. Name resolution requests from
|
||||
the containers are handled first by the embedded DNS server. If the embedded DNS
|
||||
server is unable to resolve the request it will be forwarded to any external DNS
|
||||
servers configured for the container. To facilitate this when the container is
|
||||
created, only the embedded DNS server reachable at `127.0.0.11` will be listed
|
||||
in the container's `resolv.conf` file. More information on embedded DNS server on
|
||||
user-defined networks can be found in the [embedded DNS server in user-defined networks]
|
||||
(configure-dns.md)
|
||||
|
||||
## Links
|
||||
|
||||
Before the Docker network feature, you could use the Docker link feature to
|
||||
allow containers to discover each other. With the introduction of Docker networks,
|
||||
containers can be discovered by its name automatically. But you can still create
|
||||
links but they behave differently when used in the default `docker0` bridge network
|
||||
compared to user-defined networks. For more information, please refer to
|
||||
[Legacy Links](default_network/dockerlinks.md) for link feature in default `bridge` network
|
||||
and the [linking containers in user-defined networks](work-with-networks.md#linking-containers-in-user-defined-networks) for links
|
||||
functionality in user-defined networks.
|
||||
|
||||
## Related information
|
||||
|
||||
- [Work with network commands](work-with-networks.md)
|
||||
- [Get started with multi-host networking](get-started-overlay.md)
|
||||
- [Managing Data in Containers](../containers/dockervolumes.md)
|
||||
- [Docker Machine overview](https://docs.docker.com/machine)
|
||||
- [Docker Swarm overview](https://docs.docker.com/swarm)
|
||||
- [Investigate the LibNetwork project](https://github.com/docker/libnetwork)
|
||||
326
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/get-started-overlay.md
generated
vendored
Normal file
@@ -0,0 +1,326 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Get started with multi-host networking"
|
||||
description = "Use overlay for multi-host networking"
|
||||
keywords = ["Examples, Usage, network, docker, documentation, user guide, multihost, cluster"]
|
||||
[menu.main]
|
||||
parent = "smn_networking"
|
||||
weight=-3
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Get started with multi-host networking
|
||||
|
||||
This article uses an example to explain the basics of creating a multi-host
|
||||
network. Docker Engine supports multi-host networking out-of-the-box through the
|
||||
`overlay` network driver. Unlike `bridge` networks, overlay networks require
|
||||
some pre-existing conditions before you can create one. These conditions are:
|
||||
|
||||
* Access to a key-value store. Docker supports Consul, Etcd, and ZooKeeper (Distributed store) key-value stores.
|
||||
* A cluster of hosts with connectivity to the key-value store.
|
||||
* A properly configured Engine `daemon` on each host in the cluster.
|
||||
|
||||
Though Docker Machine and Docker Swarm are not mandatory to experience Docker
|
||||
multi-host networking, this example uses them to illustrate how they are
|
||||
integrated. You'll use Machine to create both the key-value store
|
||||
server and the host cluster. This example creates a Swarm cluster.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, make sure you have a system on your network with the latest
|
||||
version of Docker Engine and Docker Machine installed. The example also relies
|
||||
on VirtualBox. If you installed on a Mac or Windows with Docker Toolbox, you
|
||||
have all of these installed already.
|
||||
|
||||
If you have not already done so, make sure you upgrade Docker Engine and Docker
|
||||
Machine to the latest versions.
|
||||
|
||||
|
||||
## Step 1: Set up a key-value store
|
||||
|
||||
An overlay network requires a key-value store. The key-value store holds
|
||||
information about the network state which includes discovery, networks,
|
||||
endpoints, IP addresses, and more. Docker supports Consul, Etcd, and ZooKeeper
|
||||
key-value stores. This example uses Consul.
|
||||
|
||||
1. Log into a system prepared with the prerequisite Docker Engine, Docker Machine, and VirtualBox software.
|
||||
|
||||
2. Provision a VirtualBox machine called `mh-keystore`.
|
||||
|
||||
$ docker-machine create -d virtualbox mh-keystore
|
||||
|
||||
When you provision a new machine, the process adds Docker Engine to the
|
||||
host. This means rather than installing Consul manually, you can create an
|
||||
instance using the [consul image from Docker
|
||||
Hub](https://hub.docker.com/r/progrium/consul/). You'll do this in the next step.
|
||||
|
||||
3. Start a `progrium/consul` container running on the `mh-keystore` machine.
|
||||
|
||||
$ docker $(docker-machine config mh-keystore) run -d \
|
||||
-p "8500:8500" \
|
||||
-h "consul" \
|
||||
progrium/consul -server -bootstrap
|
||||
|
||||
A bash expansion `$(docker-machine config mh-keystore)` is used to pass the
|
||||
connection configuration to the `docker run` command. The client starts a
|
||||
`progrium/consul` image running in the `mh-keystore` machine. The server is
|
||||
called `consul` and is listening on port `8500`.
|
||||
|
||||
4. Set your local environment to the `mh-keystore` machine.
|
||||
|
||||
$ eval "$(docker-machine env mh-keystore)"
|
||||
|
||||
5. Run the `docker ps` command to see the `consul` container.
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
4d51392253b3 progrium/consul "/bin/start -server -" 25 minutes ago Up 25 minutes 53/tcp, 53/udp, 8300-8302/tcp, 0.0.0.0:8500->8500/tcp, 8400/tcp, 8301-8302/udp admiring_panini
|
||||
|
||||
Keep your terminal open and move onto the next step.
|
||||
|
||||
|
||||
## Step 2: Create a Swarm cluster
|
||||
|
||||
In this step, you use `docker-machine` to provision the hosts for your network.
|
||||
At this point, you won't actually create the network. You'll create several
|
||||
machines in VirtualBox. One of the machines will act as the Swarm master;
|
||||
you'll create that first. As you create each host, you'll pass the Engine on
|
||||
that machine options that are needed by the `overlay` network driver.
|
||||
|
||||
1. Create a Swarm master.
|
||||
|
||||
$ docker-machine create \
|
||||
-d virtualbox \
|
||||
--swarm --swarm-master \
|
||||
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
|
||||
--engine-opt="cluster-store=consul://$(docker-machine ip mh-keystore):8500" \
|
||||
--engine-opt="cluster-advertise=eth1:2376" \
|
||||
mhs-demo0
|
||||
|
||||
At creation time, you supply the Engine `daemon` with the ` --cluster-store` option. This option tells the Engine the location of the key-value store for the `overlay` network. The bash expansion `$(docker-machine ip mh-keystore)` resolves to the IP address of the Consul server you created in "STEP 1". The `--cluster-advertise` option advertises the machine on the network.
|
||||
|
||||
2. Create another host and add it to the Swarm cluster.
|
||||
|
||||
$ docker-machine create -d virtualbox \
|
||||
--swarm \
|
||||
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
|
||||
--engine-opt="cluster-store=consul://$(docker-machine ip mh-keystore):8500" \
|
||||
--engine-opt="cluster-advertise=eth1:2376" \
|
||||
mhs-demo1
|
||||
|
||||
3. List your machines to confirm they are all up and running.
|
||||
|
||||
$ docker-machine ls
|
||||
NAME ACTIVE DRIVER STATE URL SWARM
|
||||
default - virtualbox Running tcp://192.168.99.100:2376
|
||||
mh-keystore * virtualbox Running tcp://192.168.99.103:2376
|
||||
mhs-demo0 - virtualbox Running tcp://192.168.99.104:2376 mhs-demo0 (master)
|
||||
mhs-demo1 - virtualbox Running tcp://192.168.99.105:2376 mhs-demo0
|
||||
|
||||
At this point you have a set of hosts running on your network. You are ready to create a multi-host network for containers using these hosts.
|
||||
|
||||
Leave your terminal open and go onto the next step.
|
||||
|
||||
## Step 3: Create the overlay Network
|
||||
|
||||
To create an overlay network
|
||||
|
||||
1. Set your docker environment to the Swarm master.
|
||||
|
||||
$ eval $(docker-machine env --swarm mhs-demo0)
|
||||
|
||||
Using the `--swarm` flag with `docker-machine` restricts the `docker` commands to Swarm information alone.
|
||||
|
||||
2. Use the `docker info` command to view the Swarm.
|
||||
|
||||
$ docker info
|
||||
Containers: 3
|
||||
Images: 2
|
||||
Role: primary
|
||||
Strategy: spread
|
||||
Filters: affinity, health, constraint, port, dependency
|
||||
Nodes: 2
|
||||
mhs-demo0: 192.168.99.104:2376
|
||||
└ Containers: 2
|
||||
└ Reserved CPUs: 0 / 1
|
||||
└ Reserved Memory: 0 B / 1.021 GiB
|
||||
└ Labels: executiondriver=native-0.2, kernelversion=4.1.10-boot2docker, operatingsystem=Boot2Docker 1.9.0-rc1 (TCL 6.4); master : 4187d2c - Wed Oct 14 14:00:28 UTC 2015, provider=virtualbox, storagedriver=aufs
|
||||
mhs-demo1: 192.168.99.105:2376
|
||||
└ Containers: 1
|
||||
└ Reserved CPUs: 0 / 1
|
||||
└ Reserved Memory: 0 B / 1.021 GiB
|
||||
└ Labels: executiondriver=native-0.2, kernelversion=4.1.10-boot2docker, operatingsystem=Boot2Docker 1.9.0-rc1 (TCL 6.4); master : 4187d2c - Wed Oct 14 14:00:28 UTC 2015, provider=virtualbox, storagedriver=aufs
|
||||
CPUs: 2
|
||||
Total Memory: 2.043 GiB
|
||||
Name: 30438ece0915
|
||||
|
||||
From this information, you can see that you are running three containers and two images on the Master.
|
||||
|
||||
3. Create your `overlay` network.
|
||||
|
||||
$ docker network create --driver overlay --subnet=10.0.9.0/24 my-net
|
||||
|
||||
You only need to create the network on a single host in the cluster. In this case, you used the Swarm master but you could easily have run it on any host in the cluster.
|
||||
|
||||
> **Note** : It is highly recommended to use the `--subnet` option when creating
|
||||
> a network. If the `--subnet` is not specified, the docker daemon automatically
|
||||
> chooses and assigns a subnet for the network and it could overlap with another subnet
|
||||
> in your infrastructure that is not managed by docker. Such overlaps can cause
|
||||
> connectivity issues or failures when containers are connected to that network.
|
||||
|
||||
4. Check that the network is running:
|
||||
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
412c2496d0eb mhs-demo1/host host
|
||||
dd51763e6dd2 mhs-demo0/bridge bridge
|
||||
6b07d0be843f my-net overlay
|
||||
b4234109bd9b mhs-demo0/none null
|
||||
1aeead6dd890 mhs-demo0/host host
|
||||
d0bb78cbe7bd mhs-demo1/bridge bridge
|
||||
1c0eb8f69ebb mhs-demo1/none null
|
||||
|
||||
As you are in the Swarm master environment, you see all the networks on all
|
||||
the Swarm agents: the default networks on each engine and the single overlay
|
||||
network. Notice that each `NETWORK ID` is unique.
|
||||
|
||||
5. Switch to each Swarm agent in turn and list the networks.
|
||||
|
||||
$ eval $(docker-machine env mhs-demo0)
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
6b07d0be843f my-net overlay
|
||||
dd51763e6dd2 bridge bridge
|
||||
b4234109bd9b none null
|
||||
1aeead6dd890 host host
|
||||
$ eval $(docker-machine env mhs-demo1)
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
d0bb78cbe7bd bridge bridge
|
||||
1c0eb8f69ebb none null
|
||||
412c2496d0eb host host
|
||||
6b07d0be843f my-net overlay
|
||||
|
||||
Both agents report they have the `my-net` network with the `6b07d0be843f` ID.
|
||||
You now have a multi-host container network running!
|
||||
|
||||
## Step 4: Run an application on your Network
|
||||
|
||||
Once your network is created, you can start a container on any of the hosts and it automatically is part of the network.
|
||||
|
||||
1. Point your environment to the Swarm master.
|
||||
|
||||
$ eval $(docker-machine env --swarm mhs-demo0)
|
||||
|
||||
2. Start an Nginx web server on the `mhs-demo0` instance.
|
||||
|
||||
$ docker run -itd --name=web --net=my-net --env="constraint:node==mhs-demo0" nginx
|
||||
|
||||
4. Run a BusyBox instance on the `mhs-demo1` instance and get the contents of the Nginx server's home page.
|
||||
|
||||
$ docker run -it --rm --net=my-net --env="constraint:node==mhs-demo1" busybox wget -O- http://web
|
||||
Unable to find image 'busybox:latest' locally
|
||||
latest: Pulling from library/busybox
|
||||
ab2b8a86ca6c: Pull complete
|
||||
2c5ac3f849df: Pull complete
|
||||
Digest: sha256:5551dbdfc48d66734d0f01cafee0952cb6e8eeecd1e2492240bf2fd9640c2279
|
||||
Status: Downloaded newer image for busybox:latest
|
||||
Connecting to web (10.0.0.2:80)
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to nginx!</title>
|
||||
<style>
|
||||
body {
|
||||
width: 35em;
|
||||
margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to nginx!</h1>
|
||||
<p>If you see this page, the nginx web server is successfully installed and
|
||||
working. Further configuration is required.</p>
|
||||
|
||||
<p>For online documentation and support please refer to
|
||||
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
||||
Commercial support is available at
|
||||
<a href="http://nginx.com/">nginx.com</a>.</p>
|
||||
|
||||
<p><em>Thank you for using nginx.</em></p>
|
||||
</body>
|
||||
</html>
|
||||
- 100% |*******************************| 612 0:00:00 ETA
|
||||
|
||||
## Step 5: Check external connectivity
|
||||
|
||||
As you've seen, Docker's built-in overlay network driver provides out-of-the-box
|
||||
connectivity between the containers on multiple hosts within the same network.
|
||||
Additionally, containers connected to the multi-host network are automatically
|
||||
connected to the `docker_gwbridge` network. This network allows the containers
|
||||
to have external connectivity outside of their cluster.
|
||||
|
||||
1. Change your environment to the Swarm agent.
|
||||
|
||||
$ eval $(docker-machine env mhs-demo1)
|
||||
|
||||
2. View the `docker_gwbridge` network, by listing the networks.
|
||||
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
6b07d0be843f my-net overlay
|
||||
dd51763e6dd2 bridge bridge
|
||||
b4234109bd9b none null
|
||||
1aeead6dd890 host host
|
||||
e1dbd5dff8be docker_gwbridge bridge
|
||||
|
||||
3. Repeat steps 1 and 2 on the Swarm master.
|
||||
|
||||
$ eval $(docker-machine env mhs-demo0)
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
6b07d0be843f my-net overlay
|
||||
d0bb78cbe7bd bridge bridge
|
||||
1c0eb8f69ebb none null
|
||||
412c2496d0eb host host
|
||||
97102a22e8d2 docker_gwbridge bridge
|
||||
|
||||
2. Check the Nginx container's network interfaces.
|
||||
|
||||
$ docker exec web ip addr
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 ::1/128 scope host
|
||||
valid_lft forever preferred_lft forever
|
||||
22: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
|
||||
link/ether 02:42:0a:00:09:03 brd ff:ff:ff:ff:ff:ff
|
||||
inet 10.0.9.3/24 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::42:aff:fe00:903/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
24: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
|
||||
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
|
||||
inet 172.18.0.2/16 scope global eth1
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::42:acff:fe12:2/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
The `eth0` interface represents the container interface that is connected to
|
||||
the `my-net` overlay network. While the `eth1` interface represents the
|
||||
container interface that is connected to the `docker_gwbridge` network.
|
||||
|
||||
## Step 6: Extra Credit with Docker Compose
|
||||
|
||||
Please refer to the Networking feature introduced in [Compose V2 format]
|
||||
(https://docs.docker.com/compose/networking/) and execute the
|
||||
multi-host networking scenario in the Swarm cluster used above.
|
||||
|
||||
## Related information
|
||||
|
||||
* [Understand Docker container networks](dockernetworks.md)
|
||||
* [Work with network commands](work-with-networks.md)
|
||||
* [Docker Swarm overview](https://docs.docker.com/swarm)
|
||||
* [Docker Machine overview](https://docs.docker.com/machine)
|
||||
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/bridge_network.gliffy
generated
vendored
Normal file
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/bridge_network.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/bridge_network.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/engine_on_net.gliffy
generated
vendored
Normal file
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/engine_on_net.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/engine_on_net.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 36 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/key_value.gliffy
generated
vendored
Normal file
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/key_value.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/key_value.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/network_access.gliffy
generated
vendored
Normal file
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/network_access.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/network_access.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 43 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/overlay-network-final.gliffy
generated
vendored
Normal file
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/overlay-network-final.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/overlay-network-final.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 53 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/overlay_network.gliffy
generated
vendored
Normal file
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/overlay_network.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/overlay_network.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 44 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/working.gliffy
generated
vendored
Normal file
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/working.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 18 KiB |
1
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/images/working.svg
generated
vendored
Normal file
|
After Width: | Height: | Size: 19 KiB |
21
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/index.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Network configuration"
|
||||
description = "Docker networking feature is introduced"
|
||||
keywords = ["network, networking, bridge, docker, documentation"]
|
||||
[menu.main]
|
||||
identifier="smn_networking"
|
||||
parent= "engine_guide"
|
||||
weight=7
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Docker networks feature overview
|
||||
|
||||
This sections explains how to use the Docker networks feature. This feature allows users to define their own networks and connect containers to them. Using this feature you can create a network on a single host or a network that spans across multiple hosts.
|
||||
|
||||
- [Understand Docker container networks](dockernetworks.md)
|
||||
- [Work with network commands](work-with-networks.md)
|
||||
- [Get started with multi-host networking](get-started-overlay.md)
|
||||
|
||||
If you are already familiar with Docker's default bridge network, `docker0` that network continues to be supported. It is created automatically in every installation. The default bridge network is also named `bridge`. To see a list of topics related to that network, read the articles listed in the [Docker default bridge network](default_network/index.md).
|
||||
856
vendor/github.com/hyperhq/hypercli/docs/userguide/networking/work-with-networks.md
generated
vendored
Normal file
@@ -0,0 +1,856 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Work with network commands"
|
||||
description = "How to work with docker networks"
|
||||
keywords = ["commands, Usage, network, docker, cluster"]
|
||||
[menu.main]
|
||||
parent = "smn_networking"
|
||||
weight=-4
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Work with network commands
|
||||
|
||||
This article provides examples of the network subcommands you can use to interact with Docker networks and the containers in them. The commands are available through the Docker Engine CLI. These commands are:
|
||||
|
||||
* `docker network create`
|
||||
* `docker network connect`
|
||||
* `docker network ls`
|
||||
* `docker network rm`
|
||||
* `docker network disconnect`
|
||||
* `docker network inspect`
|
||||
|
||||
While not required, it is a good idea to read [Understanding Docker
|
||||
network](dockernetworks.md) before trying the examples in this section. The
|
||||
examples for the rely on a `bridge` network so that you can try them
|
||||
immediately. If you would prefer to experiment with an `overlay` network see
|
||||
the [Getting started with multi-host networks](get-started-overlay.md) instead.
|
||||
|
||||
## Create networks
|
||||
|
||||
Docker Engine creates a `bridge` network automatically when you install Engine.
|
||||
This network corresponds to the `docker0` bridge that Engine has traditionally
|
||||
relied on. In addition to this network, you can create your own `bridge` or `overlay` network.
|
||||
|
||||
A `bridge` network resides on a single host running an instance of Docker Engine. An `overlay` network can span multiple hosts running their own engines. If you run `docker network create` and supply only a network name, it creates a bridge network for you.
|
||||
|
||||
```bash
|
||||
$ docker network create simple-network
|
||||
69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a
|
||||
$ docker network inspect simple-network
|
||||
[
|
||||
{
|
||||
"Name": "simple-network",
|
||||
"Id": "69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.22.0.0/16",
|
||||
"Gateway": "172.22.0.1/16"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {},
|
||||
"Options": {}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Unlike `bridge` networks, `overlay` networks require some pre-existing conditions
|
||||
before you can create one. These conditions are:
|
||||
|
||||
* Access to a key-value store. Engine supports Consul Etcd, and ZooKeeper (Distributed store) key-value stores.
|
||||
* A cluster of hosts with connectivity to the key-value store.
|
||||
* A properly configured Engine `daemon` on each host in the swarm.
|
||||
|
||||
The `docker daemon` options that support the `overlay` network are:
|
||||
|
||||
* `--cluster-store`
|
||||
* `--cluster-store-opt`
|
||||
* `--cluster-advertise`
|
||||
|
||||
It is also a good idea, though not required, that you install Docker Swarm
|
||||
to manage the cluster. Swarm provides sophisticated discovery and server
|
||||
management that can assist your implementation.
|
||||
|
||||
When you create a network, Engine creates a non-overlapping subnetwork for the
|
||||
network by default. You can override this default and specify a subnetwork
|
||||
directly using the the `--subnet` option. On a `bridge` network you can only
|
||||
specify a single subnet. An `overlay` network supports multiple subnets.
|
||||
|
||||
> **Note** : It is highly recommended to use the `--subnet` option while creating
|
||||
> a network. If the `--subnet` is not specified, the docker daemon automatically
|
||||
> chooses and assigns a subnet for the network and it could overlap with another subnet
|
||||
> in your infrastructure that is not managed by docker. Such overlaps can cause
|
||||
> connectivity issues or failures when containers are connected to that network.
|
||||
|
||||
In addition to the `--subnetwork` option, you also specify the `--gateway` `--ip-range` and `--aux-address` options.
|
||||
|
||||
```bash
|
||||
$ docker network create -d overlay
|
||||
--subnet=192.168.0.0/16 --subnet=192.170.0.0/16
|
||||
--gateway=192.168.0.100 --gateway=192.170.0.100
|
||||
--ip-range=192.168.1.0/24
|
||||
--aux-address a=192.168.1.5 --aux-address b=192.168.1.6
|
||||
--aux-address a=192.170.1.5 --aux-address b=192.170.1.6
|
||||
my-multihost-network
|
||||
```
|
||||
|
||||
Be sure that your subnetworks do not overlap. If they do, the network create fails and Engine returns an error.
|
||||
|
||||
When creating a custom network, the default network driver (i.e. `bridge`) has additional options that can be passed.
|
||||
The following are those options and the equivalent docker daemon flags used for docker0 bridge:
|
||||
|
||||
| Option | Equivalent | Description |
|
||||
|--------------------------------------------------|-------------|-------------------------------------------------------|
|
||||
| `com.docker.network.bridge.name` | - | bridge name to be used when creating the Linux bridge |
|
||||
| `com.docker.network.bridge.enable_ip_masquerade` | `--ip-masq` | Enable IP masquerading |
|
||||
| `com.docker.network.bridge.enable_icc` | `--icc` | Enable or Disable Inter Container Connectivity |
|
||||
| `com.docker.network.bridge.host_binding_ipv4` | `--ip` | Default IP when binding container ports |
|
||||
| `com.docker.network.mtu` | `--mtu` | Set the containers network MTU |
|
||||
| `com.docker.network.enable_ipv6` | `--ipv6` | Enable IPv6 networking |
|
||||
|
||||
For example, now let's use `-o` or `--opt` options to specify an IP address binding when publishing ports:
|
||||
|
||||
```bash
|
||||
$ docker network create -o "com.docker.network.bridge.host_binding_ipv4"="172.23.0.1" my-network
|
||||
b1a086897963e6a2e7fc6868962e55e746bee8ad0c97b54a5831054b5f62672a
|
||||
$ docker network inspect my-network
|
||||
[
|
||||
{
|
||||
"Name": "my-network",
|
||||
"Id": "b1a086897963e6a2e7fc6868962e55e746bee8ad0c97b54a5831054b5f62672a",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Options": {},
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.23.0.0/16",
|
||||
"Gateway": "172.23.0.1/16"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {},
|
||||
"Options": {
|
||||
"com.docker.network.bridge.host_binding_ipv4": "172.23.0.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
$ docker run -d -P --name redis --net my-network redis
|
||||
bafb0c808c53104b2c90346f284bda33a69beadcab4fc83ab8f2c5a4410cd129
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
bafb0c808c53 redis "/entrypoint.sh redis" 4 seconds ago Up 3 seconds 172.23.0.1:32770->6379/tcp redis
|
||||
```
|
||||
|
||||
## Connect containers
|
||||
|
||||
You can connect containers dynamically to one or more networks. These networks
|
||||
can be backed the same or different network drivers. Once connected, the
|
||||
containers can communicate using another container's IP address or name.
|
||||
|
||||
For `overlay` networks or custom plugins that support multi-host
|
||||
connectivity, containers connected to the same multi-host network but launched
|
||||
from different hosts can also communicate in this way.
|
||||
|
||||
Create two containers for this example:
|
||||
|
||||
```bash
|
||||
$ docker run -itd --name=container1 busybox
|
||||
18c062ef45ac0c026ee48a83afa39d25635ee5f02b58de4abc8f467bcaa28731
|
||||
|
||||
$ docker run -itd --name=container2 busybox
|
||||
498eaaaf328e1018042c04b2de04036fc04719a6e39a097a4f4866043a2c2152
|
||||
```
|
||||
|
||||
Then create an isolated, `bridge` network to test with.
|
||||
|
||||
```bash
|
||||
$ docker network create -d bridge --subnet 172.25.0.0/16 isolated_nw
|
||||
06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8
|
||||
```
|
||||
|
||||
Connect `container2` to the network and then `inspect` the network to verify the connection:
|
||||
|
||||
```
|
||||
$ docker network connect isolated_nw container2
|
||||
$ docker network inspect isolated_nw
|
||||
[
|
||||
{
|
||||
"Name": "isolated_nw",
|
||||
"Id": "06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.21.0.0/16",
|
||||
"Gateway": "172.21.0.1/16"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {
|
||||
"90e1f3ec71caf82ae776a827e0712a68a110a3f175954e5bd4222fd142ac9428": {
|
||||
"Name": "container2",
|
||||
"EndpointID": "11cedac1810e864d6b1589d92da12af66203879ab89f4ccd8c8fdaa9b1c48b1d",
|
||||
"MacAddress": "02:42:ac:19:00:02",
|
||||
"IPv4Address": "172.25.0.2/16",
|
||||
"IPv6Address": ""
|
||||
}
|
||||
},
|
||||
"Options": {}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
You can see that the Engine automatically assigns an IP address to `container2`.
|
||||
Given we specified a `--subnet` when creating the network, Engine picked
|
||||
an address from that same subnet. Now, start a third container and connect it to
|
||||
the network on launch using the `docker run` command's `--net` option:
|
||||
|
||||
```bash
|
||||
$ docker run --net=isolated_nw --ip=172.25.3.3 -itd --name=container3 busybox
|
||||
467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551
|
||||
```
|
||||
|
||||
As you can see you were able to specify the ip address for your container.
|
||||
As long as the network to which the container is connecting was created with
|
||||
a user specified subnet, you will be able to select the IPv4 and/or IPv6 address(es)
|
||||
for your container when executing `docker run` and `docker network connect` commands.
|
||||
The selected IP address is part of the container networking configuration and will be
|
||||
preserved across container reload. The feature is only available on user defined networks,
|
||||
because they guarantee their subnets configuration does not change across daemon reload.
|
||||
|
||||
Now, inspect the network resources used by `container3`.
|
||||
|
||||
```bash
|
||||
$ docker inspect --format='{{json .NetworkSettings.Networks}}' container3
|
||||
{"isolated_nw":{"IPAMConfig":{"IPv4Address":"172.25.3.3"},"NetworkID":"1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
|
||||
"EndpointID":"dffc7ec2915af58cc827d995e6ebdc897342be0420123277103c40ae35579103","Gateway":"172.25.0.1","IPAddress":"172.25.3.3","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:19:03:03"}}
|
||||
```
|
||||
Repeat this command for `container2`. If you have Python installed, you can pretty print the output.
|
||||
|
||||
```bash
|
||||
$ docker inspect --format='{{json .NetworkSettings.Networks}}' container2 | python -m json.tool
|
||||
{
|
||||
"bridge": {
|
||||
"NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812",
|
||||
"EndpointID": "0099f9efb5a3727f6a554f176b1e96fca34cae773da68b3b6a26d046c12cb365",
|
||||
"Gateway": "172.17.0.1",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"IPAMConfig": null,
|
||||
"IPAddress": "172.17.0.3",
|
||||
"IPPrefixLen": 16,
|
||||
"IPv6Gateway": "",
|
||||
"MacAddress": "02:42:ac:11:00:03"
|
||||
},
|
||||
"isolated_nw": {
|
||||
"NetworkID":"1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
|
||||
"EndpointID": "11cedac1810e864d6b1589d92da12af66203879ab89f4ccd8c8fdaa9b1c48b1d",
|
||||
"Gateway": "172.25.0.1",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"IPAMConfig": null,
|
||||
"IPAddress": "172.25.0.2",
|
||||
"IPPrefixLen": 16,
|
||||
"IPv6Gateway": "",
|
||||
"MacAddress": "02:42:ac:19:00:02"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You should find `container2` belongs to two networks. The `bridge` network
|
||||
which it joined by default when you launched it and the `isolated_nw` which you
|
||||
later connected it to.
|
||||
|
||||

|
||||
|
||||
In the case of `container3`, you connected it through `docker run` to the
|
||||
`isolated_nw` so that container is not connected to `bridge`.
|
||||
|
||||
Use the `docker attach` command to connect to the running `container2` and
|
||||
examine its networking stack:
|
||||
|
||||
```bash
|
||||
$ docker attach container2
|
||||
```
|
||||
|
||||
If you look a the container's network stack you should see two Ethernet interfaces, one for the default bridge network and one for the `isolated_nw` network.
|
||||
|
||||
```bash
|
||||
/ # ifconfig
|
||||
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
|
||||
inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
|
||||
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
|
||||
UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1
|
||||
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:648 (648.0 B) TX bytes:648 (648.0 B)
|
||||
|
||||
eth1 Link encap:Ethernet HWaddr 02:42:AC:15:00:02
|
||||
inet addr:172.25.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
|
||||
inet6 addr: fe80::42:acff:fe19:2/64 Scope:Link
|
||||
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
|
||||
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:648 (648.0 B) TX bytes:648 (648.0 B)
|
||||
|
||||
lo Link encap:Local Loopback
|
||||
inet addr:127.0.0.1 Mask:255.0.0.0
|
||||
inet6 addr: ::1/128 Scope:Host
|
||||
UP LOOPBACK RUNNING MTU:65536 Metric:1
|
||||
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
|
||||
|
||||
On the `isolated_nw` which was user defined, the Docker embedded DNS server enables name resolution for other containers in the network. Inside of `container2` it is possible to ping `container3` by name.
|
||||
|
||||
```bash
|
||||
/ # ping -w 4 container3
|
||||
PING container3 (172.25.3.3): 56 data bytes
|
||||
64 bytes from 172.25.3.3: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.3.3: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.3.3: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.3.3: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- container3 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
```
|
||||
|
||||
This isn't the case for the default `bridge` network. Both `container2` and `container1` are connected to the default bridge network. Docker does not support automatic service discovery on this network. For this reason, pinging `container1` by name fails as you would expect based on the `/etc/hosts` file:
|
||||
|
||||
```bash
|
||||
/ # ping -w 4 container1
|
||||
ping: bad address 'container1'
|
||||
```
|
||||
|
||||
A ping using the `container1` IP address does succeed though:
|
||||
|
||||
```bash
|
||||
/ # ping -w 4 172.17.0.2
|
||||
PING 172.17.0.2 (172.17.0.2): 56 data bytes
|
||||
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.095 ms
|
||||
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms
|
||||
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.072 ms
|
||||
64 bytes from 172.17.0.2: seq=3 ttl=64 time=0.101 ms
|
||||
|
||||
--- 172.17.0.2 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.072/0.085/0.101 ms
|
||||
```
|
||||
|
||||
If you wanted you could connect `container1` to `container2` with the `docker
|
||||
run --link` command and that would enable the two containers to interact by name
|
||||
as well as IP.
|
||||
|
||||
Detach from a `container2` and leave it running using `CTRL-p CTRL-q`.
|
||||
|
||||
In this example, `container2` is attached to both networks and so can talk to
|
||||
`container1` and `container3`. But `container3` and `container1` are not in the
|
||||
same network and cannot communicate. Test, this now by attaching to
|
||||
`container3` and attempting to ping `container1` by IP address.
|
||||
|
||||
```bash
|
||||
$ docker attach container3
|
||||
/ # ping 172.17.0.2
|
||||
PING 172.17.0.2 (172.17.0.2): 56 data bytes
|
||||
^C
|
||||
--- 172.17.0.2 ping statistics ---
|
||||
10 packets transmitted, 0 packets received, 100% packet loss
|
||||
|
||||
```
|
||||
|
||||
You can connect both running and non-running containers to a network. However,
|
||||
`docker network inspect` only displays information on running containers.
|
||||
|
||||
### Linking containers in user-defined networks
|
||||
|
||||
In the above example, container_2 was able to resolve container_3's name automatically
|
||||
in the user defined network `isolated_nw`, but the name resolution did not succeed
|
||||
automatically in the default `bridge` network. This is expected in order to maintain
|
||||
backward compatibility with [legacy link](default_network/dockerlinks.md).
|
||||
|
||||
The `legacy link` provided 4 major functionalities to the default `bridge` network.
|
||||
|
||||
* name resolution
|
||||
* name alias for the linked container using `--link=CONTAINER-NAME:ALIAS`
|
||||
* secured container connectivity (in isolation via `--icc=false`)
|
||||
* environment variable injection
|
||||
|
||||
Comparing the above 4 functionalities with the non-default user-defined networks such as
|
||||
`isolated_nw` in this example, without any additional config, `docker network` provides
|
||||
|
||||
* automatic name resolution using DNS
|
||||
* automatic secured isolated environment for the containers in a network
|
||||
* ability to dynamically attach and detach to multiple networks
|
||||
* supports the `--link` option to provide name alias for the linked container
|
||||
|
||||
Continuing with the above example, create another container `container_4` in `isolated_nw`
|
||||
with `--link` to provide additional name resolution using alias for other containers in
|
||||
the same network.
|
||||
|
||||
```bash
|
||||
$ docker run --net=isolated_nw -itd --name=container4 --link container5:c5 busybox
|
||||
01b5df970834b77a9eadbaff39051f237957bd35c4c56f11193e0594cfd5117c
|
||||
```
|
||||
|
||||
With the help of `--link` container4 will be able to reach container5 using the
|
||||
aliased name `c5` as well.
|
||||
|
||||
Please note that while creating container4, we linked to a container named `container5`
|
||||
which is not created yet. That is one of the differences in behavior between the
|
||||
`legacy link` in default `bridge` network and the new `link` functionality in user defined
|
||||
networks. The `legacy link` is static in nature and it hard-binds the container with the
|
||||
alias and it doesnt tolerate linked container restarts. While the new `link` functionality
|
||||
in user defined networks are dynamic in nature and supports linked container restarts
|
||||
including tolerating ip-address changes on the linked container.
|
||||
|
||||
Now let us launch another container named `container5` linking container4 to c4.
|
||||
|
||||
```bash
|
||||
$ docker run --net=isolated_nw -itd --name=container5 --link container4:c4 busybox
|
||||
72eccf2208336f31e9e33ba327734125af00d1e1d2657878e2ee8154fbb23c7a
|
||||
```
|
||||
|
||||
As expected, container4 will be able to reach container5 by both its container name and
|
||||
its alias c5 and container5 will be able to reach container4 by its container name and
|
||||
its alias c4.
|
||||
|
||||
```bash
|
||||
$ docker attach container4
|
||||
/ # ping -w 4 c5
|
||||
PING c5 (172.25.0.5): 56 data bytes
|
||||
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- c5 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
|
||||
/ # ping -w 4 container5
|
||||
PING container5 (172.25.0.5): 56 data bytes
|
||||
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- container5 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
```
|
||||
|
||||
```bash
|
||||
$ docker attach container5
|
||||
/ # ping -w 4 c4
|
||||
PING c4 (172.25.0.4): 56 data bytes
|
||||
64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms
|
||||
64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms
|
||||
64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms
|
||||
|
||||
--- c4 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.065/0.070/0.082 ms
|
||||
|
||||
/ # ping -w 4 container4
|
||||
PING container4 (172.25.0.4): 56 data bytes
|
||||
64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms
|
||||
64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms
|
||||
64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms
|
||||
|
||||
--- container4 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.065/0.070/0.082 ms
|
||||
```
|
||||
|
||||
Similar to the legacy link functionality the new link alias is localized to a container
|
||||
and the aliased name has no meaning outside of the container using the `--link`.
|
||||
|
||||
Also, it is important to note that if a container belongs to multiple networks, the
|
||||
linked alias is scoped within a given network. Hence the containers can be linked to
|
||||
different aliases in different networks.
|
||||
|
||||
Extending the example, let us create another network named `local_alias`
|
||||
|
||||
```bash
|
||||
$ docker network create -d bridge --subnet 172.26.0.0/24 local_alias
|
||||
76b7dc932e037589e6553f59f76008e5b76fa069638cd39776b890607f567aaa
|
||||
```
|
||||
|
||||
let us connect container4 and container5 to the new network `local_alias`
|
||||
|
||||
```
|
||||
$ docker network connect --link container5:foo local_alias container4
|
||||
$ docker network connect --link container4:bar local_alias container5
|
||||
```
|
||||
|
||||
```bash
|
||||
$ docker attach container4
|
||||
|
||||
/ # ping -w 4 foo
|
||||
PING foo (172.26.0.3): 56 data bytes
|
||||
64 bytes from 172.26.0.3: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.26.0.3: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.26.0.3: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.26.0.3: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- foo ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
|
||||
/ # ping -w 4 c5
|
||||
PING c5 (172.25.0.5): 56 data bytes
|
||||
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- c5 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
```
|
||||
|
||||
Note that the ping succeeds for both the aliases but on different networks.
|
||||
Let us conclude this section by disconnecting container5 from the `isolated_nw`
|
||||
and observe the results
|
||||
|
||||
```
|
||||
$ docker network disconnect isolated_nw container5
|
||||
|
||||
$ docker attach container4
|
||||
|
||||
/ # ping -w 4 c5
|
||||
ping: bad address 'c5'
|
||||
|
||||
/ # ping -w 4 foo
|
||||
PING foo (172.26.0.3): 56 data bytes
|
||||
64 bytes from 172.26.0.3: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.26.0.3: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.26.0.3: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.26.0.3: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- foo ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
|
||||
```
|
||||
|
||||
In conclusion, the new link functionality in user defined networks provides all the
|
||||
benefits of legacy links while avoiding most of the well-known issues with `legacy links`.
|
||||
|
||||
One notable missing functionality compared to `legacy links` is the injection of
|
||||
environment variables. Though very useful, environment variable injection is static
|
||||
in nature and must be injected when the container is started. One cannot inject
|
||||
environment variables into a running container without significant effort and hence
|
||||
it is not compatible with `docker network` which provides a dynamic way to connect/
|
||||
disconnect containers to/from a network.
|
||||
|
||||
### Network-scoped alias
|
||||
|
||||
While `links` provide private name resolution that is localized within a container,
|
||||
the network-scoped alias provides a way for a container to be discovered by an
|
||||
alternate name by any other container within the scope of a particular network.
|
||||
Unlike the `link` alias, which is defined by the consumer of a service, the
|
||||
network-scoped alias is defined by the container that is offering the service
|
||||
to the network.
|
||||
|
||||
Continuing with the above example, create another container in `isolated_nw` with a
|
||||
network alias.
|
||||
|
||||
```bash
|
||||
$ docker run --net=isolated_nw -itd --name=container6 --net-alias app busybox
|
||||
8ebe6767c1e0361f27433090060b33200aac054a68476c3be87ef4005eb1df17
|
||||
```
|
||||
|
||||
```bash
|
||||
$ docker attach container4
|
||||
/ # ping -w 4 app
|
||||
PING app (172.25.0.6): 56 data bytes
|
||||
64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- app ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
|
||||
/ # ping -w 4 container6
|
||||
PING container5 (172.25.0.6): 56 data bytes
|
||||
64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- container6 ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
```
|
||||
|
||||
Now let us connect `container6` to the `local_alias` network with a different network-scoped
|
||||
alias.
|
||||
|
||||
```
|
||||
$ docker network connect --alias scoped-app local_alias container6
|
||||
```
|
||||
|
||||
`container6` in this example now is aliased as `app` in network `isolated_nw` and
|
||||
as `scoped-app` in network `local_alias`.
|
||||
|
||||
Let's try to reach these aliases from `container4` (which is connected to both these networks)
|
||||
and `container5` (which is connected only to `isolated_nw`).
|
||||
|
||||
```bash
|
||||
$ docker attach container4
|
||||
|
||||
/ # ping -w 4 scoped-app
|
||||
PING foo (172.26.0.5): 56 data bytes
|
||||
64 bytes from 172.26.0.5: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.26.0.5: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.26.0.5: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.26.0.5: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- foo ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
|
||||
$ docker attach container5
|
||||
|
||||
/ # ping -w 4 scoped-app
|
||||
ping: bad address 'scoped-app'
|
||||
|
||||
```
|
||||
|
||||
As you can see, the alias is scoped to the network it is defined on and hence only
|
||||
those containers that are connected to that network can access the alias.
|
||||
|
||||
In addition to the above features, multiple containers can share the same network-scoped
|
||||
alias within the same network. For example, let's launch `container7` in `isolated_nw` with
|
||||
the same alias as `container6`
|
||||
|
||||
```bash
|
||||
$ docker run --net=isolated_nw -itd --name=container7 --net-alias app busybox
|
||||
3138c678c123b8799f4c7cc6a0cecc595acbdfa8bf81f621834103cd4f504554
|
||||
```
|
||||
|
||||
When multiple containers share the same alias, name resolution to that alias will happen
|
||||
to one of the containers (typically the first container that is aliased). When the container
|
||||
that backs the alias goes down or disconnected from the network, the next container that
|
||||
backs the alias will be resolved.
|
||||
|
||||
Let us ping the alias `app` from `container4` and bring down `container6` to verify that
|
||||
`container7` is resolving the `app` alias.
|
||||
|
||||
```bash
|
||||
$ docker attach container4
|
||||
/ # ping -w 4 app
|
||||
PING app (172.25.0.6): 56 data bytes
|
||||
64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
|
||||
64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
|
||||
64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms
|
||||
|
||||
--- app ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.070/0.081/0.097 ms
|
||||
|
||||
$ docker stop container6
|
||||
|
||||
$ docker attach container4
|
||||
/ # ping -w 4 app
|
||||
PING app (172.25.0.7): 56 data bytes
|
||||
64 bytes from 172.25.0.7: seq=0 ttl=64 time=0.095 ms
|
||||
64 bytes from 172.25.0.7: seq=1 ttl=64 time=0.075 ms
|
||||
64 bytes from 172.25.0.7: seq=2 ttl=64 time=0.072 ms
|
||||
64 bytes from 172.25.0.7: seq=3 ttl=64 time=0.101 ms
|
||||
|
||||
--- app ping statistics ---
|
||||
4 packets transmitted, 4 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.072/0.085/0.101 ms
|
||||
|
||||
```
|
||||
|
||||
## Disconnecting containers
|
||||
|
||||
You can disconnect a container from a network using the `docker network
|
||||
disconnect` command.
|
||||
|
||||
```
|
||||
$ docker network disconnect isolated_nw container2
|
||||
|
||||
docker inspect --format='{{json .NetworkSettings.Networks}}' container2 | python -m json.tool
|
||||
{
|
||||
"bridge": {
|
||||
"NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812",
|
||||
"EndpointID": "9e4575f7f61c0f9d69317b7a4b92eefc133347836dd83ef65deffa16b9985dc0",
|
||||
"Gateway": "172.17.0.1",
|
||||
"GlobalIPv6Address": "",
|
||||
"GlobalIPv6PrefixLen": 0,
|
||||
"IPAddress": "172.17.0.3",
|
||||
"IPPrefixLen": 16,
|
||||
"IPv6Gateway": "",
|
||||
"MacAddress": "02:42:ac:11:00:03"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$ docker network inspect isolated_nw
|
||||
[
|
||||
{
|
||||
"Name": "isolated_nw",
|
||||
"Id": "06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.21.0.0/16",
|
||||
"Gateway": "172.21.0.1/16"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {
|
||||
"467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551": {
|
||||
"Name": "container3",
|
||||
"EndpointID": "dffc7ec2915af58cc827d995e6ebdc897342be0420123277103c40ae35579103",
|
||||
"MacAddress": "02:42:ac:19:03:03",
|
||||
"IPv4Address": "172.25.3.3/16",
|
||||
"IPv6Address": ""
|
||||
}
|
||||
},
|
||||
"Options": {}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Once a container is disconnected from a network, it cannot communicate with
|
||||
other containers connected to that network. In this example, `container2` can no longer talk to `container3` on the `isolated_nw` network.
|
||||
|
||||
```
|
||||
$ docker attach container2
|
||||
|
||||
/ # ifconfig
|
||||
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
|
||||
inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
|
||||
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
|
||||
UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1
|
||||
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:648 (648.0 B) TX bytes:648 (648.0 B)
|
||||
|
||||
lo Link encap:Local Loopback
|
||||
inet addr:127.0.0.1 Mask:255.0.0.0
|
||||
inet6 addr: ::1/128 Scope:Host
|
||||
UP LOOPBACK RUNNING MTU:65536 Metric:1
|
||||
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
|
||||
collisions:0 txqueuelen:0
|
||||
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
|
||||
|
||||
/ # ping container3
|
||||
PING container3 (172.25.3.3): 56 data bytes
|
||||
^C
|
||||
--- container3 ping statistics ---
|
||||
2 packets transmitted, 0 packets received, 100% packet loss
|
||||
```
|
||||
|
||||
The `container2` still has full connectivity to the bridge network
|
||||
|
||||
```bash
|
||||
/ # ping container1
|
||||
PING container1 (172.17.0.2): 56 data bytes
|
||||
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.119 ms
|
||||
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.174 ms
|
||||
^C
|
||||
--- container1 ping statistics ---
|
||||
2 packets transmitted, 2 packets received, 0% packet loss
|
||||
round-trip min/avg/max = 0.119/0.146/0.174 ms
|
||||
/ #
|
||||
```
|
||||
|
||||
There are certain scenarios such as ungraceful docker daemon restarts in multi-host network,
|
||||
where the daemon is unable to cleanup stale connectivity endpoints. Such stale endpoints
|
||||
may cause an error `container already connected to network` when a new container is
|
||||
connected to that network with the same name as the stale endpoint. In order to cleanup
|
||||
these stale endpoints, first remove the container and force disconnect
|
||||
(`docker network disconnect -f`) the endpoint from the network. Once the endpoint is
|
||||
cleaned up, the container can be connected to the network.
|
||||
|
||||
```
|
||||
$ docker run -d --name redis_db --net multihost redis
|
||||
ERROR: Cannot start container bc0b19c089978f7845633027aa3435624ca3d12dd4f4f764b61eac4c0610f32e: container already connected to network multihost
|
||||
|
||||
$ docker rm -f redis_db
|
||||
$ docker network disconnect -f multihost redis_db
|
||||
|
||||
$ docker run -d --name redis_db --net multihost redis
|
||||
7d986da974aeea5e9f7aca7e510bdb216d58682faa83a9040c2f2adc0544795a
|
||||
```
|
||||
|
||||
## Remove a network
|
||||
|
||||
When all the containers in a network are stopped or disconnected, you can remove a network.
|
||||
|
||||
```bash
|
||||
$ docker network disconnect isolated_nw container3
|
||||
```
|
||||
|
||||
```bash
|
||||
docker network inspect isolated_nw
|
||||
[
|
||||
{
|
||||
"Name": "isolated_nw",
|
||||
"Id": "06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8",
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.21.0.0/16",
|
||||
"Gateway": "172.21.0.1/16"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {},
|
||||
"Options": {}
|
||||
}
|
||||
]
|
||||
|
||||
$ docker network rm isolated_nw
|
||||
```
|
||||
|
||||
List all your networks to verify the `isolated_nw` was removed:
|
||||
|
||||
```
|
||||
$ docker network ls
|
||||
NETWORK ID NAME DRIVER
|
||||
72314fa53006 host host
|
||||
f7ab26d71dbd bridge bridge
|
||||
0f32e83e61ac none null
|
||||
```
|
||||
|
||||
## Related information
|
||||
|
||||
* [network create](../../reference/commandline/network_create.md)
|
||||
* [network inspect](../../reference/commandline/network_inspect.md)
|
||||
* [network connect](../../reference/commandline/network_connect.md)
|
||||
* [network disconnect](../../reference/commandline/network_disconnect.md)
|
||||
* [network ls](../../reference/commandline/network_ls.md)
|
||||
* [network rm](../../reference/commandline/network_rm.md)
|
||||
216
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/aufs-driver.md
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "AUFS storage driver in practice"
|
||||
description = "Learn how to optimize your use of AUFS driver."
|
||||
keywords = ["container, storage, driver, AUFS "]
|
||||
[menu.main]
|
||||
parent = "engine_driver"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Docker and AUFS in practice
|
||||
|
||||
AUFS was the first storage driver in use with Docker. As a result, it has a
|
||||
long and close history with Docker, is very stable, has a lot of real-world
|
||||
deployments, and has strong community support. AUFS has several features that
|
||||
make it a good choice for Docker. These features enable:
|
||||
|
||||
- Fast container startup times.
|
||||
- Efficient use of storage.
|
||||
- Efficient use of memory.
|
||||
|
||||
Despite its capabilities and long history with Docker, some Linux distributions
|
||||
do not support AUFS. This is usually because AUFS is not included in the
|
||||
mainline (upstream) Linux kernel.
|
||||
|
||||
The following sections examine some AUFS features and how they relate to
|
||||
Docker.
|
||||
|
||||
## Image layering and sharing with AUFS
|
||||
|
||||
AUFS is a *unification filesystem*. This means that it takes multiple
|
||||
directories on a single Linux host, stacks them on top of each other, and
|
||||
provides a single unified view. To achieve this, AUFS uses a *union mount*.
|
||||
|
||||
AUFS stacks multiple directories and exposes them as a unified view through a
|
||||
single mount point. All of the directories in the stack, as well as the union
|
||||
mount point, must all exist on the same Linux host. AUFS refers to each
|
||||
directory that it stacks as a *branch*.
|
||||
|
||||
Within Docker, AUFS union mounts enable image layering. The AUFS storage driver
|
||||
implements Docker image layers using this union mount system. AUFS branches
|
||||
correspond to Docker image layers. The diagram below shows a Docker container
|
||||
based on the `ubuntu:latest` image.
|
||||
|
||||

|
||||
|
||||
This diagram shows that each image layer, and the container layer, is
|
||||
represented in the Docker hosts filesystem as a directory under
|
||||
`/var/lib/docker/`. The union mount point provides the unified view of all
|
||||
layers. As of Docker 1.10, image layer IDs do not correspond to the names of
|
||||
the directories that contain their data.
|
||||
|
||||
AUFS also supports the copy-on-write technology (CoW). Not all storage drivers
|
||||
do.
|
||||
|
||||
## Container reads and writes with AUFS
|
||||
|
||||
Docker leverages AUFS CoW technology to enable image sharing and minimize the
|
||||
use of disk space. AUFS works at the file level. This means that all AUFS CoW
|
||||
operations copy entire files - even if only a small part of the file is being
|
||||
modified. This behavior can have a noticeable impact on container performance,
|
||||
especially if the files being copied are large, below a lot of image layers,
|
||||
or the CoW operation must search a deep directory tree.
|
||||
|
||||
Consider, for example, an application running in a container needs to add a
|
||||
single new value to a large key-value store (file). If this is the first time
|
||||
the file is modified, it does not yet exist in the container's top writable
|
||||
layer. So, the CoW must *copy up* the file from the underlying image. The AUFS
|
||||
storage driver searches each image layer for the file. The search order is from
|
||||
top to bottom. When it is found, the entire file is *copied up* to the
|
||||
container's top writable layer. From there, it can be opened and modified.
|
||||
|
||||
Larger files obviously take longer to *copy up* than smaller files, and files
|
||||
that exist in lower image layers take longer to locate than those in higher
|
||||
layers. However, a *copy up* operation only occurs once per file on any given
|
||||
container. Subsequent reads and writes happen against the file's copy already
|
||||
*copied-up* to the container's top layer.
|
||||
|
||||
## Deleting files with the AUFS storage driver
|
||||
|
||||
The AUFS storage driver deletes a file from a container by placing a *whiteout
|
||||
file* in the container's top layer. The whiteout file effectively obscures the
|
||||
existence of the file in the read-only image layers below. The simplified
|
||||
diagram below shows a container based on an image with three image layers.
|
||||
|
||||

|
||||
|
||||
The `file3` was deleted from the container. So, the AUFS storage driver placed
|
||||
a whiteout file in the container's top layer. This whiteout file effectively
|
||||
"deletes" `file3` from the container by obscuring any of the original file's
|
||||
existence in the image's read-only layers. This works the same no matter which
|
||||
of the image's read-only layers the file exists in.
|
||||
|
||||
## Configure Docker with AUFS
|
||||
|
||||
You can only use the AUFS storage driver on Linux systems with AUFS installed.
|
||||
Use the following command to determine if your system supports AUFS.
|
||||
|
||||
$ grep aufs /proc/filesystems
|
||||
nodev aufs
|
||||
|
||||
This output indicates the system supports AUFS. Once you've verified your
|
||||
system supports AUFS, you can must instruct the Docker daemon to use it. You do
|
||||
this from the command line with the `docker daemon` command:
|
||||
|
||||
$ sudo docker daemon --storage-driver=aufs &
|
||||
|
||||
|
||||
Alternatively, you can edit the Docker config file and add the
|
||||
`--storage-driver=aufs` option to the `DOCKER_OPTS` line.
|
||||
|
||||
# Use DOCKER_OPTS to modify the daemon startup options.
|
||||
DOCKER_OPTS="--storage-driver=aufs"
|
||||
|
||||
Once your daemon is running, verify the storage driver with the `docker info`
|
||||
command.
|
||||
|
||||
$ sudo docker info
|
||||
Containers: 1
|
||||
Images: 4
|
||||
Storage Driver: aufs
|
||||
Root Dir: /var/lib/docker/aufs
|
||||
Backing Filesystem: extfs
|
||||
Dirs: 6
|
||||
Dirperm1 Supported: false
|
||||
Execution Driver: native-0.2
|
||||
...output truncated...
|
||||
|
||||
The output above shows that the Docker daemon is running the AUFS storage
|
||||
driver on top of an existing `ext4` backing filesystem.
|
||||
|
||||
## Local storage and AUFS
|
||||
|
||||
As the `docker daemon` runs with the AUFS driver, the driver stores images and
|
||||
containers within the Docker host's local storage area under
|
||||
`/var/lib/docker/aufs/`.
|
||||
|
||||
### Images
|
||||
|
||||
Image layers and their contents are stored under
|
||||
`/var/lib/docker/aufs/diff/`. With Docker 1.10 and higher, image layer IDs do
|
||||
not correspond to directory names.
|
||||
|
||||
The `/var/lib/docker/aufs/layers/` directory contains metadata about how image
|
||||
layers are stacked. This directory contains one file for every image or
|
||||
container layer on the Docker host (though file names no longer match image
|
||||
layer IDs). Inside each file are the names of the directories that exist below
|
||||
it in the stack
|
||||
|
||||
The command below shows the contents of a metadata file in
|
||||
`/var/lib/docker/aufs/layers/` that lists the the three directories that are
|
||||
stacked below it in the union mount. Remember, these directory names do no map
|
||||
to image layer IDs with Docker 1.10 and higher.
|
||||
|
||||
$ cat /var/lib/docker/aufs/layers/91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c
|
||||
d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82
|
||||
c22013c8472965aa5b62559f2b540cd440716ef149756e7b958a1b2aba421e87
|
||||
d3a1f33e8a5a513092f01bb7eb1c2abf4d711e5105390a3fe1ae2248cfde1391
|
||||
|
||||
The base layer in an image has no image layers below it, so its file is empty.
|
||||
|
||||
### Containers
|
||||
|
||||
Running containers are mounted below `/var/lib/docker/aufs/mnt/<container-id>`.
|
||||
This is where the AUFS union mount point that exposes the container and all
|
||||
underlying image layers as a single unified view exists. If a container is not
|
||||
running, it still has a directory here but it is empty. This is because AUFS
|
||||
only mounts a container when it is running. With Docker 1.10 and higher,
|
||||
container IDs no longer correspond to directory names under
|
||||
`/var/lib/docker/aufs/mnt/<container-id>`.
|
||||
|
||||
Container metadata and various config files that are placed into the running
|
||||
container are stored in `/var/lib/docker/containers/<container-id>`. Files in
|
||||
this directory exist for all containers on the system, including ones that are
|
||||
stopped. However, when a container is running the container's log files are
|
||||
also in this directory.
|
||||
|
||||
A container's thin writable layer is stored in a directory under
|
||||
`/var/lib/docker/aufs/diff/`. With Docker 1.10 and higher, container IDs no
|
||||
longer correspond to directory names. However, the containers thin writable
|
||||
layer still exists under here and is stacked by AUFS as the top writable layer
|
||||
and is where all changes to the container are stored. The directory exists even
|
||||
if the container is stopped. This means that restarting a container will not
|
||||
lose changes made to it. Once a container is deleted, it's thin writable layer
|
||||
in this directory is deleted.
|
||||
|
||||
## AUFS and Docker performance
|
||||
|
||||
To summarize some of the performance related aspects already mentioned:
|
||||
|
||||
- The AUFS storage driver is a good choice for PaaS and other similar use-cases
|
||||
where container density is important. This is because AUFS efficiently shares
|
||||
images between multiple running containers, enabling fast container start times
|
||||
and minimal use of disk space.
|
||||
|
||||
- The underlying mechanics of how AUFS shares files between image layers and
|
||||
containers uses the systems page cache very efficiently.
|
||||
|
||||
- The AUFS storage driver can introduce significant latencies into container
|
||||
write performance. This is because the first time a container writes to any
|
||||
file, the file has be located and copied into the containers top writable
|
||||
layer. These latencies increase and are compounded when these files exist below
|
||||
many image layers and the files themselves are large.
|
||||
|
||||
One final point. Data volumes provide the best and most predictable
|
||||
performance. This is because they bypass the storage driver and do not incur
|
||||
any of the potential overheads introduced by thin provisioning and
|
||||
copy-on-write. For this reason, you may want to place heavy write workloads on
|
||||
data volumes.
|
||||
|
||||
## Related information
|
||||
|
||||
* [Understand images, containers, and storage drivers](imagesandcontainers.md)
|
||||
* [Select a storage driver](selectadriver.md)
|
||||
* [Btrfs storage driver in practice](btrfs-driver.md)
|
||||
* [Device Mapper storage driver in practice](device-mapper-driver.md)
|
||||
315
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/btrfs-driver.md
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Btrfs storage in practice"
|
||||
description = "Learn how to optimize your use of Btrfs driver."
|
||||
keywords = ["container, storage, driver, Btrfs "]
|
||||
[menu.main]
|
||||
parent = "engine_driver"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Docker and Btrfs in practice
|
||||
|
||||
Btrfs is a next generation copy-on-write filesystem that supports many advanced
|
||||
storage technologies that make it a good fit for Docker. Btrfs is included in
|
||||
the mainline Linux kernel and its on-disk-format is now considered stable.
|
||||
However, many of its features are still under heavy development and users
|
||||
should consider it a fast-moving target.
|
||||
|
||||
Docker's `btrfs` storage driver leverages many Btrfs features for image and
|
||||
container management. Among these features are thin provisioning,
|
||||
copy-on-write, and snapshotting.
|
||||
|
||||
This article refers to Docker's Btrfs storage driver as `btrfs` and the overall
|
||||
Btrfs Filesystem as Btrfs.
|
||||
|
||||
>**Note**: The [Commercially Supported Docker Engine (CS-Engine)](https://www.docker.com/compatibility-maintenance) does not currently support the `btrfs` storage driver.
|
||||
|
||||
## The future of Btrfs
|
||||
|
||||
Btrfs has been long hailed as the future of Linux filesystems. With full
|
||||
support in the mainline Linux kernel, a stable on-disk-format, and active
|
||||
development with a focus on stability, this is now becoming more of a reality.
|
||||
|
||||
As far as Docker on the Linux platform goes, many people see the `btrfs`
|
||||
storage driver as a potential long-term replacement for the `devicemapper`
|
||||
storage driver. However, at the time of writing, the `devicemapper` storage
|
||||
driver should be considered safer, more stable, and more *production ready*.
|
||||
You should only consider the `btrfs` driver for production deployments if you
|
||||
understand it well and have existing experience with Btrfs.
|
||||
|
||||
## Image layering and sharing with Btrfs
|
||||
|
||||
Docker leverages Btrfs *subvolumes* and *snapshots* for managing the on-disk
|
||||
components of image and container layers. Btrfs subvolumes look and feel like
|
||||
a normal Unix filesystem. As such, they can have their own internal directory
|
||||
structure that hooks into the wider Unix filesystem.
|
||||
|
||||
Subvolumes are natively copy-on-write and have space allocated to them
|
||||
on-demand from an underlying storage pool. They can also be nested and snapped.
|
||||
The diagram blow shows 4 subvolumes. 'Subvolume 2' and 'Subvolume 3' are
|
||||
nested, whereas 'Subvolume 4' shows its own internal directory tree.
|
||||
|
||||

|
||||
|
||||
Snapshots are a point-in-time read-write copy of an entire subvolume. They
|
||||
exist directly below the subvolume they were created from. You can create
|
||||
snapshots of snapshots as shown in the diagram below.
|
||||
|
||||

|
||||
|
||||
Btfs allocates space to subvolumes and snapshots on demand from an underlying
|
||||
pool of storage. The unit of allocation is referred to as a *chunk*, and
|
||||
*chunks* are normally ~1GB in size.
|
||||
|
||||
Snapshots are first-class citizens in a Btrfs filesystem. This means that they
|
||||
look, feel, and operate just like regular subvolumes. The technology required
|
||||
to create them is built directly into the Btrfs filesystem thanks to its
|
||||
native copy-on-write design. This means that Btrfs snapshots are space
|
||||
efficient with little or no performance overhead. The diagram below shows a
|
||||
subvolume and its snapshot sharing the same data.
|
||||
|
||||

|
||||
|
||||
Docker's `btrfs` storage driver stores every image layer and container in its
|
||||
own Btrfs subvolume or snapshot. The base layer of an image is stored as a
|
||||
subvolume whereas child image layers and containers are stored as snapshots.
|
||||
This is shown in the diagram below.
|
||||
|
||||

|
||||
|
||||
The high level process for creating images and containers on Docker hosts
|
||||
running the `btrfs` driver is as follows:
|
||||
|
||||
1. The image's base layer is stored in a Btrfs *subvolume* under
|
||||
`/var/lib/docker/btrfs/subvolumes`.
|
||||
|
||||
2. Subsequent image layers are stored as a Btrfs *snapshot* of the parent
|
||||
layer's subvolume or snapshot.
|
||||
|
||||
The diagram below shows a three-layer image. The base layer is a subvolume.
|
||||
Layer 1 is a snapshot of the base layer's subvolume. Layer 2 is a snapshot of
|
||||
Layer 1's snapshot.
|
||||
|
||||

|
||||
|
||||
As of Docker 1.10, image layer IDs no longer correspond to directory names
|
||||
under `/var/lib/docker/`.
|
||||
|
||||
## Image and container on-disk constructs
|
||||
|
||||
Image layers and containers are visible in the Docker host's filesystem at
|
||||
`/var/lib/docker/btrfs/subvolumes/`. However, as previously stated, directory
|
||||
names no longer correspond to image layer IDs. That said, directories for
|
||||
containers are present even for containers with a stopped status. This is
|
||||
because the `btrfs` storage driver mounts a default, top-level subvolume at
|
||||
`/var/lib/docker/subvolumes`. All other subvolumes and snapshots exist below
|
||||
that as Btrfs filesystem objects and not as individual mounts.
|
||||
|
||||
Because Btrfs works at the filesystem level and not the block level, each image
|
||||
and container layer can be browsed in the filesystem using normal Unix
|
||||
commands. The example below shows a truncated output of an `ls -l` command an
|
||||
image layer:
|
||||
|
||||
$ ls -l /var/lib/docker/btrfs/subvolumes/0a17decee4139b0de68478f149cc16346f5e711c5ae3bb969895f22dd6723751/
|
||||
total 0
|
||||
drwxr-xr-x 1 root root 1372 Oct 9 08:39 bin
|
||||
drwxr-xr-x 1 root root 0 Apr 10 2014 boot
|
||||
drwxr-xr-x 1 root root 882 Oct 9 08:38 dev
|
||||
drwxr-xr-x 1 root root 2040 Oct 12 17:27 etc
|
||||
drwxr-xr-x 1 root root 0 Apr 10 2014 home
|
||||
...output truncated...
|
||||
|
||||
## Container reads and writes with Btrfs
|
||||
|
||||
A container is a space-efficient snapshot of an image. Metadata in the snapshot
|
||||
points to the actual data blocks in the storage pool. This is the same as with
|
||||
a subvolume. Therefore, reads performed against a snapshot are essentially the
|
||||
same as reads performed against a subvolume. As a result, no performance
|
||||
overhead is incurred from the Btrfs driver.
|
||||
|
||||
Writing a new file to a container invokes an allocate-on-demand operation to
|
||||
allocate new data block to the container's snapshot. The file is then written to
|
||||
this new space. The allocate-on-demand operation is native to all writes with
|
||||
Btrfs and is the same as writing new data to a subvolume. As a result, writing
|
||||
new files to a container's snapshot operate at native Btrfs speeds.
|
||||
|
||||
Updating an existing file in a container causes a copy-on-write operation
|
||||
(technically *redirect-on-write*). The driver leaves the original data and
|
||||
allocates new space to the snapshot. The updated data is written to this new
|
||||
space. Then, the driver updates the filesystem metadata in the snapshot to
|
||||
point to this new data. The original data is preserved in-place for subvolumes
|
||||
and snapshots further up the tree. This behavior is native to copy-on-write
|
||||
filesystems like Btrfs and incurs very little overhead.
|
||||
|
||||
With Btfs, writing and updating lots of small files can result in slow
|
||||
performance. More on this later.
|
||||
|
||||
## Configuring Docker with Btrfs
|
||||
|
||||
The `btrfs` storage driver only operates on a Docker host where
|
||||
`/var/lib/docker` is mounted as a Btrfs filesystem. The following procedure
|
||||
shows how to configure Btrfs on Ubuntu 14.04 LTS.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If you have already used the Docker daemon on your Docker host and have images
|
||||
you want to keep, `push` them to Docker Hub or your private Docker Trusted
|
||||
Registry before attempting this procedure.
|
||||
|
||||
Stop the Docker daemon. Then, ensure that you have a spare block device at
|
||||
`/dev/xvdb`. The device identifier may be different in your environment and you
|
||||
should substitute your own values throughout the procedure.
|
||||
|
||||
The procedure also assumes your kernel has the appropriate Btrfs modules
|
||||
loaded. To verify this, use the following command:
|
||||
|
||||
$ cat /proc/filesystems | grep btrfs
|
||||
|
||||
### Configure Btrfs on Ubuntu 14.04 LTS
|
||||
|
||||
Assuming your system meets the prerequisites, do the following:
|
||||
|
||||
1. Install the "btrfs-tools" package.
|
||||
|
||||
$ sudo apt-get install btrfs-tools
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
<output truncated>
|
||||
|
||||
2. Create the Btrfs storage pool.
|
||||
|
||||
Btrfs storage pools are created with the `mkfs.btrfs` command. Passing
|
||||
multiple devices to the `mkfs.btrfs` command creates a pool across all of those
|
||||
devices. Here you create a pool with a single device at `/dev/xvdb`.
|
||||
|
||||
$ sudo mkfs.btrfs -f /dev/xvdb
|
||||
WARNING! - Btrfs v3.12 IS EXPERIMENTAL
|
||||
WARNING! - see http://btrfs.wiki.kernel.org before using
|
||||
|
||||
Turning ON incompat feature 'extref': increased hardlink limit per file to 65536
|
||||
fs created label (null) on /dev/xvdb
|
||||
nodesize 16384 leafsize 16384 sectorsize 4096 size 4.00GiB
|
||||
Btrfs v3.12
|
||||
|
||||
Be sure to substitute `/dev/xvdb` with the appropriate device(s) on your
|
||||
system.
|
||||
|
||||
> **Warning**: Take note of the warning about Btrfs being experimental. As
|
||||
noted earlier, Btrfs is not currently recommended for production deployments
|
||||
unless you already have extensive experience.
|
||||
|
||||
3. If it does not already exist, create a directory for the Docker host's local
|
||||
storage area at `/var/lib/docker`.
|
||||
|
||||
$ sudo mkdir /var/lib/docker
|
||||
|
||||
4. Configure the system to automatically mount the Btrfs filesystem each time the system boots.
|
||||
|
||||
a. Obtain the Btrfs filesystem's UUID.
|
||||
|
||||
$ sudo blkid /dev/xvdb
|
||||
/dev/xvdb: UUID="a0ed851e-158b-4120-8416-c9b072c8cf47" UUID_SUB="c3927a64-4454-4eef-95c2-a7d44ac0cf27" TYPE="btrfs"
|
||||
|
||||
b. Create an `/etc/fstab` entry to automatically mount `/var/lib/docker`
|
||||
each time the system boots. Either of the following lines will work, just
|
||||
remember to substitute the UUID value with the value obtained from the previous
|
||||
command.
|
||||
|
||||
/dev/xvdb /var/lib/docker btrfs defaults 0 0
|
||||
UUID="a0ed851e-158b-4120-8416-c9b072c8cf47" /var/lib/docker btrfs defaults 0 0
|
||||
|
||||
5. Mount the new filesystem and verify the operation.
|
||||
|
||||
$ sudo mount -a
|
||||
$ mount
|
||||
/dev/xvda1 on / type ext4 (rw,discard)
|
||||
<output truncated>
|
||||
/dev/xvdb on /var/lib/docker type btrfs (rw)
|
||||
|
||||
The last line in the output above shows the `/dev/xvdb` mounted at
|
||||
`/var/lib/docker` as Btrfs.
|
||||
|
||||
Now that you have a Btrfs filesystem mounted at `/var/lib/docker`, the daemon
|
||||
should automatically load with the `btrfs` storage driver.
|
||||
|
||||
1. Start the Docker daemon.
|
||||
|
||||
$ sudo service docker start
|
||||
docker start/running, process 2315
|
||||
|
||||
The procedure for starting the Docker daemon may differ depending on the
|
||||
Linux distribution you are using.
|
||||
|
||||
You can force the the Docker daemon to start with the `btrfs` storage
|
||||
driver by either passing the `--storage-driver=btrfs` flag to the `docker
|
||||
daemon` at startup, or adding it to the `DOCKER_OPTS` line to the Docker config
|
||||
file.
|
||||
|
||||
2. Verify the storage driver with the `docker info` command.
|
||||
|
||||
$ sudo docker info
|
||||
Containers: 0
|
||||
Images: 0
|
||||
Storage Driver: btrfs
|
||||
[...]
|
||||
|
||||
Your Docker host is now configured to use the `btrfs` storage driver.
|
||||
|
||||
## Btrfs and Docker performance
|
||||
|
||||
There are several factors that influence Docker's performance under the `btrfs`
|
||||
storage driver.
|
||||
|
||||
- **Page caching**. Btrfs does not support page cache sharing. This means that
|
||||
*n* containers accessing the same file require *n* copies to be cached. As a
|
||||
result, the `btrfs` driver may not be the best choice for PaaS and other high
|
||||
density container use cases.
|
||||
|
||||
- **Small writes**. Containers performing lots of small writes (including
|
||||
Docker hosts that start and stop many containers) can lead to poor use of Btrfs
|
||||
chunks. This can ultimately lead to out-of-space conditions on your Docker
|
||||
host and stop it working. This is currently a major drawback to using current
|
||||
versions of Btrfs.
|
||||
|
||||
If you use the `btrfs` storage driver, closely monitor the free space on
|
||||
your Btrfs filesystem using the `btrfs filesys show` command. Do not trust the
|
||||
output of normal Unix commands such as `df`; always use the Btrfs native
|
||||
commands.
|
||||
|
||||
- **Sequential writes**. Btrfs writes data to disk via journaling technique.
|
||||
This can impact sequential writes, where performance can be up to half.
|
||||
|
||||
- **Fragmentation**. Fragmentation is a natural byproduct of copy-on-write
|
||||
filesystems like Btrfs. Many small random writes can compound this issue. It
|
||||
can manifest as CPU spikes on Docker hosts using SSD media and head thrashing
|
||||
on Docker hosts using spinning media. Both of these result in poor performance.
|
||||
|
||||
Recent versions of Btrfs allow you to specify `autodefrag` as a mount
|
||||
option. This mode attempts to detect random writes and defragment them. You
|
||||
should perform your own tests before enabling this option on your Docker hosts.
|
||||
Some tests have shown this option has a negative performance impact on Docker
|
||||
hosts performing lots of small writes (including systems that start and stop
|
||||
many containers).
|
||||
|
||||
- **Solid State Devices (SSD)**. Btrfs has native optimizations for SSD media.
|
||||
To enable these, mount with the `-o ssd` mount option. These optimizations
|
||||
include enhanced SSD write performance by avoiding things like *seek
|
||||
optimizations* that have no use on SSD media.
|
||||
|
||||
Btfs also supports the TRIM/Discard primitives. However, mounting with the
|
||||
`-o discard` mount option can cause performance issues. Therefore, it is
|
||||
recommended you perform your own tests before using this option.
|
||||
|
||||
- **Use Data Volumes**. Data volumes provide the best and most predictable
|
||||
performance. This is because they bypass the storage driver and do not incur
|
||||
any of the potential overheads introduced by thin provisioning and
|
||||
copy-on-write. For this reason, you should place heavy write workloads on data
|
||||
volumes.
|
||||
|
||||
## Related Information
|
||||
|
||||
* [Understand images, containers, and storage drivers](imagesandcontainers.md)
|
||||
* [Select a storage driver](selectadriver.md)
|
||||
* [AUFS storage driver in practice](aufs-driver.md)
|
||||
* [Device Mapper storage driver in practice](device-mapper-driver.md)
|
||||
412
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/device-mapper-driver.md
generated
vendored
Normal file
@@ -0,0 +1,412 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title="Device mapper storage in practice"
|
||||
description="Learn how to optimize your use of device mapper driver."
|
||||
keywords=["container, storage, driver, device mapper"]
|
||||
[menu.main]
|
||||
parent="engine_driver"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Docker and the Device Mapper storage driver
|
||||
|
||||
Device Mapper is a kernel-based framework that underpins many advanced
|
||||
volume management technologies on Linux. Docker's `devicemapper` storage driver
|
||||
leverages the thin provisioning and snapshotting capabilities of this framework
|
||||
for image and container management. This article refers to the Device Mapper
|
||||
storage driver as `devicemapper`, and the kernel framework as `Device Mapper`.
|
||||
|
||||
|
||||
>**Note**: The [Commercially Supported Docker Engine (CS-Engine) running on RHEL and CentOS Linux](https://www.docker.com/compatibility-maintenance) requires that you use the `devicemapper` storage driver.
|
||||
|
||||
|
||||
## An alternative to AUFS
|
||||
|
||||
Docker originally ran on Ubuntu and Debian Linux and used AUFS for its storage
|
||||
backend. As Docker became popular, many of the companies that wanted to use it
|
||||
were using Red Hat Enterprise Linux (RHEL). Unfortunately, because the upstream
|
||||
mainline Linux kernel did not include AUFS, RHEL did not use AUFS either.
|
||||
|
||||
To correct this Red Hat developers investigated getting AUFS into the mainline
|
||||
kernel. Ultimately, though, they decided a better idea was to develop a new
|
||||
storage backend. Moreover, they would base this new storage backend on existing
|
||||
`Device Mapper` technology.
|
||||
|
||||
Red Hat collaborated with Docker Inc. to contribute this new driver. As a result
|
||||
of this collaboration, Docker's Engine was re-engineered to make the storage
|
||||
backend pluggable. So it was that the `devicemapper` became the second storage
|
||||
driver Docker supported.
|
||||
|
||||
Device Mapper has been included in the mainline Linux kernel since version
|
||||
2.6.9. It is a core part of RHEL family of Linux distributions. This means that
|
||||
the `devicemapper` storage driver is based on stable code that has a lot of
|
||||
real-world production deployments and strong community support.
|
||||
|
||||
|
||||
## Image layering and sharing
|
||||
|
||||
The `devicemapper` driver stores every image and container on its own virtual
|
||||
device. These devices are thin-provisioned copy-on-write snapshot devices.
|
||||
Device Mapper technology works at the block level rather than the file level.
|
||||
This means that `devicemapper` storage driver's thin provisioning and
|
||||
copy-on-write operations work with blocks rather than entire files.
|
||||
|
||||
>**Note**: Snapshots are also referred to as *thin devices* or *virtual
|
||||
>devices*. They all mean the same thing in the context of the `devicemapper`
|
||||
>storage driver.
|
||||
|
||||
With `devicemapper` the high level process for creating images is as follows:
|
||||
|
||||
1. The `devicemapper` storage driver creates a thin pool.
|
||||
|
||||
The pool is created from block devices or loop mounted sparse files (more
|
||||
on this later).
|
||||
|
||||
2. Next it creates a *base device*.
|
||||
|
||||
A base device is a thin device with a filesystem. You can see which
|
||||
filesystem is in use by running the `docker info` command and checking the
|
||||
`Backing filesystem` value.
|
||||
|
||||
3. Each new image (and image layer) is a snapshot of this base device.
|
||||
|
||||
These are thin provisioned copy-on-write snapshots. This means that they
|
||||
are initially empty and only consume space from the pool when data is written
|
||||
to them.
|
||||
|
||||
With `devicemapper`, container layers are snapshots of the image they are
|
||||
created from. Just as with images, container snapshots are thin provisioned
|
||||
copy-on-write snapshots. The container snapshot stores all updates to the
|
||||
container. The `devicemapper` allocates space to them on-demand from the pool
|
||||
as and when data is written to the container.
|
||||
|
||||
The high level diagram below shows a thin pool with a base device and two
|
||||
images.
|
||||
|
||||

|
||||
|
||||
If you look closely at the diagram you'll see that it's snapshots all the way
|
||||
down. Each image layer is a snapshot of the layer below it. The lowest layer of
|
||||
each image is a snapshot of the the base device that exists in the pool. This
|
||||
base device is a `Device Mapper` artifact and not a Docker image layer.
|
||||
|
||||
A container is a snapshot of the image it is created from. The diagram below
|
||||
shows two containers - one based on the Ubuntu image and the other based on the
|
||||
Busybox image.
|
||||
|
||||

|
||||
|
||||
|
||||
## Reads with the devicemapper
|
||||
|
||||
Let's look at how reads and writes occur using the `devicemapper` storage
|
||||
driver. The diagram below shows the high level process for reading a single
|
||||
block (`0x44f`) in an example container.
|
||||
|
||||

|
||||
|
||||
1. An application makes a read request for block `0x44f` in the container.
|
||||
|
||||
Because the container is a thin snapshot of an image it does not have the
|
||||
data. Instead, it has a pointer (PTR) to where the data is stored in the image
|
||||
snapshot lower down in the image stack.
|
||||
|
||||
2. The storage driver follows the pointer to block `0xf33` in the snapshot
|
||||
relating to image layer `a005...`.
|
||||
|
||||
3. The `devicemapper` copies the contents of block `0xf33` from the image
|
||||
snapshot to memory in the container.
|
||||
|
||||
4. The storage driver returns the data to the requesting application.
|
||||
|
||||
### Write examples
|
||||
|
||||
With the `devicemapper` driver, writing new data to a container is accomplished
|
||||
by an *allocate-on-demand* operation. Updating existing data uses a
|
||||
copy-on-write operation. Because Device Mapper is a block-based technology
|
||||
these operations occur at the block level.
|
||||
|
||||
For example, when making a small change to a large file in a container, the
|
||||
`devicemapper` storage driver does not copy the entire file. It only copies the
|
||||
blocks to be modified. Each block is 64KB.
|
||||
|
||||
#### Writing new data
|
||||
|
||||
To write 56KB of new data to a container:
|
||||
|
||||
1. An application makes a request to write 56KB of new data to the container.
|
||||
|
||||
2. The allocate-on-demand operation allocates a single new 64KB block to the
|
||||
container's snapshot.
|
||||
|
||||
If the write operation is larger than 64KB, multiple new blocks are
|
||||
allocated to the container's snapshot.
|
||||
|
||||
3. The data is written to the newly allocated block.
|
||||
|
||||
#### Overwriting existing data
|
||||
|
||||
To modify existing data for the first time:
|
||||
|
||||
1. An application makes a request to modify some data in the container.
|
||||
|
||||
2. A copy-on-write operation locates the blocks that need updating.
|
||||
|
||||
3. The operation allocates new empty blocks to the container snapshot and
|
||||
copies the data into those blocks.
|
||||
|
||||
4. The modified data is written into the newly allocated blocks.
|
||||
|
||||
The application in the container is unaware of any of these
|
||||
allocate-on-demand and copy-on-write operations. However, they may add latency
|
||||
to the application's read and write operations.
|
||||
|
||||
## Configuring Docker with Device Mapper
|
||||
|
||||
The `devicemapper` is the default Docker storage driver on some Linux
|
||||
distributions. This includes RHEL and most of its forks. Currently, the
|
||||
following distributions support the driver:
|
||||
|
||||
* RHEL/CentOS/Fedora
|
||||
* Ubuntu 12.04
|
||||
* Ubuntu 14.04
|
||||
* Debian
|
||||
|
||||
Docker hosts running the `devicemapper` storage driver default to a
|
||||
configuration mode known as `loop-lvm`. This mode uses sparse files to build
|
||||
the thin pool used by image and container snapshots. The mode is designed to
|
||||
work out-of-the-box with no additional configuration. However, production
|
||||
deployments should not run under `loop-lvm` mode.
|
||||
|
||||
You can detect the mode by viewing the `docker info` command:
|
||||
|
||||
$ sudo docker info
|
||||
Containers: 0
|
||||
Images: 0
|
||||
Storage Driver: devicemapper
|
||||
Pool Name: docker-202:2-25220302-pool
|
||||
Pool Blocksize: 65.54 kB
|
||||
Backing Filesystem: xfs
|
||||
...
|
||||
Data loop file: /var/lib/docker/devicemapper/devicemapper/data
|
||||
Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
|
||||
Library Version: 1.02.93-RHEL7 (2015-01-28)
|
||||
...
|
||||
|
||||
The output above shows a Docker host running with the `devicemapper` storage
|
||||
driver operating in `loop-lvm` mode. This is indicated by the fact that the
|
||||
`Data loop file` and a `Metadata loop file` are on files under
|
||||
`/var/lib/docker/devicemapper/devicemapper`. These are loopback mounted sparse
|
||||
files.
|
||||
|
||||
### Configure direct-lvm mode for production
|
||||
|
||||
The preferred configuration for production deployments is `direct lvm`. This
|
||||
mode uses block devices to create the thin pool. The following procedure shows
|
||||
you how to configure a Docker host to use the `devicemapper` storage driver in
|
||||
a `direct-lvm` configuration.
|
||||
|
||||
> **Caution:** If you have already run the Docker daemon on your Docker host
|
||||
> and have images you want to keep, `push` them Docker Hub or your private
|
||||
> Docker Trusted Registry before attempting this procedure.
|
||||
|
||||
The procedure below will create a 90GB data volume and 4GB metadata volume to
|
||||
use as backing for the storage pool. It assumes that you have a spare block
|
||||
device at `/dev/xvdf` with enough free space to complete the task. The device
|
||||
identifier and volume sizes may be be different in your environment and you
|
||||
should substitute your own values throughout the procedure. The procedure also
|
||||
assumes that the Docker daemon is in the `stopped` state.
|
||||
|
||||
1. Log in to the Docker host you want to configure and stop the Docker daemon.
|
||||
|
||||
2. If it exists, delete your existing image store by removing the
|
||||
`/var/lib/docker` directory.
|
||||
|
||||
$ sudo rm -rf /var/lib/docker
|
||||
|
||||
3. Create an LVM physical volume (PV) on your spare block device using the
|
||||
`pvcreate` command.
|
||||
|
||||
$ sudo pvcreate /dev/xvdf
|
||||
Physical volume `/dev/xvdf` successfully created
|
||||
|
||||
The device identifier may be different on your system. Remember to
|
||||
substitute your value in the command above.
|
||||
|
||||
4. Create a new volume group (VG) called `vg-docker` using the PV created in
|
||||
the previous step.
|
||||
|
||||
$ sudo vgcreate vg-docker /dev/xvdf
|
||||
Volume group `vg-docker` successfully created
|
||||
|
||||
5. Create a new 90GB logical volume (LV) called `data` from space in the
|
||||
`vg-docker` volume group.
|
||||
|
||||
$ sudo lvcreate -L 90G -n data vg-docker
|
||||
Logical volume `data` created.
|
||||
|
||||
The command creates an LVM logical volume called `data` and an associated
|
||||
block device file at `/dev/vg-docker/data`. In a later step, you instruct the
|
||||
`devicemapper` storage driver to use this block device to store image and
|
||||
container data.
|
||||
|
||||
If you receive a signature detection warning, make sure you are working on
|
||||
the correct devices before continuing. Signature warnings indicate that the
|
||||
device you're working on is currently in use by LVM or has been used by LVM in
|
||||
the past.
|
||||
|
||||
6. Create a new logical volume (LV) called `metadata` from space in the
|
||||
`vg-docker` volume group.
|
||||
|
||||
$ sudo lvcreate -L 4G -n metadata vg-docker
|
||||
Logical volume `metadata` created.
|
||||
|
||||
This creates an LVM logical volume called `metadata` and an associated
|
||||
block device file at `/dev/vg-docker/metadata`. In the next step you instruct
|
||||
the `devicemapper` storage driver to use this block device to store image and
|
||||
container metadata.
|
||||
|
||||
7. Start the Docker daemon with the `devicemapper` storage driver and the
|
||||
`--storage-opt` flags.
|
||||
|
||||
The `data` and `metadata` devices that you pass to the `--storage-opt`
|
||||
options were created in the previous steps.
|
||||
|
||||
$ sudo docker daemon --storage-driver=devicemapper --storage-opt dm.datadev=/dev/vg-docker/data --storage-opt dm.metadatadev=/dev/vg-docker/metadata &
|
||||
[1] 2163
|
||||
[root@ip-10-0-0-75 centos]# INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
|
||||
INFO[0027] Option DefaultDriver: bridge
|
||||
INFO[0027] Option DefaultNetwork: bridge
|
||||
<output truncated>
|
||||
INFO[0027] Daemon has completed initialization
|
||||
INFO[0027] Docker daemon commit=0a8c2e3 execdriver=native-0.2 graphdriver=devicemapper version=1.8.2
|
||||
|
||||
It is also possible to set the `--storage-driver` and `--storage-opt` flags
|
||||
in the Docker config file and start the daemon normally using the `service` or
|
||||
`systemd` commands.
|
||||
|
||||
8. Use the `docker info` command to verify that the daemon is using `data` and
|
||||
`metadata` devices you created.
|
||||
|
||||
$ sudo docker info
|
||||
INFO[0180] GET /v1.20/info
|
||||
Containers: 0
|
||||
Images: 0
|
||||
Storage Driver: devicemapper
|
||||
Pool Name: docker-202:1-1032-pool
|
||||
Pool Blocksize: 65.54 kB
|
||||
Backing Filesystem: xfs
|
||||
Data file: /dev/vg-docker/data
|
||||
Metadata file: /dev/vg-docker/metadata
|
||||
[...]
|
||||
|
||||
The output of the command above shows the storage driver as `devicemapper`.
|
||||
The last two lines also confirm that the correct devices are being used for
|
||||
the `Data file` and the `Metadata file`.
|
||||
|
||||
### Examine devicemapper structures on the host
|
||||
|
||||
You can use the `lsblk` command to see the device files created above and the
|
||||
`pool` that the `devicemapper` storage driver creates on top of them.
|
||||
|
||||
$ sudo lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
|
||||
xvda 202:0 0 8G 0 disk
|
||||
└─xvda1 202:1 0 8G 0 part /
|
||||
xvdf 202:80 0 10G 0 disk
|
||||
├─vg--docker-data 253:0 0 90G 0 lvm
|
||||
│ └─docker-202:1-1032-pool 253:2 0 10G 0 dm
|
||||
└─vg--docker-metadata 253:1 0 4G 0 lvm
|
||||
└─docker-202:1-1032-pool 253:2 0 10G 0 dm
|
||||
|
||||
The diagram below shows the image from prior examples updated with the detail
|
||||
from the `lsblk` command above.
|
||||
|
||||

|
||||
|
||||
In the diagram, the pool is named `Docker-202:1-1032-pool` and spans the `data`
|
||||
and `metadata` devices created earlier. The `devicemapper` constructs the pool
|
||||
name as follows:
|
||||
|
||||
```
|
||||
Docker-MAJ:MIN-INO-pool
|
||||
```
|
||||
|
||||
`MAJ`, `MIN` and `INO` refer to the major and minor device numbers and inode.
|
||||
|
||||
Because Device Mapper operates at the block level it is more difficult to see
|
||||
diffs between image layers and containers. Docker 1.10 and later no longer
|
||||
matches image layer IDs with directory names in `/var/lib/docker`. However,
|
||||
there are two key directories. The `/var/lib/docker/devicemapper/mnt` directory
|
||||
contains the mount points for image and container layers. The
|
||||
`/var/lib/docker/devicemapper/metadata`directory contains one file for every
|
||||
image layer and container snapshot. The files contain metadata about each
|
||||
snapshot in JSON format.
|
||||
|
||||
## Device Mapper and Docker performance
|
||||
|
||||
It is important to understand the impact that allocate-on-demand and
|
||||
copy-on-write operations can have on overall container performance.
|
||||
|
||||
### Allocate-on-demand performance impact
|
||||
|
||||
The `devicemapper` storage driver allocates new blocks to a container via an
|
||||
allocate-on-demand operation. This means that each time an app writes to
|
||||
somewhere new inside a container, one or more empty blocks has to be located
|
||||
from the pool and mapped into the container.
|
||||
|
||||
All blocks are 64KB. A write that uses less than 64KB still results in a single
|
||||
64KB block being allocated. Writing more than 64KB of data uses multiple 64KB
|
||||
blocks. This can impact container performance, especially in containers that
|
||||
perform lots of small writes. However, once a block is allocated to a container
|
||||
subsequent reads and writes can operate directly on that block.
|
||||
|
||||
### Copy-on-write performance impact
|
||||
|
||||
Each time a container updates existing data for the first time, the
|
||||
`devicemapper` storage driver has to perform a copy-on-write operation. This
|
||||
copies the data from the image snapshot to the container's snapshot. This
|
||||
process can have a noticeable impact on container performance.
|
||||
|
||||
All copy-on-write operations have a 64KB granularity. As a results, updating
|
||||
32KB of a 1GB file causes the driver to copy a single 64KB block into the
|
||||
container's snapshot. This has obvious performance advantages over file-level
|
||||
copy-on-write operations which would require copying the entire 1GB file into
|
||||
the container layer.
|
||||
|
||||
In practice, however, containers that perform lots of small block writes
|
||||
(<64KB) can perform worse with `devicemapper` than with AUFS.
|
||||
|
||||
### Other device mapper performance considerations
|
||||
|
||||
There are several other things that impact the performance of the
|
||||
`devicemapper` storage driver.
|
||||
|
||||
- **The mode.** The default mode for Docker running the `devicemapper` storage
|
||||
driver is `loop-lvm`. This mode uses sparse files and suffers from poor
|
||||
performance. It is **not recommended for production**. The recommended mode for
|
||||
production environments is `direct-lvm` where the storage driver writes
|
||||
directly to raw block devices.
|
||||
|
||||
- **High speed storage.** For best performance you should place the `Data file`
|
||||
and `Metadata file` on high speed storage such as SSD. This can be direct
|
||||
attached storage or from a SAN or NAS array.
|
||||
|
||||
- **Memory usage.** `devicemapper` is not the most memory efficient Docker
|
||||
storage driver. Launching *n* copies of the same container loads *n* copies of
|
||||
its files into memory. This can have a memory impact on your Docker host. As a
|
||||
result, the `devicemapper` storage driver may not be the best choice for PaaS
|
||||
and other high density use cases.
|
||||
|
||||
One final point, data volumes provide the best and most predictable
|
||||
performance. This is because they bypass the storage driver and do not incur
|
||||
any of the potential overheads introduced by thin provisioning and
|
||||
copy-on-write. For this reason, you should to place heavy write workloads on
|
||||
data volumes.
|
||||
|
||||
## Related Information
|
||||
|
||||
* [Understand images, containers, and storage drivers](imagesandcontainers.md)
|
||||
* [Select a storage driver](selectadriver.md)
|
||||
* [AUFS storage driver in practice](aufs-driver.md)
|
||||
* [Btrfs storage driver in practice](btrfs-driver.md)
|
||||
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/aufs_delete.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/aufs_layers.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/aufs_metadata.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/base_device.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/btfs_constructs.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/btfs_container_layer.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/btfs_layers.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/btfs_pool.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/btfs_snapshots.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/btfs_subvolume.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/container-layers-cas.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/container-layers.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/dm_container.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/driver-pros-cons.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/image-layers.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/overlay_constructs.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/overlay_constructs2.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/saving-space.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/shared-uuid.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 246 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/shared-volume.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/sharing-layers.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/two_dm_container.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/zfs_clones.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/zfs_zpool.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/images/zpool_blocks.jpg
generated
vendored
Normal file
|
After Width: | Height: | Size: 42 KiB |
495
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/imagesandcontainers.md
generated
vendored
Normal file
@@ -0,0 +1,495 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Understand images, containers, and storage drivers"
|
||||
description = "Learn the technologies that support storage drivers."
|
||||
keywords = ["container, storage, driver, AUFS, btfs, devicemapper,zvfs"]
|
||||
[menu.main]
|
||||
parent = "engine_driver"
|
||||
weight = -2
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
|
||||
# Understand images, containers, and storage drivers
|
||||
|
||||
To use storage drivers effectively, you must understand how Docker builds and
|
||||
stores images. Then, you need an understanding of how these images are used by
|
||||
containers. Finally, you'll need a short introduction to the technologies that
|
||||
enable both images and container operations.
|
||||
|
||||
## Images and layers
|
||||
|
||||
Each Docker image references a list of read-only layers that represent
|
||||
filesystem differences. Layers are stacked on top of each other to form a base
|
||||
for a container's root filesystem. The diagram below shows the Ubuntu 15.04
|
||||
image comprising 4 stacked image layers.
|
||||
|
||||

|
||||
|
||||
The Docker storage driver is responsible for stacking these layers and
|
||||
providing a single unified view.
|
||||
|
||||
When you create a new container, you add a new, thin, writable layer on top of
|
||||
the underlying stack. This layer is often called the "container layer". All
|
||||
changes made to the running container - such as writing new files, modifying
|
||||
existing files, and deleting files - are written to this thin writable
|
||||
container layer. The diagram below shows a container based on the Ubuntu 15.04
|
||||
image.
|
||||
|
||||

|
||||
|
||||
### Content addressable storage
|
||||
|
||||
Docker 1.10 introduced a new content addressable storage model. This is a
|
||||
completely new way to address image and layer data on disk. Previously, image
|
||||
and layer data was referenced and stored using a a randomly generated UUID. In
|
||||
the new model this is replaced by a secure *content hash*.
|
||||
|
||||
The new model improves security, provides a built-in way to avoid ID
|
||||
collisions, and guarantees data integrity after pull, push, load, and save
|
||||
operations. It also enables better sharing of layers by allowing many images to
|
||||
freely share their layers even if they didn’t come from the same build.
|
||||
|
||||
The diagram below shows an updated version of the previous diagram,
|
||||
highlighting the changes implemented by Docker 1.10.
|
||||
|
||||

|
||||
|
||||
As can be seen, all image layer IDs are cryptographic hashes, whereas the
|
||||
container ID is still a randomly generated UUID.
|
||||
|
||||
There are several things to note regarding the new model. These include:
|
||||
|
||||
1. Migration of existing images
|
||||
2. Image and layer filesystem structures
|
||||
|
||||
Existing images, those created and pulled by earlier versions of Docker, need
|
||||
to be migrated before they can be used with the new model. This migration
|
||||
involves calculating new secure checksums and is performed automatically the
|
||||
first time you start an updated Docker daemon. After the migration is complete,
|
||||
all images and tags will have brand new secure IDs.
|
||||
|
||||
Although the migration is automatic and transparent, it is computationally
|
||||
intensive. This means it and can take time if you have lots of image data.
|
||||
During this time your Docker daemon will not respond to other requests.
|
||||
|
||||
A migration tool exists that allows you to migrate existing images to the new
|
||||
format before upgrading your Docker daemon. This means that upgraded Docker
|
||||
daemons do not need to perform the migration in-band, and therefore avoids any
|
||||
associated downtime. It also provides a way to manually migrate existing images
|
||||
so that they can be distributed to other Docker daemons in your environment
|
||||
that are already running the latest versions of Docker.
|
||||
|
||||
The migration tool is provided by Docker, Inc., and runs as a container. You
|
||||
can download it from [https://github.com/docker/v1.10-migrator/releases](https://github.com/docker/v1.10-migrator/releases).
|
||||
|
||||
While running the "migrator" image you need to expose your Docker host's data
|
||||
directory to the container. If you are using the default Docker data path, the
|
||||
command to run the container will look like this
|
||||
|
||||
$ sudo docker run --rm -v /var/lib/docker:/var/lib/docker docker/v1.10-migrator
|
||||
|
||||
If you use the `devicemapper` storage driver, you will need to include the
|
||||
`--privileged` option so that the container has access to your storage devices.
|
||||
|
||||
#### Migration example
|
||||
|
||||
The following example shows the migration tool in use on a Docker host running
|
||||
version 1.9.1 of the Docker daemon and the AUFS storage driver. The Docker host
|
||||
is running on a **t2.micro** AWS EC2 instance with 1 vCPU, 1GB RAM, and a
|
||||
single 8GB general purpose SSD EBS volume. The Docker data directory
|
||||
(`/var/lib/docker`) was consuming 2GB of space.
|
||||
|
||||
$ docker images
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
jenkins latest 285c9f0f9d3d 17 hours ago 708.5 MB
|
||||
mysql latest d39c3fa09ced 8 days ago 360.3 MB
|
||||
mongo latest a74137af4532 13 days ago 317.4 MB
|
||||
postgres latest 9aae83d4127f 13 days ago 270.7 MB
|
||||
redis latest 8bccd73928d9 2 weeks ago 151.3 MB
|
||||
centos latest c8a648134623 4 weeks ago 196.6 MB
|
||||
ubuntu 15.04 c8be1ac8145a 7 weeks ago 131.3 MB
|
||||
|
||||
$ du -hs /var/lib/docker
|
||||
2.0G /var/lib/docker
|
||||
|
||||
$ time docker run --rm -v /var/lib/docker:/var/lib/docker docker/v1.10-migrator
|
||||
Unable to find image 'docker/v1.10-migrator:latest' locally
|
||||
latest: Pulling from docker/v1.10-migrator
|
||||
ed1f33c5883d: Pull complete
|
||||
b3ca410aa2c1: Pull complete
|
||||
2b9c6ed9099e: Pull complete
|
||||
dce7e318b173: Pull complete
|
||||
Digest: sha256:bd2b245d5d22dd94ec4a8417a9b81bb5e90b171031c6e216484db3fe300c2097
|
||||
Status: Downloaded newer image for docker/v1.10-migrator:latest
|
||||
time="2016-01-27T12:31:06Z" level=debug msg="Assembling tar data for 01e70da302a553ba13485ad020a0d77dbb47575a31c4f48221137bb08f45878d from /var/lib/docker/aufs/diff/01e70da302a553ba13485ad020a0d77dbb47575a31c4f48221137bb08f45878d"
|
||||
time="2016-01-27T12:31:06Z" level=debug msg="Assembling tar data for 07ac220aeeef9febf1ac16a9d1a4eff7ef3c8cbf5ed0be6b6f4c35952ed7920d from /var/lib/docker/aufs/diff/07ac220aeeef9febf1ac16a9d1a4eff7ef3c8cbf5ed0be6b6f4c35952ed7920d"
|
||||
<snip>
|
||||
time="2016-01-27T12:32:00Z" level=debug msg="layer dbacfa057b30b1feaf15937c28bd8ca0d6c634fc311ccc35bd8d56d017595d5b took 10.80 seconds"
|
||||
|
||||
real 0m59.583s
|
||||
user 0m0.046s
|
||||
sys 0m0.008s
|
||||
|
||||
The Unix `time` command prepends the `docker run` command to produce timings
|
||||
for the operation. As can be seen, the overall time taken to migrate 7 images
|
||||
comprising 2GB of disk space took approximately 1 minute. However, this
|
||||
included the time taken to pull the `docker/v1.10-migrator` image
|
||||
(approximately 3.5 seconds). The same operation on an m4.10xlarge EC2 instance
|
||||
with 40 vCPUs, 160GB RAM and an 8GB provisioned IOPS EBS volume resulted in the
|
||||
following improved timings:
|
||||
|
||||
real 0m9.871s
|
||||
user 0m0.094s
|
||||
sys 0m0.021s
|
||||
|
||||
This shows that the migration operation is affected by the hardware spec of the
|
||||
machine performing the migration.
|
||||
|
||||
## Container and layers
|
||||
|
||||
The major difference between a container and an image is the top writable
|
||||
layer. All writes to the container that add new or modify existing data are
|
||||
stored in this writable layer. When the container is deleted the writable layer
|
||||
is also deleted. The underlying image remains unchanged.
|
||||
|
||||
Because each container has its own thin writable container layer, and all
|
||||
changes are stored this container layer, this means that multiple containers
|
||||
can share access to the same underlying image and yet have their own data
|
||||
state. The diagram below shows multiple containers sharing the same Ubuntu
|
||||
15.04 image.
|
||||
|
||||

|
||||
|
||||
The Docker storage driver is responsible for enabling and managing both the
|
||||
image layers and the writable container layer. How a storage driver
|
||||
accomplishes these can vary between drivers. Two key technologies behind Docker
|
||||
image and container management are stackable image layers and copy-on-write
|
||||
(CoW).
|
||||
|
||||
|
||||
## The copy-on-write strategy
|
||||
|
||||
Sharing is a good way to optimize resources. People do this instinctively in
|
||||
daily life. For example, twins Jane and Joseph taking an Algebra class at
|
||||
different times from different teachers can share the same exercise book by
|
||||
passing it between each other. Now, suppose Jane gets an assignment to complete
|
||||
the homework on page 11 in the book. At that point, Jane copies page 11,
|
||||
completes the homework, and hands in her copy. The original exercise book is
|
||||
unchanged and only Jane has a copy of the changed page 11.
|
||||
|
||||
Copy-on-write is a similar strategy of sharing and copying. In this strategy,
|
||||
system processes that need the same data share the same instance of that data
|
||||
rather than having their own copy. At some point, if one process needs to
|
||||
modify or write to the data, only then does the operating system make a copy of
|
||||
the data for that process to use. Only the process that needs to write has
|
||||
access to the data copy. All the other processes continue to use the original
|
||||
data.
|
||||
|
||||
Docker uses a copy-on-write technology with both images and containers. This
|
||||
CoW strategy optimizes both image disk space usage and the performance of
|
||||
container start times. The next sections look at how copy-on-write is leveraged
|
||||
with images and containers through sharing and copying.
|
||||
|
||||
### Sharing promotes smaller images
|
||||
|
||||
This section looks at image layers and copy-on-write technology. All image and
|
||||
container layers exist inside the Docker host's *local storage area* and are
|
||||
managed by the storage driver. On Linux-based Docker hosts this is usually
|
||||
located under `/var/lib/docker/`.
|
||||
|
||||
The Docker client reports on image layers when instructed to pull and push
|
||||
images with `docker pull` and `docker push`. The command below pulls the
|
||||
`ubuntu:15.04` Docker image from Docker Hub.
|
||||
|
||||
$ docker pull ubuntu:15.04
|
||||
15.04: Pulling from library/ubuntu
|
||||
1ba8ac955b97: Pull complete
|
||||
f157c4e5ede7: Pull complete
|
||||
0b7e98f84c4c: Pull complete
|
||||
a3ed95caeb02: Pull complete
|
||||
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
|
||||
Status: Downloaded newer image for ubuntu:15.04
|
||||
|
||||
From the output, you'll see that the command actually pulls 4 image layers.
|
||||
Each of the above lines lists an image layer and its UUID or cryptographic
|
||||
hash. The combination of these four layers makes up the `ubuntu:15.04` Docker
|
||||
image.
|
||||
|
||||
Each of these layers is stored in its own directory inside the Docker host's
|
||||
local storage are.
|
||||
|
||||
Versions of Docker prior to 1.10 stored each layer in a directory with the same
|
||||
name as the image layer ID. However, this is not the case for images pulled
|
||||
with Docker version 1.10 and later. For example, the command below shows an
|
||||
image being pulled from Docker Hub, followed by a directory listing on a host
|
||||
running version 1.9.1 of the Docker Engine.
|
||||
|
||||
$ docker pull ubuntu:15.04
|
||||
15.04: Pulling from library/ubuntu
|
||||
47984b517ca9: Pull complete
|
||||
df6e891a3ea9: Pull complete
|
||||
e65155041eed: Pull complete
|
||||
c8be1ac8145a: Pull complete
|
||||
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
|
||||
Status: Downloaded newer image for ubuntu:15.04
|
||||
|
||||
$ ls /var/lib/docker/aufs/layers
|
||||
47984b517ca9ca0312aced5c9698753ffa964c2015f2a5f18e5efa9848cf30e2
|
||||
c8be1ac8145a6e59a55667f573883749ad66eaeef92b4df17e5ea1260e2d7356
|
||||
df6e891a3ea9cdce2a388a2cf1b1711629557454fd120abd5be6d32329a0e0ac
|
||||
e65155041eed7ec58dea78d90286048055ca75d41ea893c7246e794389ecf203
|
||||
|
||||
Notice how the four directories match up with the layer IDs of the downloaded
|
||||
image. Now compare this with the same operations performed on a host running
|
||||
version 1.10 of the Docker Engine.
|
||||
|
||||
$ docker pull ubuntu:15.04
|
||||
15.04: Pulling from library/ubuntu
|
||||
1ba8ac955b97: Pull complete
|
||||
f157c4e5ede7: Pull complete
|
||||
0b7e98f84c4c: Pull complete
|
||||
a3ed95caeb02: Pull complete
|
||||
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
|
||||
Status: Downloaded newer image for ubuntu:15.04
|
||||
|
||||
$ ls /var/lib/docker/aufs/layers/
|
||||
1d6674ff835b10f76e354806e16b950f91a191d3b471236609ab13a930275e24
|
||||
5dbb0cbe0148cf447b9464a358c1587be586058d9a4c9ce079320265e2bb94e7
|
||||
bef7199f2ed8e86fa4ada1309cfad3089e0542fec8894690529e4c04a7ca2d73
|
||||
ebf814eccfe98f2704660ca1d844e4348db3b5ccc637eb905d4818fbfb00a06a
|
||||
|
||||
See how the four directories do not match up with the image layer IDs pulled in
|
||||
the previous step.
|
||||
|
||||
Despite the differences between image management before and after version 1.10,
|
||||
all versions of Docker still allow images to share layers. For example, If you
|
||||
`pull` an image that shares some of the same image layers as an image that has
|
||||
already been pulled, the Docker daemon recognizes this, and only pulls the
|
||||
layers it doesn't already have stored locally. After the second pull, the two
|
||||
images will share any common image layers.
|
||||
|
||||
You can illustrate this now for yourself. Starting with the `ubuntu:15.04`
|
||||
image that you just pulled, make a change to it, and build a new image based on
|
||||
the change. One way to do this is using a `Dockerfile` and the `docker build`
|
||||
command.
|
||||
|
||||
1. In an empty directory, create a simple `Dockerfile` that starts with the
|
||||
2. ubuntu:15.04 image.
|
||||
|
||||
FROM ubuntu:15.04
|
||||
|
||||
2. Add a new file called "newfile" in the image's `/tmp` directory with the
|
||||
3. text "Hello world" in it.
|
||||
|
||||
When you are done, the `Dockerfile` contains two lines:
|
||||
|
||||
FROM ubuntu:15.04
|
||||
|
||||
RUN echo "Hello world" > /tmp/newfile
|
||||
|
||||
3. Save and close the file.
|
||||
|
||||
4. From a terminal in the same folder as your `Dockerfile`, run the following
|
||||
5. command:
|
||||
|
||||
$ docker build -t changed-ubuntu .
|
||||
Sending build context to Docker daemon 2.048 kB
|
||||
Step 1 : FROM ubuntu:15.04
|
||||
---> 3f7bcee56709
|
||||
Step 2 : RUN echo "Hello world" > /tmp/newfile
|
||||
---> Running in d14acd6fad4e
|
||||
---> 94e6b7d2c720
|
||||
Removing intermediate container d14acd6fad4e
|
||||
Successfully built 94e6b7d2c720
|
||||
|
||||
> **Note:** The period (.) at the end of the above command is important. It
|
||||
> tells the `docker build` command to use the current working directory as
|
||||
> its build context.
|
||||
|
||||
The output above shows a new image with image ID `94e6b7d2c720`.
|
||||
|
||||
5. Run the `docker images` command to verify the new `changed-ubuntu` image is
|
||||
6. in the Docker host's local storage area.
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
changed-ubuntu latest 03b964f68d06 33 seconds ago 131.4 MB
|
||||
ubuntu 15.04 013f3d01d247 6 weeks ago 131.3 MB
|
||||
|
||||
6. Run the `docker history` command to see which image layers were used to
|
||||
7. create the new `changed-ubuntu` image.
|
||||
|
||||
$ docker history changed-ubuntu
|
||||
IMAGE CREATED CREATED BY SIZE COMMENT
|
||||
94e6b7d2c720 2 minutes ago /bin/sh -c echo "Hello world" > /tmp/newfile 12 B
|
||||
3f7bcee56709 6 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
|
||||
<missing> 6 weeks ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/ 1.879 kB
|
||||
<missing> 6 weeks ago /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic 701 B
|
||||
<missing> 6 weeks ago /bin/sh -c #(nop) ADD file:8e4943cd86e9b2ca13 131.3 MB
|
||||
|
||||
The `docker history` output shows the new `94e6b7d2c720` image layer at the
|
||||
top. You know that this is the new image layer added because it was created
|
||||
by the `echo "Hello world" > /tmp/newfile` command in your `Dockerfile`.
|
||||
The 4 image layers below it are the exact same image layers
|
||||
that make up the `ubuntu:15.04` image.
|
||||
|
||||
> **Note:** Under the content addressable storage model introduced with Docker
|
||||
> 1.10, image history data is no longer stored in a config file with each image
|
||||
> layer. It is now stored as a string of text in a single config file that
|
||||
> relates to the overall image. This can result in some image layers showing as
|
||||
> "missing" in the output of the `docker history` command. This is normal
|
||||
> behaviour and can be ignored.
|
||||
>
|
||||
> You may hear images like these referred to as *flat images*.
|
||||
|
||||
Notice the new `changed-ubuntu` image does not have its own copies of every
|
||||
layer. As can be seen in the diagram below, the new image is sharing its four
|
||||
underlying layers with the `ubuntu:15.04` image.
|
||||
|
||||

|
||||
|
||||
The `docker history` command also shows the size of each image layer. As you
|
||||
can see, the `94e6b7d2c720` layer is only consuming 12 Bytes of disk space.
|
||||
This means that the `changed-ubuntu` image we just created is only consuming an
|
||||
additional 12 Bytes of disk space on the Docker host - all layers below the
|
||||
`94e6b7d2c720` layer already exist on the Docker host and are shared by other
|
||||
images.
|
||||
|
||||
This sharing of image layers is what makes Docker images and containers so
|
||||
space efficient.
|
||||
|
||||
### Copying makes containers efficient
|
||||
|
||||
You learned earlier that a container is a Docker image with a thin writable,
|
||||
container layer added. The diagram below shows the layers of a container based
|
||||
on the `ubuntu:15.04` image:
|
||||
|
||||

|
||||
|
||||
All writes made to a container are stored in the thin writable container layer.
|
||||
The other layers are read-only (RO) image layers and can't be changed. This
|
||||
means that multiple containers can safely share a single underlying image. The
|
||||
diagram below shows multiple containers sharing a single copy of the
|
||||
`ubuntu:15.04` image. Each container has its own thin RW layer, but they all
|
||||
share a single instance of the ubuntu:15.04 image:
|
||||
|
||||

|
||||
|
||||
When an existing file in a container is modified, Docker uses the storage
|
||||
driver to perform a copy-on-write operation. The specifics of operation depends
|
||||
on the storage driver. For the AUFS and OverlayFS storage drivers, the
|
||||
copy-on-write operation is pretty much as follows:
|
||||
|
||||
* Search through the image layers for the file to update. The process starts
|
||||
at the top, newest layer and works down to the base layer one layer at a
|
||||
time.
|
||||
* Perform a "copy-up" operation on the first copy of the file that is found. A
|
||||
"copy up" copies the file up to the container's own thin writable layer.
|
||||
* Modify the *copy of the file* in container's thin writable layer.
|
||||
|
||||
Btrfs, ZFS, and other drivers handle the copy-on-write differently. You can
|
||||
read more about the methods of these drivers later in their detailed
|
||||
descriptions.
|
||||
|
||||
Containers that write a lot of data will consume more space than containers
|
||||
that do not. This is because most write operations consume new space in the
|
||||
container's thin writable top layer. If your container needs to write a lot of
|
||||
data, you should consider using a data volume.
|
||||
|
||||
A copy-up operation can incur a noticeable performance overhead. This overhead
|
||||
is different depending on which storage driver is in use. However, large files,
|
||||
lots of layers, and deep directory trees can make the impact more noticeable.
|
||||
Fortunately, the operation only occurs the first time any particular file is
|
||||
modified. Subsequent modifications to the same file do not cause a copy-up
|
||||
operation and can operate directly on the file's existing copy already present
|
||||
in the container layer.
|
||||
|
||||
Let's see what happens if we spin up 5 containers based on our `changed-ubuntu`
|
||||
image we built earlier:
|
||||
|
||||
1. From a terminal on your Docker host, run the following `docker run` command
|
||||
5 times.
|
||||
|
||||
$ docker run -dit changed-ubuntu bash
|
||||
75bab0d54f3cf193cfdc3a86483466363f442fba30859f7dcd1b816b6ede82d4
|
||||
$ docker run -dit changed-ubuntu bash
|
||||
9280e777d109e2eb4b13ab211553516124a3d4d4280a0edfc7abf75c59024d47
|
||||
$ docker run -dit changed-ubuntu bash
|
||||
a651680bd6c2ef64902e154eeb8a064b85c9abf08ac46f922ad8dfc11bb5cd8a
|
||||
$ docker run -dit changed-ubuntu bash
|
||||
8eb24b3b2d246f225b24f2fca39625aaad71689c392a7b552b78baf264647373
|
||||
$ docker run -dit changed-ubuntu bash
|
||||
0ad25d06bdf6fca0dedc38301b2aff7478b3e1ce3d1acd676573bba57cb1cfef
|
||||
|
||||
This launches 5 containers based on the `changed-ubuntu` image. As each
|
||||
container is created, Docker adds a writable layer and assigns it a random
|
||||
UUID. This is the value returned from the `docker run` command.
|
||||
|
||||
2. Run the `docker ps` command to verify the 5 containers are running.
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
0ad25d06bdf6 changed-ubuntu "bash" About a minute ago Up About a minute stoic_ptolemy
|
||||
8eb24b3b2d24 changed-ubuntu "bash" About a minute ago Up About a minute pensive_bartik
|
||||
a651680bd6c2 changed-ubuntu "bash" 2 minutes ago Up 2 minutes hopeful_turing
|
||||
9280e777d109 changed-ubuntu "bash" 2 minutes ago Up 2 minutes backstabbing_mahavira
|
||||
75bab0d54f3c changed-ubuntu "bash" 2 minutes ago Up 2 minutes boring_pasteur
|
||||
|
||||
The output above shows 5 running containers, all sharing the
|
||||
`changed-ubuntu` image. Each `CONTAINER ID` is derived from the UUID when
|
||||
creating each container.
|
||||
|
||||
3. List the contents of the local storage area.
|
||||
|
||||
$ sudo ls /var/lib/docker/containers
|
||||
0ad25d06bdf6fca0dedc38301b2aff7478b3e1ce3d1acd676573bba57cb1cfef
|
||||
9280e777d109e2eb4b13ab211553516124a3d4d4280a0edfc7abf75c59024d47
|
||||
75bab0d54f3cf193cfdc3a86483466363f442fba30859f7dcd1b816b6ede82d4
|
||||
a651680bd6c2ef64902e154eeb8a064b85c9abf08ac46f922ad8dfc11bb5cd8a
|
||||
8eb24b3b2d246f225b24f2fca39625aaad71689c392a7b552b78baf264647373
|
||||
|
||||
Docker's copy-on-write strategy not only reduces the amount of space consumed
|
||||
by containers, it also reduces the time required to start a container. At start
|
||||
time, Docker only has to create the thin writable layer for each container.
|
||||
The diagram below shows these 5 containers sharing a single read-only (RO)
|
||||
copy of the `changed-ubuntu` image.
|
||||
|
||||

|
||||
|
||||
If Docker had to make an entire copy of the underlying image stack each time it
|
||||
started a new container, container start times and disk space used would be
|
||||
significantly increased.
|
||||
|
||||
## Data volumes and the storage driver
|
||||
|
||||
When a container is deleted, any data written to the container that is not
|
||||
stored in a *data volume* is deleted along with the container.
|
||||
|
||||
A data volume is a directory or file in the Docker host's filesystem that is
|
||||
mounted directly into a container. Data volumes are not controlled by the
|
||||
storage driver. Reads and writes to data volumes bypass the storage driver and
|
||||
operate at native host speeds. You can mount any number of data volumes into a
|
||||
container. Multiple containers can also share one or more data volumes.
|
||||
|
||||
The diagram below shows a single Docker host running two containers. Each
|
||||
container exists inside of its own address space within the Docker host's local
|
||||
storage area (`/var/lib/docker/...`). There is also a single shared data
|
||||
volume located at `/data` on the Docker host. This is mounted directly into
|
||||
both containers.
|
||||
|
||||

|
||||
|
||||
Data volumes reside outside of the local storage area on the Docker host,
|
||||
further reinforcing their independence from the storage driver's control. When
|
||||
a container is deleted, any data stored in data volumes persists on the Docker
|
||||
host.
|
||||
|
||||
For detailed information about data volumes
|
||||
[Managing data in containers](https://docs.docker.com/userguide/dockervolumes/).
|
||||
|
||||
## Related information
|
||||
|
||||
* [Select a storage driver](selectadriver.md)
|
||||
* [AUFS storage driver in practice](aufs-driver.md)
|
||||
* [Btrfs storage driver in practice](btrfs-driver.md)
|
||||
* [Device Mapper storage driver in practice](device-mapper-driver.md)
|
||||
38
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/index.md
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Docker storage drivers"
|
||||
description = "Learn how select the proper storage driver for your container."
|
||||
keywords = ["container, storage, driver, AUFS, btfs, devicemapper,zvfs"]
|
||||
[menu.main]
|
||||
identifier = "engine_driver"
|
||||
parent = "engine_guide"
|
||||
weight = 7
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
|
||||
# Docker storage drivers
|
||||
|
||||
Docker relies on driver technology to manage the storage and interactions associated with images and the containers that run them. This section contains the following pages:
|
||||
|
||||
* [Understand images, containers, and storage drivers](imagesandcontainers.md)
|
||||
* [Select a storage driver](selectadriver.md)
|
||||
* [AUFS storage driver in practice](aufs-driver.md)
|
||||
* [Btrfs storage driver in practice](btrfs-driver.md)
|
||||
* [Device Mapper storage driver in practice](device-mapper-driver.md)
|
||||
* [OverlayFS in practice](overlayfs-driver.md)
|
||||
* [ZFS storage in practice](zfs-driver.md)
|
||||
|
||||
If you are new to Docker containers make sure you read ["Understand images, containers, and storage drivers"](imagesandcontainers.md) first. It explains key concepts and technologies that can help you when working with storage drivers.
|
||||
|
||||
### Acknowledgement
|
||||
|
||||
The Docker storage driver material was created in large part by our guest author
|
||||
Nigel Poulton with a bit of help from Docker's own Jérôme Petazzoni. In his
|
||||
spare time Nigel creates [IT training
|
||||
videos](http://www.pluralsight.com/author/nigel-poulton), co-hosts the weekly
|
||||
[In Tech We Trust podcast](http://intechwetrustpodcast.com/), and lives it large
|
||||
on [Twitter](https://twitter.com/nigelpoulton).
|
||||
|
||||
|
||||
|
||||
299
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/overlayfs-driver.md
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "OverlayFS storage in practice"
|
||||
description = "Learn how to optimize your use of OverlayFS driver."
|
||||
keywords = ["container, storage, driver, OverlayFS "]
|
||||
[menu.main]
|
||||
parent = "engine_driver"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Docker and OverlayFS in practice
|
||||
|
||||
OverlayFS is a modern *union filesystem* that is similar to AUFS. In comparison
|
||||
to AUFS, OverlayFS:
|
||||
|
||||
* has a simpler design
|
||||
* has been in the mainline Linux kernel since version 3.18
|
||||
* is potentially faster
|
||||
|
||||
As a result, OverlayFS is rapidly gaining popularity in the Docker community
|
||||
and is seen by many as a natural successor to AUFS. As promising as OverlayFS
|
||||
is, it is still relatively young. Therefore caution should be taken before
|
||||
using it in production Docker environments.
|
||||
|
||||
Docker's `overlay` storage driver leverages several OverlayFS features to build
|
||||
and manage the on-disk structures of images and containers.
|
||||
|
||||
>**Note**: Since it was merged into the mainline kernel, the OverlayFS *kernel
|
||||
>module* was renamed from "overlayfs" to "overlay". As a result you may see the
|
||||
> two terms used interchangeably in some documentation. However, this document
|
||||
> uses "OverlayFS" to refer to the overall filesystem, and `overlay` to refer
|
||||
> to Docker's storage-driver.
|
||||
|
||||
## Image layering and sharing with OverlayFS
|
||||
|
||||
OverlayFS takes two directories on a single Linux host, layers one on top of
|
||||
the other, and provides a single unified view. These directories are often
|
||||
referred to as *layers* and the technology used to layer them is known as a
|
||||
*union mount*. The OverlayFS terminology is "lowerdir" for the bottom layer and
|
||||
"upperdir" for the top layer. The unified view is exposed through its own
|
||||
directory called "merged".
|
||||
|
||||
The diagram below shows how a Docker image and a Docker container are layered.
|
||||
The image layer is the "lowerdir" and the container layer is the "upperdir".
|
||||
The unified view is exposed through a directory called "merged" which is
|
||||
effectively the containers mount point. The diagram shows how Docker constructs
|
||||
map to OverlayFS constructs.
|
||||
|
||||

|
||||
|
||||
Notice how the image layer and container layer can contain the same files. When
|
||||
this happens, the files in the container layer ("upperdir") are dominant and
|
||||
obscure the existence of the same files in the image layer ("lowerdir"). The
|
||||
container mount ("merged") presents the unified view.
|
||||
|
||||
OverlayFS only works with two layers. This means that multi-layered images
|
||||
cannot be implemented as multiple OverlayFS layers. Instead, each image layer
|
||||
is implemented as its own directory under `/var/lib/docker/overlay`.
|
||||
Hard links are then used as a space-efficient way to reference data shared with
|
||||
lower layers. As of Docker 1.10, image layer IDs no longer correspond to
|
||||
directory names in `/var/lib/docker/`
|
||||
|
||||
To create a container, the `overlay` driver combines the directory representing
|
||||
the image's top layer plus a new directory for the container. The image's top
|
||||
layer is the "lowerdir" in the overlay and read-only. The new directory for the
|
||||
container is the "upperdir" and is writable.
|
||||
|
||||
## Example: Image and container on-disk constructs
|
||||
|
||||
The following `docker pull` command shows a Docker host with downloading a
|
||||
Docker image comprising four layers.
|
||||
|
||||
$ sudo docker pull ubuntu
|
||||
Using default tag: latest
|
||||
latest: Pulling from library/ubuntu
|
||||
8387d9ff0016: Pull complete
|
||||
3b52deaaf0ed: Pull complete
|
||||
4bd501fad6de: Pull complete
|
||||
a3ed95caeb02: Pull complete
|
||||
Digest: sha256:457b05828bdb5dcc044d93d042863fba3f2158ae249a6db5ae3934307c757c54
|
||||
Status: Downloaded newer image for ubuntu:latest
|
||||
|
||||
Each image layer has it's own directory under `/var/lib/docker/overlay/`. This
|
||||
is where the the contents of each image layer are stored.
|
||||
|
||||
The output of the command below shows the four directories that store the
|
||||
contents of each image layer just pulled. However, as can be seen, the image
|
||||
layer IDs do not match the directory names in `/var/lib/docker/overlay`. This
|
||||
is normal behavior in Docker 1.10 and later.
|
||||
|
||||
$ ls -l /var/lib/docker/overlay/
|
||||
total 24
|
||||
drwx------ 3 root root 4096 Oct 28 11:02 1d073211c498fd5022699b46a936b4e4bdacb04f637ad64d3475f558783f5c3e
|
||||
drwx------ 3 root root 4096 Oct 28 11:02 5a4526e952f0aa24f3fcc1b6971f7744eb5465d572a48d47c492cb6bbf9cbcda
|
||||
drwx------ 5 root root 4096 Oct 28 11:06 99fcaefe76ef1aa4077b90a413af57fd17d19dce4e50d7964a273aae67055235
|
||||
drwx------ 3 root root 4096 Oct 28 11:01 c63fb41c2213f511f12f294dd729b9903a64d88f098c20d2350905ac1fdbcbba
|
||||
|
||||
The image layer directories contain the files unique to that layer as well as
|
||||
hard links to the data that is shared with lower layers. This allows for
|
||||
efficient use of disk space.
|
||||
|
||||
Containers also exist on-disk in the Docker host's filesystem under
|
||||
`/var/lib/docker/overlay/`. If you inspect the directory relating to a running
|
||||
container using the `ls -l` command, you find the following file and
|
||||
directories.
|
||||
|
||||
$ ls -l /var/lib/docker/overlay/<directory-of-running-container>
|
||||
total 16
|
||||
-rw-r--r-- 1 root root 64 Oct 28 11:06 lower-id
|
||||
drwxr-xr-x 1 root root 4096 Oct 28 11:06 merged
|
||||
drwxr-xr-x 4 root root 4096 Oct 28 11:06 upper
|
||||
drwx------ 3 root root 4096 Oct 28 11:06 work
|
||||
|
||||
These four filesystem objects are all artefacts of OverlayFS. The "lower-id"
|
||||
file contains the ID of the top layer of the image the container is based on.
|
||||
This is used by OverlayFS as the "lowerdir".
|
||||
|
||||
$ cat /var/lib/docker/overlay/73de7176c223a6c82fd46c48c5f152f2c8a7e49ecb795a7197c3bb795c4d879e/lower-id
|
||||
1d073211c498fd5022699b46a936b4e4bdacb04f637ad64d3475f558783f5c3e
|
||||
|
||||
The "upper" directory is the containers read-write layer. Any changes made to
|
||||
the container are written to this directory.
|
||||
|
||||
The "merged" directory is effectively the containers mount point. This is where
|
||||
the unified view of the image ("lowerdir") and container ("upperdir") is
|
||||
exposed. Any changes written to the container are immediately reflected in this
|
||||
directory.
|
||||
|
||||
The "work" directory is required for OverlayFS to function. It is used for
|
||||
things such as *copy_up* operations.
|
||||
|
||||
You can verify all of these constructs from the output of the `mount` command.
|
||||
(Ellipses and line breaks are used in the output below to enhance readability.)
|
||||
|
||||
$ mount | grep overlay
|
||||
overlay on /var/lib/docker/overlay/73de7176c223.../merged
|
||||
type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay/1d073211c498.../root,
|
||||
upperdir=/var/lib/docker/overlay/73de7176c223.../upper,
|
||||
workdir=/var/lib/docker/overlay/73de7176c223.../work)
|
||||
|
||||
The output reflects that the overlay is mounted as read-write ("rw").
|
||||
|
||||
## Container reads and writes with overlay
|
||||
|
||||
Consider three scenarios where a container opens a file for read access with
|
||||
overlay.
|
||||
|
||||
- **The file does not exist in the container layer**. If a container opens a
|
||||
file for read access and the file does not already exist in the container
|
||||
("upperdir") it is read from the image ("lowerdir"). This should incur very
|
||||
little performance overhead.
|
||||
|
||||
- **The file only exists in the container layer**. If a container opens a file
|
||||
for read access and the file exists in the container ("upperdir") and not in
|
||||
the image ("lowerdir"), it is read directly from the container.
|
||||
|
||||
- **The file exists in the container layer and the image layer**. If a
|
||||
container opens a file for read access and the file exists in the image layer
|
||||
and the container layer, the file's version in the container layer is read.
|
||||
This is because files in the container layer ("upperdir") obscure files with
|
||||
the same name in the image layer ("lowerdir").
|
||||
|
||||
Consider some scenarios where files in a container are modified.
|
||||
|
||||
- **Writing to a file for the first time**. The first time a container writes
|
||||
to an existing file, that file does not exist in the container ("upperdir").
|
||||
The `overlay` driver performs a *copy_up* operation to copy the file from the
|
||||
image ("lowerdir") to the container ("upperdir"). The container then writes the
|
||||
changes to the new copy of the file in the container layer.
|
||||
|
||||
However, OverlayFS works at the file level not the block level. This means
|
||||
that all OverlayFS copy-up operations copy entire files, even if the file is
|
||||
very large and only a small part of it is being modified. This can have a
|
||||
noticeable impact on container write performance. However, two things are
|
||||
worth noting:
|
||||
|
||||
* The copy_up operation only occurs the first time any given file is
|
||||
written to. Subsequent writes to the same file will operate against the copy of
|
||||
the file already copied up to the container.
|
||||
|
||||
* OverlayFS only works with two layers. This means that performance should
|
||||
be better than AUFS which can suffer noticeable latencies when searching for
|
||||
files in images with many layers.
|
||||
|
||||
- **Deleting files and directories**. When files are deleted within a container
|
||||
a *whiteout* file is created in the containers "upperdir". The version of the
|
||||
file in the image layer ("lowerdir") is not deleted. However, the whiteout file
|
||||
in the container obscures it.
|
||||
|
||||
Deleting a directory in a container results in *opaque directory* being
|
||||
created in the "upperdir". This has the same effect as a whiteout file and
|
||||
effectively masks the existence of the directory in the image's "lowerdir".
|
||||
|
||||
## Configure Docker with the overlay storage driver
|
||||
|
||||
To configure Docker to use the overlay storage driver your Docker host must be
|
||||
running version 3.18 of the Linux kernel (preferably newer) with the overlay
|
||||
kernel module loaded. OverlayFS can operate on top of most supported Linux
|
||||
filesystems. However, ext4 is currently recommended for use in production
|
||||
environments.
|
||||
|
||||
The following procedure shows you how to configure your Docker host to use
|
||||
OverlayFS. The procedure assumes that the Docker daemon is in a stopped state.
|
||||
|
||||
> **Caution:** If you have already run the Docker daemon on your Docker host
|
||||
> and have images you want to keep, `push` them Docker Hub or your private
|
||||
> Docker Trusted Registry before attempting this procedure.
|
||||
|
||||
1. If it is running, stop the Docker `daemon`.
|
||||
|
||||
2. Verify your kernel version and that the overlay kernel module is loaded.
|
||||
|
||||
$ uname -r
|
||||
3.19.0-21-generic
|
||||
|
||||
$ lsmod | grep overlay
|
||||
overlay
|
||||
|
||||
3. Start the Docker daemon with the `overlay` storage driver.
|
||||
|
||||
$ docker daemon --storage-driver=overlay &
|
||||
[1] 29403
|
||||
root@ip-10-0-0-174:/home/ubuntu# INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
|
||||
INFO[0000] Option DefaultDriver: bridge
|
||||
INFO[0000] Option DefaultNetwork: bridge
|
||||
<output truncated>
|
||||
|
||||
Alternatively, you can force the Docker daemon to automatically start with
|
||||
the `overlay` driver by editing the Docker config file and adding the
|
||||
`--storage-driver=overlay` flag to the `DOCKER_OPTS` line. Once this option
|
||||
is set you can start the daemon using normal startup scripts without having
|
||||
to manually pass in the `--storage-driver` flag.
|
||||
|
||||
4. Verify that the daemon is using the `overlay` storage driver
|
||||
|
||||
$ docker info
|
||||
Containers: 0
|
||||
Images: 0
|
||||
Storage Driver: overlay
|
||||
Backing Filesystem: extfs
|
||||
<output truncated>
|
||||
|
||||
Notice that the *Backing filesystem* in the output above is showing as
|
||||
`extfs`. Multiple backing filesystems are supported but `extfs` (ext4) is
|
||||
recommended for production use cases.
|
||||
|
||||
Your Docker host is now using the `overlay` storage driver. If you run the
|
||||
`mount` command, you'll find Docker has automatically created the `overlay`
|
||||
mount with the required "lowerdir", "upperdir", "merged" and "workdir"
|
||||
constructs.
|
||||
|
||||
## OverlayFS and Docker Performance
|
||||
|
||||
As a general rule, the `overlay` driver should be fast. Almost certainly faster
|
||||
than `aufs` and `devicemapper`. In certain circumstances it may also be faster
|
||||
than `btrfs`. That said, there are a few things to be aware of relative to the
|
||||
performance of Docker using the `overlay` storage driver.
|
||||
|
||||
- **Page Caching**. OverlayFS supports page cache sharing. This means multiple
|
||||
containers accessing the same file can share a single page cache entry (or
|
||||
entries). This makes the `overlay` driver efficient with memory and a good
|
||||
option for PaaS and other high density use cases.
|
||||
|
||||
- **copy_up**. As with AUFS, OverlayFS has to perform copy-up operations any
|
||||
time a container writes to a file for the first time. This can insert latency
|
||||
into the write operation — especially if the file being copied up is
|
||||
large. However, once the file has been copied up, all subsequent writes to that
|
||||
file occur without the need for further copy-up operations.
|
||||
|
||||
The OverlayFS copy_up operation should be faster than the same operation
|
||||
with AUFS. This is because AUFS supports more layers than OverlayFS and it is
|
||||
possible to incur far larger latencies if searching through many AUFS layers.
|
||||
|
||||
- **RPMs and Yum**. OverlayFS only implements a subset of the POSIX standards.
|
||||
This can result in certain OverlayFS operations breaking POSIX standards. One
|
||||
such operation is the *copy-up* operation. Therefore, using `yum` inside of a
|
||||
container on a Docker host using the `overlay` storage driver is unlikely to
|
||||
work without implementing workarounds.
|
||||
|
||||
- **Inode limits**. Use of the `overlay` storage driver can cause excessive
|
||||
inode consumption. This is especially so as the number of images and containers
|
||||
on the Docker host grows. A Docker host with a large number of images and lots
|
||||
of started and stopped containers can quickly run out of inodes.
|
||||
|
||||
Unfortunately you can only specify the number of inodes in a filesystem at the
|
||||
time of creation. For this reason, you may wish to consider putting
|
||||
`/var/lib/docker` on a separate device with its own filesystem, or manually
|
||||
specifying the number of inodes when creating the filesystem.
|
||||
|
||||
The following generic performance best practices also apply to OverlayFS.
|
||||
|
||||
- **Solid State Devices (SSD)**. For best performance it is always a good idea
|
||||
to use fast storage media such as solid state devices (SSD).
|
||||
|
||||
- **Use Data Volumes**. Data volumes provide the best and most predictable
|
||||
performance. This is because they bypass the storage driver and do not incur
|
||||
any of the potential overheads introduced by thin provisioning and
|
||||
copy-on-write. For this reason, you should place heavy write workloads on data
|
||||
volumes.
|
||||
206
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/selectadriver.md
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "Select a storage driver"
|
||||
description = "Learn how select the proper storage driver for your container."
|
||||
keywords = ["container, storage, driver, AUFS, btfs, devicemapper,zvfs"]
|
||||
[menu.main]
|
||||
parent = "engine_driver"
|
||||
weight = -1
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Select a storage driver
|
||||
|
||||
This page describes Docker's storage driver feature. It lists the storage
|
||||
driver's that Docker supports and the basic commands associated with managing
|
||||
them. Finally, this page provides guidance on choosing a storage driver.
|
||||
|
||||
The material on this page is intended for readers who already have an
|
||||
[understanding of the storage driver technology](imagesandcontainers.md).
|
||||
|
||||
## A pluggable storage driver architecture
|
||||
|
||||
Docker has a pluggable storage driver architecture. This gives you the
|
||||
flexibility to "plug in" the storage driver that is best for your environment
|
||||
and use-case. Each Docker storage driver is based on a Linux filesystem or
|
||||
volume manager. Further, each storage driver is free to implement the
|
||||
management of image layers and the container layer in its own unique way. This
|
||||
means some storage drivers perform better than others in different
|
||||
circumstances.
|
||||
|
||||
Once you decide which driver is best, you set this driver on the Docker daemon
|
||||
at start time. As a result, the Docker daemon can only run one storage driver,
|
||||
and all containers created by that daemon instance use the same storage driver.
|
||||
The table below shows the supported storage driver technologies and their
|
||||
driver names:
|
||||
|
||||
|Technology |Storage driver name |
|
||||
|--------------|---------------------|
|
||||
|OverlayFS |`overlay` |
|
||||
|AUFS |`aufs` |
|
||||
|Btrfs |`btrfs` |
|
||||
|Device Mapper |`devicemapper` |
|
||||
|VFS* |`vfs` |
|
||||
|ZFS |`zfs` |
|
||||
|
||||
To find out which storage driver is set on the daemon , you use the
|
||||
`docker info` command:
|
||||
|
||||
$ docker info
|
||||
Containers: 0
|
||||
Images: 0
|
||||
Storage Driver: overlay
|
||||
Backing Filesystem: extfs
|
||||
Execution Driver: native-0.2
|
||||
Logging Driver: json-file
|
||||
Kernel Version: 3.19.0-15-generic
|
||||
Operating System: Ubuntu 15.04
|
||||
... output truncated ...
|
||||
|
||||
The `info` subcommand reveals that the Docker daemon is using the `overlay`
|
||||
storage driver with a `Backing Filesystem` value of `extfs`. The `extfs` value
|
||||
means that the `overlay` storage driver is operating on top of an existing
|
||||
(ext) filesystem. The backing filesystem refers to the filesystem that was used
|
||||
to create the Docker host's local storage area under `/var/lib/docker`.
|
||||
|
||||
Which storage driver you use, in part, depends on the backing filesystem you
|
||||
plan to use for your Docker host's local storage area. Some storage drivers can
|
||||
operate on top of different backing filesystems. However, other storage
|
||||
drivers require the backing filesystem to be the same as the storage driver.
|
||||
For example, the `btrfs` storage driver on a Btrfs backing filesystem. The
|
||||
following table lists each storage driver and whether it must match the host's
|
||||
backing file system:
|
||||
|
||||
|Storage driver |Must match backing filesystem |Incompatible with |
|
||||
|---------------|------------------------------|--------------------|
|
||||
|`overlay` |No |`btrfs` `aufs` `zfs`|
|
||||
|`aufs` |No |`btrfs` `aufs` |
|
||||
|`btrfs` |Yes | N/A |
|
||||
|`devicemapper` |No | N/A |
|
||||
|`vfs` |No | N/A |
|
||||
|`zfs` |Yes | N/A |
|
||||
|
||||
|
||||
> **Note**
|
||||
> Incompatible with means some storage drivers can not run over certain backing
|
||||
> filesystem.
|
||||
|
||||
You can set the storage driver by passing the `--storage-driver=<name>` option
|
||||
to the `docker daemon` command line, or by setting the option on the
|
||||
`DOCKER_OPTS` line in the `/etc/default/docker` file.
|
||||
|
||||
The following command shows how to start the Docker daemon with the
|
||||
`devicemapper` storage driver using the `docker daemon` command:
|
||||
|
||||
$ docker daemon --storage-driver=devicemapper &
|
||||
|
||||
$ docker info
|
||||
Containers: 0
|
||||
Images: 0
|
||||
Storage Driver: devicemapper
|
||||
Pool Name: docker-252:0-147544-pool
|
||||
Pool Blocksize: 65.54 kB
|
||||
Backing Filesystem: extfs
|
||||
Data file: /dev/loop0
|
||||
Metadata file: /dev/loop1
|
||||
Data Space Used: 1.821 GB
|
||||
Data Space Total: 107.4 GB
|
||||
Data Space Available: 3.174 GB
|
||||
Metadata Space Used: 1.479 MB
|
||||
Metadata Space Total: 2.147 GB
|
||||
Metadata Space Available: 2.146 GB
|
||||
Udev Sync Supported: true
|
||||
Deferred Removal Enabled: false
|
||||
Data loop file: /var/lib/docker/devicemapper/devicemapper/data
|
||||
Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
|
||||
Library Version: 1.02.90 (2014-09-01)
|
||||
Execution Driver: native-0.2
|
||||
Logging Driver: json-file
|
||||
Kernel Version: 3.19.0-15-generic
|
||||
Operating System: Ubuntu 15.04
|
||||
<output truncated>
|
||||
|
||||
Your choice of storage driver can affect the performance of your containerized
|
||||
applications. So it's important to understand the different storage driver
|
||||
options available and select the right one for your application. Later, in this
|
||||
page you'll find some advice for choosing an appropriate driver.
|
||||
|
||||
## Shared storage systems and the storage driver
|
||||
|
||||
Many enterprises consume storage from shared storage systems such as SAN and
|
||||
NAS arrays. These often provide increased performance and availability, as well
|
||||
as advanced features such as thin provisioning, deduplication and compression.
|
||||
|
||||
The Docker storage driver and data volumes can both operate on top of storage
|
||||
provided by shared storage systems. This allows Docker to leverage the
|
||||
increased performance and availability these systems provide. However, Docker
|
||||
does not integrate with these underlying systems.
|
||||
|
||||
Remember that each Docker storage driver is based on a Linux filesystem or
|
||||
volume manager. Be sure to follow existing best practices for operating your
|
||||
storage driver (filesystem or volume manager) on top of your shared storage
|
||||
system. For example, if using the ZFS storage driver on top of *XYZ* shared
|
||||
storage system, be sure to follow best practices for operating ZFS filesystems
|
||||
on top of XYZ shared storage system.
|
||||
|
||||
## Which storage driver should you choose?
|
||||
|
||||
Several factors influence the selection of a storage driver. However, these two
|
||||
facts must be kept in mind:
|
||||
|
||||
1. No single driver is well suited to every use-case
|
||||
2. Storage drivers are improving and evolving all of the time
|
||||
|
||||
With these factors in mind, the following points, coupled with the table below,
|
||||
should provide some guidance.
|
||||
|
||||
### Stability
|
||||
For the most stable and hassle-free Docker experience, you should consider the
|
||||
following:
|
||||
|
||||
- **Use the default storage driver for your distribution**. When Docker
|
||||
installs, it chooses a default storage driver based on the configuration of
|
||||
your system. Stability is an important factor influencing which storage driver
|
||||
is used by default. Straying from this default may increase your chances of
|
||||
encountering bugs and nuances.
|
||||
- **Follow the configuration specified on the CS Engine
|
||||
[compatibility matrix](https://www.docker.com/compatibility-maintenance)**. The
|
||||
CS Engine is the commercially supported version of the Docker Engine. It's
|
||||
code-base is identical to the open source Engine, but it has a limited set of
|
||||
supported configurations. These *supported configurations* use the most stable
|
||||
and mature storage drivers. Straying from these configurations may also
|
||||
increase your chances of encountering bugs and nuances.
|
||||
|
||||
### Experience and expertise
|
||||
|
||||
Choose a storage driver that you and your team/organization have experience
|
||||
with. For example, if you use RHEL or one of its downstream forks, you may
|
||||
already have experience with LVM and Device Mapper. If so, you may wish to use
|
||||
the `devicemapper` driver.
|
||||
|
||||
If you do not feel you have expertise with any of the storage drivers supported
|
||||
by Docker, and you want an easy-to-use stable Docker experience, you should
|
||||
consider using the default driver installed by your distribution's Docker
|
||||
package.
|
||||
|
||||
### Future-proofing
|
||||
|
||||
Many people consider OverlayFS as the future of the Docker storage driver.
|
||||
However, it is less mature, and potentially less stable than some of the more
|
||||
mature drivers such as `aufs` and `devicemapper`. For this reason, you should
|
||||
use the OverlayFS driver with caution and expect to encounter more bugs and
|
||||
nuances than if you were using a more mature driver.
|
||||
|
||||
The following diagram lists each storage driver and provides insight into some
|
||||
of their pros and cons. When selecting which storage driver to use, consider
|
||||
the guidance offered by the table below along with the points mentioned above.
|
||||
|
||||

|
||||
|
||||
|
||||
## Related information
|
||||
|
||||
* [Understand images, containers, and storage drivers](imagesandcontainers.md)
|
||||
* [AUFS storage driver in practice](aufs-driver.md)
|
||||
* [Btrfs storage driver in practice](btrfs-driver.md)
|
||||
* [Device Mapper storage driver in practice](device-mapper-driver.md)
|
||||
296
vendor/github.com/hyperhq/hypercli/docs/userguide/storagedriver/zfs-driver.md
generated
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
<!--[metadata]>
|
||||
+++
|
||||
title = "ZFS storage in practice"
|
||||
description = "Learn how to optimize your use of ZFS driver."
|
||||
keywords = ["container, storage, driver, ZFS "]
|
||||
[menu.main]
|
||||
parent = "engine_driver"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Docker and ZFS in practice
|
||||
|
||||
ZFS is a next generation filesystem that supports many advanced storage
|
||||
technologies such as volume management, snapshots, checksumming, compression
|
||||
and deduplication, replication and more.
|
||||
|
||||
It was created by Sun Microsystems (now Oracle Corporation) and is open sourced
|
||||
under the CDDL license. Due to licensing incompatibilities between the CDDL
|
||||
and GPL, ZFS cannot be shipped as part of the mainline Linux kernel. However,
|
||||
the ZFS On Linux (ZoL) project provides an out-of-tree kernel module and
|
||||
userspace tools which can be installed separately.
|
||||
|
||||
The ZFS on Linux (ZoL) port is healthy and maturing. However, at this point in
|
||||
time it is not recommended to use the `zfs` Docker storage driver for
|
||||
production use unless you have substantial experience with ZFS on Linux.
|
||||
|
||||
> **Note:** There is also a FUSE implementation of ZFS on the Linux platform.
|
||||
> This should work with Docker but is not recommended. The native ZFS driver
|
||||
> (ZoL) is more tested, more performant, and is more widely used. The remainder
|
||||
> of this document will relate to the native ZoL port.
|
||||
|
||||
|
||||
## Image layering and sharing with ZFS
|
||||
|
||||
The Docker `zfs` storage driver makes extensive use of three ZFS datasets:
|
||||
|
||||
- filesystems
|
||||
- snapshots
|
||||
- clones
|
||||
|
||||
ZFS filesystems are thinly provisioned and have space allocated to them from a
|
||||
ZFS pool (zpool) via allocate on demand operations. Snapshots and clones are
|
||||
space-efficient point-in-time copies of ZFS filesystems. Snapshots are
|
||||
read-only. Clones are read-write. Clones can only be created from snapshots.
|
||||
This simple relationship is shown in the diagram below.
|
||||
|
||||

|
||||
|
||||
The solid line in the diagram shows the process flow for creating a clone. Step
|
||||
1 creates a snapshot of the filesystem, and step two creates the clone from
|
||||
the snapshot. The dashed line shows the relationship between the clone and the
|
||||
filesystem, via the snapshot. All three ZFS datasets draw space form the same
|
||||
underlying zpool.
|
||||
|
||||
On Docker hosts using the `zfs` storage driver, the base layer of an image is a
|
||||
ZFS filesystem. Each child layer is a ZFS clone based on a ZFS snapshot of the
|
||||
layer below it. A container is a ZFS clone based on a ZFS Snapshot of the top
|
||||
layer of the image it's created from. All ZFS datasets draw their space from a
|
||||
common zpool. The diagram below shows how this is put together with a running
|
||||
container based on a two-layer image.
|
||||
|
||||

|
||||
|
||||
The following process explains how images are layered and containers created.
|
||||
The process is based on the diagram above.
|
||||
|
||||
1. The base layer of the image exists on the Docker host as a ZFS filesystem.
|
||||
|
||||
This filesystem consumes space from the zpool used to create the Docker
|
||||
host's local storage area at `/var/lib/docker`.
|
||||
|
||||
2. Additional image layers are clones of the dataset hosting the image layer
|
||||
directly below it.
|
||||
|
||||
In the diagram, "Layer 1" is added by making a ZFS snapshot of the base
|
||||
layer and then creating a clone from that snapshot. The clone is writable and
|
||||
consumes space on-demand from the zpool. The snapshot is read-only, maintaining
|
||||
the base layer as an immutable object.
|
||||
|
||||
3. When the container is launched, a read-write layer is added above the image.
|
||||
|
||||
In the diagram above, the container's read-write layer is created by making
|
||||
a snapshot of the top layer of the image (Layer 1) and creating a clone from
|
||||
that snapshot.
|
||||
|
||||
As changes are made to the container, space is allocated to it from the
|
||||
zpool via allocate-on-demand operations. By default, ZFS will allocate space in
|
||||
blocks of 128K.
|
||||
|
||||
This process of creating child layers and containers from *read-only* snapshots
|
||||
allows images to be maintained as immutable objects.
|
||||
|
||||
## Container reads and writes with ZFS
|
||||
|
||||
Container reads with the `zfs` storage driver are very simple. A newly launched
|
||||
container is based on a ZFS clone. This clone initially shares all of its data
|
||||
with the dataset it was created from. This means that read operations with the
|
||||
`zfs` storage driver are fast – even if the data being read was note
|
||||
copied into the container yet. This sharing of data blocks is shown in the
|
||||
diagram below.
|
||||
|
||||

|
||||
|
||||
Writing new data to a container is accomplished via an allocate-on-demand
|
||||
operation. Every time a new area of the container needs writing to, a new block
|
||||
is allocated from the zpool. This means that containers consume additional
|
||||
space as new data is written to them. New space is allocated to the container
|
||||
(ZFS Clone) from the underlying zpool.
|
||||
|
||||
Updating *existing data* in a container is accomplished by allocating new
|
||||
blocks to the containers clone and storing the changed data in those new
|
||||
blocks. The original blocks are unchanged, allowing the underlying image
|
||||
dataset to remain immutable. This is the same as writing to a normal ZFS
|
||||
filesystem and is an implementation of copy-on-write semantics.
|
||||
|
||||
## Configure Docker with the ZFS storage driver
|
||||
|
||||
The `zfs` storage driver is only supported on a Docker host where
|
||||
`/var/lib/docker` is mounted as a ZFS filesystem. This section shows you how to
|
||||
install and configure native ZFS on Linux (ZoL) on an Ubuntu 14.04 system.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If you have already used the Docker daemon on your Docker host and have images
|
||||
you want to keep, `push` them Docker Hub or your private Docker Trusted
|
||||
Registry before attempting this procedure.
|
||||
|
||||
Stop the Docker daemon. Then, ensure that you have a spare block device at
|
||||
`/dev/xvdb`. The device identifier may be be different in your environment and
|
||||
you should substitute your own values throughout the procedure.
|
||||
|
||||
### Install Zfs on Ubuntu 14.04 LTS
|
||||
|
||||
1. If it is running, stop the Docker `daemon`.
|
||||
|
||||
1. Install `the software-properties-common` package.
|
||||
|
||||
This is required for the `add-apt-repository` command.
|
||||
|
||||
$ sudo apt-get install software-properties-common
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
<output truncated>
|
||||
|
||||
2. Add the `zfs-native` package archive.
|
||||
|
||||
$ sudo add-apt-repository ppa:zfs-native/stable
|
||||
The native ZFS filesystem for Linux. Install the ubuntu-zfs package.
|
||||
<output truncated>
|
||||
gpg: key F6B0FC61: public key "Launchpad PPA for Native ZFS for Linux" imported
|
||||
gpg: Total number processed: 1
|
||||
gpg: imported: 1 (RSA: 1)
|
||||
OK
|
||||
|
||||
3. Get the latest package lists for all registered repositories and package
|
||||
archives.
|
||||
|
||||
$ sudo apt-get update
|
||||
Ign http://us-west-2.ec2.archive.ubuntu.com trusty InRelease
|
||||
Get:1 http://us-west-2.ec2.archive.ubuntu.com trusty-updates InRelease [64.4 kB]
|
||||
<output truncated>
|
||||
Fetched 10.3 MB in 4s (2,370 kB/s)
|
||||
Reading package lists... Done
|
||||
|
||||
4. Install the `ubuntu-zfs` package.
|
||||
|
||||
$ sudo apt-get install -y ubuntu-zfs
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
<output truncated>
|
||||
|
||||
5. Load the `zfs` module.
|
||||
|
||||
$ sudo modprobe zfs
|
||||
|
||||
6. Verify that it loaded correctly.
|
||||
|
||||
$ lsmod | grep zfs
|
||||
zfs 2768247 0
|
||||
zunicode 331170 1 zfs
|
||||
zcommon 55411 1 zfs
|
||||
znvpair 89086 2 zfs,zcommon
|
||||
spl 96378 3 zfs,zcommon,znvpair
|
||||
zavl 15236 1 zfs
|
||||
|
||||
## Configure ZFS for Docker
|
||||
|
||||
Once ZFS is installed and loaded, you're ready to configure ZFS for Docker.
|
||||
|
||||
|
||||
1. Create a new `zpool`.
|
||||
|
||||
$ sudo zpool create -f zpool-docker /dev/xvdb
|
||||
|
||||
The command creates the `zpool` and gives it the name "zpool-docker". The name is arbitrary.
|
||||
|
||||
2. Check that the `zpool` exists.
|
||||
|
||||
$ sudo zfs list
|
||||
NAME USED AVAIL REFER MOUNTPOINT
|
||||
zpool-docker 55K 3.84G 19K /zpool-docker
|
||||
|
||||
3. Create and mount a new ZFS filesystem to `/var/lib/docker`.
|
||||
|
||||
$ sudo zfs create -o mountpoint=/var/lib/docker zpool-docker/docker
|
||||
|
||||
4. Check that the previous step worked.
|
||||
|
||||
$ sudo zfs list -t all
|
||||
NAME USED AVAIL REFER MOUNTPOINT
|
||||
zpool-docker 93.5K 3.84G 19K /zpool-docker
|
||||
zpool-docker/docker 19K 3.84G 19K /var/lib/docker
|
||||
|
||||
Now that you have a ZFS filesystem mounted to `/var/lib/docker`, the daemon
|
||||
should automatically load with the `zfs` storage driver.
|
||||
|
||||
5. Start the Docker daemon.
|
||||
|
||||
$ sudo service docker start
|
||||
docker start/running, process 2315
|
||||
|
||||
The procedure for starting the Docker daemon may differ depending on the
|
||||
Linux distribution you are using. It is possible to force the Docker daemon
|
||||
to start with the `zfs` storage driver by passing the
|
||||
`--storage-driver=zfs`flag to the `docker daemon` command, or to the
|
||||
`DOCKER_OPTS` line in the Docker config file.
|
||||
|
||||
6. Verify that the daemon is using the `zfs` storage driver.
|
||||
|
||||
$ sudo docker info
|
||||
Containers: 0
|
||||
Images: 0
|
||||
Storage Driver: zfs
|
||||
Zpool: zpool-docker
|
||||
Zpool Health: ONLINE
|
||||
Parent Dataset: zpool-docker/docker
|
||||
Space Used By Parent: 27648
|
||||
Space Available: 4128139776
|
||||
Parent Quota: no
|
||||
Compression: off
|
||||
Execution Driver: native-0.2
|
||||
[...]
|
||||
|
||||
The output of the command above shows that the Docker daemon is using the
|
||||
`zfs` storage driver and that the parent dataset is the
|
||||
`zpool-docker/docker` filesystem created earlier.
|
||||
|
||||
Your Docker host is now using ZFS to store to manage its images and containers.
|
||||
|
||||
## ZFS and Docker performance
|
||||
|
||||
There are several factors that influence the performance of Docker using the
|
||||
`zfs` storage driver.
|
||||
|
||||
- **Memory**. Memory has a major impact on ZFS performance. This goes back to
|
||||
the fact that ZFS was originally designed for use on big Sun Solaris servers
|
||||
with large amounts of memory. Keep this in mind when sizing your Docker hosts.
|
||||
|
||||
- **ZFS Features**. Using ZFS features, such as deduplication, can
|
||||
significantly increase the amount of memory ZFS uses. For memory consumption
|
||||
and performance reasons it is recommended to turn off ZFS deduplication.
|
||||
However, deduplication at other layers in the stack (such as SAN or NAS arrays)
|
||||
can still be used as these do not impact ZFS memory usage and performance. If
|
||||
using SAN, NAS or other hardware RAID technologies you should continue to
|
||||
follow existing best practices for using them with ZFS.
|
||||
|
||||
- **ZFS Caching**. ZFS caches disk blocks in a memory structure called the
|
||||
adaptive replacement cache (ARC). The *Single Copy ARC* feature of ZFS allows a
|
||||
single cached copy of a block to be shared by multiple clones of a filesystem.
|
||||
This means that multiple running containers can share a single copy of cached
|
||||
block. This means that ZFS is a good option for PaaS and other high density use
|
||||
cases.
|
||||
|
||||
- **Fragmentation**. Fragmentation is a natural byproduct of copy-on-write
|
||||
filesystems like ZFS. However, ZFS writes in 128K blocks and allocates *slabs*
|
||||
(multiple 128K blocks) to CoW operations in an attempt to reduce fragmentation.
|
||||
The ZFS intent log (ZIL) and the coalescing of writes (delayed writes) also
|
||||
help to reduce fragmentation.
|
||||
|
||||
- **Use the native ZFS driver for Linux**. Although the Docker `zfs` storage
|
||||
driver supports the ZFS FUSE implementation, it is not recommended when high
|
||||
performance is required. The native ZFS on Linux driver tends to perform better
|
||||
than the FUSE implementation.
|
||||
|
||||
The following generic performance best practices also apply to ZFS.
|
||||
|
||||
- **Use of SSD**. For best performance it is always a good idea to use fast
|
||||
storage media such as solid state devices (SSD). However, if you only have a
|
||||
limited amount of SSD storage available it is recommended to place the ZIL on
|
||||
SSD.
|
||||
|
||||
- **Use Data Volumes**. Data volumes provide the best and most predictable
|
||||
performance. This is because they bypass the storage driver and do not incur
|
||||
any of the potential overheads introduced by thin provisioning and
|
||||
copy-on-write. For this reason, you should place heavy write workloads on data
|
||||
volumes.
|
||||