By Alwyn Botha, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.
This tutorial continues to give you practical experience using Dockerfile instructions. To follow the steps in this tutorial, make sure you have access to an Alibaba Cloud Elastic Compute Service instance with a recent version of Docker already installed. You can refer to this tutorial to learn how to install Docker on your Linux server.
It explores:
In this section you are going to learn how to use HEALTHCHECK in a Dockerfile.
HEALTHCHECK automate checks the health of your containers on a schedule you specify.
HEALTHCHECK [OPTIONS] CMD command
The options that can appear before CMD are:
--interval=DURATION (default: 30s)
--timeout=DURATION (default: 30s)
--start-period=DURATION (default: 0s)
--retries=N (default: 3)
For the purposes of this tutorial those durations are VERY long. We want to immediatly test and see the checks work.
Add only this to Dockerfile using
nano Dockerfile
FROM alpine:3.8
HEALTHCHECK --interval=3s --timeout=1s \
CMD curl -f http://localhost/ || exit 1
Important: please note the curl -f http://localhost/ health check command will ALWAYS fail in this specific Alpine container: we have no webserver running in the container.
Build the image using
docker build --tag tutorial:demo --file Dockerfile .
Let's start up a container to see the result.
docker stop -t 0 tutorial ; docker container prune -f
docker run -ti -d --name tutorial tutorial:demo /bin/sh -c 'while true; do sleep 60; done'
After the container starts, you have to execute docker ps -a repeatedly every second ( for 10 seconds ) to see how the health checks progress.
docker ps -a
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
27134771d5dd tutorial:demo "/bin/sh -c 'while t�" 3 seconds ago Up 1 second (health: starting)
ten seconds later below:
docker ps -a
Expected output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
27134771d5dd tutorial:demo "/bin/sh -c 'while t�" 12 seconds ago Up 10 seconds (unhealthy) tutorial
(health: starting) gets shown for 10 seconds since the checks get done in intervals of 3 seconds ( --interval=3s) and we specified a --timeout=1s.
Let's reduce the interval to 1 second so that we can see the health results faster.
Let's also reduce the retries from the default of 3 to just 1 using: --retries=1
In a PROD environment you will almost never use retries = 1. The 3 is a much better realistic real-life value.
Add this to Dockerfile using
nano Dockerfile
FROM alpine:3.8
HEALTHCHECK --interval=1s --timeout=1s --retries=1 \
CMD curl -f http://localhost/ || exit 1
Build the image using
docker build --tag tutorial:demo --file Dockerfile .
Let's start up a container to see the result.
docker stop -t 0 tutorial ; docker container prune -f
docker run -ti -d --name tutorial tutorial:demo /bin/sh -c 'while true; do sleep 60; done';docker ps -a; sleep .4; docker ps -a; sleep .4; docker ps -a; sleep .4; docker ps -a; sleep .4;
Notice I am checking the container status every .4 seconds.
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e83c476c2ee tutorial:demo "/bin/sh -c 'while t�" 1 second ago Up Less than a second (health: starting) tutorial
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e83c476c2ee tutorial:demo "/bin/sh -c 'while t�" 2 seconds ago Up Less than a second (health: starting) tutorial
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e83c476c2ee tutorial:demo "/bin/sh -c 'while t�" 2 seconds ago Up 1 second (unhealthy) tutorial
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e83c476c2ee tutorial:demo "/bin/sh -c 'while t�" 3 seconds ago Up 1 second (unhealthy) tutorial
For 0.8 seconds the health status is (health: starting)
After one second the status changes to (unhealthy).
It is up to you as admin to tinker these settings to suit your actual prod env:
--interval=DURATION (default: 30s)
--timeout=DURATION (default: 30s)
--start-period=DURATION (default: 0s)
--retries=N (default: 3)
You as admin must also determine in your prod env what appropriate health check commands would be. Web server containers, database containers, haproxy containers all have different health check requirements.
One second is too low a duration: it was just used here to show quickly how the status changes.
Just to see what healthy looks like, let's do a sample health check that succeeds.
Add this to Dockerfile using
nano Dockerfile
FROM alpine:3.8
HEALTHCHECK --interval=.1s --timeout=.4s --retries=1\
CMD sleep .1 || exit 1
Build the image using
docker build --tag tutorial:demo --file Dockerfile .
Let's start up a container to see the result.
docker stop -t 0 tutorial ; docker container prune -f
docker run -ti -d --name tutorial tutorial:demo /bin/sh -c 'while true; do sleep 60; done';docker ps -a; sleep .4; docker ps -a; sleep .4; docker ps -a; sleep .4; docker ps -a; sleep .4;
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c83552f66511 tutorial:demo "/bin/sh -c 'while t�" 1 second ago Up Less than a second (health: starting) tutorial
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c83552f66511 tutorial:demo "/bin/sh -c 'while t�" 2 seconds ago Up Less than a second (healthy) tutorial
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c83552f66511 tutorial:demo "/bin/sh -c 'while t�" 2 seconds ago Up 1 second (healthy) tutorial
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c83552f66511 tutorial:demo "/bin/sh -c 'while t�" 3 seconds ago Up 2 seconds (healthy) tutorial
Notice how the status changes to (healthy) in less that a second: the sleep .1 sleeps successfully for a tenth of a second then returns a successful status return code.
Unfortunately the docker ps -a command status filter does NOT match containers by HEALTH status. You can ONLY filter using created, restarting, running, removing, paused, exited and dead.
You cannot execute: docker ps --filter status=healthy
You cannot execute: docker ps --filter status=unhealthy
You have to use:
docker ps -a | grep '(healthy)'
and
docker ps -a | grep '(unhealthy)'
In this section you will learn how Dockerfile uses EXPOSE to expose ports of the container.
Containers are isolated running processes. They must specify explicitly which ports are accessible to other containers.
A port is the official way a process allows other processes to contact it and send it commands.
For example with Apache port 80 in normally exposed. Apache hides isolated within its container. The ONLY way to get it to do something is to access it via port 80.
The EXPOSE instruction declares the ports the container listens on.
You can state whether the port listens on the TCP or UDP protocol, The default is TCP if the protocol is not specified.
The EXPOSE instruction does not actually publish the port - it does not make it available to others.
EXPOSE only serves as documentation. It declares which ports in the container are intended to be available to be published.
From https://docs.docker.com/engine/reference/builder/#expose
To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.
By default, EXPOSE assumes TCP. You can also specify UDP:
EXPOSE 80/tcp
EXPOSE 80/udp
In this tutorial we are going to expose port 80, tcp and udp.
Edit your Dockerfile to look like:
nano Dockerfile
FROM alpine:3.8
EXPOSE 80/tcp
EXPOSE 80/udp
Build the image using
docker build --tag tutorial:demo --file Dockerfile .
Let's start up a container to see the result.
docker run -ti -d --name tutorial tutorial:demo /bin/sh -c 'while true; do sleep 60; done'
Expected output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6269a988e1dd tutorial:demo "/bin/sh -c 'while t�" 1 second ago Up Less than a second (health: starting) 80/tcp, 80/udp tutorial
In the ports column we can see those ports exposed: but they are not available for use. We must publish them. We do this using -p 30000:80/tcp on the docker run command.
-p 30000:80/tcp
The 30000 specifies the host port number. 80/tcp specifies the container port number.
Let's create the container and see the result:
docker stop -t 0 tutorial; ; docker container prune -f
docker run -p 30000:80/tcp -ti -d --name tutorial tutorial:demo /bin/sh -c '\''while true; do sleep 60; done'\'''
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8b3e43916708 tutorial:demo "/bin/sh -c 'while t�" 1 second ago Up Less than a second 0.0.0.0:30000->80/tcp, 80/udp tutorial
0.0.0.0:30000->80/tcp
Port 30000 on localhost is mapped to port 80 in the container.
We can check that port 30000 is now open on the host:
The ss command is used to show information about sockets. It is similar to netstat command. ( The netstat command no longer exists in default installation of the CentOS distro. It is replaced with service command. )
ss -t -a -n
short, long versions of the options:
Expected output
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
ESTAB 0 0 192.168.56.44:22 192.168.56.11:4118
ESTAB 0 64 192.168.56.44:22 192.168.56.11:2719
LISTEN 0 128 :::30000 :::*
LISTEN 0 128 :::22 :::*
We can see that port 30000 is now listening on the host.
The 30000 has no special meaning. Its just used here as an easy to find port number.
Let's publish udp port 80 as well. Run:
docker stop -t 0 tutorial; ; docker container prune -f
docker run -p 40080:80/udp 30000:80/tcp -
Check to see if the publish worked:
ss -u -a -n
Expected output
State Recv-Q Send-Q Local Address:Port Peer Address:Port
UNCONN 0 0 :::40080 :::*
Noticed this time I used -u argument to show udp ports.
You can use environment variables to send values to running containers.
They are part of the environment in which a container runs: you will see how this works below.
Syntax:
ENV
ENV =
The ENV instruction sets the environment variable to the value .
Examples:
ENV myVar1=1
ENV myVar42=42
ENV myAlfaVar=alfa value abc
Let's use our small Alpine Linux distro to see env variables within the env.
Create a Dockerfile with this content:
FROM alpine:3.8
ENV myVar1 1
ENV my42 42
ENV myVar42=42
ENV myAlfaVar='alfa abc'
Notice I used 2 different ways to declare env variables: one is space separated, one is = separated.
Build the image using
docker build --tag tutorial:demo --file Dockerfile .
Run:
docker stop -t 0 tutorial ; docker container prune -f
docker run -ti -d --name tutorial tutorial:demo /bin/sh -c 'while true; do sleep 60; done'
docker exec -it tutorial /bin/sh
Enter the printenv command at the # prompt:
Expected output
/ # printenv
HOSTNAME=1314796592cf
SHLVL=1
HOME=/root
my42=42
TERM=xterm
myVar1=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
myAlfaVar=alfa abc
myVar42=42
PWD=/
/ # exit
All the env variables we declared are there.
You can override the env variables when using docker run:
Run:
docker stop -t 0 tutorial ; docker container prune -f
docker run -e 'my42=44000' -ti -d --name tutorial tutorial:demo /bin/sh -c 'while true; do sleep 60; done'
If you now enter the container you will see my42 is 44000.
docker exec -it tutorial /bin/sh
Expected output
/ # printenv
HOSTNAME=1190753a779e
SHLVL=1
HOME=/root
my42=44000
TERM=xterm
myVar1=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
myAlfaVar=alfa abc
myVar42=42
PWD=/
You now have some practical experience declaring ENV variables in a Dockerfile as well as overriding them when using docker run -e 'my-env-var-name=new value'
You can also inspect the content of env variables using printenv. ( You could also use set or env to show env variables at the shell prompt. )
More information https://en.wikipedia.org/wiki/Environment_variable
https://docs.docker.com/engine/reference/builder/#env
https://docs.docker.com/engine/reference/builder/#environment-replacement
This concludes Part 2 of 4: Get to know all the Dockerfile Instructions. Continue reading Part 3 to learn more.
2,599 posts | 758 followers
FollowAlibaba Clouder - December 28, 2018
Alibaba Clouder - December 29, 2018
Alibaba Clouder - January 2, 2019
JDP - June 10, 2022
Alibaba Clouder - April 12, 2018
Farruh - March 6, 2023
2,599 posts | 758 followers
FollowLearn More
Alibaba Cloud Container Service for Kubernetes is a fully managed cloud container management service that supports native Kubernetes and integrates with other Alibaba Cloud products.
Learn MoreElastic and secure virtual cloud servers to cater all your cloud hosting needs.
Learn MoreMore Posts by Alibaba Clouder