Kubernetes – Partie 2

4 avril 2023

K8s, déployer une application de complexité moyenne

Contenu:

  1. Démonstration d’une app MongoDB + MongoExpress
  2. Laboratoire
    1. Déployer une application WordPress
    2. Déployer super Minou en 25 duplicatas
    3. Déployer PostgreSQL et pgadmin4
  3. Les ‘configmaps’
  4. Monter un volume à partir d’un configmap
  5. Laboratoire
    1. Déployer une application utilisant un configmap comme source d’un dossier
  6. Les ‘secrets’
  7. Exemple complet, mosquitto+Node-RED+volume+configMap+secret (TP02)

0 – Une petite révision d’un manifeste K8s

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx-123
spec:
  replicas: 2
  selector:
    matchLabels:
      mon-app: nginx-456
  template:
    metadata:
      labels:
        mon-app: nginx-456
    spec:
      containers:
      - name: nginx
        image: alainboudreault/superminou:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    mon-app: nginx-456
  type: LoadBalancer    
  ports:
    - protocol: TCP
      port: 81
      targetPort: 80

1 – Déploiement de MongoDB + MongoExpress

Étape 1.1 – Dans l’exemple suivant, nous allons déployer un système proposant un SGBD MongoDB et deux instances de – pour des raisons de fiabilité – Mongo-Express.

Action 1.1.1 – Voici le manifeste de MongoDB:

# Fichier mongo.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb-deploiement
  # Section facultative
  labels:
    app: mongodb
# 1 - Niveau du déploiement
spec:
  replicas: 1
  # Section obligatoire
  selector:
    matchLabels:
      app: mongodb
  # Section obligatoire
  template:
    metadata:
      labels:
        app: mongodb
    # 2 - Niveau du Pod
    spec:
      containers:
      # 3 - niveau des conteneurs
      - name: mongodb
        image: mongo
        ports:
        - containerPort: 27017
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          value: 4204d4
        - name: MONGO_INITDB_ROOT_PASSWORD
          value: secret

---

apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

Action 1.2 – Voici le manifeste de Mongo-Express:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-express
  labels:
    app: mongo-express
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mongo-express
  template:
    metadata:
      labels:
        app: mongo-express
    spec:
      containers:
      - name: mongo-express
        image: mongo-express
        ports:
        - containerPort: 8081
        env:
        - name: ME_CONFIG_MONGODB_ADMINUSERNAME
          value: 4204d4
        - name: ME_CONFIG_MONGODB_ADMINPASSWORD
          value: secret
        - name: ME_CONFIG_MONGODB_SERVER
          # ATTENTION, il faut utiliser le service pour l'accès à la BD
          value: mongodb-service
---
apiVersion: v1
kind: Service
metadata:
  name: mongo-express-service
spec:
  selector:
    app: mongo-express

  # *** type = LoadBalancer pour un accès externe au réseau K8S
  type: LoadBalancer  

  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081
      nodePort: 30000

Action 1.3 – Déployer les systèmes:

$ kubectl apply -f mongo.yml
$ kubectl apply -f mongo-express.yml

Action 1.4 – Vérifier les status:

$ kubectl get deployments.apps 

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
mongo-express         2/2     2            2           22m
mongodb-deploiement   1/1     1            1           26m
$ kubectl get pods

NAME                                  READY   STATUS      RESTARTS   AGE
mongo-express-5f96bb564d-997kr        1/1     Running     0          12m
mongo-express-5f96bb564d-9xlr2        1/1     Running     0          3m34s
mongodb-deploiement-5dcfb65b4-rldpq   1/1     Running     0          26m

Action 1.5 – Au besoin, afficher les logs – dans l’exemple suivant, le nom du service pointant vers la BD est erroné.

