Kubernetes multi cluster et multi région en GitOps avec ArgoCD
Je présenterai dans cet article comment gérer les applications et ressources déployées sur plusieurs clusters Kubernetes, déployés dans plusieurs datacenters, avec ArgoCD.
ArgoCD
ArgoCD est un outil de déploiement continu pour Kubernetes, permettant de configurer en GitOps
vos clusters. Cet outil est capable de gérer tout type de ressources Kubernetes (sans aucune limitations, CRD incluses).
Il supporte également très bien l’écosystème Kubernetes standard pour gérer les manifests de déploiements (Helm, Kustomize… mais étendre l’outil avec ses propres outils est également possible), et dispose égalemement d’une très bonne interface utilisateur.
ArgoCD est l’outil que je recommande le plus aujourd’hui pour les utilisateurs de Kubernetes.
Nous commencerons dans cet article par expliquer rapidement le fonctionnement d’ArgoCD, puis nous déploierons 3 clusters Kubernetes sur Exoscale. SKS, l’offre Kubernetes as a service d’Exoscale, est actuellement la meilleure offre "managed Kubernetes" européenne, meilleure en tout point de vue par rapport à celles de Scaleway et OVH. C’est aussi celle la plus facile et rapide à déployer et à administrer.
Mais il serait tout à fait possible de réaliser l’architecture de ce tutoriel sur un autre cloud provider, on premise, ou même en mode "multi cloud" pour une meilleure tolérance aux pannes ! C’est une des forces de Kubernetes: c’est disponible partout.
Un cluster sera utilisé pour déployer ArgoCD. Les deux autres seront eux gérés par l’instance ArgoCD installée sur le premier cluster. Chaque cluster sera déployé dans un datacenter séparé, dans des pays différents. Je trouve cette approche intéressante pour plusieurs raisons:
-
ArgoCD pilote l’ensemble des clusters et permet donc d’avoir une gestion de configuration de ces clusters centralisée, notamment grâce aux
ApplicationSet
que je présenterai plus loin. Toutes les ressources déployées dans tous les clusters seront par exemple visibles dans l’interface d’ArgoCD. -
Le cluster où ArgoCD tourne peut être très simple (avec seulement ArgoCD et pour un cas réel de production quelques outils de monitoring). Cela donne un cluster facile à administrer, facile à reconstruire, et peu coûteux. Cela peut avoir l’air d’un Single Point of Failure mais perdre ArgoCD n’est pas très grave: toutes les applications continuent de tourner, seulement les mises à jour seront impossibles.
Si le cluster est complètement reconstructible en quelques minutes (ce qui est largement faisable sur le cloud), ArgoCD n’est plus vraiment un SPOF. Vous pouvez même si vous le souhaitez avoir un cluster Kubernetespassif
avec ArgoCD préinstallé mais désactivé (0 replica), pour pouvoir à tout moment le redémarrer en cas de perte du cluster principal. Votre source de vérité sera de toute façon Git, le cluster ArgoCD sera complètement stateless.
On voit sur cette image que seul le cluster Kubernetes à Genève aura ArgoCD d’installé. Il pilotera les deux autres clusters installés dans deux autres datacenters (Zurich et Vienne), et pourra également être utilisé pour se configure soit même.
Avec cette architecture, des load balancers devant vos clusters Kubernetes et du DNS, vous pouvez facilement avoir des applications fortement tolérantes aux pannes, en actif/passif entre régions et clouds ou même en actif/actif si votre architecture le permet.
Je vais maintenant présenter très brièvement les différentes CRD d’ArgoCD. Pour plus d’informations, lisez la documentation de l’outil.
Project
La première ressource importante d’ArgoCD est AppProject
. Un AppProject est une abstraction permettant de regrouper des Applications
(présentées juste après) ensemble.
Les AppProject permettent d’exprimer des choses comme "dans le namespace monitoring
de Kubernetes, je n’ai le droit que de déployer que les applications venant du dépot gît dont l’URL est github.com/mon-org/monitoring.git
, et j’autorise seulement ces types de ressources Kubernetes (deployment, service, ingress…) à être déployés".
Un exemple:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: example-project
namespace: argocd
spec:
sourceRepos:
- '*'
destinations:
- namespace: '*'
server: '*'
clusterResourceWhitelist:
- group: '*'
kind: '*'
Ce projet appelé example-project
autorise tout. SourceRepos
, la liste des dépôts Git autorisés à être déployés pour ce projet, contient *
. On pourrait la remplacer comme dit précédemment par les addresses des dépôts autorisés à être déployés. destinations
permet de configurer dans quelles namespaces et servers (clusters kubernetes) les applications peuvent être déployées. Enfin, clusterResourceWhitelist
permet de spécifier quelles types de ressources Kubernetes sont autorisées.
Application
Une Application
représente un groupe de ressources Kubernetes gérées par ArgoCD:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/argoproj/argocd-example-apps.git
targetRevision: HEAD
path: guestbook
destination:
server: https://kubernetes.default.svc
namespace: guestbook
Cette application s’appelle guestbook
. Le paramètre source
dans la spec permet de référencer un dépôt Git contenant les fichiers Kubernetes à déployer. Le paramètre destination
indique sur quel cluster les déployer, et dans quel namespace. Ici c’est le cluster où ArgoCD est déployé qui est ciblé.
Ici, ArgoCD récupérera les fichiers présents dans https://github.com/argoproj/argocd-example-apps
, dans le dossier guestbook
(le paramètre path
de la source), et les déploiera sur le cluster Kubernetes local (où ArgoCD tourne, accessible sur https://kubernetes.default.svc
) et dans le namespace guestbook
ApplicationSet
On voit que la partie destination
permet déjà de déployer sur plusieurs clusters Kubernetes depuis une même instance d’ArgoCD. Cela est pratique mais a un désavantage: si vous souhaitez déployer la même ressource sur 3 clusters, vous allez devoir définir 3 applications, chacunes avec une destination
différente. C’est là que les ApplicationSet
interviennent.
Voici un exemple d’ApplicationSet:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
namespace: argocd
spec:
generators:
- clusters: {}
template:
metadata:
name: '{{name}}-guestbook'
spec:
project: "default"
source:
repoURL: https://github.com/argoproj/argocd-example-apps/
targetRevision: HEAD
path: guestbook
destination:
server: '{{server}}'
namespace: guestbook
On voit qu’une ApplicationSet
est assez similaire à une Application
: la partie template
contient d’ailleurs la définition d’une Application
. L’ApplicationSet va en fait être utilisée pour générer des ressources de type Application
en fonction de générateurs (generators
dans la configuration).
Dans cet exemple, on utilise le generateur clusters
qui génère par défaut une Application
ArgoCD pour chaque cluster configuré dans ArgoCD (la partie suivante montrera comment configurer des clusters). La ressource ApplicationSet
permet également de templatiser en fonction du générateur utilisé la configuration des Applications
générées. Par exemple ici:
-
La variable
{{name}}
contiendra le nom du cluster cible de l’application générée. -
La variable
{{server}}
contiendra l’URL du cluster cible.
Si j’ai par exemple deux clusters configurés dans ArgoCD, l’un appelé cluster1
ayant pour URL cluster1.com
, et l’autre appelé cluster2
ayant pour URL cluster2.com
, cette ApplicationSet
me génèrera 2 applications dont les noms seront cluster1-guestbook
et cluster2-guestbook
et dont les destinations seront les URL correspondantes.
Il existe de très nombreux générateurs, permettant d’automatiser la génération d’applications ArgoCD en se basant sur de nombreux critères (clusters, Pull Requests ouvertes sur un projet Git, en fonction de fichiers, en fonction d’une simple liste de variables…). Les ApplicationSet
sont un très bon outil pour éviter de passer son temps à réécrire plusieurs fois des Applications
quasiment identiques.
Les ApplicationSet autorisent aussi depuis peu des rollout progressifs, pour mettre à jour des clusters un par un dans un ordre pré-déterminé.
Cas pratique
Création des clusters
Comme dit précédemment je vais utiliser Exoscale pour ce tutoriel. Vous pouvez reproduire l’exercice sur un autre cloud également avec quelques variations mais je vous recommande vraiment d’essayer l’offre d’Exoscale qui est de bonne qualité, et qui permet d’avoir dans son mode starter
un contrôle plane Kubernetes gratuit.
La documentation d’Exoscale vous explique comment créer un cluster grâce à sa CLI. Vous aurez besoin aussi de kubectl pour interagir avec Kubernetes.
Le script suivant vous permettra de créer les 3 clusters comme montré dans la première image (dans 3 régions différentes). A noter qu’en production il vaudrait mieux créer un security group par cluster pour plus de sécurité, mais dans ce contexte de POC ce n’est pas trop grave de partager le même:
#!/bin/bash
set -e
## Création des règles réseaux
exo compute security-group create sks-argo-tuto
exo compute security-group rule add sks-argo-tuto \
--description "NodePort services" \
--protocol tcp \
--network 0.0.0.0/0 \
--port 30000-32767
exo compute security-group rule add sks-argo-tuto \
--description "SKS kubelet" \
--protocol tcp \
--port 10250 \
--security-group sks-argo-tuto
exo compute security-group rule add sks-argo-tuto \
--description "Calico traffic" \
--protocol udp \
--port 4789 \
--security-group sks-argo-tuto
## Création des 3 clusters
### Premier cluster dans la région ch-gva-2 qui hébergera ArgoCD
exo compute sks create argocd \
--zone ch-gva-2 \
--service-level starter \
--nodepool-name argocd \
--nodepool-instance-prefix argocd \
--nodepool-size 3 \
--nodepool-security-group sks-argo-tuto
### Second cluster dans la région ch-zrh-1 (anciennement appelée ch-dk-2)
exo compute sks create zrh1 \
--zone ch-dk-2 \
--service-level starter \
--nodepool-name zrh1 \
--nodepool-instance-prefix zrh1 \
--nodepool-size 3 \
--nodepool-security-group sks-argo-tuto
### Troisième cluster dans la région at-vie-1
exo compute sks create vie1 \
--zone at-vie-1 \
--service-level starter \
--nodepool-name vie1 \
--nodepool-instance-prefix vie1 \
--nodepool-size 3 \
--nodepool-security-group sks-argo-tuto
Récupération des kubeconfig
Nous allons maintenant récupérer des fichiers Kubeconfig root pour chaque cluster dans le but de pouvoir intéragir avec eux via kubectl
:
exo compute sks kubeconfig argocd kube-admin --zone ch-gva-2 --group system:masters > argocd.kubeconfig
exo compute sks kubeconfig zrh1 kube-admin --zone ch-dk-2 --group system:masters > zrh1.kubeconfig
exo compute sks kubeconfig vie1 kube-admin --zone at-vie-1 --group system:masters > vie1.kubeconfig
Vous devriez maintenant pouvoir par exemple lister les noeuds de vos clusters, avec kubectl --kubeconfig <kubeconfig-file> get nodes
, par exemple kubectl --kubeconfig argocd.kubeconfig get nodes
.
Installation d’ArgoCD
Nous allons maintenant installer ArgoCD sur le cluster Kubernetes de la zone ch-gva-2:
kubectl --kubeconfig argocd.kubeconfig create namespace argocd
kubectl --kubeconfig argocd.kubeconfig apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Pour ce tutoriel nous désactivons pour plus de facilité l’authentification d’ArgoCD. ArgoCD supporte une gestion fine des utilisateurs et permissions (et supporte également des protocoles comme OIDC), donc n’hésitez pas à jeter un oeil à la documentation officielle.
Exécutez tout d’abord kubectl --kubeconfig argocd.kubeconfig -n argocd edit configmap argocd-cm
pour désactiver l’authentification. Rajoutez le block suivant dans le YAML affiché, sauvegardez et fermez votre éditeur:
data:
users.anonymous.enabled: "true"
Faisons la même chose pour une seconde configmap via kubectl --kubeconfig argocd.kubeconfig -n argocd edit configmap argocd-rbac-cm
, pour rendre admin l’utilisateur par défaut.
data:
policy.default: role:admin
Rappel: ne faites pas ça sur un "vrai" cluster, ou même un cluster de test où ArgoCD est exposé sur internet !
Je ne vais pas configurer d’ingress controller dans ce tutoriel l’accès à ArgoCD se fera via kubectl port-forward
.
Lancez kubectl --kubeconfig argocd.kubeconfig port-forward svc/argocd-server -n argocd 8080:443
et ouvrez votre navigateur sur localhost:8080
: une fois le certificat auto signé accepté vous devriez pouvoir accéder à l’interface d’ArgoCD.
Configuration des clusters
ArgoCD permet par défaut de déployer des applications sur le cluster où il est installé mais pas ailleurs. Nous allons donc reconfigurer les clusters dans ArgoCD.
Cela se fait en créant un secret Kubernetes par cluster. Nous utiliserons ici directement les certificats contenus dans les kubeconfig générés précédemment pour s’authentifier aux clusters distants (pour le cluster local, l’authentification se fera par défaut via le service account d’ArgoCD).
Voici la configuration à appliquer, en remplaçant les valeurs server
et les certificats attendus par chaque cluster par ce que vous avez dans vos kubeconfig:
---
apiVersion: v1
kind: Secret
metadata:
name: cluster-gva2
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
name: gva2
server: https://kubernetes.default.svc
---
apiVersion: v1
kind: Secret
metadata:
name: cluster-zrh1
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
name: zrh1
server: "<contenu de server dans zrh1.kubeconfig>"
config: |
{
"tlsClientConfig": {
"caData": "<contenu de certificate-authority-data dans dans zrh1.kubeconfig>",
"certData": "<contenu de client-certificate-data dans dans zrh1.kubeconfig>",
"keyData": "<contenu de client-key-data dans dans zrh1.kubeconfig>"
}
}
---
apiVersion: v1
kind: Secret
metadata:
name: cluster-vie1
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
name: vie1
server: "<contenu de server dans vie1.kubeconfig>"
config: |
{
"tlsClientConfig": {
"caData": "<contenu de certificate-authority-data dans dans vie1.kubeconfig>",
"certData": "<contenu de client-certificate-data dans dans vie1.kubeconfig>",
"keyData": "<contenu de client-key-data dans dans vie1.kubeconfig>"
}
}
Note
|
Dans le cas d’Exoscale, la bonne pratique serait de créer un ClusterRole dédié pour ArgoCD pour éviter l’utilisations de La commande Voir mon article sur le TLS et l’authentification dans Kubernetes pour plus de détails. |
Une fois les valeurs remplacées, et le fichier appliqué via kubectl --kubeconfig argocd.kubeconfig apply -f <fichier>
, les clusters devraient être visibles dans l’interface d’ArgoCD à l’adresse https://localhost:8080/settings/clusters
:
Déploiement d’un ApplicationSet
Déployez maintenant l’ApplicationSet suivant pour tester le setup, toujours via kubectl --kubeconfig argocd.kubeconfig apply -f <fichier>
:
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
namespace: argocd
spec:
generators:
- clusters: {}
template:
metadata:
name: '{{name}}-guestbook'
spec:
project: "default"
source:
repoURL: https://github.com/argoproj/argocd-example-apps/
targetRevision: HEAD
path: guestbook
destination:
server: '{{server}}'
namespace: guestbook
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
prune: true
selfHeal: true
ArgoCD devrait vous générer automatiquement 3 applications, chacunes sur un cluster différent, le tout en fonction de ce qui est stocké dans le dossier guestbook
sur le répertoire github https://github.com/argoproj/argocd-example-apps/
. Elles seront également visibles dans l’interface.
On remarque que le nom de chaque application est bien <cluster>-guestbook
, par exemple vie1-guestbook
. Rappelez vous que les générateurs des ApplicationSet vous permettent de filtrer si besoin sur quelles clusters les applications doivent être déployées, via des labels par exemple.
Dans le setup actuel, ArgoCD créera automatiquement l’application pour chaque nouveau cluster ajouté, ou la supprimera si un cluster est supprimé. Chaque changement dans Git sera répercuté sur l’ensemble des clusters automatiquement également (grâce à l’option syncPolicy.automated
, vous pouvez également choisir de "sync" manuellement les applications).
Vous pouvez également vérifier sur vos clusters avec kubectl
que l’application a bien été déployée, par exemple avec kubectl --kubeconfig vie1.kubeconfig get po -n guestbook
.
Un dernier point avant la conclusion: rien ne vous empêche d’utiliser les Application
ET les ApplicationSet
ArgoCD en parallèle selon les besoins.
Conclusion
ArgoCD est un outil puissant, qui peut grandement simplifier le multi region ou le multi cloud Kubernetes.
On voit encore une fois ici l’avantage de Kubernetes: l’outillage est là pour répondre à des problématiques assez complexes, et ça fonctionne très bien.
Add a comment
If you have a bug/issue with the commenting system, please send me an email (my email is in the "About" section).