# devops - docker

docs.docker.com

hub.docker.com/explore

registry - docs.docker.com

docker-overview - docs.docker.com

# VMs vs Containers

Containers and VMs - A Practical Comparison


      **VM**                                                   **Containers**

+-----------------+                                         +-----------------+ <-+
|       App       |                                         |       App       |   | All
|                 |                                         |                 |   | this part
+-----------------+                                         +-----------------+   | is a
         |                                                  | OS Dependencies |   | container
         |                                                  +-----------------+ <-+
         V
+-----------------+                                         +--------+--------+
|   Dependencies  |  <-- config                             |        | Docker |
+-----------------+                                         |        +--------+
|       OS        |                                         |                 |
|                 |                                         |      OS         |
+-----------------+                                         +-----------------+

     < VM >   NIC, Storage, Size                                  < VM >
     < VSphere, HV, NSX, VSAN > NIC, Storage,                     < HV >
                                Agents, Kernel

+-----------------+                                         +-----------------+
|                 |                                         |                 |
|    Physical     |                                         |    Physical     |
|                 |                                         |                 |
+-----------------+                                         +-----------------+
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

# service

www.docker.com/pricing

# installation

Install Docker Desktop on Linux - docs.docker.com

Install Docker Desktop on Ubuntu - docs.docker.com

Not directly mentioned in the doc but we need to add first the docker apt repo to the system. See this.

After installation, Docker Desktop is available from Gnome UI.

You can also check it from the CLI

marco@marco-ubuntu:~/Téléchargements$ docker compose version
Docker Compose version v2.19.1
marco@marco-ubuntu:~/Téléchargements$ docker --version
Docker version 24.0.4, build 3713ee1
marco@marco-ubuntu:~/Téléchargements$ docker version
Client: Docker Engine - Community
 Cloud integration: v1.0.35
 Version:           24.0.4
 API version:       1.43
 Go version:        go1.20.5
 Git commit:        3713ee1
 Built:             Fri Jul  7 14:50:55 2023
 OS/Arch:           linux/amd64
 Context:           desktop-linux

Server: Docker Desktop 4.21.1 (114176)
 Engine:
  Version:          24.0.2
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.4
  Git commit:       659604f
  Built:            Thu May 25 21:52:17 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.21
  GitCommit:        3dce8eb055cbb6872793272b4f20ed16117344f8
 runc:
  Version:          1.1.7
  GitCommit:        v1.1.7-0-g860f061
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

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

With docker info :

marco@marco-ubuntu:~/dev/test-projects/poc-ci-cdeploy$ sudo docker info
Client: Docker Engine - Community
 Version:    24.0.4
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.11.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.19.1
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 2
  Running: 1
  Paused: 0
  Stopped: 1
 Images: 3
 Server Version: 24.0.4
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 3dce8eb055cbb6872793272b4f20ed16117344f8
 runc version: v1.1.7-0-g860f061
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 5.15.0-76-generic
 Operating System: Ubuntu 22.04.2 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 15.57GiB
 Name: marco-ubuntu
 ID: 1db1fde2-c4fd-4bb3-b217-001f5a914a1a
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

The location of volumes on Docker Desktop host? - https://forums.docker.com

This is because Docker Desktop is not just a Graphical interface. It creates a virtual machine and runs Docker inside that virtual machine. You will not find volumes on your host and you will not be able to access the container IP addresses directly.

Linux post-installation steps for Docker Engine - Manage Docker as a non-root user

# basic definitions

Docker overview

# image

An image is a read-only template with instructions for creating a Docker container.

Often, an image is based on another image, with some additional customization. For example, you may build an image which is based on the ubuntu image, but installs the Apache web server and your application, as well as the configuration details needed to make your application run.

# Dockerfile

It is a blueprint to build an image.

To build your own image, you create a Dockerfile with a simple syntax for defining the steps needed to create the image and run it.

Each instruction in a Dockerfile creates a layer in the image. When you change the Dockerfile and rebuild the image, only those layers which have changed are rebuilt.

# container

A container is a runnable instance of an image. You can create, start, stop, move, or delete a container using the Docker API or CLI. You can connect a container to one or more networks, attach storage to it, or even create a new image based on its current state.

By default, a container is relatively well isolated from other containers and its host machine. You can control how isolated a container’s network, storage, or other underlying subsystems are from other containers or from the host machine.

A container is defined by its image as well as any configuration options you provide to it when you create or start it. When a container is removed, any changes to its state that are not stored in persistent storage disappear.

# usage

# list docker images (docker images)

marco@marco-ubuntu:~/Téléchargements$ docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE
1
2

# list running containers (docker ps)

marco@marco-ubuntu:~/Téléchargements$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
1
2

To get stopped containers add -a option : docker ps -a.

The output list can be easily filtered with grep : docker ps -a | grep <container-id|container-name>.

We run containers from images.

# pull an image (docker pull <image>:<version>)

