Besoin : une page de maintenance pour des services hébergés sur un cluster kubernetes. Contraintes pour cette page de maintenance :
- être stateless
- avoir la possibilité de donner une raison à la maintenance en cours
Je voulais tester Caddy v2 depuis un petit moment, ca a été l’occasion pour ce besoin.
L’idée retenue :
- Un serveur caddy en reverse proxy d’un minio qui héberge les données de ma page de maintenance (html, css et un simple js).
- Il a une route
/reason
qui me permettra de changer la raison de la maintenance. - Tous les uris non connus sont renvoyés vers mon index.html pour que la page de maintenance fonctionne pour tous les uris (et ne pas chercher n’importe quoi via le reverse proxy).
- L’ingress controller Nginx utilise cette page de maintenance en default-backend.
Configurer le Minio (ou votre s3)
- Je créé un nouveau bucket pour héberger le contenu de la page de maintenance :
mc mb minio/maintenance
- Je copie le contenu de ma page de maintenance :
mc cp --recursive data/ minio/maintenance
- Je donne un accès publique à ces fichiers :
mc policy set download minio/maintenance
Si vous avez à votre disposition un backend HTTP x ou y, la suite de cet exemple fonctionnera.
Caddy
La configuration Caddy en json est disponible sur ce gist. Attention : l’api Caddy est exposée sur toutes les interfaces. A adapter selon votre besoin. Il y a peut-être moyen de faire plus simple avec Caddy, je découvre tout juste :)
Tester en local avec Docker
Pour tester en local sur votre machine, vous pouvez utiliser tout simplement cette commande :
docker run -p 10080:80 -p 2019:2019 -v $PWD/caddy.json:/caddy.json -it caddy caddy run -config /caddy.json
En pointant votre navigateur sur http://localhost:10080, Caddy devrait servir les pages de votre backend. Pour mon exemple, ca ressemble à ca :
Je peux modifier la raison de la maintenance avec un curl :
curl \
localhost:2019/config/apps/http/servers/maintenance/routes/0/handle/0/body \
-X POST \
-H "Content-Type: application/json" \
-d '"<b>Le cluster Etcd du K8S est HS :(</b>"'
Cette petite magie fonctionne grace au JS trouvé ici. J’ai dans ma page HTML :
<div w3-include-html="/reason" class="reason"></div>
Le JS charge donc la raison de ma maintenance via la route Caddy /reason
qui sert le contenu envoyé par le POST Json.
Pour information, il est aussi possible de changer la configuration et de forcer le rechargement :
curl localhost:2019/load \
-X POST \
-H "Content-Type: application/json" \
-d @caddy.json
Déployer sur un kubernetes
Rien de particulier à rajouter à ce niveau là. A vous d’adapter pour exposer en toute sécurité et selon votre besoin l’api Caddy.
apiVersion: v1
kind: Service
metadata:
name: maintenance
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
- name: api
port: 2019
protocol: TCP
targetPort: api
sessionAffinity: None
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: maintenance
spec:
replicas: 1
selector:
matchLabels:
name: maintenance
template:
metadata:
labels:
name: maintenance
spec:
containers:
- image: caddy:v2.2.1
command:
- caddy
- run
- -config
- /etc/caddy/caddy.json
name: maintenance
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 2109
name: api
protocol: TCP
resources:
limits:
cpu: 200m
memory: 200Mi
requests:
cpu: 100m
memory: 64Mi
volumeMounts:
- name: maintenance-config
mountPath: /etc/caddy/caddy.json
subPath: caddy.json
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 60
volumes:
- name: maintenance-config
configMap:
name: maintenance-config
Changer le default-backend de votre ingress
Sur l’ingress devant votre service, rajoutez l’annotation suivante pour utiliser cette page de maintenance si les endpoints du service défini dans l’ingress sont HS :
nginx.ingress.kubernetes.io/default-backend: maintenance
A savoir qu’il est également possible de renvoyer certaines erreurs http sur cette page de maintenance avec l’annotation nginx.ingress.kubernetes.io/custom-http-errors
.
Plus d’information dans la documentation.
Vous pouvez tester le bon fonctionnement de la page de maintenance avec un scale à 0 des pods du service derrière cet ingress.
Bref :) Tout ceci est là pour vous inspirer et sera à adapter en fonction de votre stratégie de mise à jour, déploiement … Bon tests !