For information on how to install Docker, please refer to: Docker Series (Chapter 0): Installing docker-engine in Ubuntu.

For guidance on how to create and use Docker images, please refer to: Docker Series (Chapter 1): Building and using images.

Alright, let’s continue learning the following Chapter.

Best Practices for Building Dockerfiles

  1. Containers should be ephemeral/temporary.

  2. Avoid installing unnecessary packages.

  3. Each container should have only one purpose.

  4. Avoid having too many layers in a container.

  5. Multi-line sorting.

  6. Leveraging cache.

Let me list an example here.

1
2
3
4
5
6
7
8
9
10
11
# Base image
FROM httpd
# The person who creates and maintains it
MAINTAINER Haoyang Sun
# RUN command to execute
RUN echo hello container > \
/usr/local/apache2/htdocs/index.html
# expose port as 80
EXPOSE 80
# Define the working directory
WORKDIR /usr/local/apache2/htdocs

Let’s use the Dockerfile to create a new image here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
shy@flash-shy:/HDD/learn/docker/apache2$ docker build -t web:v1 .
[+] Building 14.4s (8/8) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 189B 0.0s
=> WARN: MaintainerDeprecated: Maintainer instruction is deprecated in f 0.0s
=> [internal] load metadata for docker.io/library/httpd:latest 4.8s
=> [auth] library/httpd:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/3] FROM docker.io/library/httpd:latest@sha256:437b9f7d469dd606fa6d 8.9s
=> => resolve docker.io/library/httpd:latest@sha256:437b9f7d469dd606fa6d 0.0s
=> => sha256:3b71e7157e7a19c02c985d0962e01b5bbda6e329b24 2.10kB / 2.10kB 0.0s
=> => sha256:c14eb63a15a0449b7f25117f57bc1846c023cd706769acb 145B / 145B 1.7s
=> => sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d 32B / 32B 0.5s
=> => sha256:437b9f7d469dd606fa6d2a5f9a3be55fe3af7e0c6 10.16kB / 10.16kB 0.0s
=> => sha256:f7d8bafbd9a9fc570c19628411a8441e8dc6697aa43 7.88kB / 7.88kB 0.0s
=> => sha256:af302e5c37e9dc1dbe2eadc8f5059d82a914066b5 28.21MB / 28.21MB 7.1s
=> => sha256:abbcd5aab3664cf64a964a4c608f66689db8bcfe8ab 4.20MB / 4.20MB 4.9s
=> => sha256:04e5e6c6b4973d97b8b076a550d50ef5ddbfc6d12 26.06MB / 26.06MB 8.4s
=> => sha256:7f5fb3689eaee4c87c2455a8e061d6bb52da300369b0325 293B / 293B 5.4s
=> => extracting sha256:af302e5c37e9dc1dbe2eadc8f5059d82a914066b541b0d1a 0.6s
=> => extracting sha256:c14eb63a15a0449b7f25117f57bc1846c023cd706769acb8 0.0s
=> => extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6 0.0s
=> => extracting sha256:abbcd5aab3664cf64a964a4c608f66689db8bcfe8abea5b9 0.1s
=> => extracting sha256:04e5e6c6b4973d97b8b076a550d50ef5ddbfc6d125439f26 0.3s
=> => extracting sha256:7f5fb3689eaee4c87c2455a8e061d6bb52da300369b03257 0.0s
=> [2/3] RUN echo hello container > /usr/local/apache2/htdocs/index.ht 0.5s
=> [3/3] WORKDIR /usr/local/apache2/htdocs 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.0s
=> => writing image sha256:e30e7b98cd48deef0229fbdea27d499b039bf06f2bf3c 0.0s
=> => naming to docker.io/library/web:v1 0.0s

1 warning found (use docker --debug to expand):
- MaintainerDeprecated: Maintainer instruction is deprecated in favor of using label (line 3)

After building the iamge called: web:v1, let’s check the list of images.

1
2
3
4
5
shy@flash-shy:/HDD/learn/docker/apache2$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web v1 e30e7b98cd48 7 seconds ago 148MB
ubuntu 20.04 9df6d6105df2 5 months ago 72.8MB
......

Best Practices for naming the image