k logs mongo-express-6d9b4f9cb6-sdhsm
Waiting for mongodb:27017...
/docker-entrypoint.sh: line 14: mongodb: Name does not resolve
/docker-entrypoint.sh: line 14: /dev/tcp/mongodb/27017: Invalid argument
Tue Mar 23 20:29:32 UTC 2021 retrying to connect to mongodb:27017 (2/5)
/docker-entrypoint.sh: line 14: mongodb: Name does not resolve
/docker-entrypoint.sh: line 14: /dev/tcp/mongodb/27017: Invalid argument
Tue Mar 23 20:29:33 UTC 2021 retrying to connect to mongodb:27017 (3/5)
/docker-entrypoint.sh: line 14: mongodb: Name does not resolve
/docker-entrypoint.sh: line 14: /dev/tcp/mongodb/27017: Invalid argument
Tue Mar 23 20:29:34 UTC 2021 retrying to connect to mongodb:27017 (4/5)
/docker-entrypoint.sh: line 14: mongodb: Name does not resolve
/docker-entrypoint.sh: line 14: /dev/tcp/mongodb/27017: Invalid argument
Tue Mar 23 20:29:35 UTC 2021 retrying to connect to mongodb:27017 (5/5)
/docker-entrypoint.sh: line 14: mongodb: Name does not resolve
/docker-entrypoint.sh: line 14: /dev/tcp/mongodb/27017: Invalid argument
Welcome to mongo-express
------------------------


Mongo Express server listening at http://0.0.0.0:8081
Server is open to allow connections from anyone (0.0.0.0)
basicAuth credentials are "admin:pass", it is recommended you change this in your config.js!

/node_modules/mongodb/lib/server.js:265
        process.nextTick(function() { throw err; })
                                      ^
Error [MongoError]: failed to connect to server [mongodb:27017] on first connect
    at Pool.<anonymous> (/node_modules/mongodb-core/lib/topologies/server.js:326:35)
    at Pool.emit (events.js:314:20)
    at Connection.<anonymous> (/node_modules/mongodb-core/lib/connection/pool.js:270:12)
    at Object.onceWrapper (events.js:421:26)
    at Connection.emit (events.js:314:20)
    at Socket.<anonymous> (/node_modules/mongodb-core/lib/connection/connection.js:175:49)
    at Object.onceWrapper (events.js:421:26)
    at Socket.emit (events.js:314:20)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)

Action 1.6 – Afficher les informations d’un Déploiement

$ kubectl describe deployment mongo-express
Name:                   mongo-express
Namespace:              default
CreationTimestamp:      Tue, 23 Mar 2021 16:25:52 -0400
Labels:                 app=mongo-express
Annotations:            deployment.kubernetes.io/revision: 3
Selector:               app=mongo-express
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=mongo-express
  Containers:
   mongo-express:
    Image:      mongo-express
    Port:       8081/TCP
    Host Port:  0/TCP
    Environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME:  4204d4
      ME_CONFIG_MONGODB_ADMINPASSWORD:  secret
      ME_CONFIG_MONGODB_SERVER:         mongodb-service
    Mounts:                             <none>
  Volumes:                              <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Progressing    True    NewReplicaSetAvailable
  Available      True    MinimumReplicasAvailable
