Skip to content

Commit 4da3f8b

Browse files
maricaantonaccistefanonicotridciangotzangrand
authored
Update 2024 (#1)
* Fix repo url * Trigger site build * Modify tree * Fix navigation * Add image building part * Add images * Fix typo * Add installation guide * Fix command line * Fix post-installation steps * Add health checks section * modified persisted data section * corrected typos * Update sections order * modified networking section * merge mess * merge fix * Restore env variables section * fix errors in docker image * add ci tutorial * Fix baltig remote url * Fix typo * Add section on gitlab runner * Fix syntax error * Update image * modified networking and data challenges * Update home page * Add lab challenge * Fix typo * corrected typo in volumes lab challenge * Update intro, container, gui (#2) * Enable code copy * Fix gitlab cli installation * Update gitlab runner section * Fix multi-stage Dockerfile * Fix multi-stage Dockerfile * fixed typo in networking.md (#3) * Dagger.io example (#4) * Add compose section * Add "#include <stdio.h>" to hello.c example (#5) --------- Co-authored-by: Stefano Nicotri <stefano.nicotri@gmail.com> Co-authored-by: dciangot <dciangot@cern.ch> Co-authored-by: ciangottini <diego.ciangottini@pg.infn.it> Co-authored-by: Stefano Nicotri <stefanonicotri@users.noreply.github.com> Co-authored-by: dciangot <diego.ciangottini@gmail.com> Co-authored-by: Lisa <lisa.zangrando@pd.infn.it>
1 parent b626eac commit 4da3f8b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2447
-593
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# docker-tutorial
22

3-
[https://maricaantonacci.github.io/docker-tutorial/](https://maricaantonacci.github.io/docker-tutorial/)
3+
[https://infn-bari-school.github.io/docker-tutorial/](https://infn-bari-school.github.io/docker-tutorial/)
4+

docs/compose/howto.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Todo

docs/compose/intro.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Todo

docs/container/env_vars.md

+11-5
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ When we launch our Docker container, **we can pass environment variables as key-
99
For instance, let's execute the following command:
1010

1111
```
12-
$ docker run --rm --env VARIABLE1=foobar alpine env
12+
docker run --rm --env VARIABLE1=foobar alpine env
1313
```
1414

15+
!!! tip
16+
Docker Alpine is the “Dockerized” version of Alpine Linux, a Linux distribution known for being exceptionally lightweight and secure. For these reasons and others, Docker Alpine is a popular choice for developers looking for a base image on which to create their own containerized apps.
17+
1518
The environment variables we set will be printed to the console:
1619

1720
```
21+
...
1822
VARIABLE1=foobar
1923
```
2024

@@ -37,6 +41,7 @@ docker run --rm --env VARIABLE2 alpine env
3741
And we can see Docker still picked up the value, this time from the surrounding environment:
3842

3943
```
44+
...
4045
VARIABLE2=foobar2
4146
```
4247

@@ -50,20 +55,21 @@ Let's define a few variables in a file we'll call _my-env.txt_:
5055

5156

5257
```
53-
$ echo VARIABLE1=foobar1 > my-env.txt
54-
$ echo VARIABLE2=foobar2 >> my-env.txt
55-
$ echo VARIABLE3=foobar3 >> my-env.txt
58+
echo VARIABLE1=foobar1 > my-env.txt
59+
echo VARIABLE2=foobar2 >> my-env.txt
60+
echo VARIABLE3=foobar3 >> my-env.txt
5661
```
5762

5863
Now, let's inject this file into our Docker container:
5964

6065
```
61-
$ docker run --env-file my-env.txt alpine:3 env
66+
docker run --env-file my-env.txt alpine env
6267
```
6368

6469
Finally, let's take a look at the output:
6570

6671
```
72+
...
6773
VARIABLE1=foobar1
6874
VARIABLE2=foobar2
6975
VARIABLE3=foobar3

docs/container/example.md

+119-118
Large diffs are not rendered by default.

docs/container/health_checks.md

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
Health checks (available since Docker 1.12) allow a container to expose its workload’s availability. This stands apart from whether the container is running. If your database goes down, your API server won’t be able to handle requests, even though its Docker container is still running.
2+
3+
When a health check command is specified, it tells Docker how to test the container to see if it's working. With no health check specified, Docker has no way of knowing whether or not the services running within your container are actually up or not.
4+
5+
Health checks can be configured in different ways:
6+
7+
- directly in the docker image (Dockerfile)
8+
- when you launch your standalone container with `docker run` (we will cover this case below) or in your docker compose file
9+
10+
In all cases, the health check is configured as a command that the docker daemon will execute every 30 seconds (default interval that can be overriden). Docker uses the command’s exit code to determine your container’s healthiness:
11+
12+
* 0 – The container is healthy and working normally.
13+
* 1 – The container is unhealthy; the workload may not be functioning.
14+
* 2 – This status code is reserved by Docker and should not be used.
15+
16+
Without health checks, a simple `docker ps` would report the container as available. Adding a health check extends the `docker ps` output to include the container’s true state.
17+
18+
## Health Check Configuration
19+
20+
There are a few options that we can use to customize our health check instruction:
21+
22+
- interval - DURATION (default: 30s)
23+
- timeout - DURATION (default: 30s)
24+
- start-period - DURATION (default: 0s)
25+
- retries - DURATION (default: 3)
26+
27+
where
28+
29+
- **interval** (option: `--health-interval`, default: 30s) - specifies the time between the health check for the application container. it waits for the specified time from one check to another.
30+
31+
- **timeout** (option: `--health-timeout`, default: 30s) - specifies the time that the health check waits for a response to consider the status of the container. For example, if we define 30 seconds and our server doesn’t respond within 30 seconds, then it’s considered as failed.
32+
33+
- **start-period** (option: `--health-start-period`, default: 0s) - specifies the number of seconds the container needs to start; health check will wait for that time to start.
34+
35+
- **retries** (option: `--health-retries`, default: 3) - specifies the number of consecutive health check failures required to declare the container status as unhealthy. Health check will only try up to the specified retry number. If the server fails consecutively up to the specified times, it is then considered unhealthy.
36+
37+
## Example
38+
39+
We will now add a health check to our `nginx` container: the check will be implemented using [`curl`](https://curl.se/docs/manpage.html) command `curl --fail http://localhost`:
40+
41+
```
42+
docker run --name nginx -d --health-cmd='curl --fail http://localhost:80 || exit 1' nginx
43+
```
44+
45+
The `curl` command makes a request to `localhost:80` and if the request returns the http code 200, it will return exit code 0; otherwise, it will return exit code 1.
46+
47+
Look at the container status using `docker ps`. The container can have three states:
48+
49+
* starting – Initial status when the container is still starting
50+
* healthy – If the command succeeds then the container is healthy
51+
* unhealthy – If a single run of the command takes longer than the specified timeout then it is considered unhealthy. If a health check fails, retries will be run for the requested number of times and the container status will be declared unhealthy if the check still fails.
52+
53+
```
54+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
55+
75beb1db3d27 nginx "/docker-entrypoint.…" 9 seconds ago Up 3 seconds (health: starting) 80/tcp nginx
56+
```
57+
58+
Initially, it will take some time to start the health check and update, whether the application is healthy or not.
59+
After the start period, if the application is healthy you will get:
60+
61+
```
62+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
63+
75beb1db3d27 nginx "/docker-entrypoint.…" 46 seconds ago Up 44 seconds (healthy) 80/tcp nginx
64+
```
65+
66+
You can have a look at the container log and see the requests made to check the health status of the application:
67+
68+
```
69+
docker logs nginx
70+
```
71+
```
72+
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
73+
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
74+
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
75+
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
76+
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
77+
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
78+
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
79+
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
80+
/docker-entrypoint.sh: Configuration complete; ready for start up
81+
2023/09/06 06:44:20 [notice] 1#1: using the "epoll" event method
82+
2023/09/06 06:44:20 [notice] 1#1: nginx/1.25.2
83+
2023/09/06 06:44:20 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
84+
2023/09/06 06:44:20 [notice] 1#1: OS: Linux 5.15.0-82-generic
85+
2023/09/06 06:44:20 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
86+
2023/09/06 06:44:20 [notice] 1#1: start worker processes
87+
2023/09/06 06:44:20 [notice] 1#1: start worker process 28
88+
2023/09/06 06:44:20 [notice] 1#1: start worker process 29
89+
127.0.0.1 - - [06/Sep/2023:06:44:49 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
90+
127.0.0.1 - - [06/Sep/2023:06:45:20 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
91+
127.0.0.1 - - [06/Sep/2023:06:45:51 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
92+
127.0.0.1 - - [06/Sep/2023:06:46:22 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
93+
127.0.0.1 - - [06/Sep/2023:06:46:53 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
94+
127.0.0.1 - - [06/Sep/2023:06:47:25 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
95+
127.0.0.1 - - [06/Sep/2023:06:47:55 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
96+
```
97+
98+
As you can see, the check runs every 30s (default) but you can change the interval with the option `--health-interval`.
99+
100+
Now let's remove the `index.html` file that nginx serves on http://localhost in order to simulate an application failure:
101+
102+
```
103+
docker exec nginx sh -c 'mv /usr/share/nginx/html/index.html /usr/share/nginx/html/index.html.1'
104+
```
105+
106+
Look again at the log:
107+
108+
```
109+
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
110+
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
111+
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
112+
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
113+
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
114+
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
115+
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
116+
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
117+
/docker-entrypoint.sh: Configuration complete; ready for start up
118+
2023/09/06 06:44:20 [notice] 1#1: using the "epoll" event method
119+
2023/09/06 06:44:20 [notice] 1#1: nginx/1.25.2
120+
2023/09/06 06:44:20 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
121+
2023/09/06 06:44:20 [notice] 1#1: OS: Linux 5.15.0-82-generic
122+
2023/09/06 06:44:20 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
123+
2023/09/06 06:44:20 [notice] 1#1: start worker processes
124+
2023/09/06 06:44:20 [notice] 1#1: start worker process 28
125+
2023/09/06 06:44:20 [notice] 1#1: start worker process 29
126+
127.0.0.1 - - [06/Sep/2023:06:44:49 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
127+
127.0.0.1 - - [06/Sep/2023:06:45:20 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
128+
127.0.0.1 - - [06/Sep/2023:06:45:51 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
129+
127.0.0.1 - - [06/Sep/2023:06:46:22 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
130+
127.0.0.1 - - [06/Sep/2023:06:46:53 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
131+
127.0.0.1 - - [06/Sep/2023:06:47:25 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
132+
127.0.0.1 - - [06/Sep/2023:06:47:55 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
133+
127.0.0.1 - - [06/Sep/2023:06:48:26 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
134+
127.0.0.1 - - [06/Sep/2023:06:48:57 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
135+
2023/09/06 06:49:27 [error] 29#29: *10 directory index of "/usr/share/nginx/html/" is forbidden, client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost"
136+
127.0.0.1 - - [06/Sep/2023:06:49:27 +0000] "GET / HTTP/1.1" 403 153 "-" "curl/7.88.1" "-"
137+
2023/09/06 06:49:58 [error] 29#29: *11 directory index of "/usr/share/nginx/html/" is forbidden, client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost"
138+
127.0.0.1 - - [06/Sep/2023:06:49:58 +0000] "GET / HTTP/1.1" 403 153 "-" "curl/7.88.1" "-"
139+
2023/09/06 06:50:29 [error] 29#29: *12 directory index of "/usr/share/nginx/html/" is forbidden, client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost"
140+
127.0.0.1 - - [06/Sep/2023:06:50:29 +0000] "GET / HTTP/1.1" 403 153 "-" "curl/7.88.1" "-"
141+
```
142+
143+
The `curl` command now returns the http error code 403 and therefore the check returns an exit code 1. Check the status of the container with `docker ps`:
144+
145+
```
146+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
147+
75beb1db3d27 nginx "/docker-entrypoint.…" 6 minutes ago Up 6 minutes (unhealthy) 80/tcp nginx
148+
```
149+
150+
The container is flagged as unhealthy after three failures of the check (you can change the number of retries with the option `--health-retries`).
151+
152+
!!! question "Exercise"
153+
Restore the `index.html` file and verify the container status.
154+
155+
## Example: create a MariaDB container configuring a custom health check to check whether the server is available.
156+
157+
1. Set the following environment variables with appropriate values for your MySQL configuration:
158+
```
159+
export MYSQL_USER=... # MySQL user (replace with your desired value)
160+
export MYSQL_PASSWORD=... # MySQL user password (replace with your desired value)
161+
export MYSQL_ROOT_PASSWORD=... # MySQL root user password (replace with your desired value)
162+
export MYSQL_DATABASE=... # MySQL database name (replace with your desired value)
163+
```
164+
165+
2. Run the container with the custom health check:
166+
```
167+
docker run -d --name db \
168+
-e MYSQL_DATABASE=${MYSQL_DATABASE} \
169+
-e MYSQL_USER=${MYSQL_USER} \
170+
-e MYSQL_PASSWORD=${MYSQL_PASSWORD} \
171+
-e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \
172+
--health-cmd='mysqladmin -p${MYSQL_ROOT_PASSWORD} ping -h localhost' \
173+
--health-interval=20s \
174+
--health-retries=3 \
175+
mariadb:latest
176+
```
177+
178+
In this command:
179+
180+
* `--name db`: Specifies the name of the container as "db."
181+
* `-e MYSQL_DATABASE=${MYSQL_DATABASE}`: Sets the MySQL database name as an environment variable.
182+
* `-e MYSQL_USER=${MYSQL_USER}`: Sets the MySQL user as an environment variable.
183+
* `-e MYSQL_PASSWORD=${MYSQL_PASSWORD}`: Sets the MySQL user's password as an environment variable.
184+
* `-e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}`: Sets the MySQL root user's password as an environment variable.
185+
* `--health-cmd`: Specifies the custom health check command, which uses the provided MySQL root password to check if the MariaDB server is responsive.
186+
* `--health-interval=20s`: Sets the health check interval to 20 seconds.
187+
* `--health-retries=3`: Specifies the number of retries before marking the container as "unhealthy."
188+
189+
190+
## Lab challenge
191+
192+
**Goal**: create a PostgreSQL container and setup a health check to monitor its status
193+
194+
!!! info "Hints"
195+
* Search for PostgreSQL official docker image on [docker hub](https://hub.docker.com/)
196+
* Read the documentation and understand how to start your server
197+
* Specify a simple health check using the tool "[pg_isready](https://www.postgresql.org/docs/current/app-pg-isready.html)" to check if the server is alive

0 commit comments

Comments
 (0)