# devops - docker
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 |
| | | |
+-----------------+ +-----------------+
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
# 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
# print docker informations
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
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
# 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
2
# list running containers (docker ps
)
marco@marco-ubuntu:~/Téléchargements$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
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
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
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
To set a specific name to a container :
marco@marco-ubuntu:~/Téléchargements$ docker run --name web-app -d nginx
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
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
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>
# 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>
# 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:/#
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:/#
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
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 fromand adds them to the filesystem of the container at the path . - The
WORKDIR
is likecd
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"]
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
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
2
3
# managing secrets
# articles
- Don’t leak your Docker image’s build secrets
- Docker BuildKit: faster builds, new features, and now it’s stable
- Build secrets in Docker and Compose v1, the secure way
- The Complete Guide to Docker Secrets
# doc off
- Manage sensitive data with Docker secrets
- How to use secrets in Docker Compose
- compose file services secrets ref
- compose file secrets top level element doc
- compose file secrets top level element ref
# 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]
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