OldReplicaSets:  <none>
NewReplicaSet:   mongo-express-5f96bb564d (2/2 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  24m    deployment-controller  Scaled up replica set mongo-express-6d9b4f9cb6 to 1
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled up replica set mongo-express-7577cdb9c7 to 1
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled down replica set mongo-express-6d9b4f9cb6 to 0
  Normal  ScalingReplicaSet  13m    deployment-controller  Scaled up replica set mongo-express-5f96bb564d to 1
  Normal  ScalingReplicaSet  13m    deployment-controller  Scaled down replica set mongo-express-7577cdb9c7 to 0
  Normal  ScalingReplicaSet  4m43s  deployment-controller  Scaled up replica set mongo-express-5f96bb564d to 2

Action 1.7 – Exposer le service ‘mongo-express’ au monde extérieur:

$ minikube service mongo-express-service

Ce qui va donner:


2 – Laboratoires

Laboratoire 1 – Déployer une application WordPress

Durée: 40 minutes

Il faut mettre en place, grace à deux manifestes, un déploiement WordPress avec un SGBD ‘mariadb‘ et un ‘Pod’ wordpress.

Action Labo01.1

Action Labo01.2

Action Labo01.3


Laboratoire 2 – Déployer super Minou avec 25 duplicatas

Durée: 30 minutes

Résultat:


Laboratoire 3 – Déployer PostgreSQL et pgadmin4

Durée: 30 minutes




3 – Les ‘configMaps’

configMap – définition:

Les ‘configMaps‘ offrent un moyen d’implémenter une couche d’abstraction sur les informations, des fichiers manifestes, qui peuvent varier dans le temps. Habituellement utilisés pour les fichiers de configurations des applications.

Par exemple,

Au lieu de coder, en dur, ces informations dans les fichiers manifestes, il est possible de les enregistrer dans une BD locale.

Voici un exemple:

Action 3.1 – Renseigner le fichier ‘unConfigMap.yml’

# ------------------------------------------------------------------------------
# Fichier: unConfigMap.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.03.31-2023.04.04
# ------------------------------------------------------------------------------
# Description:  Exemple d'un configMap K8s
# ------------------------------------------------------------------------------
kind: ConfigMap
apiVersion: v1
metadata:
  name: kekun
data:
  # Voici des variables définies à la pièce:
  nom: Bob
  prenom: Binette

  # Voici des variables définies en bloc:
  unBlocDeClef: |

    age.bloc=33
    email.bloc=binette@brrr.poff
    cell.bloc=123.456.7890

Voici comment utiliser ce configMap:

Action 3.2 – Renseigner le fichier manisfeste ‘busybox.yml’

# ------------------------------------------------------------
# Fichier: busybox.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.03.31-2023.04.04
# ------------------------------------------------------------
# Exemple d'un manifeste pour un Pod avec des variables d'env,
# renseignées par un configMap
# https://cloud.google.com/kubernetes-engine/docs/concepts/configmap?hl=fr
# ------------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
  name: meta-busybox
spec:
  containers:
  - name: ma-busybox
    image: busybox
    command: ["/bin/sh", "-c",  "env"]

# Lors des exemples précédents, nous avons renseigné la Var ENV comme suit:
#   env:
#   - name: ENV01
#     value: YoDouloudou
# Remarquez qu'avec un configMap, la syntaxe est un peu différente!
    env:
    # Voici des exemples d'utilisation de variables définies à la pièce:
    - name: NOM
      valueFrom: 
        configMapKeyRef:
          name: kekun  # kekun est le nom de la configMap
          key: nom

    - name: PRENOM
      valueFrom: 
        configMapKeyRef:
          name: kekun
          key: prenom

    # Voici un exemple d'utilisation de variables définies en bloc:
    - name: LEBLOC
      valueFrom: 
        configMapKeyRef:
          name: kekun
          key: unBlocDeClef

Labo 3.2.1 – Appliquer les deux (2) manifestes et valider la présence des variables d’environnement.


MySql avec un configmap

Voici un exemple d’utilisation ‘MySQL’ de variables individuelles d’environnement, via un ‘configMap’

Action 3.3 – Renseigner le fichier suivant:

# Fichier: mysqlConfigMap.yml
# Projet: 420-4D4-Semaine 09
# Date: 2021.03.31-2023.04.04
# ------------------------------------------------------------------------------
# Description:  Exemple d'un configMap pour un Pod MySQL
# ------------------------------------------------------------------------------
kind: ConfigMap
apiVersion: v1
metadata:
  name: mysql-env
data:
  MYSQL_ROOT_PASSWORD: yo
  MYSQL_DATABASE: wordpress
  MYSQL_USER: wp
  MYSQL_PASSWORD: wp

Action 3.4 – Renseigner le fichier suivant:

# ------------------------------------------------------------
# Fichier: mysql.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.01-2023.04.04
# -------------------------------------------------------------------------
# Exemple d'un manifeste pour un Pod mysql avec des variables d'env,
# renseignées par un configMap
# -------------------------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
  name: meta-mysql
spec:
  containers:
  - name: mysql
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom: 
        configMapKeyRef:
          name: mysql-env  # mysql-env est le nom de la configMap
          key: MYSQL_ROOT_PASSWORD # MYSQL_ROOT_PASSWORD est le nom de la var dans le configMap

    - name: MYSQL_DATABASE
      valueFrom: 
        configMapKeyRef:
          name: mysql-env
          key: MYSQL_DATABASE

    - name: MYSQL_USER
      valueFrom: 
        configMapKeyRef:
          name: mysql-env
          key: MYSQL_USER

    - name: MYSQL_PASSWORD
      valueFrom: 
        configMapKeyRef:
          name: mysql-env
          key: MYSQL_PASSWORD

Action 3.4.1 – Appliquer les deux manifestes:

Kubectl apply -f mysqlConfigMap.yml

# Attention, l'ordre est important.  
# Le 'configmap' doit exister avant de créer le 'pod'. 

Kubectl apply -f mysql.yml

Validation:

Action 3.5 – Valider la création de la BD ‘wordpress’

kubectl exec -it meta-mysql -- bash
mysql> show databases;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| wordpress          |
+--------------------+

Action 3.5.1 – Valider la création du compte ‘wp’

mysql> SELECT user,host FROM mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| root             | %         |
| wp               | %         |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+

Action 3.5.2 – Valider les droits du compte ‘wp’

mysql> show grants for 'wp';
+--------------------------------------------------+
| Grants for wp@%                                  |
+--------------------------------------------------+
| GRANT USAGE ON *.* TO `wp`@`%`                   |
| GRANT ALL PRIVILEGES ON `wordpress`.* TO `wp`@`%`|
+--------------------------------------------------+

NOTE:

Un version ‘bloc’ ne fonctionnera pas ici. Le conteneur ‘mysql’ s’attend à trouver des variables individuelles. Dans le cas d’une consolidation de l’insertion de plusieurs variables, il est possible d’utiliser la directive ‘envFrom:‘.  Voici un exemple;

3.6 – La directive ‘envFrom’

La directive ‘envFrom‘ permet l’importation des toutes les variables d’un ‘configMap‘.

Action 3.6.1 – Renseigner le fichier suivant:

# -----------------------------------------------------------------
# Fichier: mysql-v2.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.01-2023.04.04
# ------------------------------------------------------------------
# Exemple d'un manifeste pour un Pod mysql avec des variables d'env,
# renseignées par un configMap complet, la directive 'envFrom'
# ------------------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
  name: meta-mysql-v2
spec:
  containers:
  - name: mysql-v2
    image: mysql

    # Noter que la directive est 'envFrom:' 
    # et non pas 'env:' 
    envFrom:

      # Noter que la directive est 'configMapRef 
      # et non pas 'configMapKeyRef' 
    - configMapRef:
        name: mysql-env

Action 3.6.2 – Appliquer le manifeste et vérifier que le SGBD fonctionne selon les directives des variables d’environnement.

kubectl apply -f mysql-v2.yml

Kubectl exec -it meta-mysql-v2 -- bash

Laboratoire 4

Reprendre le Laboratoire 1 en utilisant la directive envFrom pour les variables d’environnement du SGDB et de WordPress.

Note:  Il faut utiliser deux ‘configMap’.


4 – Monter un volume à partir d’un configmap

Note: Dans ce module, nous verrons comment présenter des donnés stockées dans un configmap sous forme d’un volume. Les notions plus approfondies sur volumes K8S sont disponibles dans ce document.


Voici l’exemple d’un volume K8S monté localement.

Note: Ceci n’est pas une pratique recommandée.

Action 4.1 – Créer un dossier et un fichier index.html, pour la liaison avec un pod de type nginx:

# 1 - créer un dossier
mkdir web-data

# 2 - Obtenir le chemin absolu du dossier pour référence dans l'étape suivante:
pwd

# Dans mon cas:

  /Users/alain/420-4D4/semaine09/web-data/

# 3 - Dans ce répertoire, créer un fichier 'index.html' avec le contenu suivant:

echo 'Ceci est la page index.html du serveur web.' > web-data/index.html

Action 4.2 – Renseigner le manifeste suivant:

# -------------------------------------------------------------
# Fichier: nginx_volume.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.03-2023.04.04
# -------------------------------------------------------------
# Exemple d'un manifeste pour un Pod nginx avec un volume local
# https://kubernetes.io/fr/docs/concepts/storage/volumes/
# https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
# -------------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
  name: serveur-web
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: volume-web

# Définition des volumes
  volumes:
  - name: volume-web
    hostPath:
      # chemin du dossier sur l'hôte
      # Il faut renseigner le chemin en utilisant l'adressage absolu.
      # Utiliser le chemin absolu de 4.1
      path: /Users/alain/420-4D4/semaine09/web-data/
      # ce champ est optionnel
      type: Directory

Action 4.3 – Appliquer le manifeste et tester la liaison de volume:

# 1 - appliquer le manifeste
kubectl apply -f nginx+volume.yml

# 2 - Se connecter au shell du pod
kubectl exec -it serveur-web -- bash

# 3 - AU BESOIN, installer 'curl'
apt update
apt install curl

$ 4 - Tester le service web
curl localhost

Résultat -->

  Ceci est la page index.html du serveur web.

L’exemple précédent est l’utilisation la plus simple possible d’un volume.  Kubernetes offre un large éventail de volumes permettant d’assurer le partage et la persistance des données.

Nous explorerons plus de possibilités dans un laboratoire à venir.

Référence Kubernetes sur les volumes


NOTE: Volume hostPath Minikube sur Linux

La version Minikube de Linux n’expose pas automatiquement le système de fichiers du host aux Pods.

Il faut monter manuellement  les volumes de la façon suivante:

minikube mount /home/alain/420-4d4/web-data:/usr/share/nginx/html

Une autre alternative et d’utiliser la directive ‘DirectoryOrCreate

  volumes:
  - name: volume-web
    hostPath:
     path: /420-4d4/web-data/
     type: DirectoryOrCreate

Cette directive va créer le dossier à l’intérieur de la VM de Minikube.

En s’y connectant, il sera possible de valider la présence du dossier:

$ minikube ssh
                         _             _            
            _         _ ( )           ( )           
  ___ ___  (_)  ___  (_)| |/')  _   _ | |_      __  
/' _ ` _ `\| |/' _ `\| || , <  ( ) ( )| '_`\  /'__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )(  ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)

$ ls /home/alain/420-4d4/web-data
index.html

4.4 – configMap + volume

Dans l’exemple suivant, nous allons renseigner le contenu d’un fichier lié à un pod à partir d’un configMap.

Action 4.4.1 – Renseigner le manifeste suivant:

# ------------------------------------------------------------------------------
# Fichier: configMapNginx.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.03-2023.04.04
# ------------------------------------------------------------------------------
# Description:  Exemple d'un volume (fichier) à partir d'un configMap
# ------------------------------------------------------------------------------
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config-map
data:
 # Voici le contenu, défini en bloc:
  contenu: |
    <head>
      <meta charset="UTF-8">
    </head>
    Il fît de la sorte,<br/>
    un assez long chemin.<br/>
    <bold>;-)</bold>

