Esempio di Chart

Desideriamo produrre un Chart di Helm che automatizzi l'installazione di un nostro precedente applicativo: Wordpress e MySQL.

L'esercizio presume che le immagini verranno scaricate dal registry locale.

Se non presenti dare i comandi:

docker pull mysql:5.6
docker tag mysql:5.6 localhost:5000/mysql:5.6
docker push localhost:5000/mysql:5.6
docker pull wordpress:4.8-apache
docker tag wordpress:4.8-apache localhost:5000/wordpress:4.8-apache
docker push localhost:5000/wordpress:4.8-apache

Scaffolding del Chart

Un Chart non è altro che una directory con una determinata struttura.

Preparare lo scaffolding:

mkdir -p wordpress/charts wordpress/templates/tests
touch wordpress/Chart.yaml wordpress/values.yaml
touch wordpress/templates/01pvpvc-mysql.yaml
touch wordpress/templates/02mysql.yaml 
touch wordpress/templates/03pvpvc-wpress.yaml
touch wordpress/templates/04wpress.yaml

Tutti i file contenuti nella directory templates sono considerati dei manifest a meno che il loro nome inizi con _ (underscore).

Vengono inviati allo API Server in ordine alfabetico. Per indicare l'ordine, come trucco diamo ai nomi dei template un numero progressivo.

I PV e PVC gestiti da Helm sono delicati. Meglio avere un manifest che si occupa solo di loro.

tree wordpress
wordpress
├── charts
├── Chart.yaml
├── templates
│   ├── 01pvpvc-mysql.yaml
│   ├── 02mysql.yaml
│   ├── 03pvpvc-wpress.yaml
│   ├── 04wpress.yaml
│   └── tests
└── values.yaml

Elementi del Chart

Per prima cosa preparare le specifiche del chart:

vim wordpress/Chart.yaml
apiVersion: v2
name: wordpress
description: Wordpress app with MySQL backend

type: application

version: 0.1.0

appVersion: "1.0.0"

Inserire il primo template, della parte MySQL - namespace, PV e PVC:

vim wordpress/templates/01pvpvc-mysql.yaml
kind: Namespace
apiVersion: v1
metadata:
  name: mysql-db
  labels:
    name: mysql-db
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv-volume
spec:
  storageClassName: standard
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /data/my/
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: my-pv-claim
  namespace: mysql-db
spec:
  volumeName: my-pv-volume
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Preparare il secondo template, della parte MySQL - secret, deployment e servizio:

vim wordpress/templates/02mysql.yaml
apiVersion: v1
kind: Secret
metadata:
  namespace: mysql-db
  name: mysql-pass
type: Opaque
data:
# secret
  root-password: c2VjcmV0
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  namespace: mysql-db
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:             
      containers:     
      - image: localhost:5000/mysql:5.6
        name: mysql     
        env:            
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:               
            secretKeyRef:          
              name: mysql-pass     
              key: root-password   
        ports:                     
        - containerPort: 3306      
          name: mysql              
        volumeMounts:              
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql     
      volumes:                          
      - name: mysql-persistent-storage  
        persistentVolumeClaim:          
          claimName: my-pv-claim
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: mysql-db
  labels:
    app: wordpress
spec:
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
  selector:
    app: wordpress
    tier: mysql

La terza è la parte WordPress - PV e PVC:

vim wordpress/templates/03pvpvc-wpress.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: wp-pv-volume
spec:
  storageClassName: standard
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /data/wp/
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: wp-pv-claim 
spec:                
  volumeName: wp-pv-volume
  accessModes:            
    - ReadWriteOnce
  resources:       
    requests:
      storage: 5Gi

La quarta è la parte Wordpress - secret, deployment e servizio:

vim wordpress/templates/04wpress.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysql-pass   
type: Opaque      
data:       
  root-password: c2VjcmV0
---
apiVersion: apps/v1   
kind: Deployment      
metadata:                                        
  name: wordpress                                
  labels:                                        
    app: wordpress                               
