POD parameters : | OpenStack Group-1 | user0 | aio110 | 10.1.64.110 | compute120 | 10.1.64.120 | [email protected] |
User | aioX | computeY | Network & Allocation Pool |
user0
ssh : [email protected]
vnc : lab.onecloudinc.com:5900
|
aio110
eth0 : 10.1.64.110
eth1 : 10.1.65.110
eth2 : ext-net
Netmask : 255.255.255.0
Gateway : 10.1.64.1
|
compute120
eth0 : 10.1.64.120
eth1 : 10.1.65.120
eth2 : ext-net
Netmask : 255.255.255.0
|
Float Range : 10.1.65.00 – 10.1.65.00
Network : 10.1.65.0/24
Gateway : 10.1.65.1
DNS : 10.1.1.92
|
Introduction
Docker images are the basis of containers. In lab -1 we used Docker images that already exist, for example the centos image and 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.
1. Basic Commands
The following table summarizes the instructions; many of these options map directly to option in the “docker run” command:
Command | Description |
---|---|
ADD | Copies a file from the host system onto the container |
CMD | The command that runs when the container starts |
ENTRYPOINT | Allows to configure a container that will run as an executable |
ENV | Sets an environment variable in the new container |
EXPOSE | Opens a port for linked containers |
FROM | The base image to use in the build. This is mandatory and must be the first command in the file. |
MAINTAINER | An optional value for the maintainer of the script |
ONBUILD | A command that is triggered when the image in the Docker file is used as a base for another image |
RUN | Executes a command and save the result as a new layer |
USER | Sets the default user within the container |
VOLUME | Creates a shared volume that can be shared among containers or by the host machine |
WORKDIR | Set the default working directory for the container |
Once we have created a Docker file and added all instructions, we can use it to build an image using the docker build command. The format for this command is:
$ docker build [OPTIONS] PATH | URL | -
The build command results in a new image that user can start using docker run, just like any other image. Each line in the Docker file will correspond to a layer in the images’ commit history.
2. Building a Docker Image
The general Docker workflow is:
- Start a container based on an image in a known state
- Add things to the filesystem, such as packages, codebases, libraries, files, or anything else
- Commit the changes as layers to make a new image
2.1 Committing Docker Image
It is useful to commit a container’s file changes or settings into a new image. This allows user to debug a container by running an interactive shell, or to export a working dataset to another server.
As with the previous labs, you will need to SSH the aio node.
If you have logged out, SSH into your AIO node:
ssh centos@aio110
If asked, the user password (as with the sudo password) would be centos, then become root via the sudo password:
sudo su –
- Search for a suitable image by using the docker search command to find all the images that contain the term centos.
- Identified a suitable image, centos and now download it using the docker pull command.
- List the images locally on host.
- Run a container, refer to a tagged image.
- Installing Maria dB-server packages inside the image.
- Exit from the interactive mode.
- To check all the containers, use this command.
- Now have a container with the change want to make. Then commit a copy of this container to an image using the docker commit command.
- Check images list.
docker search fedora
docker pull fedora
docker images
docker run --name fedora_custom -it fedora /bin/bash
dnf install mariadb-server -y
dnf install git -y
exit
docker ps -a
docker commit -m "added mariadb-server and git" -a "OneCloud" fedora_custom labs/fedora_custom
Here we used the docker commit command. We specified two flags: -m and -a. The -m flag allows us to specify a commit message, much like we would with a commit on a version control system. The -a flag allows us to specify an author for our update.
docker images
Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
labs/fedora_custom latest bf294a57bdc0 8 minutes ago 579.7 MB
2.2 Building Image from a Dockerfile
Dockerfile is used for automation of work by specifying all step that we want on docker image. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using Docker build users can create an automated build that executes several command-line instructions in succession.
- First, create a directory and a Dockerfile.
- Each instruction creates a new layer of the image.
- Now let’s take Dockerfile and use the docker build command to build an image.
- Add a tag to an existing image after commit or build it. We can do this using the docker tag command. Now, add a new tag to example image.
- Check the image we have built on host.
mkdir example
cd example
cat > Dockerfile <<EOF
# This is a comment
FROM ubuntu
RUN apt-get update && apt-get install -y ruby ruby-dev
EOF
docker build -t example .
Output:
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu
---> bd3d4369aebc
Step 2 : RUN apt-get update && apt-get install -y ruby ruby-dev
---> Using cache
---> 9f65bddd0425
Successfully built 9f65bddd0425
Syntax
docker tag docker-image-id repo-name:tag
docker tag example example:ver1
docker images
Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
example latest 9f65bddd0425 3 minutes ago 206.8 MB
example ver1 9f65bddd0425 3 minutes ago 206.8 MB
Some more activity on Dockerfile
- Create a dockerfile.
- Take Dockerfile and use the docker build command to build an image.
- Check the image built on host.
- Add a tag to an existing image after commit or build it. We can do this using the docker tag command. Now, add a new tag to example image.
- Check the image that has built.
- Come out of the directory “example”.
cat > test <<EOF
############################################################
# Dockerfile to build MongoDB container images
# Based on Ubuntu
############################################################
# Set the base image to Ubuntu
FROM ubuntu
# File Author / Maintainer
MAINTAINER Example Test
# Update the repository sources list
RUN apt-get update
################## BEGIN INSTALLATION ######################
# Install MongoDB Following the Instructions at MongoDB Docs
# Ref: http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/
# Add the package verification key
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
# Add MongoDB to the repository sources list
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/mongodb.list
# Update the repository sources list once more
RUN apt-get update
# Install MongoDB package (.deb)
RUN apt-get install -y mongodb-10gen
# Create the default data directory
RUN mkdir -p /data/db
##################### INSTALLATION END #####################
# Expose the default port
EXPOSE 27017
# Default port to execute the entrypoint (MongoDB)
CMD ["--port 27017"]
# Set default container command
ENTRYPOINT usr/bin/mongod
EOF
docker build -f /root/example/test .
docker images
docker tag `docker images | head -2 | tail -1 | cut -d " " -f 30` monogodb:ubuntu
docker images
cd
2.3 Launching a newly built Container
In this step, verify the new images and then run new image. Open a command line terminal type docker images. This command lists the images we have locally.
docker images
Specify tag_name it will automatically run image with ‘latest’ tag. Instead of image_name we can also specify Image Id (no tag_name).
Run newly built image,
Syntax
docker run image-name:tag
docker run --name custom_container -dit monogodb:ubuntu
2.4 Configuring automatic restart
To ensure containers are always running with Docker’s Restart Policy, let’s understand a bit more about how Docker behaves when an application crashes. To facilitate this, we’ll create a Docker container that executes a simple bash script named crash.sh.
mkdir scripts
cd scripts
cat > crash.sh <<EOF
/bin/bash
sleep 30
exit 1
EOF
The above script is simple; when started, it will sleep for 30 seconds, and then it will exit with an exit code of 1 indicating an error.
Building and running a custom container
In order to run this script within a container, we’ll need to build a custom Docker container which includes the crash.sh script. In order to build a custom container, we first need to create a simple Dockerfile.
cat > Dockerfile <<EOF
FROM ubuntu:14.04
ADD crash.sh /
CMD /bin/bash /crash.sh
EOF
The above Dockerfile will build a container based on the latest ubuntu:14.04 image. It will also add the crash.sh script into the / directory of the container. The final line tells Docker to execute the crash.sh script when the container is started.
With the Dockerfile defined, we can now build our custom container using the docker build command.
docker build -f /root/scripts/Dockerfile .
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM ubuntu:14.04
---> e36c55082fa6
Step 2 : ADD crash.sh /
---> eb6057d904ef
Removing intermediate container 5199db00ba76
Step 3 : CMD /bin/bash /crash.sh
---> Running in 01e6f5e12c3f
---> 0e2f4ac52f19
Removing intermediate container 01e6f5e12c3f
Successfully built 0e2f4ac52f19
This build command created a Docker image with a tagged name of testing_restarts. We can now start a container using the testing_restarts image by executing docker run.
docker images
docker tag `docker images | head -2 | tail -1 | cut -d " " -f 30` testing_restarts:ver1
docker images
Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
testing_restarts ver1 532b81fe3ed4 46 seconds ago 187.9 MB
docker run -d --name testing_restart testing_restarts:ver1
Output:
a35bb16634a029039c8b34dddba41854e9a5b95222d32e3ca5624787c4c8914a
From the above, it appears that Docker was able to start a container named testing_restarts. Let’s check the status of that container by running docker ps.
docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
The docker ps command doesn’t show any running containers. The reason for this is because docker ps by default only shows running containers. Let’s take a look at running and non-running containers by using the -a flag.
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a35bb16634a0 testing_restarts "/bin/sh -c '/bin/bas" 9 minutes ago Exited (1) 8 minutes ago
With the docker ps results, we can see that when an application within a Docker container exits, that container is also stopped. This means that, by default, if an application that is running within a container crashes, the container stops and that container will remain stopped until someone or something restarts it.
Changing Docker’s Default Behavior
It’s possible to automatically restart crashed containers by specifying a restart policy when initiating the container. To understand restart policies better, let’s see what happens when we use the always restart policy with this same container.
docker run -d --name testing_restart1 --restart always testing_restarts:ver1
Output:
8320e96172e4403cf6527df538fb7054accf3a55513deb12bb6a5535177c1f19
In the above command, we specified that Docker should apply the always restart policy to this container via the –restart flag. Let’s see what effect this has on our container by executing a docker ps again.
docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAME
8320e96172e4 testing_restarts "/bin/sh -c '/bin/bas" About a minute ago Up 21 seconds
This time we can see that the container is up and running but only for 21 seconds. If we run docker ps
again, we will see something interesting.
docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8320e96172e4 testing_restarts "/bin/sh -c '/bin/bas" About a minute ago Up 19 seconds
The second run shows the container has only been up for 19 seconds. This means that even though our application (crash.sh) continues to exit with an error, Docker is continuously restarting the container every time it exits.
Now that we understand how restart policies can be used to change Docker’s default behavior, let’s take a look at what restart policies Docker has available.
Docker’s Restart Policy
Docker currently has four restart policies:
- No
- on-failure
- unless-stopped
- always
The no policy is the default restart policy and simply does not restart a container under any circumstance.
Restarting on failure but stopping on success
The on-failure policy is a bit interesting as it allows to tell Docker to restart a container if the exit code indicates error but not if the exit code indicates success. Also specify a maximum number of times Docker will automatically restart the container.
Let’s try this restart policy out with our testing_restarts container and set a limit of 5 restarts.
docker run -d --name testing_restart2 --restart on-failure:5 testing_restarts:ver1
Output:
85ff2f096bac9965a9b8cffbb73c1642bf7b64a2173bbd145961231861b95819
If we run docker ps
within a minute of launching the container, we will see that the container is running and has been recently started.
docker ps
Ouput:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85ff2f096bac testing_restarts:ver1 "/bin/sh -c '/bin/bas" About a minute ago Up 8 seconds
The same will not be true, however, if we run the docker ps
command 3 minutes after launching the container.
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85ff2f096bac testing_restarts:ver1 "/bin/sh -c '/bin/bas" 3 minutes ago Exited (1) 20 seconds ago
We can see from the above that after 3 minutes the container is stopped. This is due to the fact that the container has been restarted more than our max-retries setting.
With success
The benefit of on-failures is that when an application exits with a successful exit code, the container will not be restarted. Let’s see this in action by making a quick minor change to the crash.sh script.
The change will be to set the exit code to 0.
cat > crash.sh <<EOF
/bin/bash
sleep 30
exit 0
EOF
By setting the script to exit with a 0 exit code, we will be removing the error indicator from the script. Meaning as far as Docker can tell, this script will execute successfully every time. With the script changed, we will need to rebuild the container before we can run it again.
docker build -f /root/scripts/Dockerfile .
Output:
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM ubuntu:14.04
---> e36c55082fa6
Step 2 : ADD crash.sh /
---> a4e7e4ad968f
Removing intermediate container 88115fe05456
Step 3 : CMD /bin/bash /crash.sh
---> Running in fc8bbaffd9b9
---> 8aaa3d99f432
Removing intermediate container fc8bbaffd9b9
Successfully built 8aaa3d99f432
With the container image rebuilt, let’s launch this container again with the same on-failures and max-retries settings.
docker images
docker tag `docker images | head -2 | tail -1 | cut -d " " -f 30` testing_restarts:ver2
docker run -d --name testing_restarts3 --restart on-failure:5 testing_restarts:ver2
Ouput:
f0052e0c509dfc1c1b112c3b3717c23bc66db980f222144ca1c9a6b51cabdc19
This time, when we perform a docker ps -a execution, we should see some different results.
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f0052e0c509d testing_restarts:ver2 "/bin/sh -c '/bin/bas" 41 seconds ago Exited (0) 11seconds ago
Since the crash.sh script exited with a successful exit code (0), Docker understood this as a success and did not restart the container.
Always restart the container
If we wanted the container to be restarted regardless of the exit code, we have a couple of restart policies we could use:
- always
- unless-stopped
The always restart policy tells Docker to restart the container under every circumstance. We experimented with the always restart policy earlier, but let’s see what happens when we restart the current container with the always restart policy.
docker run -d --name testing_restarts4 --restart always testing_restarts:ver2
Output:
676f12c9cd4cac7d3dd84d8b70734119ef956b3e5100b2449197c2352f3c4a55
If we wait for a few minutes and run docker ps -a
again, we should see that the container has been restarted even with the exit code showing success.
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9afad0ccd068 testing_restarts:ver2 "/bin/sh -c '/bin/bas" 4 minutes ago Up 22 seconds
What’s special about the always restart policy is that even if our Docker host was to crash on boot, the Docker service will restart our container. Let’s see this in action to fully appreciate why this is useful.
reboot
Run the below commands after reboot.
ssh centos@aio110
sudo su -
By default, or even with on-failures, our container would not be running on reboot. Which, depending on what task the container performs, may be problematic.
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
676f12c9cd4c testing_restarts:ver2 "/bin/sh -c '/bin/bas" 9 minutes ago Up 2 seconds
With the always restart policy, that is not the case. The always restart policy will always restart the container. This is true even if the container has been stopped before the reboot.
Let’s look at that scenario in action.
docker stop testing_restarts4
Output:
testing_restarts4
reboot
Run the below commands after reboot.
ssh centos@aio110
sudo su -
Before rebooting our system, we simply stopped the container. This means the container is still there, just not running. Once the system is back up after our reboot however, the container will be running.
docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
676f12c9cd4c testing_restarts:ver2 "/bin/sh -c '/bin/bas" 11 minutes ago Up 24 second
The reason our container is running after a reboot is because of the always policy. Whenever the Docker service is restarted, containers using the always policy will be restarted regardless of whether they were running or not. The problem is that restarting a container that has been previously stopped after a reboot can be a bit problematic. What if our container was stopped for a valid reason, or worse, what if the container is out of date?
The solution for this is the unless-stopped restart policy.
Only stop when Docker is stopped
The unless-stopped restart policy behaves the same as always with one exception. When a container is stopped and the server is rebooted or the Docker service is restarted, the container will not be restarted. Let’s see this in action by starting the container with the unless-stopped policy and repeating our last example.
docker run -d --name testing_restarts5 --restart unless-stopped testing_restarts:ver2
Output:
fec5be52b9559b4f6421b10fe41c9c1dc3a16ff838c25d74238c5892f2b0b36
With the container running, let’s stop it and reboot the system again.
docker stop testing_restarts5
Output:
testing_restarts5
reboot
Run the below commands after reboot.
ssh centos@aio110
sudo su -
This time when the system restarts, we should see the container is in a stopped state.
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fec5be52b955 testing_restarts:ver2 "/bin/sh -c '/bin/bas" 2 minutes ago Exited (137) About a minute ago
One important item with unless-stopped is that if the container was running before the reboot, the container would be restarted once the system restarted. We can see this in action by restarting our container and rebooting the system again.
docker start testing_restarts5
Output:
testing_restarts5
reboot
Run the below commands after reboot.
ssh centos@aio110
sudo su -
After this reboot, the container should be running.
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fec5be52b955 testing_restarts:ver2 "/bin/sh -c '/bin/bas" 5 minutes ago Up 13 seconds testing_restarts
The difference between always and unless-stopped may be small, but in some environments this small difference may be a critical decision.
To remove all the containers run the below commands.
docker rm `docker ps -a -q` -f
To remove all the images run the below commands.
docker rmi `docker images -q` -f