Action 4.4.2 – Renseigner le manifeste suivant:

# -------------------------------------------------------------
# Fichier: nginx+volumeVer2.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.03-2023.04.04
# -------------------------------------------------------------
# Exemple d'un manifeste pour un Pod nginx avec un volume local
#   défini via un configMap.
# -------------------------------------------------------------
apiVersion: apps/v1
kind: Deployment
# Section 1 - Les Méta-données
metadata:
  name: nginx-deployment
  labels:
    app: nginx
# Section 2 - Les spécifications
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: volume-web
    # Définition des volumes
      volumes:
      - name: volume-web
        configMap:
          name: nginx-config-map # tel que nommé dans le configMap
          items:
            - key: contenu       # tel que nommé dans le configMap
              path: index.html
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
    - protocol: TCP
      # Port à exposer au reseau local K8s
      port: 80
      # Port du conteneur - containerPort
      targetPort: 80
      nodePort: 30003

Action 4.4.3 – Appliquer les manifestes et tester l’application

kubectl apply -f configMapNginx.yml
kubectl apply -f nginx+volumeVer2.yml
minikube service nginx-service

Note: Le manifeste pour nginx est identique à celui que nous avons vu ici à l’action 3.10.  Seules les directives au volume ont été ajoutées.


4.5 – Utilisation d’un configMap comme source d’un dossier

