5 Working With Containers and Images
WARNING:
Oracle Linux 7 is now in Extended Support. See Oracle Linux Extended Support and Oracle Open Source Support Policies for more information.
Migrate applications and data to Oracle Linux 8 or Oracle Linux 9 as soon as possible.
This chapter describes how to use the Docker Engine to run containers and how to obtain the images that are used to create a container. Other information specific to container and image configuration is also provided. In this chapter is assumed that images and containers are hosted on Oracle Linux 7.
Pulling Oracle Linux Images From a Container Registry
You can get Oracle Linux images to run on the Docker Engine from the
oraclelinux
repository at the Docker Hub. For a
list of the Oracle Linux images that are available, see
https://hub.docker.com/_/oraclelinux/).
An Internet connection is required to pull images from the Docker Hub or the Oracle Container Registry. If you make use of a proxy server to access the Internet, see Configuring a Proxy Server.
Oracle Linux images, along with many other Oracle product images, are also hosted on the Oracle Container Registry at https://container-registry.oracle.com and on the Docker Hub at https://hub.docker.com. More information on using the Oracle Container Registry to pull images is covered in Pulling Images From the Oracle Container Registry. See Using Third-Party Registries for more information on using the Docker Hub.
To download an Oracle Linux image, use the docker pull command. For example, to pull an Oracle Linux image from the Docker Hub:
docker pull oraclelinux:7-slim
Trying to pull repository docker.io/library/oraclelinux ... 7-slim: Pulling from docker.io/library/oraclelinux 977461c90301: Pull complete Digest: sha256:0743f72832d8744a89b7be31b38b9fb2e5390044cbb153cd97b3e797723e4704 Status: Downloaded newer image for oraclelinux:7-slim
To display a list of the images that you have downloaded to a system, use the docker images command, for example:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE oraclelinux 7-slim c2b5cb5bcd9d 7 days ago 118MB oraclelinux 7 31f4bed1dc33 7 days ago 232MB oraclelinux latest 31f4bed1dc33 7 days ago 232MB oraclelinux 8 8988c7081e1f 5 weeks ago 411MB
Each image in the repository is distinguished by its
TAG
value and its unique IMAGE
ID
. In the example, the tags 7
and
latest
refer to the same image ID for Oracle Linux 7.
When new images are made available for Oracle Linux updates, the tags
7
, 8
, and
latest
are updated in the
oraclelinux
repository to refer to the
appropriate newest version.
If an image is downloaded from an alternate registry to the
default registry, the REPOSITORY
value also
indicates the registry from which the image was pulled. For
example:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE container-registry.oracle.com/os/oraclelinux latest 31f4bed1dc33 7 days ago 232MB
See Setting Container Registry Options for more information on adding registries and configuring a default registry.
Enabling or Disabling Docker Content Trust
Content Trust allows you to verify the authenticity, integrity, and publication date of Docker images that are made available on the Docker Hub Registry.
By default, Content Trust is disabled. To enable Content Trust
for signing and verifying Docker images that you build, push to,
or pull from the Docker Hub, set the
DOCKER_CONTENT_TRUST
environment variable, for
example:
export DOCKER_CONTENT_TRUST=1
If you use sudo to run Docker commands,
specify the -E option to preserve the
environment or use visudo to add the
following line to /etc/sudoers
:
Defaults env_keep += "DOCKER_CONTENT_TRUST"
For individual docker build, docker push, or docker pull commands, you can specify the --disable-content-trust=false and --disable-content-trust=true options to enable or disable Content Trust.
For more information, see https://docs.docker.com/engine/security/trust/content_trust/.
Enabling FIPS Mode in Containers
To run containers in FIPS mode, you must first enable FIPS mode on your Oracle Linux host system.
For more information about Oracle Linux 7 releases that have FIPS validated cryptographic modules available for installation, see Oracle Linux 7: Security Guide.
Note:
Oracle provides FIPS compliant container images by using the slim-fips
tag. Container images tagged as FIPS compliant include compliant cryptographic package
versions and initial image setup required for container FIPS mode. See The slim Tag for more information.
For Oracle Linux 7 Containers:
To enable FIPS mode in an Oracle Linux 7 container, install the
dracut-fips
package or mount
/etc/system-fips
from the host. For more
information about mounting host files and directories from
inside a container, see
Accessing External Files From Docker Containers.
For Oracle Linux 8 Containers:
To enable FIPS mode in an Oracle Linux 8 container, mount
/etc/system-fips
from the host. For more
information about mounting host files and directories from
inside a container, see
Accessing External Files From Docker Containers.
Additionally, bind mount FIPS cryptographic policies within
the container from
/usr/share/crypto-policies/back-ends/FIPS
to /etc/crypto-policies/back-ends
:
mount --bind /usr/share/crypto-policies/back-ends/FIPS /etc/crypto-policies/back-ends
Creating and Running Docker Containers
You use the docker run command to run an application inside a container, for example:
docker run -i -t --name guest oraclelinux:7-slim
bash-4.2# cat /etc/oracle-release Oracle Linux Server release 7.7 bash-4.2# exit
This example runs an interactive bash shell
using the Oracle Linux 7 image named oraclelinux:7-slim
to provide the container. The /bin/bash
command
is the default command run for all oraclelinux
base images. The -t and -i
options allow you to use a pseudo-terminal to run the container
interactively.
The following examples may use the prompt [root@host ~]
and
[root@guest ~]
(or similar) to represent the prompts shown by the host and
by the container respectively. The actual prompt displayed by the container may be different.
The --name option specifies the name
guest
for the container instance.
Docker does not remove the container when it exits and we can restart it at a later time, for example:
[root@host ~]# docker start guest guest
If an image does not already exist on your system, the Docker Engine performs a docker pull operation to download the image from the Docker Hub (or from another repository that you specify) as shown in the following example:
[root@host ~]# docker run -i -t --rm container-registry.oracle.com/os/oraclelinux:7-slim Unable to find image 'container-registry.oracle.com/os/oraclelinux:7-slim' locally Trying to pull repository container-registry.oracle.com/os/oraclelinux ... 7-slim: Pulling from container-registry.oracle.com/os/oraclelinux Digest: sha256:267f37439471f1c5eae586394c85e743b887c7f97e4733e10e466158083c021e Status: Downloaded newer image for container-registry.oracle.com/os/oraclelinux:7-slim [root@guest /]# cat /etc/oracle-release Oracle Linux Server release 7.7 [root@guest /]# exit exit [root@host ~]#
Because we specified the --rm option instead of naming the container, Docker removes the container when it exits and we cannot restart it.
From another shell window, you can use the docker ps command to display information about the containers that are currently running, for example:
[root@host ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 68359521c0b7 oraclelinux:7-slim "/bin/bash" 2 hours ago Up 8 minutes guest
The container named guest
with the ID
68359521c0b7
is currently running the command
/bin/bash
. It is more convenient to manage a
container by using its name than by its ID.
To display the processes that a container is running, use the docker top command:
[root@host ~]# docker top guest UID PID PPID C STIME TTY TIME CMD root 31252 31235 0 05:59 pts/0 00:00:00 /bin/bash
You can use the docker exec command to run additional processes in a container that is already running, for example:
[root@host ~]# docker exec -i -t guest bash [root@guest ~]#
You can also use the docker create command to set up a container that you can start at a later time, for example:
[root@host ~]# docker create -i -t --name newguest oraclelinux:7-slim b4c224f83e35927f67b973febb006b0af4d037f41c30e1f4bdcc4b822e12fd0f [root@host ~]# docker start -a -i newguest [root@newguest ~]#
The -a and -i options to docker start attach the current shell's standard input, output, and error streams to those of the container and also cause all signals to be forwarded to the container.
You can exit a container by typing Ctrl-D
or
exit at the bash command
prompt inside the container or by using the docker
stop command:
[root@host ~]# docker stop guest
The -a option to docker ps displays all containers that are currently running or that have exited.
[root@host ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b4c224f83e35 oraclelinux:7-slim ... ... Exited (0) About a minute ago newguest 68359521c0b7 oraclelinux:7-slim ... ... Exited (137) 45 seconds ago guest
You can use docker start to restart a stopped container. After reattaching to it, the contents remain unchanged from the last time that you used the container.
[root@host ~]# docker start -a -i guest [root@guest ~]# touch /tmp/foobar [root@guest ~]# exit [root@host ~]# docker start -a -i guest [root@guest ~]# ls -l /tmp/foobar -rw-r--r-- 1 root root 0 Nov 26 06:27 /tmp/foobar
Because the container preserves any changes that you make to it, you can reconfigure files and install packages in the container without worrying that your changes will disappear.
You can use the docker logs command to watch what is happening inside a container, for example:
[root@host ~]# docker logs -f guest bash-4.2# exit exit bash-4.2# ls -l /tmp/foobar -rw-r--r-- 1 root root 0 Nov 26 06:33 /tmp/foobar
The -f option causes the command to update its
output as events happen in the container. Type
Ctrl-C
to exit the command.
You can obtain full information about a container in JSON format by using the docker inspect command. This command also allows you to retrieve specified elements of the configuration, for example:
[root@host ~]# docker inspect --format='{{ .State.Running }}' guest
If you need to remove a container permanently so that you can create a new container with the same name, use the docker rm command:
[root@host ~]# docker rm guest
Note:
If you specify the --rm option when you run a container, Docker removes the container when the container exits. You cannot combine the --rm option with the -d option.
Specifying the -f option to docker rm kills a running container before removing it. In previous versions, the same command stops the container before removing it. If you want to stop a container safely, use docker stop.
Configuring How Docker Restarts Containers
To specify how you want Docker to handle a container when it exits, you can use the --restart option with docker run and docker create:
- --restart=always
-
Docker always attempts to restart the container when the container exits.
- --restart=no
-
Docker does not attempt to restart the container when the container exits. This is the default policy.
- --restart=on-failure[:max-retry ]
-
Docker attempts to restarts the container if the container returns a non-zero exit code. You can optionally specify the maximum number of times that Docker will try to restart the container.
Controlling Capabilities and Making Host Devices Available to Containers
If you specify the --privileged=true option to docker create or docker run, the container has access to all the devices on the host, which can present a security risk. For more precise control, you can use the --cap-add and --cap-drop options to restrict the capabilities of a container, for example:
[root@host ~]# docker run --cap-add=ALL --cap-drop=NET_ADMIN -i -t --rm oraclelinux:7 [root@guest /]# ip route del default RTNETLINK answers: Operation not permitted
This example grants all capabilities except
NET_ADMIN
to the container so that it is not
able to perform network-administration operations. For more
information, see the capabilities(7)
manual
page.
To make only individual devices on the host available to a container, you can use the --device option with docker run and docker create:
- --device=host_devname [:container_devname [:permissions ]]
-
host_devname is the name of the host device.
container_devname is an optional name for the name of the device in the container.
permissions optionally specifies the permissions that the container has on the device, which is a combination of the following codes:
- m
-
Grants mknod permission. For example, you can use mknod to set permission bits or the SELinux context for the device file.
- r
-
Grants read permission.
- w
-
Grants write permission. For example, you can use a command such as mkfs to format the device.
For example, --device=/dev/sdd:/dev/xvdd:r
would make the host device /dev/sdd
available
to the container as the device /dev/xvdd
with
read-only permission.
Attention:
Do not make block devices that can easily be removed from the system available to untrusted containers.
Accessing the Host's Process ID Namespace
You can make the host's process ID namespace visible from inside a container by specifying the --pid=host option to docker run. A suggested use of this mode is to debug host processes by using containerized debugging tools.
Attention:
Host mode is inherently insecure as it gives a container full access to D-Bus and other system services on the host.
Creating a Docker Image From an Existing Container
If you modify the contents of a container, you can use the docker commit command to save the current state of the container as an image.
The following example demonstrates how to modify a container based
on the oraclelinux:7-slim
image so that it can
run an Apache HTTP server. After stopping the container, the image
mymod/httpd:v1
is created from it.
Tip:
The oraclelinux:7-slim
and
oraclelinux:8-slim
images provide the bare
minimum operating system required for Oracle Linux 7 and Oracle Linux 8. Using
these images can help to reduce resource usage when running
containers based on them. You can also ensure that the image
that you create is limited to the base requirements for your
application.
To create an Apache server image from an
oraclelinux:7-slim
container:
-
Run the bash shell inside a container named
httpd1
:docker run -i -t --name httpd1 oraclelinux:7-slim /bin/bash
[root@httpd1 ~]#
-
If you use a web proxy, edit the yum configuration on the guest as described in Oracle Linux 7: Managing Software.
-
Install the
httpd
package:[root@httpd1 ~]# yum -y install httpd
-
If required, create the web content to be displayed under the
/var/www/html
directory hierarchy on the guest. -
Exit the guest by simply using the exit command from within the interactive guest session:
[root@httpd1 ~]# exit exit
Or by using the docker stop command on the host:
docker stop httpd1
-
Create the image
mymod/httpd
with the tagv1
using the ID of the container that you stopped:docker commit -m "ol7-slim + httpd" -a "A N Other" \ `docker ps -l -q` mymod/httpd:v1
sha256:b03fbc3216882a25e32c92caa2e797469a1ac98e5fc90affa07263b8cb0aa799
Use the -m and -a options to document the image and its author. The command returns the full version of the new image's ID.
Tip:
The docker ps -l -q command returns the ID of the last created container. We used this command in the example to obtain the ID of the container that we wanted to use to generate the image. You may, alternatively, specify the ID directly or use an alternate variation on this command to obtain the correct ID.
If you use the docker images command, the new image now appears in the list:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE mymod/httpd v1 b03fbc321688 2 minutes ago 426MB oraclelinux 7-slim c2b5cb5bcd9d 7 days ago 118MB
-
Remove the container named
httpd1
.docker rm httpd1
You can now use the new image to create a container that works as a web server, for example:
docker run -d --name newguest -p 8080:80 mymod/httpd:v1 /usr/sbin/httpd -D FOREGROUND
The -d option runs the command non-interactively in the background and displays the full version of the unique container ID. The -p 8080:80 option maps port 80 in the guest to port 8080 on the host. You can view the port mapping by running docker ps, for example:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 154f05ea464e mymod/httpd:v1 "/usr/sbin/httpd -D …" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp newguest
Alternately, use the docker port command, for example:
docker port newguest 80
0.0.0.0:8080
Note:
The docker ps command displays the short version of the container ID. You can use the --no-trunc option to display the long version.
The default IP address value of 0.0.0.0 means that the port mapping applies to all network interfaces on the host. You can restrict the IP addresses to which the remapping applies by using multiple -p options, for example:
docker run -d --name newguest -p 127.0.0.1:8080:80 -p 192.168.1.2:8080:80 \ mymod/httpd:v1 /usr/sbin/httpd -D FOREGROUND
You can view the web content served by the guest by pointing a browser at port 8080 on the host. If you access the content from a different system, you might need to allow incoming connections to the port on the host, for example:
firewall-cmd --zone=public --permanent --add-port=8080/tcp
If you need to remove an image, use the docker rmi command:
docker rmi mymod/httpd:v1
Untagged: mymod/httpd:v1 Deleted: sha256:b03fbc3216882a25e32c92caa2e797469a1ac98e5fc90affa07263b8cb0aa799 Deleted: sha256:f10c5b69ca9c3df53412238eefac72522720bc7c1a6a8eb6d21801c23a81c126
Note:
You cannot remove the image of a running container.
In a production environment, using the docker commit command to create an image does not provide a convenient record of how you created the image so you might find it difficult to recreate an image that has been lost or become corrupted. The preferred method for creating an image is to set up a Dockerfile, in which you define instructions that allow Docker to build the image for you. See Creating a Docker Image From a Dockerfile.
Creating a Docker Image From a Dockerfile
You use the docker build command to create a Docker image from the definition contained in a Dockerfile.
The following example demonstrates how to build an image named
mymod/httpd
with the tag v2
based on the oraclelinux:7-slim
image so that
it can run an Apache HTTP server.
To create a Docker image from a Dockerfile:
-
Make a directory where you can create the Dockerfile, for example:
mkdir -p /var/docker_projects/mymod/httpd
Note:
You do not need to create the Dockerfile on the same system on which you want to deploy containers that you create from the image. The only requirement is that the Docker Engine can access the Dockerfile.
-
In the new directory, create the Dockerfile, which is usually named
Dockerfile
. The following Dockerfile contents are specific to the example:# Dockerfile that modifies oraclelinux:7-slim to include an Apache HTTP server FROM oraclelinux:7-slim MAINTAINER A N Other <another@example.com> RUN sed -i -e '/^\[main\]/aproxy=http://proxy.example.com:80' /etc/yum.conf RUN yum -y install httpd RUN echo "HTTP server running on guest" > /var/www/html/index.html EXPOSE 80 ENTRYPOINT /usr/sbin/httpd -D FOREGROUND
The
#
prefix in the first line indicates that the line is a comment. The remaining lines start with the following instruction keywords that define how Docker creates the image:-
ENTRYPOINT
-
Specifies the command that a container created from the image always runs. In this example, the command is /usr/sbin/httpd -D FOREGROUND, which starts the HTTP server process.
-
EXPOSE
-
Defines that the specified port is available to service incoming requests. You can use the -p or -P options with docker run to map this port to another port on the host. Alternatively, you can use the --link option with docker run to allow another container to access the port over Docker's internal network (see Communicating Between Docker Containers).
-
FROM
-
Defines the image that Docker uses as a basis for the new image.
-
MAINTAINER
-
Defines who is responsible for the Dockerfile.
-
RUN
-
Defines the commands that Docker runs to modify the new image. In the example, the
RUN
lines set up the web proxy, install thehttpd
package, and create a simple home page for the server.
For more information about other instructions that you can use in a Dockerfile, see https://docs.docker.com/engine/reference/builder/.
-
-
Use the docker build command to create the image :
docker build --tag="mymod/httpd:v2" /var/docker_projects/mymod/httpd/
Sending build context to Docker daemon 2.048kB Step 1/6 : FROM oraclelinux:7-slim Trying to pull repository docker.io/library/oraclelinux ... 7-slim: Pulling from docker.io/library/oraclelinux a8d84c1f755a: Pull complete Digest: sha256:d574213fa96c19ae00269730510c4d81a9979ce2a432ede7a62b62d594cc5f0b Status: Downloaded newer image for oraclelinux:7-slim ---> c3d869388183 Step 2/6 : MAINTAINER A N Other <another@example.com> ---> Running in 26b0ba9f45e8 Removing intermediate container 26b0ba9f45e8 ---> f399f426b849 Step 3/6 : RUN yum -y install httpd ---> Running in d75a9f312202 Loaded plugins: ovl Resolving Dependencies --> Running transaction check ---> Package httpd.x86_64 0:2.4.6-88.0.1.el7 will be installed ... Complete! Removing intermediate container d75a9f312202 ---> aa3ab87bcae3 Step 4/6 : RUN echo "HTTP server running on guest" > /var/www/html/index.html ---> Running in dddedfc56849 Removing intermediate container dddedfc56849 ---> 8fedc8516013 Step 5/6 : EXPOSE 80 ---> Running in 6775d6e3996f Removing intermediate container 6775d6e3996f ---> 74a960cf0ae9 Step 6/6 : ENTRYPOINT /usr/sbin/httpd -D FOREGROUND ---> Running in 8b6e6f61a2c7 Removing intermediate container 8b6e6f61a2c7 ---> b29dea525f0a Successfully built b29dea525f0a Successfully tagged mymod/httpd:v2
Having built the image, you can test it by creating a container
instance named httpd2
:
docker run -d --name httpd2 -P mymod/httpd:v2
Note:
You do not need to specify /usr/sbin/httpd -D FOREGROUND as this command is now built into the container.
The -P option specifies that Docker should map the ports exposed by the guest to a random available high-order port (higher than 30000) on the host.
You can use docker inspect to return the host port that Docker maps to TCP port 80:
docker inspect --format='{{ .NetworkSettings.Ports }}' httpd2
map[80/tcp:[map[HostIp:0.0.0.0 HostPort:49153]]]
In this example, TCP port 80 in the guest is mapped to TCP port 49153 on the host.
You can view the web content served by the guest by pointing a browser at port 49153 on the host. If you access the content from a different system, you might need to allow incoming connections to the port on the host.
You can open the port by updating the firewall:
firewall-cmd --add-port=49153/tcp firewall-cmd --permanent --add-port=49153/tcp
You can also use curl to test that the server is working:
curl http://localhost:49153
HTTP server running on guest
Creating Multi-Stage Docker Image Builds
From Oracle Container Runtime for Docker 17.06, it is possible to perform multi-stage builds from a single Dockerfile. This allows you to perform interim build or compilation steps during the creation of the final image, without including all of the build tools and artifacts in the final image. This helps to reduce image sizes, and improves performance. It also allows you to deliver an image containing only the required binary and not all of the layers that were required to produce the binary.
In this section, we provide a very simple example scenario, where the source of a program is built in an interim compiler image and the resulting binary is copied into a separate image to produce the final target image. This entire build is handled by a single Dockerfile.
Create a simple "hello world" style program in C, by pasting the
following text into a file named hello.c
:
#include <stdio.h> int main (void) { printf ("Hello, world!\n"); return 0; }
Create a Dockerfile that contains the following text:
FROM gcc AS BUILD COPY . /usr/src/hello WORKDIR /usr/src/hello RUN gcc -Wall hello.c -o hello FROM oraclelinux:7-slim COPY --from=BUILD /usr/src/hello/hello hello CMD ["./hello"]
Note that there are two FROM
lines in this
Dockerfile. The first FROM
statement pulls the
latest gcc
image from the Docker hub and uses
the AS
syntax to assign it a name that we can
refer to later when copying elements from this temporary build
environment to our target image.
In the build environment, the source file is copied into the image
and the gcc compiler is run against the source
file to produce a hello
binary.
The second FROM
statement pulls the
oraclelinux:7-slim
image. This image is used to
host the hello
binary, which is copied into it
directly from the build environment. By doing this, the source,
the compiler and any other build artifacts can be excluded from
the final image.
To build the new image and run it, try running the following:
docker build -t hello-world ./
Sending build context to Docker daemon 35.38MB Step 1/7 : FROM gcc AS BUILD ---> 7d9419e269c3 Step 2/7 : COPY . /usr/src/hello ---> ee7310cc4464 Removing intermediate container 1d51e6f16833 Step 3/7 : WORKDIR /usr/src/hello ---> 2c0298733ba0 Removing intermediate container 46a09ccc06d6 Step 4/7 : RUN gcc -Wall hello.c -o hello ---> Running in f003deeebc20 ---> 67c85367cac1 Removing intermediate container f003deeebc20 Step 5/7 : FROM oraclelinux:7-slim ---> da5e55a16f7a Step 6/7 : COPY --from=BUILD /usr/src/hello/hello hello ---> 8bd284b0d7eb Removing intermediate container d71eee578325 Step 7/7 : CMD ./hello ---> Running in d6051d9e0a9d ---> dac5aa2d651d Removing intermediate container d6051d9e0a9d Successfully built dac5aa2d651d Successfully tagged hello-world:latest
docker run hello-world
Hello, world!
The hello-world
image is generated to contain
and run the hello
binary, but doesn't contain
any of the components that were required to build the binary. The
final image has less layers, is smaller and excludes any of the
build steps in its history.
About Docker Networking
The Docker networking features allow you to create secure networks of web applications that can communicate while running in separate containers. By default, Docker configures two types of network (as displayed by the docker network ls command):
-
host
-
If you specify the --net=host option to the docker create or docker run commands, Docker uses the host's network stack for the container. The network configuration of the container is the same as that of the host and the container shares the service ports that are available to the host. This configuration does not provide any network isolation for a container.
-
bridge
-
By default, Docker attaches containers to a bridge network named
bridge
. When you run a command such as ip link show on the host, the bridge is visible as thedocker0
network interface. You can use the bridge network to connect separate application containers. The docker network inspect bridge command allows you to examine the network configuration of the bridge, which is displayed in JSON format. Docker sets up a default subnet address, network mask, and gateway for the bridge network and automatically assigns subnet addresses to containers that you add to the bridge network. Containers on the default bridge network can communicate with each other on this network directly, although there is domain name resolution within this network to make containers specifically aware of each other.A container can communicate with other containers on a bridge network but not with other networks unless you also attach it to those networks. To define the networks that a container should use, specify a --net= bridge-network-name option for each network to the docker create or docker run commands. To attach a running container to a network, you can use the docker network connect network-name container-name command.
You can use the docker network create --driver bridge bridge-network-name command to create user-defined bridge networks that expose container network ports that can be accessed by external networks and other containers. You specify --net= bridge-network-name to docker create or docker run to attach the container to this network. More information on user-defined networking is provided in Communicating Between Docker Containers.
About Multihost Networking
A bridge network provides network isolation but it limits
container connections to a single host system unless you use a
complex user-defined bridge. Docker includes the VXLAN-based
overlay
network driver that supports
multihost networking, where you can attach separate application
containers running on multiple Docker hosts to the same virtual
overlay network. Before you can create an overlay network, you
must configure a key-value (KV) service such as Consul, Etcd, or
ZooKeeper that the Docker hosts can access to share
configuration information. You can then configure the Docker
daemon on each host to access the KV server by specifying
appropriate values to the
–cluster-advertise and
--cluster-store options. Next you use the
docker network create -driver overlay
multihost-network-name command on one
of the hosts to create the overlay network. Having created the
overlay network, you can attach the container to this network by
specifying
--net=
multihost-network-name
to docker create or docker
run.
For more information, see https://docs.docker.com/engine/userguide/networking/.
Communicating Between Docker Containers
All containers are automatically added to the default bridge network and assigned IP addresses by the Docker Engine. This means that containers are effectively able to communicate directly using the bridge network. However there is no automatic service discovery on the default bridge network. If containers need to be able to resolve IP addresses by container name, you should use a user-defined network instead.
You can use the --link option with docker run to make network connection information about a server container available to a client container. For example to link a client container, client1, to a server container, httpd_server, you could run:
docker run --rm -t -i --name client1 --link http-server:server oraclelinux /bin/bash
The client container uses a private networking interface to access
the exposed port in the server container. Docker sets environment
variables about the server container in the client container that
describe the interface and the ports that are available. The
server container name and IP address are also set in
/etc/hosts
in the client container, to
facilitate easy access.
The --link option is considered a legacy feature and may be deprecated in future releases. It is not recommended in most cases.
The preferred approach to setting up communications between containers is to create user-defined networks. These networks provide better isolation and can perform DNS resolution of container names to IP addresses. A variety of network drivers are available, but the most commonly used is the bridged network which behaves similarly to the default bridge network but which provides additional features.
The following example shows how to create a simple user-defined network bridge and how to connect containers to it, to allow them to communicate easily with each other.
-
Create a network using the bridge driver.
docker network create --driver bridge http_network
In the example, the network is named http_network.
You can check that the network has been created and which driver it is using:
docker network ls
NETWORK ID NAME DRIVER SCOPE 094c50739e14 bridge bridge local 7eff8115af9a host host local 4a03450bf054 http_network bridge local 457c4070f5a2 none null local
You can also inspect the network object to discover more information:
docker network inspect http_network
[ { "Name": "http_network", "Id": "4a03450bf054a6d4d4db52da36eab8d934d35bf961b3b3adb4fe20be54c0fdac", "Created": "2019-02-06T04:40:47.177691733-08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ]
-
Connect existing containers to the user-defined network.
docker network connect http_network http-server docker network connect http_network client1
In this example, http-server and client1 are existing containers that are connected to the newly created http_network bridge network.
-
Connect a new container to the user-defined network, using the --network option.
docker run --rm -t -i --name client2 --network http_network oraclelinux:7 /bin/bash
You can check that domain name resolution is working from within the container by pinging any other container on the network by its container name:
[root@client1 ~]# ping -c 1 http-server PING http-server (172.18.0.2) 56(84) bytes of data. 64 bytes from http-server.http_network (172.18.0.2): icmp_seq=1 ttl=64 time=0.162 ms --- http-server ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.162/0.162/0.162/0.000 ms
You can access services on containers within the network using their container names. For example:
[root@client1 ~]# curl http://http-server HTTP server running on guest
For more information, see https://docs.docker.com/engine/userguide/networking/.
Accessing External Files From Docker Containers
You can use the -v option with docker run to make a file or file system available inside a container. The following example demonstrates how to make web pages on the host available to an HTTP server running in a container.
Create the file /var/www/html/index.html
on the
host and run an HTTP server container that mounts this file:
echo "This text was created in a file on the host" > /var/www/html/index.html docker run -d --name newguest3 -P \ -v /var/www/html/index.html:/var/www/html/index.html:ro mymod/httpd:v2
The :ro modifier specifies that a container mounts a file or file system read-only. To mount a file or file system read-writable, specify the :rw modifier instead or omit the modifier altogether.
Check that the HTTP server is not running on the host:
[root@host ~]# curl http://localhost curl: (7) couldn't connect to host [root@host ~]# systemctl status httpd httpd is stopped
Even though an HTTP server is not running directly on the host,
you can display the new web page served by the
newguest3
container:
docker inspect --format='{{ .NetworkSettings.Ports }}' newguest3
map[80/tcp:[map[HostIp:0.0.0.0 HostPort:49153]]]
[root@host ~]# curl http://localhost:49153 This text was created in a file on the host
Any changes that you make to the
/var/www/html/index.html
file on the host are
reflected in the mounted file in the container:
echo "Change the file on the host" > /var/www/html/index.html
[root@host ~]# curl http://localhost:49153 Change the file on the host
Even if you delete the file on the host, it is still visible in the container:
rm -f /var/www/html/index.html
[root@host ~]# ls -l /var/www/html/index.html ls: cannot access /var/www/html/index.html: No such file or directory [root@host ~]# curl http://localhost:49153 Change the file on the host
It is not possible to use a Dockerfile to define how to mount a file or file system from a host. Docker applications are intended to be portable and it is unlikely that a file or file system that exists on the original host would be available on another system. If you want external file data to be portable, you can encapsulate it in a data volume container. See Creating and Using Data Volume Containers.
Creating and Using Data Volume Containers
If you specify a single directory argument to the
-v option of docker run,
Docker creates the directory in the container and marks it as a
data volume that other containers can mount.
You can also use the VOLUME
instruction in a
Dockerfile to create this data volume in an image. A container
that contains such a data volume is called a data volume
container. After populating the data volume with files, you can
use the --volumes-from option of
docker run to have other containers mount the
volume and access its data.
Note:
When you use docker rm to remove a container that has associated data volumes, specify the -v option to remove these volumes. Unassociated volumes waste disk space and are difficult to remove.
The following example creates a data volume container that an HTTP server container can use as the source of its web content.
To create a data volume container image and an instance of a data volume container from this image:
-
Make a directory where you can create the Dockerfile for the data volume container image, for example:
mkdir -p /var/docker_projects/mymod/dvc
-
In the new directory, create a Dockerfile named
Dockerfile
that defines the image for a data volume container:# Dockerfile that modifies oraclelinux:7-slim to create a data volume container FROM oraclelinux:7-slim MAINTAINER A N Other <another@example.com> RUN mkdir -p /var/www/html RUN echo "This is the content for file1.html" > /var/www/html/file1.html RUN echo "This is the content for file2.html" > /var/www/html/file2.html RUN echo "This is the content for index.html" > /var/www/html/index.html VOLUME /var/www/html ENTRYPOINT /usr/bin/tail -f /dev/null
The
RUN
instructions create a/var/www/html
directory that contains three simple files.The
VOLUME
instruction makes the directory available as a volume that other containers can mount by using the --volumes-from option to docker run.The
ENTRYPOINT
instruction specifies the command that a container created from the image always runs. To prevent the container from exiting, the /usr/bin/tail -f /dev/null command blocks until you use a command such as docker stop dvc1 to stop the container. -
Use the docker build command to create the image:
docker build --tag="mymod/dvc:v1" /var/docker_projects/mymod/dvc/
Sending build context to Docker daemon 2.048kB Step 1/8 : FROM oraclelinux:7-slim ---> c2b5cb5bcd9d Step 2/8 : MAINTAINER A N Other <another@example.com> ---> Running in 56c7b79c246e Removing intermediate container 56c7b79c246e ---> 620ff82e21cb Step 3/8 : RUN mkdir -p /var/www/html ---> Running in ac91306f3d74 Removing intermediate container ac91306f3d74 ---> 379c58d9eab9 Step 4/8 : RUN echo "This is the content for file1.html" > /var/www/html/file1.html ---> Running in 981773ba0210 Removing intermediate container 981773ba0210 ---> 2ee97d83b582 Step 5/8 : RUN echo "This is the content for file2.html" > /var/www/html/file2.html ---> Running in 36e8550c9a8b Removing intermediate container 36e8550c9a8b ---> 4ba8d28df981 Step 6/8 : RUN echo "This is the content for index.html" > /var/www/html/index.html ---> Running in 6f15a403b4f6 Removing intermediate container 6f15a403b4f6 ---> 550bb92c154b Step 7/8 : VOLUME /var/www/html ---> Running in 1806e5d6e643 Removing intermediate container 1806e5d6e643 ---> 0e3de4ac4c9c Step 8/8 : ENTRYPOINT /usr/bin/tail -f /dev/null ---> Running in 6cde4f965504 Removing intermediate container 6cde4f965504 ---> 5e4e2780503b Successfully built 5e4e2780503b Successfully tagged mymod/dvc:v1
-
Create an instance of the data volume container, for example
dvc1
:docker run -d --name dvc1 mymod/dvc:v1 tail -f /dev/null
To test that other containers can mount the data volume
(/var/www/html
) from dvc1
,
create a container named websvr
that runs an
HTTP server and mounts its data volume from
dvc1
.
docker run -d --volumes-from dvc1 --name websvr -P mymod/httpd:v2
After finding out the correct port to use on the host, use curl to
test that websvr
correctly serves the content of all three files that were
set up in the image. For example:
[root@host ~]# docker port websvr 80 0.0.0.0:32769 [root@host ~]# curl http://localhost:32769 This is the content for index.html [root@host ~]# curl http://localhost:32769/file1.html This is the content for file1.html [root@host ~]# curl http://localhost:32769/file2.html This is the content for file2.html
Moving Data Between Docker Containers and the Host
You can use the -v option of docker run to copy volume data between a data volume container and the host. For example, you might want to back up the data so that you can restore it to the same data volume container or to copy it to a different data volume container.
mymod/dvc:v1
that is described in Creating and Using Data Volume Containers.
You can use the following commands to start these containers:
docker run -d --name dvc1 mymod/dvc:v1 docker run -d --name dvc2 mymod/dvc:v1To copy the data from a data volume to the host, mount the volume from another container and use the cp command to copy the data to the host, for example:
docker run --rm --volumes-from dvc1 -v /var/tmp:/host:rw oraclelinux:7-slim \ cp -r /var/www/html /host/dvc1_files
The container mounts the host directory
/var/tmp
read-writable as
/host
, mounts all the volumes, including
/var/www/html
, that dvc1
exports, and copies the file hierarchy under
/var/www/html
to
/host/dvc1_files
, which corresponds to
/var/tmp/dvc1_files
on the host.
To copy the backup of dvc1
's data from the host
to another data volume container dvc2
, use a
command such as the following:
docker run --rm --volumes-from dvc2 -v /var/tmp:/host:ro \ oraclelinux:7-slim cp -a -T /host/dvc1_files /var/www/html
The container mounts the host directory
/var/tmp
read-only as /host
,
mounts the volumes exported by dvc2
, and copies
the file hierarchy under /host/dvc1_files
(/var/tmp/dvc1_files
on the host) to
/var/www/html
, which corresponds to a volume
that dvc2
exports.
You could also use a command such as tar to back up and restore the data as a single archive file, for example:
docker run --rm --volumes-from dvc1 -v /var/tmp:/host:rw \ oraclelinux:7-slim tar -cPvf /host/dvc1_files.tar /var/www/html
ls -l /var/tmp/dvc1_files.tar
-rw-r--r--. 1 root root 10240 Aug 31 14:37 /var/tmp/dvc1_files.tar
docker run --rm --volumes-from dvc2 -i -t --name guest -v /var/tmp:/host:ro \ oraclelinux:7-slim /bin/bash
On the guest, run the following commands:
[root@guest ~]# rm /var/www/html/*.html [root@guest ~]# ls -l /var/www/html/*.html total 0 [root@guest ~]# tar -xPvf /host/dvc1_files.tar var/www/html/ var/www/html/file1.html var/www/html/file2.html var/www/html/index.html [root@guest ~]# ls -l /var/www/html total 12 -rw-r--r--. 1 root root 35 Aug 30 09:02 file1.html -rw-r--r--. 1 root root 35 Aug 30 09:03 file2.html -rw-r--r--. 1 root root 35 Aug 30 09:03 index.html [root@guest ~]# exit exit
This example uses a transient, interactive container named
guest
to extract the contents of the archive to
dvc2
.
Using Labels to Define Metadata
You can use labels to add metadata to the Docker daemon and to
Docker containers and images. In the Dockerfile, a
LABEL
instruction defines an image label that
can contain one or more key-value pairs, for example:
LABEL com.mydom.dept="ITGROUP" \ com.mydom.version="1.0.0-ga" \ com.mydom.is-final \ com.mydom.released="June 6, 2015"
In this example, each key name is prefixed by the domain name in
reverse DNS form (com.mydom.
) to guard against
name-space conflicts. Key values are always expressed as strings
and are not interpreted by Docker. If you omit the value, you can
use the presence or absence of the key in the metadata to encode
information such as the release status. The backslash characters
allow you to extend the label definition across several lines.
You can use the docker inspect command to display the labels that are associated with an image, for example:
docker inspect 7ac15076dcc1 ... "Labels": { "com.mydom.dept": "ITGROUP", "com.mydom.version": "1.0.0-ga", "com.mydom.is-final": "", "com.mydom.release-date": "June 6, 2015" } ...
You can use the --filter "label=key [=value ]" option with the docker images and docker ps commands to list the images and running containers on which a metadata value has been set, for example:
docker images --filter "label=com.mydom.dept='DEVGROUP'" docker ps --filter "label=com.mydom.is-beta2" docker ps --filter "label=env=Oracle\ Linux\ 7"
For containers, you can use --label key=[value] options with the docker create and docker run commands to define key-value pairs, for example:
docker run -i -t --rm testapp:1.0 --label run="11" --label platform="Oracle Linux 7"
For the Docker Engine, you can use --label
key=[value]
options if you start docker from the command
line or edit the docker configuration file
/etc/sysconfig/docker
.
OPTIONS=" --label com.mydom.dept='DEVGROUP'"
Alternately, you can append these options to a list in the
/etc/docker/daemon.json
file, for example:
{ "labels": ["com.mydom.dept='DEVGROUP'", "com.mydom.version='1.0.0-ga'"] }
Note:
After adding or modifying a configuration file while the
docker
service is running, run the command
systemctl daemon-reload to tell
systemd
to reload the configuration for the
service.
As containers and the Docker daemon are transitory and run in a known environment, it is not usually necessary to apply reverse domain name prefixes to key names.
Defining the Logging Driver
You can use the --log-driver option with the docker create and docker run commands to specify the logging driver that a container should use:
- json-file
-
Write log messages to a JSON file that you can examine by using the docker logs command, for example:
docker logs --follow --timestamps=false container_name
This is the default logging driver.
- none
-
Disable logging.
- syslog
-
Write log messages to
syslog
.
About Image Digests
Registry version 2 or later images can be identified by their
digest (for example,
sha256:digest_value_in_hexadecimal
).
You can list the digest by specifying the
--digests option to the docker
images command. You can use a digest with the
docker create, docker pull,
docker rmi, and docker run
commands and with the FROM
instruction in a
Dockerfile.
Specifying Control Groups for Containers
You can use the --cgroup-parent option with the docker create command to specify the control group (cgroup) in which a container should run.
Limiting CPU Usage by Containers
To control a container's CPU usage, you can use the --cpu-period and --cpu-quota options with the docker create and docker run commands.
The --cpu-quota option specifies the number of microseconds that a container has access to CPU resources during a period specified by --cpu-period. As the default value of --cpu-period is 100000, setting the value of --cpu-quota to 25000 limits a container to 25% of the CPU resources. By default, a container can use all available CPU resources, which corresponds to a --cpu-quota value of -1.
Enabling a Container to Use the Host's UTS Namespace
By default, a container runs with a UTS namespace (which defines the system name and domain) that is different from the UTS namespace of the host. To make a container use the same UTS namespace as the host, you can use the --uts=host option with the docker create and docker run commands. This setting allows the container to track the UTS namespace of the host or to set the host name and domain from the container.
Attention:
As the container has full access to the UTS namespace of the host, this feature is inherently insecure.
Setting ulimit Values on Containers
The --ulimit option to docker
run allows you to specify ulimit
values for a container, for example:
docker run -i -t --rm myapp:2.0 --ulimit nofile=128:256 --ulimit nproc=32:64
This example sets a soft limit of 128 open files and 32 child processes and a hard limit of 256 open files and 64 child processes on the container.
You can set default ulimit
values for all
containers by specifying default-ulimits
options in a /etc/docker/daemon.json
configuration file, for example:
"default-ulimits": { "nofile": { "Name": "nofile", "Hard": 128, "Soft": 256 }, "nproc" : { "Name": "nproc", "Hard": 32, "Soft": 64 } },
Note:
After adding or modifying the configuration file while the
docker
service is running, run the command
systemctl daemon-reload to tell
systemd
to reload the configuration for the
service.
Any ulimit
values that you specify for a
container override the default values that you set for the daemon.
Building Images With Resource Constraints
You can specify cgroup resource constraints to docker build, for example:
docker build --cpu-shares=100 --memory=1024m \ --tag="mymod/myapp:1.0" /var/docker_projects/mymod/myapp/
Any containers that you generate from the image inherit these resource constraints.
You can use the docker stats command to display a container's resource usage, for example:
docker stats cntr1 cntr2
CONTAINER ID NAME CPU % MEM USAGE/LIMIT MEM % NET I/O BLOCK I/O PIDS 1ab12958b915 cntr1 0.05% 504 KiB/128 MiB 0.39% 2.033 KiB/40 B 13.7MB/1MB 1 3cf41296a324 cntr2 0.08% 1.756 MiB/128 MiB 1.37% 5.002 KiB/92 B 15.8MB/3MB 1
Committing, Exporting, and Importing Images
You can use the docker commit command to save the current state of a container to an image.
docker commit \ [--author="name"] \ [--change="instructions"]... \ [--message="text"] \ [--pause=false] container [repository[:tag]
You can use this image to create new containers, for example to debug the container independently of the existing container.
You can use the docker export command to export a container to another system as an image tar file.
docker export [--output="filename"] container
Note:
You need to export separately any data volumes that the container uses. See Moving Data Between Docker Containers and the Host.
To import the image tar file, use docker import and specify the image URL or read the file from the standard input.
docker import [--change="instructions"]... URL [repository[:tag] docker import [--change="instructions"]... - [repository[:tag] < filename
You can use --change options with docker commit and docker import to specify Dockerfile instructions that modify the configuration of the image, for example:
docker commit --change "LABEL com.mydom.status='Debug'" 7ac15076dcc1 mymod/debugimage:v1
For docker commit, you can specify the
following instructions: ADD
,
CMD
, COPY
,
ENTRYPOINT
, ENV
,
EXPOSE
, FROM
,
LABEL
, MAINTAINER
,
RUN
, USER
,
VOLUME
, and WORKDIR
.
For docker import, you can specify the
following instructions: CMD
,
ENTRYPOINT
, ENV
,
EXPOSE
, ONBUILD
,
USER
, VOLUME
, and
WORKDIR
.