Accueil Solution du challenge Poznań de SadServers.com
Post
Annuler

Solution du challenge Poznań de SadServers.com

Scenario: “Poznań”: Helm Chart Issue in Kubernetes

Level: Medium

Type: Fix

Tags: kubernetes

Description: A DevOps engineer created a Helm Chart web-chart with a custom nginx site, however he still gets the default nginx index.html.

You can check for example with POD_IP=$(kubectl get pods -n default -o jsonpath='{.items[0].status.podIP}') and curl -s "${POD_IP}">.

In addition, he should set replicas to 3.

The chart is not working as expected. Fix the configurations, so you get the custom HTML page from any nginx pod.

Root access is not needed (“admin” user cannot sudo).

Credit Kamil Błaż

Test: Doing curl on the default port (:80) of any nginx pod returns a Welcome SadServers page. The “Check My Solution” button runs the script /home/admin/agent/check.sh, which you can see and execute.

Time to Solve: 15 minutes.

Tous les fichiers helm sont regroupés dans le dossier web_chat :

1
2
3
4
5
6
7
8
9
10
11
12
admin@i-051bc370604c4a393:~$ ls -Rl web_chart/
web_chart/:
total 12
-rw-r--r-- 1 admin admin  114 Feb 26 01:35 Chart.yaml
drwxr-xr-x 2 admin admin 4096 Feb 26 01:36 templates
-rw-r--r-- 1 admin admin  184 Feb 26 01:35 values.yaml

web_chart/templates:
total 12
-rw-r--r-- 1 admin admin 235 Feb 26 01:36 configmap.yaml
-rw-r--r-- 1 admin admin 551 Feb 26 01:35 deployment.yaml
-rw-r--r-- 1 admin admin 341 Feb 26 01:36 service.yaml

Sur le système, je remarque un conteneur docker, mais il s’agit du registry :

1
2
3
admin@i-051bc370604c4a393:~$ docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED       STATUS              PORTS                                       NAMES
313c4db27012   registry:2   "/entrypoint.sh /etc…"   13 days ago   Up About a minute   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   docker-registry

Je vois aussi un Nginx qui écoute en local, évidemment ce n’est pas celui qui nous intéresse.

1
2
3
4
admin@i-051bc370604c4a393:~/web_chart$ ps aux | grep nginx
root        2333  0.0  0.2  32660  5024 ?        Ss   13:37   0:00 nginx: master process nginx -g daemon off;
systemd+    2454  0.0  0.1  33116  3156 ?        S    13:37   0:00 nginx: worker process
admin       3671  0.0  0.0   5264   640 pts/0    S<+  13:51   0:00 grep nginx

Avec kubectl je vois un pod qui tourne :

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
61
62
63
64
admin@i-05973edec9df3b9dd:~$ kubectl describe pods
Name:             web-chart-nginx-c867f54dc-c6z9g
Namespace:        default
Priority:         0
Service Account:  default
Node:             node1/172.31.36.94
Start Time:       Mon, 26 Feb 2024 01:36:45 +0000
Labels:           app=nginx
                  pod-template-hash=c867f54dc
Annotations:      <none>
Status:           Running
IP:               10.42.0.19
IPs:
  IP:           10.42.0.19
Controlled By:  ReplicaSet/web-chart-nginx-c867f54dc
Containers:
  web-chart:
    Container ID:   containerd://68165e9c1b4883db65435c9a72b59dee6cb6560fe3701017a3aa61f8a0016b1f
    Image:          localhost:5000/nginx:1.17.0
    Image ID:       localhost:5000/nginx@sha256:079aa93463d2566b7a81cbdf856afc6d4d2a6f9100ca3bcbecf24ade92c9a7fe
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sun, 10 Mar 2024 13:57:58 +0000
    Last State:     Terminated
      Reason:       Unknown
      Exit Code:    255
      Started:      Mon, 26 Feb 2024 01:36:48 +0000
      Finished:     Sun, 10 Mar 2024 13:57:52 +0000
    Ready:          True
    Restart Count:  1
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-dq7b2 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-dq7b2:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason          Age   From               Message
  ----     ------          ----  ----               -------
  Normal   Scheduled       13d   default-scheduler  Successfully assigned default/web-chart-nginx-c867f54dc-c6z9g to node1
  Normal   Pulling         13d   kubelet            Pulling image "localhost:5000/nginx:1.17.0"
  Normal   Pulled          13d   kubelet            Successfully pulled image "localhost:5000/nginx:1.17.0" in 2.867s (2.867s including waiting)
  Normal   Created         13d   kubelet            Created container web-chart
  Normal   Started         13d   kubelet            Started container web-chart
  Warning  FailedMount     25s   kubelet            MountVolume.SetUp failed for volume "kube-api-access-dq7b2" : object "default"/"kube-root-ca.crt" not registered
  Normal   SandboxChanged  25s   kubelet            Pod sandbox changed, it will be killed and re-created.
  Normal   Pulled          24s   kubelet            Container image "localhost:5000/nginx:1.17.0" already present on machine
  Normal   Created         24s   kubelet            Created container web-chart
  Normal   Started         23s   kubelet            Started container web-chart

Le script de vérification du challenge récupère l’IP de ce pod et effectue une requête sur son port 80 pour voir la réponse.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/bash
# DO NOT MODIFY THIS FILE ("Check My Solution" will fail)

helm get values web-chart | grep -q "replicaCount: 3"
GET_REPLICAS=$?
POD_IP=$(kubectl get pods -n default -o jsonpath='{.items[0].status.podIP}')
curl -s "${POD_IP}" | grep -q "Welcome SadServers"
CHECK_WEB_SERVER=$?