Action 4.5.0 – Créer deux fichiers, i1.html et i2.html, dans le dossier web-data:

echo "Ceci est le fichier i1.html" > web-data/i1.html
echo "Ceci est le fichier i2.html" > web-data/i2.html


Créer un configmap à partir de la ligne de commande

Action 4.5 – Créer un ConfigMap avec le cli, kubectl create configmap:

# Créer un configMap, contenant deux fichiers, avec le cli:
kubectl create configmap un-dir --from-file=web-data/i1.html --from-file=web-data/i2.html

Action 4.5.1 – Afficher le contenu du configmap:

kubectl describe configmaps un-dir 
Name:         un-dir
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
i1.html:
----
Ceci est le fichier i1.html
i2.html:
----
Ceci est le fichier i2.html
Events:  <none>

Action 4.5.2 – Renseigner un manifeste qui utilise le configmap comme source d’un dossier local:

# ------------------------------------------------------
# Fichier: nginx+volumeVer3.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.03-2023.04.04
# ------------------------------------------------------
# Exemple d'un manifeste pour un Pod nginx avec un 
#   dossier local défini via un configMap.
# ------------------------------------------------------
apiVersion: apps/v1
kind: Deployment
# Section 1 - Les Méta-données
metadata:
  name: nginx-deployment-v3
  labels:
    app: nginx
