Accueil Solution du challenge Tarifa de SadServers.com
Post
Annuler

Solution du challenge Tarifa de SadServers.com

Scenario: “Tarifa”: Between Two Seas

Level: Medium

Type: Fix

Tags: docker haproxy realistic-interviews

Description: There are three Docker containers defined in the docker-compose.yml file: an HAProxy accepting connections on port :5000 of the host, and two nginx containers, not exposed to the host.

The person who tried to set this up wanted to have HAProxy in front of the (backend or upstream) nginx containers load-balancing them but something is not working.

Test: Running curl localhost:5000 several times returns both hello there from nginx_0 and hello there from nginx_1

Check /home/admin/agent/check.sh for the test that “Check My Solution” runs.

Time to Solve: 20 minutes.

On peut constater le problème nous même en demandant plusieurs fois la page HTML :

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
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ curl localhost:5000
hello there from nginx_0
admin@i-064e74fec80bbfdae:~$ docker ps -a
CONTAINER ID   IMAGE           COMMAND                  CREATED        STATUS          PORTS                                       NAMES
c79c9eb25143   haproxy:2.8.4   "docker-entrypoint.s…"   3 months ago   Up 48 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   haproxy
4052b12402a3   nginx:1.25.3    "/docker-entrypoint.…"   3 months ago   Up 48 seconds   80/tcp                                      nginx_1
2624cd20f3c4   nginx:1.25.3    "/docker-entrypoint.…"   3 months ago   Up 49 seconds   80/tcp                                      nginx_0

Avec docker inspect on peut voir comment sont configurés les conteneurs qui tournent :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/home/admin/custom-nginx_0.conf",
                "Destination": "/etc/nginx/conf.d/default.conf",
                "Mode": "ro",
                "RW": false,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/home/admin/custom_index/nginx_0",
                "Destination": "/usr/share/nginx/html",
                "Mode": "rw",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

Pour ce qui est du contenu monté ça semble correct :

1
2
3
admin@i-064e74fec80bbfdae:~$ cat custom_index/nginx_*/index.html
hello there from nginx_0
hello there from nginx_1

Jetons un œil au docker-compose.yaml :

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
version: '3'

services:
  nginx_0:
    image: nginx:1.25.3
    container_name: nginx_0
    restart: always
    volumes:
      - ./custom_index/nginx_0:/usr/share/nginx/html
      - ./custom-nginx_0.conf:/etc/nginx/conf.d/default.conf:ro
    networks:
      - frontend_network

  nginx_1:
    image: nginx:1.25.3
    container_name: nginx_1
    restart: always
    volumes:
      - ./custom_index/nginx_1:/usr/share/nginx/html
      - ./custom-nginx_1.conf:/etc/nginx/conf.d/default.conf:ro
    networks:
      - backend_network

  haproxy:
    image: haproxy:2.8.4
    container_name: haproxy
    restart: always
    ports:
      - "5000:5000"
    depends_on:
      - nginx_0
      - nginx_1
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
    networks:
      - frontend_network

networks:
  frontend_network:
    driver: bridge
  backend_network:
    driver: bridge

On remarque déjà que haproxy n’a qu’un seul des réseaux dans ses dépendances networks. Il faut rajouter une ligne pour backend_network.

On peut relancer les conteneurs, mais le résultat n’est pas meilleur. Je me connecte à chaque conteneur pour voir s’ils répondent :

1
2
3
4
5
6
7
admin@i-064e74fec80bbfdae:~$ docker exec -it 7f3733ea9925 /bin/sh
# curl http://127.0.0.1
hello there from nginx_0
# 
admin@i-064e74fec80bbfdae:~$ docker exec -it 0f59ba2de70d /bin/sh
# curl http://127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80 after 0 ms: Couldn't connect to server

La raison est que le second écoute sur un autre port :

1
2
3
4
5
admin@i-064e74fec80bbfdae:~$ diff ./custom-nginx_0.conf  ./custom-nginx_1.conf
2c2
<     listen 80;
---
>     listen 81;

Il faut modifier la configuration du HAProxy comme ceci :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
global
    daemon
    maxconn 256

defaults
    mode http
    default-server init-addr last,libc,none
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend http-in
    bind *:5000
    default_backend nginx_backends

backend nginx_backends
    balance roundrobin
    server nginx_0 nginx_0:80 check
    server nginx_1 nginx_1:81 check

On peut alors tout relancer et ça fonctionne comme attendu :

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
admin@i-064e74fec80bbfdae:~$ docker compose down
[+] Running 5/5
 ✔ Container haproxy               Removed                                                                                                                                                                    0.2s 
 ✔ Container nginx_0               Removed                                                                                                                                                                    0.3s 
 ✔ Container nginx_1               Removed                                                                                                                                                                    0.3s 
 ✔ Network admin_backend_network   Removed                                                                                                                                                                    0.1s 
 ✔ Network admin_frontend_network  Removed                                                                                                                                                                    0.2s 
admin@i-064e74fec80bbfdae:~$ docker compose up
[+] Running 5/5
 ✔ Network admin_frontend_network  Created                                                                                                                                                                    0.0s 
 ✔ Network admin_backend_network   Created                                                                                                                                                                    0.1s 
 ✔ Container nginx_0               Created                                                                                                                                                                    0.1s 
 ✔ Container nginx_1               Created                                                                                                                                                                    0.1s 
 ✔ Container haproxy               Created                                                                                                                                                                    0.0s 
Attaching to haproxy, nginx_0, nginx_1
nginx_1  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_1  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx_1  | 10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?)
nginx_1  | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx_0  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_0  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx_1  | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx_0  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx_0  | 10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?)
nginx_0  | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx_0  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx_0  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx_0  | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: using the "epoll" event method
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: nginx/1.25.3
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) 
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: OS: Linux 5.10.0-23-cloud-amd64
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: start worker processes
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: start worker process 21
nginx_1  | 2024/03/10 09:37:13 [notice] 1#1: start worker process 22
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: using the "epoll" event method
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: nginx/1.25.3
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) 
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: OS: Linux 5.10.0-23-cloud-amd64
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: start worker processes
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: start worker process 21
nginx_0  | 2024/03/10 09:37:13 [notice] 1#1: start worker process 22
haproxy  | [NOTICE]   (1) : New worker (9) forked
haproxy  | [NOTICE]   (1) : Loading success.
Cet article est sous licence CC BY 4.0 par l'auteur.