Claudie
Mots clés :
- Kubernetes
- AWS (Amazon Web Services)
- DevOps
- Azure
- GCP (Google Cloud Platform)
- Kubernetes-cluster
- PaaS (Platform as a Service)
- Cloudflare
- OCI (Oracle Cloud Infrastructure)
- cloud-native
- Hetzner
- hybrid-cloud
- multi-cloud
- managed-kubernetes
- inter-cloud
1: Analyse de la solution
Cas d'utilisation et fonctionnalités de Claudie:
Cas d'utilisations typiques:
- Réaliser des économies de coûts.
- Respect de la localisation des données et de la conformité (ex. RGPD)
- Offrir du Kubernetes managé pour les fournisseurs qui n'en proposent pas
- Faire du cloud bursting (débordement vers le cloud, ex. extension d'un cluster vers un fournisseur moins cher pendant certaines phases d'un projet)
- Interconnecter des services
Fonctionnalités:
- Gérer des clusters Kubernetes multi-cloud et hybrides
- Gestion via infrastructure as code (IaC)
- Montée en charge/descente en charge rapide de l'infrastructure
- Load balancing intégré
- Volumes de stockage persistants
Comment fonctionne claudie
Claudie est une plateforme conçue pour gérer des infrastructures Cloud à travers plusieurs fournisseurs de Cloud. Elle utilise une architecture basée sur des microservices, chacun ayant un rôle spécifique dans le processus de déploiement et de gestion de l'infrastructure.
Les composants principaux de Claudie sont :
-
Context-box : C'est l'unité de contrôle qui s'occupe de gérer les configurations en attente. Il détecte les changements de configuration et interagit avec l'InputManifest CRD.
-
Scheduler : Ce microservice travaille pour amener l'infrastructure à l'état désiré en fonction du manifeste reçu.
-
Builder : Il aligne l'état actuel de l'infrastructure avec l'état désiré en utilisant divers outils comme Terraformer et Ansibler.
-
Terraformer, Ansibler, Kube-eleven, Kuber : Ce sont des outils qui gèrent différentes parties de l'infrastructure, comme la création des clusters Kubernetes ou la configuration des nœuds.
-
Claudie-operator : C'est un contrôleur pour la ressource personnalisée InputManifest dans Kubernetes. Il surveille et maintient l'état du manifeste soumis par l'utilisateur.
Les données sont stockées dans des bases de données : MongoDB, Minio et DynamoDB, et les outils Terraform, Ansible, KubeOne, Longhorn, Nginx et Calico sont utilisés pour gérer divers aspects de l'infrastructure.
Le flux général de Claudie consiste à recevoir une configuration de l'utilisateur sous forme de InputManifest CRD, que Claudie-operator détecte et traite.
Lorsque l'utilisateur supprime ce manifeste, Claudie-operator initie un processus de suppression de l'infrastructure correspondante.
Les services comme Scheduler et Builder n'offrent pas d'API car ils fonctionnent en tant que clients gRPC.
Ils communiquent avec Context-box pour réaliser leurs tâches.
Kuber, par exemple, utilise kubectl pour manipuler les ressources du cluster et gérer des aspects spécifiques comme la configuration de l'autoscaling ou la suppression de nœuds.
claudie implémente sa propre solution de stockage.
Claudie permet de gérer les charges de travail avec état dans des environnements multi-cloud en créant un "cluster de stockage" à travers plusieurs fournisseurs de cloud. Chaque fournisseur a sa propre "zone" dans le cluster de stockage, et chaque zone stocke ses données de volumes persistants séparément.
La solution utilise Longhorn, un système de stockage distribué pour Kubernetes, qui est préinstallé dans les clusters créés par Claudie. Longhorn utilise les nœuds de travail pour stocker des données et fournit une classe de stockage par défaut nommée longhorn. Cette classe de stockage crée des volumes répliqués sur des nœuds aléatoires du cluster.
En plus de la classe de stockage par défaut, Claudie peut créer des classes de stockage personnalisées qui contraignent les volumes persistants à être créés sur des nœuds spécifiques en fonction de l'instance de fournisseur utilisée.
Cela signifie que vous pouvez avoir des nœuds pour le stockage provisionnés par un fournisseur et d'autres nœuds pour les tâches de calcul provisionnés par un autre fournisseur.
claudie implémente sa propre solution de loadbalancing
claudie permet de créer des load balancers pour les clusters Kubernetes afin d'assurer une haute disponibilité.
Voici les points clés :
-
Rôles : Dans Claudie, les rôles définissent la configuration des load balancers pour différents usages. Un cluster de load balancers peut avoir plusieurs rôles assignés.
-
Cluster Kubernetes ciblé : Chaque répartiteur de charge est assigné à un cluster Kubernetes spécifique, identifié par le champ targetedK8s. Un seul répartiteur de charge peut avoir le rôle du serveur API (port 6443) pour un cluster donné.
-
DNS : Claudie gère automatiquement les enregistrements DNS A pour les load balancers, en utilisant l'adresse IP publique des machines. En cas de changement de configuration, Claudie met à jour ces enregistrements DNS.
-
Nodepools : Les load balancers sont construits à partir de groupes de nœuds définis par l'utilisateur, permettant une échelle et des modifications faciles.
-
Ingress Controller Cluster : Il est nécessaire de déployer son propre ingress controller pour utiliser le load balancer, qui doit être configuré pour utiliser le node port définis dans la configuration des rôles.
Support de l'autoscaling
Claudie est une plateforme qui prend en charge l'autoscaling (mise à l'échelle automatique) des clusters qu'elle crée en installant le Cluster Autoscaler avec une implémentation personnalisée appelée autoscaler-adapter.
Pour que l'autoscaling soit actif, il suffit qu'un cluster ait au moins un groupe de nœuds (node pool) configuré avec le champ autoscaler.
Vous pouvez modifier la spécification du groupe de nœuds pour activer ou désactiver l'autoscaling à tout moment, et Claudie s'occupera de la configuration nécessaire automatiquement.
L'augmentation de la taille d'un groupe de nœuds (scale up) est déclenchée lorsque :
- Il y a des pods dans le cluster qui ne peuvent pas être planifiés (unschedulable) et qui pourraient l'être si un groupe de nœuds avec l'autoscaling activé augmentait sa taille.
- Ces groupes de nœuds ne sont pas encore à leur taille maximale.
Notez que si les demandes de ressources des pods sont plus importantes que ce que les nouveaux nœuds peuvent offrir, l'augmentation ne sera pas déclenchée.
Le cluster est vérifié toutes les 10 secondes pour s'assurer d'une réponse rapide aux besoins.
La réduction de la taille d'un groupe de nœuds (scale down) est déclenchée lorsque :
- La somme des demandes de CPU et de mémoire de tous les pods sur un nœud est inférieure à 50 % (à l'exception des pods DaemonSet et des Mirror pods).
Tous les pods sur le nœud (sauf ceux qui s'exécutent par défaut sur tous les nœuds, comme les pods exécutés via DaemonSets) peuvent être planifiés sur d'autres nœuds.
Le nœud n'a pas une annotation qui désactive la réduction de taille.
Claudie déploie le Cluster Autoscaler et l'Autoscaler Adapter dans chaque cluster configuré pour l'autoscaling.
Ces composants sont déployés dans le même cluster que Claudie.
Il est important de suivre les bonnes pratiques de Cluster Autoscaler lors de l'utilisation de l'autoscaling avec Claudie.
De plus, comme le nombre de nœuds dans les groupes de nœuds autoscalés peut varier, il faut planifier attentivement l'utilisation du stockage sur ces groupes.
Le support de Longhorn pour l'autoscaling est encore en phase expérimentale.
2: On teste pour vous la solution
Hé bien, sur le papier, ca à l'air top qu'en est il en réalité ?
Cas d'usage
- Multiples nodepools sur Azure dans des souscriptions et régions différentes
- Gestion DNS sur cloudflare
- Débordement sur AWS
Préparation
Création d'un cluster de management
Je vais prendre un cluster sur azure qui me sert à toutes mes démos. Le pré-requis (cert-manager) pour claudie est déjà déployé.
Déploiement du control-plane de claudie
On applique le manifeste suivant : https://github.com/berops/claudie/releases/latest/download/claudie.yaml
J'ai modifié la variable d'environnement GOLANG_LOG
en passant sa valeur a debug dans le configmap : dynamodb-cm
kubectl apply -f https://github.com/berops/claudie/releases/latest/download/claudie.yaml
❯ kubectl get deployment,sts,svc
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ansibler 1/1 1 1 4m15s
deployment.apps/builder 1/1 1 1 4m15s
deployment.apps/claudie-operator 1/1 1 1 4m15s
deployment.apps/context-box 1/1 1 1 4m14s
deployment.apps/dynamodb 1/1 1 1 4m14s
deployment.apps/kube-eleven 1/1 1 1 4m14s
deployment.apps/kuber 1/1 1 1 4m14s
deployment.apps/mongodb 1/1 1 1 4m14s
deployment.apps/scheduler 1/1 1 1 4m14s
deployment.apps/terraformer 1/1 1 1 4m13s
NAME READY AGE
statefulset.apps/minio 4/4 4m14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ansibler ClusterIP 10.0.122.72 <none> 50053/TCP 4m18s
service/claudie-operator ClusterIP 10.0.126.166 <none> 443/TCP,50058/TCP 4m18s
service/context-box ClusterIP 10.0.207.125 <none> 50055/TCP 4m17s
service/dynamo ClusterIP 10.0.222.117 <none> 8000/TCP 4m17s
service/kube-eleven ClusterIP 10.0.157.138 <none> 50054/TCP 4m17s
service/kuber ClusterIP 10.0.72.241 <none> 50057/TCP 4m17s
service/minio ClusterIP None <none> 9000/TCP,9001/TCP 4m17s
service/mongodb ClusterIP 10.0.168.125 <none> 27017/TCP 4m17s
service/terraformer ClusterIP 10.0.129.116 <none> 50052/TCP 4m16s
❯ k get po
NAME READY STATUS RESTARTS AGE
ansibler-ff79c4964-5tjpg 1/1 Running 0 4m26s
builder-67bcf777bd-tcmk8 1/1 Running 0 62s
claudie-operator-6884fcc477-kjt88 1/1 Running 0 4m26s
context-box-5c6bd5bf99-fr8xt 1/1 Running 0 4m25s
create-table-job-v66hv 0/1 Completed 3 4m24s
dynamodb-6d65df988-c9prh 1/1 Running 0 4m25s
kube-eleven-6fb6db6b57-jg2gw 1/1 Running 0 4m25s
kuber-5dcff7c6f5-dntwz 1/1 Running 0 4m25s
make-bucket-job-djzkg 0/1 Completed 1 4m24s
minio-0 1/1 Running 0 4m24s
minio-1 1/1 Running 0 4m24s
minio-2 1/1 Running 0 4m24s
minio-3 1/1 Running 0 4m24s
mongodb-5574c9b7-dg5nv 1/1 Running 0 4m25s
scheduler-69485fbb6c-rrkzz 1/1 Running 0 4m24s
terraformer-7f5fb999d9-x2zc2 1/1 Running 0 4m24s
Création des différents secrets pour permettre a claudie de déployer des clusters kubernetes
- Azure
- Création d'un rôle custom pour la gestion des resources groups
J'ai un tenant avec 2 souscriptions
- 86xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- 2dxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
#### Role Policy
Je vais créer des "role policy" pour claudie sur les 2 souscriptions de mon tenant
cat > policy.json <<EOF
{
"Name":"Claudie ControlPlane",
"Id":"aacd72a7-1185-99ef-bn56-f777fba81xe0",
"IsCustom":true,
"Description":"Claudie ControlPlane: resource groups, network contributor, ",
"Actions":[
"Microsoft.Resources/subscriptions/resourceGroups/read",
"Microsoft.Resources/subscriptions/resourceGroups/write",
"Microsoft.Resources/subscriptions/resourceGroups/delete",
"Microsoft.Authorization/*/read",
"Microsoft.Insights/alertRules/*",
"Microsoft.Network/*",
"Microsoft.ResourceHealth/availabilityStatuses/read",
"Microsoft.Resources/deployments/*",
"Microsoft.Resources/subscriptions/resourceGroups/read",
"Microsoft.Support/*",
"Microsoft.Authorization/*/read",
"Microsoft.Compute/availabilitySets/*",
"Microsoft.Compute/locations/*",
"Microsoft.Compute/virtualMachines/*",
"Microsoft.Compute/virtualMachineScaleSets/*",
"Microsoft.Compute/cloudServices/*",
"Microsoft.Compute/disks/write",
"Microsoft.Compute/disks/read",
"Microsoft.Compute/disks/delete",
"Microsoft.DevTestLab/schedules/*",
"Microsoft.Insights/alertRules/*",
"Microsoft.Network/applicationGateways/backendAddressPools/join/action",
"Microsoft.Network/loadBalancers/backendAddressPools/join/action",
"Microsoft.Network/loadBalancers/inboundNatPools/join/action",
"Microsoft.Network/loadBalancers/inboundNatRules/join/action",
"Microsoft.Network/loadBalancers/probes/join/action",
"Microsoft.Network/loadBalancers/read",
"Microsoft.Network/locations/*",
"Microsoft.Network/networkInterfaces/*",
"Microsoft.Network/networkSecurityGroups/join/action",
"Microsoft.Network/networkSecurityGroups/read",
"Microsoft.Network/publicIPAddresses/join/action",
"Microsoft.Network/publicIPAddresses/read",
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.RecoveryServices/locations/*",
"Microsoft.RecoveryServices/Vaults/backupFabrics/backupProtectionIntent/write",
"Microsoft.RecoveryServices/Vaults/backupFabrics/protectionContainers/protectedItems/*/read",
"Microsoft.RecoveryServices/Vaults/backupFabrics/protectionContainers/protectedItems/read",
"Microsoft.RecoveryServices/Vaults/backupFabrics/protectionContainers/protectedItems/write",
"Microsoft.RecoveryServices/Vaults/backupPolicies/read",
"Microsoft.RecoveryServices/Vaults/backupPolicies/write",
"Microsoft.RecoveryServices/Vaults/read",
"Microsoft.RecoveryServices/Vaults/usages/read",
"Microsoft.RecoveryServices/Vaults/write",
"Microsoft.ResourceHealth/availabilityStatuses/read",
"Microsoft.Resources/deployments/*",
"Microsoft.Resources/subscriptions/resourceGroups/read",
"Microsoft.SerialConsole/serialPorts/connect/action",
"Microsoft.SqlVirtualMachine/*",
"Microsoft.Storage/storageAccounts/listKeys/action",
"Microsoft.Storage/storageAccounts/read"
],
"assignableScopes": [
"/subscriptions/86...",
"/subscriptions/2d..."
]
}
EOF
Service Account
Je vais créer un compte de service et lui appliquer le custom role
# Création du service account
az ad sp create-for-rbac --name claudie-sp -o json
{
"appId": "appid-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"displayName": "claudie-sp",
"password": "appPassword",
"tenant": "tenantid-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
# Affection du rôle au sp subscription 1
az role assignment create \
--assignee [appId retourné par la commande précédente ] \
--role "Claudie ControlPlane" \
--scope /subscriptions/86... \
-o json
# Affection du role au sp subscription 2
az role assignment create \
--assignee [appId retourné par la commande précédente ] \
--role "Claudie ControlPlane" \
--scope /subscriptions/2d... \
-o json
APP_ID="appid-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
APP_SECRET="appPassword"
TENANT_ID="tenantid-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
SUBSCRIPTION_ID="86..."
cat > azure-secret-1.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: azure-secret-1
stringData:
clientid: $APP_ID
clientsecret: $APP_SECRET
subscriptionid: $SUBSCRIPTION_ID
tenantid: $TENANT_ID
type: Opaque
EOF
SUBSCRIPTION_ID="2d..."
cat > azure-secret-2.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: azure-secret-2
strinData:
clientid: $APP_ID
clientsecret: $APP_SECRET
subscriptionid: $SUBSCRIPTION_ID
tenantid: $TENANT_ID
type: Opaque
EOF
-
Création du secret azure dans le namespace de claudie
-
Cloudflare
-
J'ai un domaine géré pat cloudflare : leclerc.biz
-
Je génère un token d'API (https://dash.cloudflare.com/profile/api-tokens avec les droits suivants :
- Zone: Read
- DNS: Read
- DNS: Edit
Ce qui me permettra de gérer dynamiquement la zone
-
Création du secret dans le namespace de claudie
API_TOKEN="cloudflareapitokengivenbycf"
cat > cloudflare-secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-secret
stringData:
apitoken: $API_TOKEN
type: Opaque
EOF
Par commodité, je vais créer un namespace ou je vais déployer toutes les ressources nécessaires pour que claudie déploie les nœuds de mon cluster multi zone.
kubectl create ns aw-claudie-cluster
Création des secrets
kubectl create -n aw-claudie-cluster -f azure-secret-1.yaml
kubectl create -n aw-claudie-cluster -f azure-secret-2.yaml
kubectl create -n aw-claudie-cluster -f cloudflare-secret.yaml
Création de la custom resource nous permettant de créer le cluster.
apiVersion: claudie.io/v1beta1
kind: InputManifest
metadata:
name: aw-claudie-cluster
labels:
app.kubernetes.io/part-of: claudie
spec:
providers:
- name: cloudflare-1
providerType: cloudflare
secretRef:
name: cloudflare-secret
namespace: aw-claudie-cluster
- name: azure-1
providerType: azure
secretRef:
name: azure-secret-1
namespace: aw-claudie-cluster
- name: azure-2
providerType: azure
secretRef:
name: azure-secret-2
namespace: aw-claudie-cluster
nodePools:
dynamic:
- name: control-azure-1
providerSpec:
# Name of the provider instance.
name: azure-1
# Location of the nodepool.
region: westeurope
# Zone of the nodepool.
zone: "1"
count: 1
# VM size name.
serverType: Standard_B2s
# URN of the image.
image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
#- name: control-azure-2
# providerSpec:
# # Name of the provider instance.
# name: azure-2
# # Location of the nodepool.
# region: northeurope
# # Zone of the nodepool.
# zone: "2"
# count: 1
# # VM size name.
# serverType: Standard_B2s
# # URN of the image.
# image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
- name: compute-azure-1
providerSpec:
# Name of the provider instance.
name: azure-1
# Location of the nodepool.
region: westeurope
# Zone of the nodepool.
zone: "2"
count: 1
# VM size name.
serverType: Standard_B2s
# URN of the image.
image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
storageDiskSize: 50
#- name: compute-azure-2
# providerSpec:
# # Name of the provider instance.
# name: azure-2
# # Location of the nodepool.
# region: northeurope
# # Zone of the nodepool.
# zone: "3"
# count: 1
# # VM size name.
# serverType: Standard_B2s
# # URN of the image.
# image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
# storageDiskSize: 50
- name: loadbalancer-1
providerSpec:
# Name of the provider instance.
name: azure-1
# Location of the nodepool.
region: northeurope
# Zone of the nodepool.
zone: "1"
count: 1
# VM size name.
serverType: Standard_B2s
# URN of the image.
image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
storageDiskSize: 50
kubernetes:
clusters:
# targetedK8s
- name: aw-claudie-cluster
version: "v1.26.0"
network: 192.168.2.0/24
pools:
control:
- control-azure-1
#- control-azure-2
compute:
- compute-azure-1
# - compute-azure-2
loadBalancers:
roles:
- name: apiserver
protocol: tcp
port: 6443
targetPort: 6443
target: k8sControlPlane
clusters:
- name: apiserver-lb-claudie
roles:
- apiserver
dns:
dnsZone: leclerc.biz
provider: cloudflare-1
targetedK8s: aw-claudie-cluster
pools:
- loadbalancer-1
Création du cluster via la custom resource
kubectl -n aw-claudie-cluster -f aw-claudie-cluster.yaml
inputmanifest.claudie.io/aw-claudie-cluster created
Vérification de l'avancement de la création du cluster.
kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"state": "IN_PROGRESS"
}
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"message": "building infrastructure",
"phase": "TERRAFORMER",
"state": "IN_PROGRESS"
}
},
"state": "IN_PROGRESS"
}
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"message": "installing VPN",
"phase": "ANSIBLER",
"state": "IN_PROGRESS"
}
},
"state": "IN_PROGRESS"
}
...
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"message": "setting up Loadbalancers",
"phase": "ANSIBLER",
"state": "IN_PROGRESS"
}
},
"state": "IN_PROGRESS"
}
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"message": "building kubernetes cluster",
"phase": "KUBE_ELEVEN",
"state": "IN_PROGRESS"
}
},
"state": "IN_PROGRESS"
}
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"message": "setting up storage",
"phase": "KUBER",
"state": "IN_PROGRESS"
}
},
"state": "IN_PROGRESS"
}
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"message": "patching k8s nodes",
"phase": "KUBER",
"state": "IN_PROGRESS"
}
},
"state": "IN_PROGRESS"
}
❯ kubectl get inputmanifests.claudie.io -n aw-claudie-cluster aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"phase": "NONE",
"state": "DONE"
}
},
"state": "DONE"
}
On peut suivre toutes les étapes de création du cluster, et l'utilisation de tous les microservices.
Coup d'œil au niveau de log des microservices de claudie
Vous pouvez utiliser stern qui un outils très sympa pour afficher les logs des pods.
Je surveille toutes les log dans le namespace claudie de cette façon.
stern -n claudie -l app.kubernetes.io/part-of=claudie
Récupération du kubeconfig
❯ kubectl get secrets -n claudie -l claudie.io/output=kubeconfig
NAME TYPE DATA AGE
aw-claudie-cluster-yhbfwvh-kubeconfig Opaque 1 2m13s
kubectl get secrets -n claudie -l claudie.io/output=kubeconfig -o jsonpath='{.items[0].data.kubeconfig}' | base64 -d > kubeconfig-aw-claudie-cluster.yaml
Utilisation du kubeconfig
❯ kubectl --kubeconfig=kubeconfig-aw-claudie-cluster.yaml get nodes
NAME STATUS ROLES AGE VERSION
compute-azure-1-hkkzwc0-1 Ready <none> 4m8s v1.26.0
control-azure-1-tbridau-1 Ready control-plane 5m28s v1.26.0
Si on regarde le fichier kubeconfig-aw-claudie-cluster.yaml
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ..==
server: https://3vhzg91r15evfjn0z.leclerc.biz:6443
name: aw-claudie-cluster
contexts:
- context:
cluster: aw-claudie-cluster
user: kubernetes-admin
name: kubernetes-admin@aw-claudie-cluster
current-context: kubernetes-admin@aw-claudie-cluster
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0..
client-key-data: LS0..
On voit bien que le nom de domaine est leclerc.biz et que le cluster s'appelle 3vhzg91r15evfjn0z
Vérification a niveau d'azure et cloudflare
Resources groupes
- aw-claudie-cluster-yhbfwvh-westeurope
-
apiserver-lb-claudie-qeqdqf7-northeurope
-
Le cluster est positionner en West Europe et le LoadBalancer du control plane en North Europe
-
Loadbalancing est assuré par une machine virtuelle
- Son adresse ip est :
- Vérification au niveau Cloudflare
Le loadbalancing est fait par le déploiement d'un nginx
La configuration est dans le fichier /etc/nginx/passthrough.conf
cat /etc/nginx/passthrough.conf;
stream{
upstream apiserver{
server 192.168.2.1:6443 max_fails=3 fail_timeout=10s;
}
server {
listen 6443;
proxy_pass apiserver;
proxy_next_upstream on;
}
L'adresse ip 192.168.2.1 correspond à l'adresse du vpn point a point géré par wireguard
Quand on regarde la configuration du Wireguard
cat wg0.conf
[Interface]
Address = 192.168.2.3/24
PrivateKey = KKW...=
ListenPort = 51820
[Peer]
PublicKey = 5VS...=
Endpoint = 13.81.102.110:51820
AllowedIps = 192.168.2.1/32
[Peer]
PublicKey = iyp...=
Endpoint = 13.81.102.148:51820
AllowedIps = 192.168.2.2/32
Les adresses ips correspondent aux adresses ip du controle plane et le nœud de compute
Tentative d'ajout d'un nœud de compute dans une autre souscription
On va décommenter les sections compute-azure-2 dans le fichier yaml
- name: compute-azure-2
providerSpec:
# Name of the provider instance.
name: azure-2
...
...
kubernetes:
clusters:
# targetedK8s
- name: aw-claudie-cluster
version: "v1.26.0"
network: 192.168.2.0/24
pools:
control:
- control-azure-1
#- control-azure-2
compute:
- compute-azure-1
- compute-azure-2
On applique le nouveau manifeste pour voir si la boucle de reconciliation fonctionne.
kubectl apply -n aw-claudie-cluster -f aw-claudie-cluster.yaml
❯ kubectl get -n aw-claudie-cluster inputmanifests.claudie.io aw-claudie-cluster -o jsonpath={.status} | jq .
{
"clusters": {
"aw-claudie-cluster": {
"message": "building infrastructure",
"phase": "TERRAFORMER",
"state": "IN_PROGRESS"
}
},
"state": "IN_PROGRESS"
}
- Ca ne fonctionne pas car on a des messages d'erreurs au niveau de terraform :
Error: Duplicate provider configuration
-
En regardant le code on voit qu'il n'est pas possible d'avoir plusieurs providers azure avec par exemple des souscription différentes.
-
Je vais ouvrir une issue sur ce sujet
-
Donc on va changer name: azure-2 en name: azure-1 dans les spec du worker node et relancer l'ajout
-
La je rencontre aussi un problème terraform reste en mode "failed". Je n'ai pas trouvé de moyen de lui dire de regénérer un plan et de le réappliquer
-
Donc je choisis de supprimer l' inputmanifests pour repartir sur un cluster from scratch
-
La aussi je rencontre des problèmes car terraform a encore la définition du provider en double
-
Donc je vais patcher le providers directement dans le pod terraformer et mettre un alias sur le deuxième provider azure pour débloquer la situation.
Vérifications que les resources sur Azure sont bien supprimées
Oui tout est bien supprimé
Conclusions
-
En terme de "concurrents" il y a clusterAPI et crossplane (qui utilise clusterAPI).
-
Claudie fait partie de ces outils qui permettent de facilement créer des clusters kubernetes hybrides, multi CSP, multi région sans utiliser les services managés des CSP avec une approche IAAS.
-
Claudie utilise terraform pour provisionner l'infrastructure et ansible pour les middleware
-
Dans certains cas d'utilisation cela peut être très interessant si on a des cas comme ceux vus dans l'introduction.
-
Claudie est moins extensible que crossplane
-
Claudie est plus souple que crossplane pour gérer un cluster multi-csp ou multi-région
-
Claudie ne déploie pas de kubernetes en service managés du CSP alors que crossplane va le faire.
-
Ce sont 2 approches complètement différentes.
Critère | Berops/Claudie | Crossplane | ClusterAPI |
---|---|---|---|
Tendances Émergentes | Intégration avec Cluster Autoscaler pour la gestion multi-cloud. | S'utilise pour construire des plans de contrôle de cloud natif. | Simplification du cycle de vie des clusters via API déclaratives. |
Forces | Gestion multi-cloud, cloud bursting, interconnexion de services, VPN Wireguard, GitOps. | Projet CNCF, gestion abstraite de l'infrastructure, API Kubernetes. | Modèle opérateur Kubernetes, automatisation, support multi-fournisseur. |
Faiblesses | Nouveauté et complexité de gestion multi-cloud. | Complexité de configuration, dépendance sur l'écosystème Kubernetes. | Compréhension des API déclaratives, gestion de multi-fournisseurs. |
Aspect Distinctif | Approche multi-cloud et hybrid-cloud au niveau des nodepools. | Abstraction de haut niveau pour la gestion des ressources cloud. | Gestion du cycle de vie des clusters Kubernetes. |
Compatibilité GitOps | Oui | Oui | Oui |
Conclusion | Choix pour gestion multi-cloud et hybrid-cloud avancée. | Choix pour ceux recherchant une gestion abstraite avec Kubernetes. | Choix pour une gestion simplifiée des clusters Kubernetes. |
Manifest fonctionnel
apiVersion: claudie.io/v1beta1
kind: InputManifest
metadata:
name: aw-claudie-cluster
labels:
app.kubernetes.io/part-of: claudie
run: "2"
spec:
providers:
- name: cloudflare-1
providerType: cloudflare
secretRef:
name: cloudflare-secret
namespace: aw-claudie-cluster
- name: azure-1
providerType: azure
secretRef:
name: azure-secret-1
namespace: aw-claudie-cluster
nodePools:
dynamic:
- name: control-azure-1
providerSpec:
# Name of the provider instance.
name: azure-1
# Location of the nodepool.
region: westeurope
# Zone of the nodepool.
zone: "1"
count: 1
# VM size name.
serverType: Standard_B2s
# URN of the image.
image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
- name: compute-azure-1
providerSpec:
# Name of the provider instance.
name: azure-1
# Location of the nodepool.
region: westeurope
# Zone of the nodepool.
zone: "2"
count: 1
# VM size name.
serverType: Standard_B2s
# URN of the image.
image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
storageDiskSize: 50
- name: compute-azure-2
providerSpec:
# Name of the provider instance.
name: azure-1
# Location of the nodepool.
region: northeurope
# Zone of the nodepool.
zone: "3"
count: 1
# VM size name.
serverType: Standard_B2s
# URN of the image.
image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
storageDiskSize: 50
- name: loadbalancer-1
providerSpec:
# Name of the provider instance.
name: azure-1
# Location of the nodepool.
region: northeurope
# Zone of the nodepool.
zone: "1"
count: 1
# VM size name.
serverType: Standard_B2s
# URN of the image.
image: Canonical:0001-com-ubuntu-minimal-jammy:minimal-22_04-lts:22.04.202212120
storageDiskSize: 50
kubernetes:
clusters:
# targetedK8s
- name: aw-claudie-cluster
version: "v1.26.0"
network: 192.168.2.0/24
pools:
control:
- control-azure-1
#- control-azure-2
compute:
- compute-azure-1
- compute-azure-2
loadBalancers:
roles:
- name: apiserver
protocol: tcp
port: 6443
targetPort: 6443
target: k8sControlPlane
clusters:
- name: apiserver-lb-claudie
roles:
- apiserver
dns:
dnsZone: leclerc.biz
provider: cloudflare-1
targetedK8s: aw-claudie-cluster
pools:
- loadbalancer-1
Découvrez les derniers articles d'alter way
- kubevpn
- Kubernetes 1.32
- re:Invent 2024 : AWS mise tout sur l'IA pour son Cloud
- OVHcloud Summit 2024 : L’innovation au cœur d’un cloud souverain et performant
- Big Data & AI Paris 2024 : L'IA au cœur de toutes les transformations.
- Un retour vers l'open-source ? Vos outils DevOps préférés et leurs equivalents open-source.