# Section 2 - Les spécifications
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: contenu-web

    # Définition des volumes
      volumes:
      - name: contenu-web
        configMap:
          name: un-dir
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
    - protocol: TCP
      # Port à exposer au reseau local K8s
      port: 85
      # Port du conteneur - containerPort
      targetPort: 80
      nodePort: 30003

Action 4.5.3 – À vous de tester, dans un fureteur, les deux documents du serveur Web.


6 – Les ‘secrets’

« Ce que tu veux tenir secret ne le dis à personne »


Kubernetes offre la possibilité d’insérer des informations encryptées grace à l’utilisation de l’objet ‘secret’.

Voyons comment cela fonctionne.

Pré-requis – Savoir créer le contenu d’un objet à partir d’un littéral.  Par exemple,

Action 6.0 – Créer, avec le cli, un configmap à partir d’un littéral:

kubectl create configmap nom-projet --from-literal=NOM_PROJET="Intro aux secrets K8s"

kubectl describe configmaps nom-projet 
Name:         nom-projet
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
NOM_PROJET:
----
Intro aux secrets K8s
Events:  <none>

Action 6.0.1 – Éditer le configmap, ajouter la ligne 6 (VERSION: V1.0):

$ kubectl edit configmaps nom-projet

apiVersion: v1
data:
  NOM_PROJET: Intro aux secrets K8s
  VERSION: V1.0
kind: ConfigMap
metadata:
  creationTimestamp: "2021-04-03T17:42:12Z"
  name: nom-projet
  namespace: default
  resourceVersion: "845860"
  uid: 2943be07-a21d-4f1e-a000-b8a89f39df6e

Action 6.0.2 – Afficher le contenu du configmap édité:

$ kubectl describe configmaps nom-projet

Name:         nom-projet
Namespace:    default

Data
====
NOM_PROJET:
----
Intro aux secrets K8s
VERSION:
----
V1.0
Events:  <none>

Voila, nous sommes prêt à passer à l’action.

Action 6.1 – Créer, avec le cli, un ‘secret‘ à partir d’un littéral:

kubectl create secret generic mysql-password --from-literal=MYSQL_ROOT_PASSWORD=JTELEDISPAS

secret/mysql-password created

# ATTENTION au nom du secret, seulement [a-z,-,.]

Action 6.1.1 – Afficher l’objet ‘secret:mysql-password‘:

$ kubectl get secrets

NAME               TYPE                                  DATA   AGE
mysql-password     Opaque                                1      29m