marco@marco-ubuntu:~/Téléchargements$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
faef57eae888: Pull complete
76579e9ed380: Pull complete
cf707e233955: Pull complete
91bb7937700d: Pull complete
4b962717ba55: Pull complete
f46d7b05649a: Pull complete
103501419a0a: Pull complete
Digest: sha256:08bc36ad52474e528cc1ea3426b5e3f4bad8a130318e3140d6cfe29c8892c7ef
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

What's Next?
View summary of image vulnerabilities and recommendations → docker scout quickview nginx
marco@marco-ubuntu:~/Téléchargements$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
nginx        latest    021283c8eb95   4 days ago   187MB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# delete an image (docker rmi <image-id>)

If the image is used in any container, even a stopped one, it will fail.

You must delete first the containers where the image is used.

# create a new container from an image (docker run <image>:<version>)

marco@marco-ubuntu:~/Téléchargements$ docker run nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/07/09 15:48:23 [notice] 1#1: using the "epoll" event method
2023/07/09 15:48:23 [notice] 1#1: nginx/1.25.1
2023/07/09 15:48:23 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2023/07/09 15:48:23 [notice] 1#1: OS: Linux 5.15.49-linuxkit-pr
2023/07/09 15:48:23 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/07/09 15:48:23 [notice] 1#1: start worker processes
2023/07/09 15:48:23 [notice] 1#1: start worker process 29
2023/07/09 15:48:23 [notice] 1#1: start worker process 30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

It creates a new container then starts it.

Notice that docker run creates a new container everytime.

Add -d option to detach it from the terminal :

marco@marco-ubuntu:~/Téléchargements$ docker run -d nginx
1

To set a specific name to a container :

marco@marco-ubuntu:~/Téléchargements$ docker run --name web-app -d nginx
1

port binding between host and container (docker run -d -p <host-port>:<container-port> <image>:<version>)

Application in a container run in an isolated docker network. This allows us to run the same app running on the same port multiples times. So we need to expose the container port to the host (the system where the container runs on) :

marco@marco-ubuntu:~/Téléchargements$ docker run -d -p 9000:80 nginx
1

nginx runs inside the container on port 80, so here we are telling docker to map the nginx 80 port to localhost:9000.

# restart an existing container (docker start <container-id|container-name>)

Stopped container still exists :

marco@marco-ubuntu:~$ docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
b6b7b95102ef   nginx     "/docker-entrypoint.…"   4 minutes ago    Exited (0) 33 seconds ago             funny_williamson
de292300226c   nginx     "/docker-entrypoint.…"   21 minutes ago   Exited (0) 17 minutes ago             eager_moser
1
2
3
4

It means we can restart an old container by running docker start <container-id|container-name> instead of docker run <image:tag>.

Options used to create the container with docker run are used by default.

# to stop a detached container (docker logs <container-id|container-name>)

marco@marco-ubuntu:~/Téléchargements$ docker stop <container-id|container-name>
1

# to remove a container (docker rm <container-id>)

Of course the container must be stopped first before trying to delete it.

# to see the app logs (docker logs <container-id|container-name>)

marco@marco-ubuntu:~/Téléchargements$ docker logs <container-id|container-name>
1

# open a shell from a container (docker exec -it <container-id|container-name> <shell-to-use>)

<shell-to-use> can vary depending on the base image used. The more commons are /bin/sh and /bin/bash.

marco@marco-ubuntu:~$ docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS                    PORTS     NAMES
b6b7b95102ef   nginx     "/docker-entrypoint.…"   42 hours ago   Exited (0) 42 hours ago             funny_williamson
de292300226c   nginx     "/docker-entrypoint.…"   43 hours ago   Exited (0) 43 hours ago             eager_moser
marco@marco-ubuntu:~$ docker start eager_moser
eager_moser
marco@marco-ubuntu:~$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS         PORTS     NAMES
de292300226c   nginx     "/docker-entrypoint.…"   43 hours ago   Up 3 seconds   80/tcp    eager_moser
marco@marco-ubuntu:~$ docker exec -it eager_moser /bin/bash
root@de292300226c:/# ls
bin   dev                  docker-entrypoint.sh  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   lib64  media   opt  root  sbin  sys  usr
root@de292300226c:/# ls -la
total 72
drwxr-xr-x   1 root root 4096 Jul  9 15:48 .
drwxr-xr-x   1 root root 4096 Jul  9 15:48 ..
-rwxr-xr-x   1 root root    0 Jul  9 15:48 .dockerenv
lrwxrwxrwx   1 root root    7 Jul  3 00:00 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Mar  2 13:55 boot
drwxr-xr-x   5 root root  340 Jul 11 10:27 dev
drwxr-xr-x   1 root root 4096 Jul  4 17:24 docker-entrypoint.d
-rwxrwxr-x   1 root root 1616 Jul  4 17:23 docker-entrypoint.sh
drwxr-xr-x   1 root root 4096 Jul  9 15:48 etc
drwxr-xr-x   2 root root 4096 Mar  2 13:55 home
lrwxrwxrwx   1 root root    7 Jul  3 00:00 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Jul  3 00:00 lib32 -> usr/lib32
lrwxrwxrwx   1 root root    9 Jul  3 00:00 lib64 -> usr/lib64
lrwxrwxrwx   1 root root   10 Jul  3 00:00 libx32 -> usr/libx32
drwxr-xr-x   2 root root 4096 Jul  3 00:00 media
drwxr-xr-x   2 root root 4096 Jul  3 00:00 mnt
drwxr-xr-x   2 root root 4096 Jul  3 00:00 opt
dr-xr-xr-x 221 root root    0 Jul 11 10:27 proc
drwx------   2 root root 4096 Jul  3 00:00 root
drwxr-xr-x   1 root root 4096 Jul 11 10:27 run
lrwxrwxrwx   1 root root    8 Jul  3 00:00 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Jul  3 00:00 srv
dr-xr-xr-x  13 root root    0 Jul 11 10:27 sys
drwxrwxrwt   1 root root 4096 Jul  4 17:24 tmp
drwxr-xr-x   1 root root 4096 Jul  3 00:00 usr
drwxr-xr-x   1 root root 4096 Jul  3 00:00 var
root@de292300226c:/#
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
36
37
38
39
40
41
42