Obviously, We successfully creating a new images about 7 seconds ago. The image’s name is web and its tag is v1. Its size is about 148MB.

So, what is the reason we could quickly find the image we want?

Image naming format

REPOSITORY+TAG. It is recommended to use version number as the naming convention.

A simple and clear image naming format allows users to quickly identify the image they need without the need for testing.

Explanation of the ‘latest’ tag and its usage

If no tag is specified when building the image, the default latest tag will be used.

Therefore, when you see ‘latest’ as the tag of an image, it does not necessarily mean that this is the latest version. It simply means that no tag was specified when the image was created, and nothing more.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
shy@flash-shy:/HDD/learn/docker/apache2$ docker build -t web .
[+] Building 2.4s (8/8) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 189B 0.0s
=> WARN: MaintainerDeprecated: Maintainer instruction is deprecated in favor of using label (line 3) 0.0s
=> [internal] load metadata for docker.io/library/httpd:latest 2.3s
=> [auth] library/httpd:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/3] FROM docker.io/library/httpd:latest@sha256:437b9f7d469dd606fa6d2a5f9a3be55fe3af7e0c66e0329da8c14b291ae0d31c 0.0s
=> CACHED [2/3] RUN echo hello container > /usr/local/apache2/htdocs/index.html 0.0s
=> CACHED [3/3] WORKDIR /usr/local/apache2/htdocs 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:e30e7b98cd48deef0229fbdea27d499b039bf06f2bf3c1d137230e5266cd40a5 0.0s
=> => naming to docker.io/library/web 0.0s

1 warning found (use docker --debug to expand):
- MaintainerDeprecated: Maintainer instruction is deprecated in favor of using label (line 3)

It is visibly that each period of creating the same image is zero.

Here is the function of cache. Because I have already creating the same image before, it may reuse the cache this time.

Therefore, it will dramatically shorten the creating time.

1
2
3
4
5
6
shy@flash-shy:/HDD/learn/docker/apache2$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web latest e30e7b98cd48 15 minutes ago 148MB
web v1 e30e7b98cd48 15 minutes ago 148MB
ubuntu 20.04 9df6d6105df2 5 months ago 72.8MB
......

We could find there are two images, both of them are called web and the image id are the same. The difference is tag, this time I did not add the tag after the image name.

Therefore, the default tag is latest.

Basic commands about images

  • docker build -t image_name:tag_name .
1
docker build -t web:v1 .
  • docker commit container_name image_name:tag_name
1
docker commit web web:v2
  • docker save image_name:tag_name -o compression_name.tar
1
docker save web:v2 -o web_v2.tar
  • docker load -i compression_name
1
2
scp web_v2.tar user@ip:/path/to/images
docker load -i web_v2.tar

2 Methods of creating containers with image

As we discuss in Docker Series (Chapter 1): Building and using images, there are two methods to create a container by using an image.

  • docker run

    docker run is a basic Docker command used to directly start a new container. It is ideal for running a container individually to perform simple tasks or experiments.

    1
    docker run -d -p 8080:80 --name my-container nginx
  • docker compose

    docker-compose is a tool used to define and manage multi-container Docker applications.

    It configures services, networks, volumes, and more through a docker-compose.yaml file. docker-compose is ideal for managing applications made up of multiple containers, simplifying the configuration and startup of containers.

    It is used for one-click start, stop, and management of multiple containers.

    So, docker-compose builds on top of docker run, providing a more efficient and manageable way to handle multiple containers. It is especially useful for managing microservices architectures in development, testing, and production environments.

Feature docker run docker-compose
Use Case Single container, simple tasks or testing Multiple containers, complex applications, service dependencies management
Configuration Method Configured through command-line arguments Defined through the docker-compose.yml file with multiple containers, networks, volumes, etc.
Start Multiple Containers Need to start each container individually Use docker-compose up to start all containers at once
Service Dependency Management Manually manage dependencies between containers Define dependencies between containers in the docker-compose.yml file
Port Mapping Manually map ports, set individually for each container Unified port mapping management for multiple containers in the docker-compose.yml file
File Management No file configuration, relies on command-line arguments Uses docker-compose.yml file for centralized configuration and service management