$ kubectl describe secrets mysql-password

Name:         mysql-password
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
MYSQL_ROOT_PASSWORD:  11 bytes

# ---------

$ kubectl edit secrets mysql-password

# Note: Remarquez l'encodage du mot de passe, base64.

Action 6.2 – Renseigner le manifeste suivant:

# ------------------------------------------------------------
# Fichier: mysql+secret.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.03-2023.04.04
# -------------------------------------------------------------------------
# Exemple d'un manifeste pour un Pod mysql avec le mot de passe 'root'
#   dans un 'secret'.
# -------------------------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
  name: mysql-secret
spec:
  containers:
  - name: mysql
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom:
        # Noter que la directive est 'secretKeyRef' 
        # et non pas 'configMapKeyRef'  
        secretKeyRef:
          name: mysql-password  # mysql-password est le nom de l'objet 'secret'
          key: MYSQL_ROOT_PASSWORD # MYSQL_ROOT_PASSWORD est le nom de la var dans le secret

Action 6.2.1 – Appliquer le manifeste et tester le SGDB:

kubectl apply -f mysql+secret.yml 

kubectl exec -it mysql-secret -- bash

root@mysql-secret:/# mysql -uroot -JTELEDISPAS

mysql> show DATABASES;

Création et utilisation d’un manifeste de type ‘secret’

Voici comment renseigner un manifeste de type ‘secret’ et l’utiliser en un seul bloc dans un conteneur.

Action 6.3 – Renseigner un manifeste de type ‘secret’, ‘top-secret-mysql.yml’:

# Fichier: top-secret-mysql.yml
apiVersion: v1
kind: Secret
metadata:
  name: top-secret-mysql
type: Opaque
data:
  mysql-user: d3A=                          # echo -n 'wp' | base64
  mysql-user-password: dGVwYXNzZXJpZXV4     # echo -n 'tepasserieux' | base64
  mysql-database: d29yZHByZXNz              # echo -n 'wordpress' | base64
  mysql-root-password: aWxmaXRkZWxhc29ydGU= # echo -n 'ilfitdelasorte' | base64

Action 6.3.1 – Renseigner un manifeste de type ‘Pod’, ‘mysql_secretV2.yml’:

# ------------------------------------------------------------
# Fichier: mysql+secretV2.yml
# Auteur: Alain Boudreault
# Projet: 420-4D4-Semaine 09
# Date: 2021.04.03-2023.04.04
# -------------------------------------------------------------------------
# Exemple d'un manifeste pour un Pod mysql avec toutes les informations
#   de création du conteneur, dans un 'secret'.
# -------------------------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
  name: mysql-secret-v2
spec:
  containers:
  - name: mysql
    image: mysql
    # Note: envFrom: au lieu de env:
    envFrom:
    - secretRef:
        name: top-secret-mysql

Action 6.3.1 – Appliquer les deux (2) manifestes et tester l’application

NOTE: Le SGBD retournera des messages d’erreur lors du démarrage (kubectl logs mysql-secret-v2):

2023-04-04 17:11:01+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
    You need to specify one of the following as an environment variable:
    - MYSQL_ROOT_PASSWORD
    - MYSQL_ALLOW_EMPTY_PASSWORD
    - MYSQL_RANDOM_ROOT_PASSWORD

Expliquer les erreurs:

_____________________________________________________________

_____________________________________________________________

Corriger le(s) manifeste(s) et relancer l’application.

kubectl apply -f top-secret-mysql.yml
kubectl apply -f mysql+secretV2.yml
kubectl exec -it mysql-secret-v2 -- bash

root@mysql-secret-v2:/# mysql -uroot -pilfitdelasorte

mysql> show DATABASES;

Laboratoire 6

Reprendre le Laboratoire 3 en utilisant une ressource ‘secret’ pour le mot de passe et un configMap pour les autres informations.


7 – TP2: Mosquitto+node-red

Encodage en Base64, encodeur/décodeur

Référence: K8s-secret


Document rédigé par Alain Boudreault (c) 2021-2023 – version 2023.04.04.02