if [[ "${GET_REPLICAS}" -eq 0 ]] && [[ "${CHECK_WEB_SERVER}" -eq 0 ]]; then
    echo -n "OK"
else
    echo -n "NO"
fi

Avec la commande suivante on peut voir que le pod est configuré pour n’avoir qu’une seule replica (instance) :

1
2
3
4
5
6
7
8
9
10
11
12
admin@i-051bc370604c4a393:~$ helm get values web-chart
USER-SUPPLIED VALUES:
image:
  pullPolicy: IfNotPresent
  repository: localhost:5000/nginx
  tag: 1.17.0
replicaCount: 1
service:
  name: nginx-service
  port: 8080
  targetPort: 9000
  type: ClusterIP

Le numéro de release est indiqué dans le fichier Chart.yaml, ici 0.1.0.

1
2
3
4
5
6
apiVersion: v2
name: web-chart
description: Helm Chart Nginx
type: application
version: 0.1.0
appVersion: "1.0.0"

Dans le fichier values.yaml on voit l’image utilisée ainsi que sa configuration :

1
2
3
4
5
6
7
8
9
10
11
12
replicaCount: 1

image:
  repository: localhost:5000/nginx
  tag: "1.17.0"
  pullPolicy: IfNotPresent

service:
  name: nginx-service
  type: ClusterIP
  port: 8080
  targetPort: 9000

Dans templates/configmap.yaml on trouve la configuration qui doit normalement placer le contenu HTML où il faut…

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: ConfigMap
metadata:
  name: -cm-index-html
  namespace: default
data:
  index.html: |
    <html>
    <h1>Welcome SadServers</h1>
    </br>
    <h1>Hi! I got deployed successfully</h1>
    </html>

Pour terminer, le fichier templates/deployment.yaml rassemble les différentes resources que l’on a vu via des références :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: apps/v1
kind: Deployment
metadata:
  name: -nginx
  labels:
    app: nginx
spec:
  replicas: 
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: 
          image: ":"
          imagePullPolicy: 
          ports:
            - name: http
              containerPort: 80
              protocol: TCP

Ce qu’on peut noter ici, c’est que le fichier configmap ne semble pas inclus dans le déploiement.

Si on se connecte au pod pour chercher le fichier index.html on constate en effet qu’il n’a pas été remplacé :

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
admin@i-05973edec9df3b9dd:~$ kubectl exec -it web-chart-nginx-c867f54dc-c6z9g /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# find / -name "index.html"
/usr/share/nginx/html/index.html
find: '/proc/7/map_files': Permission denied
# cat /usr/share/nginx/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

kubectl a bien connaissance de l’entrée configmap, mais il manque une relation avec le pod.

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
admin@i-05973edec9df3b9dd:~$ kubectl get configmaps -n default
NAME                      DATA   AGE
kube-root-ca.crt          1      21d
web-chart-cm-index-html   1      13d
admin@i-05973edec9df3b9dd:~$ kubectl describe configmap web-chart-cm-index-html -n default
Name:         web-chart-cm-index-html
Namespace:    default
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  meta.helm.sh/release-name: web-chart
              meta.helm.sh/release-namespace: default

Data
====
index.html:
----
<html>
<h1>Welcome SadServers</h1>
</br>
<h1>Hi! I got deployed successfully</h1>
</html>


BinaryData
====

Events:  <none>

Pour corriger ça il faut rajouter un volume qui utilise le configMap :

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
apiVersion: apps/v1
kind: Deployment
metadata:
  name: -nginx
  labels:
    app: nginx
spec:
  replicas: 
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
        - name: config-volume
          configMap:
            name: web-chart-cm-index-html
      containers:
        - name: 
          image: ":"
          imagePullPolicy: 
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          volumeMounts:
            - name: config-volume
              mountPath: /usr/share/nginx/html/

Il faut aussi changer la version de la release dans Chart.yaml. On peut ensuite faire un nouveau paquet :

1
2
3
4
5
6
7
8
9
10
admin@i-0de01eeb4911ab689:~$ helm package web_chart
Successfully packaged chart and saved it to: /home/admin/web-chart-0.1.1.tgz
admin@i-0de01eeb4911ab689:~$ helm upgrade web-chart /home/admin/web-chart-0.1.1.tgz
Release "web-chart" has been upgraded. Happy Helming!
NAME: web-chart
LAST DEPLOYED: Sun Mar 10 14:35:09 2024
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: Non

Cette fois, on obtient le bon contenu :

1
2
3
4
5
6
7
8
9
10
11
12
13
admin@i-0de01eeb4911ab689:~$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
web-chart-nginx-d5ff548b9-dn6wq   1/1     Running   0          50s
admin@i-0de01eeb4911ab689:~$ ./agent/check.sh 
NOadmin@i-0de01eeb4911ab689:~POD_IP=$(kubectl get pods -n default -o jsonpath='{.items[0].status.podIP}')')
admin@i-0de01eeb4911ab689:~$ echo $POD_IP
10.42.0.21
admin@i-0de01eeb4911ab689:~$ curl http://10.42.0.21
<html>
<h1>Welcome SadServers</h1>
</br>
<h1>Hi! I got deployed successfully</h1>
</html>

Il aura aussi fallu que je force le changement de replicas (édité dans values.yaml) avec cette commande :

1
2
3
4
5
6
7
8
admin@i-0de01eeb4911ab689:~$ helm upgrade web-chart /home/admin/web-chart-0.1.1.tgz -f web_chart/values.yaml
Release "web-chart" has been upgraded. Happy Helming!
NAME: web-chart
LAST DEPLOYED: Sun Mar 10 14:41:25 2024
NAMESPACE: default
STATUS: deployed
REVISION: 3
TEST SUITE: None
Cet article est sous licence CC BY 4.0 par l'auteur.