print container env var

root@de292300226c:/# env
HOSTNAME=de292300226c
PWD=/
PKG_RELEASE=1~bookworm
HOME=/root
NJS_VERSION=0.7.12
TERM=xterm
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_VERSION=1.25.1
_=/usr/bin/env
OLDPWD=/
root@de292300226c:/#
1
2
3
4
5
6
7
8
9
10
11
12
13

# docker network

# list docker networks available (docker network ls)

marco@marco-ubuntu:~$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
58bfe8771a6a   bridge    bridge    local
03bb08e12a19   host      host      local
5e16a0f46c9b   none      null      local
1
2
3
4
5

# create a new docker network (docker network create <network-name>)

# create a new container specifying the network (docker run --net <network-name> <image>:<version>)

# build an image from a Dockerfile

How to build our own docker images ?

Using a Dockerfile (the D matters, that's the naming convention).

A Dockerfile is a text file that contains commands to assemble an image.

Docker can then build an image by reading those instructions.

Rules :

  • A Dockerfile start from a parent image (or "base image").
  • It's a docker image that your image is based on.
  • Dockerfile must begin with a FROM instruction.
  • To run a shell command (like npm ci), use the RUN instruction.
  • The COPY <src> <dest> instruction copies files or dir from and adds them to the filesystem of the container at the path .
  • The WORKDIR is like cd in a shell.
  • The CMD command is the last command in a Dockerfile, it is the command to start the dockerized app.

Instructions references - docs.docker.com

A Dockerfile for node@19 example (a simple express server with just a package.json and a src/server.js file) :

FROM node:19-alpine

COPY package.json /app/
COPY src /app/

WORKDIR /app

RUN npm install

CMD ["node", "server.js"]
1
2
3
4
5
6
7
8
9
10

To build an image from a Dockerfile, use the docker build --tag <name>:<version> <path> command.

For example with the Dockerfile above : docker build -t node-app:1.0 . (the . means current dir).

Remember that a docker image consists of layers. Each instruction in the Dockerfile creates one layer. These layers are stored & each one is a delta of the changes from the previous layer.

Once the new image is built, it can be listed with docker images command.

# docker compose

When you need several services to run your solution, instead of :

  • creating a docker network where the services can talk to each other
  • docker run each service manually

You can write a yaml file specifying all these commands. Notice that the docker network is automatically created by docker-compose -f <file-name.yaml> up -d.

See:

# docker volumes

Volumes - docs.docker.com

Without defining volumes, the data written inside a container are wiped out when the container is removed.

Can be used from a docker compose file or directly from the docker run command as a parameter.

Example : docker run <other-args> -v <volume-name>:<container-path>.

<volume-name> is the name of the volume for docker.

<container-path> is the path for the data from the container perspective.

The data are saved on the host in /var/lib/docker/volumes/<random-hash>/_data/.

Docker Files and Volumes: Permission Denied

# list existing volumes

marco@marco-ubuntu:~/dev/test-projects/poc-ci-cdeploy$ sudo docker volume ls
DRIVER    VOLUME NAME
local     webapp-db
1
2
3

# managing secrets

# articles

# doc off

# best practices

10 best practices to containerize Node.js web applications with Docker

Top 8 Docker Best Practices for using Docker in Production

Best practices for writing Dockerfiles - docs.docker.com

Top 20 Dockerfile best practices

Docker ARG, ENV and .env - a Complete Guide

# getting started

6 Docker Basics You Should Completely Grasp When Getting Started

Docker Crash Course for Absolute Beginners

Docker Tutorial for Beginners [FULL COURSE in 3 Hours]

Get Docker CE for Ubuntu

Post-installation steps for Linux

Get Started, Part 1: Orientation and setup

# running context

# as a CLI tool

Interactive command-line application in a Docker container - stackoverflow.com - 20160726

Distributing Command Line Tools with Docker - spin.atomicobject.com - 20151130

# as a node app

nodejs/docker-node - github.com

# articles

Mise en place d'une Docker Registry privée - blog.eleven-labs.com - 20161207

5 minutes pour les conteneurs (docker) - romain.soufflet.io - 20190522