spec:                                            
  selector:                                      
    matchLabels:                                 
      app: wordpress                             
      tier: frontend                             
  strategy:                                      
    type: Recreate                               
  template:                                      
    metadata:                                    
      labels:                                    
        app: wordpress                           
        tier: frontend                           
    spec:                                        
      containers:                                
      - image: localhost:5000/wordpress:4.8-apache
        name: wordpress
        env:                                     
        - name: WORDPRESS_DB_HOST                
          value: mysql.mysql-db                  
        - name: WORDPRESS_DB_PASSWORD            
          valueFrom:                             
            secretKeyRef:                        
              name: mysql-pass                   
              key: root-password                 
        ports:                                   
        - containerPort: 80                      
          name: wordpress                        
        volumeMounts:                            
        - name: wordpress-persistent-storage     
          mountPath: /var/www/html               
      volumes:                                   
      - name: wordpress-persistent-storage       
        persistentVolumeClaim:                   
          claimName: wp-pv-claim
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  type: LoadBalancer
  ports:      
    - port: 8080        
      targetPort: 80 
  selector:         
    app: wordpress  
    tier: frontend

Installazione del Chart

Con questi elementi dovremmo essere subito in grado di installare il chart:

helm install myword wordpress
NAME: myword
LAST DEPLOYED: Tue Feb 27 17:01:51 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

Verifichiamo gli oggetti nello spazio di default:

kubectl get all
NAME                             READY   STATUS    RESTARTS   AGE
pod/wordpress-5cdb8f4c8f-ghbs5   1/1     Running   0          74s

NAME                 TYPE           CLUSTER-IP   EXTERNAL-IP      PORT(S)          AGE
service/kubernetes   ClusterIP      10.96.0.1    <none>           443/TCP          22h
service/wordpress    LoadBalancer   10.96.5.6    172.18.255.201   8080:31037/TCP   76s

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wordpress   1/1     1            1           75s

NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/wordpress-5cdb8f4c8f   1         1         1       75s

Verifichiamo gli oggetti nello spazio nomi `mysql-db``:

kubectl get all -n mysql-db
NAME                         READY   STATUS    RESTARTS   AGE
pod/mysql-5d5db54ccd-fpmhh   1/1     Running   0          3m38s

NAME            TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)          AGE
service/mysql   LoadBalancer   10.96.149.15   172.18.255.200   3306:30001/TCP   3m39s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql   1/1     1            1           3m38s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/mysql-5d5db54ccd   1         1         1       3m38s

Verifichiamo i PV:

kubectl get pv
NAME           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS   REASON   AGE
my-pv-volume   20Gi       RWO            Retain           Bound    mysql-db/my-pv-claim   standard                5m49s
wp-pv-volume   5Gi        RWO            Retain           Bound    default/wp-pv-claim    standard                5m49s

I PVC nello spazio nomi di default:

kubectl get pvc
NAME          STATUS   VOLUME         CAPACITY   ACCESS MODES   STORAGECLASS   AGE
wp-pv-claim   Bound    wp-pv-volume   5Gi        RWO            standard       7m24s

I PVC nello spazio nomi mysql-db:

kubectl get pvc -n mysql-db
NAME          STATUS   VOLUME         CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pv-claim   Bound    my-pv-volume   20Gi       RWO            standard       8m57s

Tutto è presente.

Listiamo il chart installato:

helm list
NAME  	NAMESPACE	REVISION	UPDATED                                	STATUS  	CHART          	APP VERSION
myword	default  	1       	2024-02-27 17:01:51.254489827 +0100 CET	deployed	wordpress-0.1.0	1.0.0      

Proviamo il collegamento con un browser a 172.18.255.201:8080.

Vediamo l'accesso a WordPress.

Wpress

Sembra funzionare.

Possiamo disinstallare il chart:

helm uninstall myword

Verifichiamo poi che tutti gli elementi dell'applicativo siano stati tolti.

Pacchettizzazione

Pacchettizziamo ora il chart:

helm package wordpress

Questo genera il file di package wordpress-0.1.0.tgz.

Lo potremo porre nel nostro repository personale quando ne avremo uno.

Il chart pacchettizzato è anche scaricabile al link wordpress-0.1.0.tgz.

Note

Il nostro chart non è per niente parametrico: non usa il linguaggi di templating. E' puramente un primo esercizio dimostrativo.

Volendo parte ora una lunga sequenza di Refactoring a passi successivi: a ciacun passo aggiungiamo un cero grado di parametrizzazione.

Diviene utile usare un ambiente di Controllo Versione, come Git, e un chain di CD/CI.

Ma questo è fuori dallo scopo del corso.