k0rdent on Azure

thumbernail Kubernetes

k0rdent sur Azure avec AKS : Premiers pas

Les organisations doivent aujourd’hui faire face à une complexité croissante dans la gestion de leurs infrastructures. La centralisation du contrôle et l’automatisation des tâches récurrentes deviennent des impératifs pour assurer la scalabilité, la sécurité et l’efficacité opérationnelle.

C’est ici qu’intervient k0rdent, en offrant :

  • Un contrôle centralisé sur plusieurs clusters Kubernetes
  • Une approche déclarative qui permet de réutiliser des templates pour une cohérence inter-environnements
  • Une extensibilité facilitée grâce à des modules complémentaires (comme kcm pour la gestion du cycle de vie des clusters, ou kof pour l’observabilité)

Ce billet de blog détaille l’expérimentation de trois configurations de déploiement sur Azure en utilisant les templates préconçus par k0rdent.

1. Création d'un cluster d'administration

Pré-requis :

  • Une VM sur Azure 22.04.5 LTS, Jammy Jellyfish
  • Homebrew (/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)")
  • k0s (curl --proto '=https' --tlsv1.2 -sSf https://get.k0s.sh | sudo sh)
  • krew (brew install krew))
  • kubectl (brew install kubectl)
  • helm (brew install helm)
  • azure CLI (az) (brew install azure-cli)
  • jq (brew install jq)

1.1 Création du cluster d'administration

# Création du cluster d'un seul noeud
sudo k0s install controller --single

# Démarrage du cluster
sudo k0s start

# Aliasing
echo 'source <(kubectl completion bash)' >>~/.bashrc
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
source ~/.bashrc

# Copie du kubeconfig 
mkdir ~/.kube
sudo cp /var/lib/k0s/pki/admin.conf ~/.kube/config
sudo chmod +r ~/.kube/config
sudo chown devops: /home/devops/.kube/config


# Installation des plugins krew
kubectl krew install ns 
kubectl krew install ctx 
kubectl krew install neat
kubectl krew install view-secret
kubectl krew install stern


kubectl get nodes

# Résultat : 
NAME          STATUS   ROLES           AGE     VERSION
herlec-icdc   Ready    control-plane   6m11s   v1.32.1+k0s

1.2 Installation de k0rdent

# Récupération des valeurs par défaut(au cas ou...)

helm inspect values oci://ghcr.io/k0rdent/kcm/charts/kcm > kcm-values.yaml

Interroge le chart Helm disponible dans le registre OCI (ici sur ghcr.io) pour récupérer les valeurs de configuration par défaut. Le résultat est ensuite redirigé vers le fichier kcm-values.yaml, que vous pourrez modifier si nécessaire.

# Installation du kcm
helm install kcm oci://ghcr.io/k0rdent/kcm/charts/kcm --version 0.1.0 -n kcm-system --create-namespace -f kcm-values.yaml

# Résultat : 

Pulled: ghcr.io/k0rdent/kcm/charts/kcm:0.1.0
Digest: sha256:accb6d1f9035d3dd46abbd86e10a7cd2c8bf235f8a77d079edeab58dfa9d38e8
NAME: kcm
LAST DEPLOYED: Thu Feb 13 08:02:08 2025
NAMESPACE: kcm-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

Installe le chart Helm nommé kcm dans le namespace kcm-system (en créant le namespace si celui-ci n'existe pas) en utilisant la version 0.1.0 du chart. Elle applique également les configurations définies dans le fichier kcm-values.yaml pour personnaliser l'installation.

# Check du déploiement
kubectl get pods -n kcm-system 

# Cela peut prendre du temps pour avoir tous les composants installés, 
# car c'est le contrôleur qui les installe.
NAME                                                          READY   STATUS    RESTARTS   AGE
azureserviceoperator-controller-manager-6b4dd86894-gvz8c      1/1     Running   0          109s
capa-controller-manager-64bbcb9f8-gx5qz                       1/1     Running   0          94s
capi-controller-manager-66f8998ff5-tt9xd                      1/1     Running   0          3m4s
capo-controller-manager-588f45c7cf-57tr2                      1/1     Running   0          76s
capv-controller-manager-69f7fc65d8-pbgmt                      1/1     Running   0          64s
capz-controller-manager-544845f786-q24nd                      1/1     Running   0          109s
helm-controller-7644c4d5c4-98ff7                              1/1     Running   0          6m
k0smotron-controller-manager-bootstrap-9fc48d76f-558fw        2/2     Running   0          2m40s
k0smotron-controller-manager-control-plane-7df9bc7bf-hzlfv    2/2     Running   0          2m37s
k0smotron-controller-manager-infrastructure-f7f94dd76-vpv8t   2/2     Running   0          84s
kcm-cert-manager-895954d88-pmwd4                              1/1     Running   0          5m59s
kcm-cert-manager-cainjector-685ffdf549-kz2jn                  1/1     Running   0          6m
kcm-cert-manager-webhook-59ddc6b56-4ld68                      1/1     Running   0          6m
kcm-cluster-api-operator-8487958779-ln8qd                     1/1     Running   0          3m48s
kcm-controller-manager-7998cdb69-l7ksk                        1/1     Running   0          3m48s
kcm-velero-b68fd5957-xcnrs                                    1/1     Running   0          6m
source-controller-6cd7676f7f-25hnw                            1/1     Running   0          6m

# Verification que projectsveltos est déployé et fonctionnement
kubectl get ns

# Résultat : 
NAME              STATUS   AGE
default           Active   18m
k0s-autopilot     Active   17m
kcm-system        Active   8m37s
kube-node-lease   Active   18m
kube-public       Active   18m
kube-system       Active   18m
mgmt              Active   4m49s
projectsveltos    Active   5m16s


kubectl get po -n projectsveltos

# Résultat : 
kubectl get pods -n projectsveltos  
NAME                                     READY   STATUS    RESTARTS   AGE
access-manager-56696cc7f-plxns           1/1     Running   0          6m36s
addon-controller-7c98776c79-wqbjw        1/1     Running   0          6m36s
classifier-manager-7b85f96469-swwjk      1/1     Running   0          6m36s
event-manager-67f6db7f44-btvmj           1/1     Running   0          6m36s
hc-manager-6d579d675f-lnxvb              1/1     Running   0          6m36s
sc-manager-55c99d494b-7d5cx              1/1     Running   0          6m36s
shard-controller-5ff9cd796d-hsm48        1/1     Running   0          6m36s
sveltos-agent-manager-7467959f4f-vd2sb   1/1     Running   0          5m43s

Si Projectsveltos vous intéresse, vous pouvez consulter le blog d'Alter Way pour lire les articles à ce sujet.

1.3 Check des différents composant de k0rdent

Il faut que tout soit à true

kubectl get Management,providertemplate,clustertemplate -n kcm-system

# Résultats :

NAME                                  READY   RELEASE     AGE
management.k0rdent.mirantis.com/kcm   True    kcm-0-1-0   21m

NAME                                                                         VALID
providertemplate.k0rdent.mirantis.com/cluster-api-0-1-0                      true
providertemplate.k0rdent.mirantis.com/cluster-api-provider-aws-0-1-0         true
providertemplate.k0rdent.mirantis.com/cluster-api-provider-azure-0-1-0       true
providertemplate.k0rdent.mirantis.com/cluster-api-provider-openstack-0-1-0   true
providertemplate.k0rdent.mirantis.com/cluster-api-provider-vsphere-0-1-0     true
providertemplate.k0rdent.mirantis.com/k0smotron-0-1-0                        true
providertemplate.k0rdent.mirantis.com/kcm-0-1-0                              true
providertemplate.k0rdent.mirantis.com/projectsveltos-0-45-0                  true

NAME                                                                 VALID
clustertemplate.k0rdent.mirantis.com/adopted-cluster-0-1-0           true
clustertemplate.k0rdent.mirantis.com/aws-eks-0-1-0                   true
clustertemplate.k0rdent.mirantis.com/aws-hosted-cp-0-1-0             true
clustertemplate.k0rdent.mirantis.com/aws-standalone-cp-0-1-0         true
clustertemplate.k0rdent.mirantis.com/azure-aks-0-1-0                 true
clustertemplate.k0rdent.mirantis.com/azure-hosted-cp-0-1-0           true
clustertemplate.k0rdent.mirantis.com/azure-standalone-cp-0-1-0       true
clustertemplate.k0rdent.mirantis.com/openstack-standalone-cp-0-1-0   true
clustertemplate.k0rdent.mirantis.com/vsphere-hosted-cp-0-1-0         true
clustertemplate.k0rdent.mirantis.com/vsphere-standalone-cp-0-1-0     true

2. Usage sur Azure

2.1 Connexion à votre compte Azure

az login 

To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code C9EQUM9SG to authenticate.


Retrieving tenants and subscriptions for the selection...

# Choisir le tenant sur lequel vous allez manager vos AKS

# Verifier les providers disponibles
az provider list --query "[?registrationState=='Registered']" --output table | \
grep -e "Microsoft.Compute" \
-e "Microsoft.Network" \
-e "Microsoft.ContainerService" \
-e "Microsoft.ManagedIdentity" \
-e "Microsoft.Authorization"

# Résultats
Microsoft.Compute                   Registered           RegistrationRequired
Microsoft.Network                   Registered           RegistrationRequired
Microsoft.ContainerService          Registered           RegistrationRequired
Microsoft.ManagedIdentity           Registered           RegistrationRequired
Microsoft.Authorization             Registered           RegistrationFree

Si vous avez déjà créé un cluster AKS sur Azure tout devrait être déjà enregistré

Si ce n'est pas le cas utiliser la commande az provider register --namespace [nom du service]

Par exemple az provider register --namespace Microsoft.ContainerService

2.2 Récupérer les information de la souscription courante

export SUBSCRIPTION_ID=$(az account show --query id -o tsv)
export TENANT_ID=$(az account show --query tenantId -o tsv)

2.3 Création d'un compte de service avec le role contributeur sur la souscription

SP_INFO=$(az ad sp create-for-rbac --role contributor --scopes="/subscriptions/$SUBSCRIPTION_ID" --output json)

export AZURE_CLIENT_ID=$(echo $SP_INFO | jq -r '.appId')
export AZURE_CLIENT_SECRET=$(echo $SP_INFO | jq -r '.password')
export AZURE_TENANT_ID=$(echo $SP_INFO | jq -r '.tenant')

echo $AZURE_CLIENT_ID
echo $AZURE_CLIENT_SECRET
echo $AZURE_TENANT_ID

2.4 Création du secret pour l'authentification de kcm

kubectl apply -f- <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: azure-cluster-identity-secret
  namespace: kcm-system
  labels:
    k0rdent.mirantis.com/component: "kcm"
stringData:
  clientSecret: $AZURE_CLIENT_SECRET # Password retrieved from the Service Principal
type: Opaque
EOF

2.5 Création du secret azure-aks-credential (pour le template AKS)

kubectl apply -f- <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: azure-aks-credential
  namespace: kcm-system
  labels:
    k0rdent.mirantis.com/component: "kcm"
stringData:
  AZURE_CLIENT_ID: "${AZURE_CLIENT_ID}"
  AZURE_CLIENT_SECRET: "${AZURE_CLIENT_SECRET}"
  AZURE_SUBSCRIPTION_ID: "${SUBSCRIPTION_ID}"
  AZURE_TENANT_ID: "${AZURE_TENANT_ID}"
type: Opaque
EOF

# Résultat :
secret/azure-cluster-identity-secret created

# Vérifier le contenu du secret avec 
kubectl view-secret azure-cluster-identity-secret -n kcm-system

# Résultat :
Viewing only available key: clientSecret
xxxxxxxxxx

2.6 Création des authentifications pour k0rdent et capz.

Tout est fait par références ce qui permet de ne pas avoir de mot de passe dans les manifestes

kubectl apply -f- <<EOF
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: AzureClusterIdentity
metadata:
  name: azure-cluster-identity
  namespace: kcm-system
  labels:
    clusterctl.cluster.x-k8s.io/move-hierarchy: "true"
    k0rdent.mirantis.com/component: "kcm"
spec:
  allowedNamespaces: {}
  clientID: $AZURE_CLIENT_ID
  clientSecret:
    name: azure-cluster-identity-secret
    namespace: kcm-system
  tenantID: $AZURE_TENANT_ID
  type: ServicePrincipal
EOF

# Résultat :
azureclusteridentity.infrastructure.cluster.x-k8s.io/azure-cluster-identity created

# Vérifier les informations
kubectl describe azureclusteridentity.infrastructure.cluster.x-k8s.io/azure-cluster-identity

2.7 Création des crédences pour kcm

Tout se fait par référence aussi

kubectl apply -f- <<EOF
apiVersion: k0rdent.mirantis.com/v1alpha1
kind: Credential
metadata:
  name: azure-cluster-identity-cred
  namespace: kcm-system
spec:
  identityRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: AzureClusterIdentity
    name: azure-cluster-identity
    namespace: kcm-system
EOF
kubectl apply -f- <<EOF
apiVersion: k0rdent.mirantis.com/v1alpha1
kind: Credential
metadata:
  name: azure-aks-credential
  namespace: kcm-system
spec:
  description: Azure AKS credentials
  identityRef:
    apiVersion: v1
    kind: Secret
    name: azure-aks-credential
    namespace: kcm-system
EOF


# Résultat :
credential.k0rdent.mirantis.com/azure-cluster-identity-cred created

# Check 
kubectl describe credential.k0rdent.mirantis.com/azure-cluster-identity-cred 

# Regardez les informations du status
Status:
  Conditions:
    Last Transition Time:  2025-02-13T09:44:25Z
    Message:               Credential is ready
    Reason:                Succeeded
    Status:                True
    Type:                  CredentialReady
  Ready:                   true

2.8 Choix de la localisation du cluster

Nous prendons par exemple northeurope. Prenez celle qui vous sied le mieux

2.9 Choix du template de cluster

kubectl get clustertemplate -n kcm-system | grep azure

# Résultat :
azure-aks-0-1-0                 true
azure-hosted-cp-0-1-0           true
azure-standalone-cp-0-1-0       true
  • azure-standalone-cp-0-1-0 : Permet de déployer un cluster k0s sur Azure
  • azure-hosted-cp-0-1-0 : Permet de déployer un cluster kubernetes dont le control plane est géré dans le cluster d'administration (k0smotron)
  • azure-aks-0-1-0 : Déploiement d'un cluster AKS classique

3. Test du template azure-aks-0-1-0


Objectif : Déployer un cluster Kubernetes managé via Azure Kubernetes Service (AKS). Cette approche tire parti de la robustesse d’AKS en termes de scalabilité, sécurité et intégration native avec les services Azure.

Points forts :

Simplicité de déploiement : Intégration directe avec le portail Azure et ses API. Gestion optimisée des ressources : Évolutivité automatique et surveillance native. Sécurité renforcée : Conformité aux standards Azure et mise à jour des correctifs gérée par Microsoft. Cas d’usage : Idéal pour des environnements de production nécessitant une haute disponibilité et une maintenance réduite, avec une prise en charge native par le cloud.

3.1 Création du déploiement du cluster

Notes : Faites bien attention au type des machines les nom sont sensible à la casse.

ex: standard_a4_v2 ne fonctionnera pas il faut avoir Standard_A4_v2

Pour connaitre tout les paramètres possible au niveau de l'attribut config il faut regarder le fichier values.yaml situé dans le répertoire templates/cluster/azure-aks du repo https://github.com/k0rdent/kcm.git

kubectl apply -f- <<EOF
apiVersion: k0rdent.mirantis.com/v1alpha1
kind: ClusterDeployment
metadata:
  name: aks-by-k0rdent
  namespace: kcm-system
spec:
  template: azure-aks-0-1-0
  credential: azure-aks-credential
  propagateCredentials: false
  config:
    clusterLabels: {}
    location: "northeurope"
    machinePools:
      system:
        count: 1
        vmSize: Standard_A4_v2
      user:
        count: 1
        vmSize: Standard_A4_v2
EOF


# Résultats : 
clusterdeployment.k0rdent.mirantis.com/aks-by-k0rdent created

3.2 Suivi de la création du cluster

kubectl get clusterdeployment

# Résultat
NAME             READY   STATUS
aks-by-k0rdent   False   aks-by-k0rdent: Waiting for control plane provider to indicate the control plane has been initialized. aks-by-k0rdent. aks-by-k0rdent.

La clusterAPI crée l'insfrastructure Azure pour déployer l'AKS managé

kubectl get resourcegroups.resources.azure.com

# Résultat
NAME             READY   SEVERITY   REASON      MESSAGE
aks-by-k0rdent   True               Succeeded

On voit que le cluster AKS aks-by-k0rdent a bien été créé

kubectl get managedclusters
NAME             READY   SEVERITY   REASON      MESSAGE
aks-by-k0rdent   True               Succeeded

  • Node machinePools
kubectl get azureasomanagedmachinepools

# Résultat : 
NAME                    AGE
aks-by-k0rdent-system   18m
aks-by-k0rdent-user     18m

Au final on a :

kubectl get clusterdeployment

# Résultat :
NAME             READY   STATUS
aks-by-k0rdent   True    ClusterDeployment is ready

3.3 Récupération du kubeconfig

az aks get-credentials --resource-group aks-by-k0rdent --name aks-by-k0rdent --overwrite-existing -f aks-by-k0rdent.conf

3.4 Test du cluster

KUBECONFIG=aks-by-k0rdent.conf kubectl get nodes

# Résultat : 
NAME                                 STATUS   ROLES    AGE   VERSION
aks-systempool-34952453-vmss000000   Ready    <none>   14m   v1.31.1
aks-userpool-34952453-vmss000000     Ready    <none>   14m   v1.31.1

3.5 Nettoyage

kubectl delete clusterdeployments aks-by-k0rdent

Toutes les resources Azure créées sont supprimées


4. Test du Template azure-standalone-cp-0-1-0


Ce template permet de créer un cluster kubernetes standard le control plane et worker en VM.

Objectif : Déployer un cluster Kubernetes avec un control plane dédié, entièrement indépendant des services managés d’Azure. Cette configuration permet une personnalisation poussée et une isolation accrue des composants critiques.

Points forts :

Personnalisation avancée : Permet de définir des configurations spécifiques pour le control plane sans être limité par les contraintes d’un service managé. Isolation et sécurité : Un control plane autonome peut offrir une isolation renforcée, essentielle pour des environnements sensibles. Contrôle total sur la configuration : Les équipes peuvent affiner chaque aspect du déploiement pour répondre à des exigences précises. Cas d’usage : Particulièrement intéressant pour des scénarios où la personnalisation et l’optimisation fine du contrôle sont nécessaires, notamment dans des contextes de R&D ou d’infrastructures hybrides.

4.1 Création du manifeste de déploiement du cluster

export CLUSTER_DEPLOYMENT_NAME="standalone-cp-azure"

kubectl apply -f- <<EOF
apiVersion: k0rdent.mirantis.com/v1alpha1
kind: ClusterDeployment
metadata:
  name: "${CLUSTER_DEPLOYMENT_NAME}"
  namespace: kcm-system
spec:
  template: azure-standalone-cp-0-1-0
  credential: azure-cluster-identity-cred
  propagateCredentials: true
  config:
    clusterLabels: {}
    controlPlaneNumber: 1
    workersNumber: 1
    location: "northeurope"
    subscriptionID: "${SUBSCRIPTION_ID}"
    clusterIdentity:
      name: "azure-cluster-identity"
    controlPlane:
      vmSize: Standard_A4_v2
    worker:
      vmSize: Standard_A4_v2
    #tenantID: "${AZURE_TENANT_ID}"
    #clientID: "${AZURE_CLIENT_ID}"
    #clientSecret: "${AZURE_CLIENT_SECRET}"
EOF

Dans ce cas, nous allons avoir la création sur azure d'un esemble de resource permettant d'avoir une cluster kubernetes complet : noeuds de "control plane" et worker. Dans notre cas 1 noued de control plane et 1 noeud worker.

Composants créés :

Ressource Type
pip-standalone-cp-azure-apiserver Public IP address
pip-standalone-cp-azure-node-natgw Public IP address
standalone-cp-azure-controlplane-nsg Network security group
standalone-cp-azure-cp-0 Virtual machine
standalone-cp-azure-cp-0-nic Network Interface
standalone-cp-azure-cp-0_OSDisk Disk
standalone-cp-azure-md-n5rsj-2kqvm Virtual machine
standalone-cp-azure-md-n5rsj-2kqvm-nic Network Interface
standalone-cp-azure-md-n5rsj-2kqvm_OSDisk Disk
standalone-cp-azure-node-natgw NAT gateway
standalone-cp-azure-node-nsg Network security group
standalone-cp-azure-node-routetable Route table
standalone-cp-azure-public-lb Load balancer
standalone-cp-azure-vnet Virtual network

4.2 Vérifications

kubectl get resourcegroups,virtualnetworks,virtualnetworkssubnets,natgateways

# Résultat :
NAME                                                    READY   SEVERITY   REASON      MESSAGE
resourcegroup.resources.azure.com/standalone-cp-azure   True               Succeeded

NAME                                                        READY   SEVERITY   REASON      MESSAGE
virtualnetwork.network.azure.com/standalone-cp-azure-vnet   True               Succeeded

NAME                                                                                                       READY   SEVERITY   REASON      MESSAGE
virtualnetworkssubnet.network.azure.com/standalone-cp-azure-vnet-standalone-cp-azure-controlplane-subnet   True               Succeeded
virtualnetworkssubnet.network.azure.com/standalone-cp-azure-vnet-standalone-cp-azure-node-subnet           True               Succeeded

NAME                                                          READY   SEVERITY   REASON      MESSAGE
natgateway.network.azure.com/standalone-cp-azure-node-natgw   True               Succeeded
kubectl get azuremachines

# Résultat :
NAME                                 READY   SEVERITY   REASON                    STATE       AGE
standalone-cp-azure-cp-0             False   Info       Creating                  Succeeded   85s
standalone-cp-azure-md-jmnmx-qrqxt   False   Info       WaitingForBootstrapData               67s

devops@herlec-icdc:~$ kubectl get azuremachines

# Résultat :
NAME                                 READY   SEVERITY   REASON     STATE       AGE
standalone-cp-azure-cp-0             True                          Succeeded   3m3s
standalone-cp-azure-md-jmnmx-qrqxt   False   Info       Creating   Succeeded   2m45s

kubectl get azuremachines


# Résultat :
NAME                                 READY   SEVERITY   REASON   STATE       AGE
standalone-cp-azure-cp-0             True                        Succeeded   21m
standalone-cp-azure-md-n5rsj-2kqvm   True                        Succeeded   20m
kubectl get clusterdeployments

# Résultat :
NAME                  READY   STATUS
standalone-cp-azure   True    ClusterDeployment is ready

4.3 Récupération du kubeconfig

kubectl get standalone-cp-azure-kubeconfig -n kcm-system

# Utilisation du plugin view-secret

kubectl view-secret standalone-cp-azure-kubeconfig -n kcm-system > kubeconfig.yaml

4.4 Test du cluster

KUBECONFIG=kubeconfig.yaml kubectl get nodes

# Résultat :
NAME                                 STATUS   ROLES           AGE   VERSION
standalone-cp-azure-cp-0             Ready    control-plane   25m   v1.31.5+k0s
standalone-cp-azure-md-n5rsj-2kqvm   Ready    <none>          25m   v1.31.5+k0s
KUBECONFIG=kubeconfig.yaml kubectl get po -A
NAMESPACE        NAME                                        READY   STATUS             RESTARTS       AGE
kube-system      calico-kube-controllers-6cd7d8cc9f-bpfzh    1/1     Running            0              27m
kube-system      calico-node-4cpmm                           1/1     Running            0              27m
kube-system      calico-node-ktjxt                           1/1     Running            0              26m
kube-system      cloud-controller-manager-765494fb6f-b67bb   0/1     CrashLoopBackOff   9 (58s ago)    27m
kube-system      cloud-node-manager-8qpvz                    1/1     Running            0              27m
kube-system      cloud-node-manager-hvzc8                    1/1     Running            0              26m
kube-system      coredns-645c5d6f5b-m7jxq                    1/1     Running            0              26m
kube-system      coredns-645c5d6f5b-qnnzg                    1/1     Running            0              26m
kube-system      csi-azuredisk-controller-54ff6d4cb7-h4sg5   1/6     CrashLoopBackOff   21 (76s ago)   5m12s
kube-system      csi-azuredisk-controller-54ff6d4cb7-ppggp   1/6     CrashLoopBackOff   21 (75s ago)   5m12s
kube-system      csi-azuredisk-node-fz4x6                    3/3     Running            0              5m12s
kube-system      csi-azuredisk-node-q5pj8                    3/3     Running            0              5m12s
kube-system      kube-proxy-dbq2r                            1/1     Running            0              26m
kube-system      kube-proxy-hvtkv                            1/1     Running            0              27m
kube-system      metrics-server-78c4ccbc7f-6ng5r             1/1     Running            0              27m
projectsveltos   sveltos-agent-manager-789964cb68-6vqtk      1/1     Running            0              27m

4.5 Gestion des erreurs

pour le cloud-controller-manager

Run: Cloud provider azure could not be initialized dynamically from secret kube-system/azure-cloud-
provider: NewCloudFromSecret: failed to get config from secret kube-system/azure-cloud-provider: secrets "azure-cloud-provider" not found

La doc n'est pas claire sur ce sujet : (https://docs.k0rdent.io/latest/admin-credentials/?h=cloud+controller+manager#cloud-provider-credentials-propagation)

4.6 Tentative de patching à la main

kubectl view-secret standalone-cp-azure-cp-mt-azure-json

J'ai créé sur le cluster le secret azure-cloud-provider dans le ns kube-system avec les information suivantes :

KUBECONFIG=kubeconfig.yaml kubectl apply -f- <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: azure-cloud-provider
  namespace: kube-system
type: Opaque
stringData:
  cloud-config: |-
    {
    "cloud": "AzurePublicCloud",
    "tenantId": "${AZURE_TENANT_ID}",
    "subscriptionId": "${AZURE_SUBSCRIPTION_ID}",
    "aadClientId": "${AZURE_CLIENT_ID}",
    "aadClientSecret": "${AZURE_CLIENT_SECRET}",
    "resourceGroup": "${CLUSTER_DEPLOYMENT_NAME}",
    "securityGroupName": "${CLUSTER_DEPLOYMENT_NAME}-node-nsg",
    "securityGroupResourceGroup": "${CLUSTER_DEPLOYMENT_NAME}",
    "location": "northeurope",
    "vmType": "vmss",
    "vnetName": "${CLUSTER_DEPLOYMENT_NAME}-vnet",
    "vnetResourceGroup": "${CLUSTER_DEPLOYMENT_NAME}",
    "subnetName": "${CLUSTER_DEPLOYMENT_NAME}-node-subnet",
    "routeTableName": "${CLUSTER_DEPLOYMENT_NAME}-node-routetable",
    "loadBalancerSku": "Standard",
    "loadBalancerName": "",
    "maximumLoadBalancerRuleCount": 250,
    "useManagedIdentityExtension": false,
    "useInstanceMetadata": true
    }

EOF
KUBECONFIG=kubeconfig.yaml  kubectl delete po -n kube-system -l component=cloud-controller-manager
KUBECONFIG=kubeconfig.yaml  kubectl delete po -n kube-system -l app=csi-azuredisk-node
KUBECONFIG=kubeconfig.yaml kubectl get po -n kube-system

# Résultat 

NAME                                        READY   STATUS    RESTARTS   AGE
calico-kube-controllers-6cd7d8cc9f-ldl9q    1/1     Running   0          82m
calico-node-fwssw                           1/1     Running   0          82m
calico-node-t5ppw                           1/1     Running   0          81m
cloud-controller-manager-765494fb6f-5c5kk   1/1     Running   0          14m
cloud-node-manager-j4f4f                    1/1     Running   0          81m
cloud-node-manager-kmkfn                    1/1     Running   0          82m
coredns-645c5d6f5b-mnnfz                    1/1     Running   0          81m
coredns-645c5d6f5b-wkfrb                    1/1     Running   0          81m
csi-azuredisk-controller-54ff6d4cb7-6bfr5   6/6     Running   0          13m
csi-azuredisk-controller-54ff6d4cb7-jm2rj   6/6     Running   0          13m
csi-azuredisk-node-ckvd4                    3/3     Running   0          30m
csi-azuredisk-node-ps79t                    3/3     Running   0          30m
kube-proxy-fk7mt                            1/1     Running   0          81m
kube-proxy-nqvcd                            1/1     Running   0          82m
metrics-server-78c4ccbc7f-5hvpb             1/1     Running   0          82m

All Good !

Fin du test azure-standalone-cp-0-1-0

4.7 Cleaning

kubectl delete clusterdeployment standalone-cp-azure

# Résultat :

clusterdeployment.k0rdent.mirantis.com "standalone-cp-azure" deleted

# CA PREND DU TEMPS ! (Nettoyage de toutes les ressources Azure)

5. Test du template azure-hosted-cp-0-1-0


En pré-requis il faut du stockage sur le cluster de management

Je vais faire très simple et installer localpath-provisioner de rancher

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.31/deploy/local-path-storage.yaml

kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

Ce template permet de créer un cluster kubernetes dont le control plane est managé par k0smotron dans le cluster de management. Les workers sont déployés sous forme de VMs Azure.

Le cluster de management se trouve dans un resource group qui s'appelle aaaaa-herlec-icdc

J'ai :

  • un vnet : herlec-icdc-vnet
  • un subnet : default
  • un nsg : herlec-icdc-nsg
  • une route table herlec-icdc-routetable

5.1 Création du manifeste de déploiement du cluster

kubectl apply -f- <<EOF
apiVersion: k0rdent.mirantis.com/v1alpha1
kind: ClusterDeployment
metadata:
  name: azure-hosted-cp
spec:
  template: azure-hosted-cp-0-1-0
  credential: azure-cluster-identity-cred
  config:
    clusterLabels: {}
    location: "westeurope"
    subscriptionID: "${AZURE_SUBSCRIPTION_ID}"
    vmSize: Standard_A4_v2
    workersNumber: 2
    resourceGroup: aaaaa-herlec-icdc
    network:
      vnetName: herlec-icdc-vnet
      nodeSubnetName: default
      routeTableName: herlec-icdc-routetable
      securityGroupName: herlec-icdc-nsg
    k0smotron:
      service:
        type: ClusterIP
        #apiPort: 30443
        #konnectivityPort: 30132
EOF

J'ai une erreur concernant k0smotron qui n'a pas d'adresse IP sur son service loadbalancer. Il faudra que je regarde si au niveau du déploiement on peut gérer ce paramètre. Je vais la forcer avec l'adresse ip publique et privée de ma VM.

kubectl get svc mc-azure-hosted-cp-lb -n kcm-system

# Résultat :

mc-azure-hosted-cp-lb       LoadBalancer   10.104.136.148   <pending>     6443:30661/TCP,8132:30619/TCP   58m
  • Patching
kubectl patch svc kmc-azure-hosted-cp-lb --type='merge' -p '{"spec":{"externalIPs":["10.0.0.4", "13.xx.xx.xx"]}}'
kubectl get svc mc-azure-hosted-cp-lb -n kcm-system

# Résultat :
kmc-azure-hosted-cp-lb       LoadBalancer   10.104.136.148   10.0.0.4,13.xxx.xx.xx   6443:30661/TCP,8132:30619/TCP   64m

5.2 Méthode alternative

Même comme ca, en forçant l'adresse IP sur l'ip publique de la VM ca ne marche pas.

Je vais donc redéployer kcml sur un cluster d'administration basé sur AKS. de cette manière l'intégration à l'eco-système Azure sera plus simple. Stockage, loadbalancers.

Je vais créer un vnet, subnet, Route table et un nsg

- resourcegroup   :   001-kcm-k8s-hosted-cp
- un vnet         :   001-kcm-k8s-hosted-cp-vnet
- un subnet       :   001-kcm-k8s-hosted-cp-subnet-001
- un nsg          :   001-kcm-k8s-hosted-cp-nsg-001
- une route table :   001-kcm-k8s-hosted-cp-rt-001

kubectl apply -f- <<EOF
apiVersion: k0rdent.mirantis.com/v1alpha1
kind: ClusterDeployment
metadata:
  name: 001-kcm-k8s-hosted-cp
spec:
  template: azure-hosted-cp-0-1-0
  credential: azure-cluster-identity-cred
  config:
    clusterLabels: {}
    location: "northeurope"
    subscriptionID: "${AZURE_SUBSCRIPTION_ID}"
    vmSize: Standard_A4_v2
    workersNumber: 2
    resourceGroup: 001-kcm-k8s-hosted-cp
    network:
      vnetName: 001-kcm-k8s-hosted-cp-vnet
      nodeSubnetName: 001-kcm-k8s-hosted-cp-subnet-001
      routeTableName: 001-kcm-k8s-hosted-cp-rt-001
      securityGroupName: 001-kcm-k8s-hosted-cp-nsg-001
EOF

J'ai bien la création d'un loadbalancer pour le control plane géré par k0smotron

kmc-001-kcm-k8s-hosted-cp-lb  LoadBalancer   10.0.228.50    135.x.x.9   6443:32191/TCP,8132:30190/TCP  

# Test curl 
curl -k https://135.x.x.9:6443

# Résultat :
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}

C'est OK!

5.3 Récupération du kubeconfig

kubectl view-secret 001-kcm-k8s-hosted-cp-kubeconfig -n kcm-system > 001-kcm-k8s-hosted-cp.conf


# Vérifications 
KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl get nodes 
No resources found


KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl get po -A

# Résultats
NAMESPACE        NAME                                        READY   STATUS    RESTARTS   AGE
kube-system      calico-kube-controllers-6cd7d8cc9f-k8xd7    0/1     Pending   0          48s
kube-system      cloud-controller-manager-668b5cf9b6-trzsv   0/1     Pending   0          48s
kube-system      coredns-7b7b486b6c-vjh7v                    0/1     Pending   0          49s
kube-system      metrics-server-78c4ccbc7f-kcmqs             0/1     Pending   0          48s
projectsveltos   sveltos-agent-manager-7c967bfdd5-7c4d9      0/1     Pending   0          24s


# Aucun des pods n'est prets !

Quand on regarde la documentation il y a une note qui n'est pas clair, car on ne sait pas quand il faut patcher la resource azurecluster

Référence : https://docs.k0rdent.io/v0.1.0/template-azure/

kubectl get azurecluster

# Résultat :

NAME                    CLUSTER                 READY   REASON   AGE
001-kcm-k8s-hosted-cp   001-kcm-k8s-hosted-cp                    3m21s

J'ai donc patché la resource pour voir si ca changeait quelque chose 😀

kubectl patch azurecluster 001-kcm-k8s-hosted-cp  --type=merge --subresource status --patch 'status: {ready: true}'

# Résultat :
azurecluster.infrastructure.cluster.x-k8s.io/001-kcm-k8s-hosted-cp patched

Et ... ca fonctionne !!!

J'ai bien 2 vm qui sont provisionnées

Maintenant on a :

KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl get po -A

NAMESPACE        NAME                                        READY   STATUS             RESTARTS       AGE
kube-system      calico-kube-controllers-6cd7d8cc9f-pvvwh    1/1     Running            0              86m
kube-system      calico-node-2wfrf                           1/1     Running            0              4m9s
kube-system      calico-node-tw7vs                           1/1     Running            0              4m10s
kube-system      cloud-controller-manager-668b5cf9b6-k9jx4   0/1     CrashLoopBackOff   3 (41s ago)    6m26s
kube-system      cloud-node-manager-nllzg                    1/1     Running            0              4m10s
kube-system      cloud-node-manager-vl2j8                    1/1     Running            0              4m9s
kube-system      coredns-645c5d6f5b-2tldj                    1/1     Running            0              3m59s
kube-system      coredns-645c5d6f5b-cv4nz                    1/1     Running            0              3m59s
kube-system      csi-azuredisk-controller-54ff6d4cb7-44q7b   4/6     CrashLoopBackOff   12 (23s ago)   2m41s
kube-system      csi-azuredisk-controller-54ff6d4cb7-k6zvx   3/6     CrashLoopBackOff   12 (8s ago)    2m41s
kube-system      csi-azuredisk-node-4p268                    3/3     Running            0              2m41s
kube-system      csi-azuredisk-node-qjp8j                    3/3     Running            0              2m41s
kube-system      konnectivity-agent-j4r4n                    1/1     Running            0              4m10s
kube-system      konnectivity-agent-j7lng                    1/1     Running            0              4m9s
kube-system      kube-proxy-nq7z6                            1/1     Running            0              4m9s
kube-system      kube-proxy-s6m2s                            1/1     Running            0              4m10s
kube-system      metrics-server-78c4ccbc7f-qdz88             1/1     Running            0              86m
projectsveltos   sveltos-agent-manager-665b9479b8-8mmm4      1/1     Running            0              86m

Il va falloir fixer encore le cloud-controller-manager comme à l'étape précédente

export CLUSTER_DEPLOYMENT_NAME="001-kcm-k8s-hosted-cp"
export LOCATION="northeurope"

KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl apply -f- <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: azure-cloud-provider
  namespace: kube-system
type: Opaque
stringData:
  cloud-config: |-
    {
    "cloud": "AzurePublicCloud",
    "tenantId": "${AZURE_TENANT_ID}",
    "subscriptionId": "${AZURE_SUBSCRIPTION_ID}",
    "aadClientId": "${AZURE_CLIENT_ID}",
    "aadClientSecret": "${AZURE_CLIENT_SECRET}",
    "resourceGroup": "${CLUSTER_DEPLOYMENT_NAME}",
    "securityGroupName": "${CLUSTER_DEPLOYMENT_NAME}-nsg-001",
    "securityGroupResourceGroup": "${CLUSTER_DEPLOYMENT_NAME}",
    "location": "${LOCATION}",
    "vmType": "vmss",
    "vnetName": "${CLUSTER_DEPLOYMENT_NAME}-vnet",
    "vnetResourceGroup": "${CLUSTER_DEPLOYMENT_NAME}",
    "subnetName": "${CLUSTER_DEPLOYMENT_NAME}-subnet-001",
    "routeTableName": "${CLUSTER_DEPLOYMENT_NAME}-rt-001",
    "loadBalancerSku": "Standard",
    "loadBalancerName": "",
    "maximumLoadBalancerRuleCount": 250,
    "useManagedIdentityExtension": false,
    "useInstanceMetadata": true
    }

EOF

Je provoque un redémarrage des pods du namespace kube-system

KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl -n kube-system  rollout restart deploy cloud-controller-manager csi-azuredisk-controller calico-kube-controllers metrics-server coredns
deployment.apps/cloud-controller-manager restarted
deployment.apps/csi-azuredisk-controller restarted
deployment.apps/calico-kube-controllers restarted
deployment.apps/metrics-server restarted
deployment.apps/coredns restarted


# Vérifications :

KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl get po -A

NAMESPACE        NAME                                        READY   STATUS    RESTARTS   AGE
kube-system      calico-kube-controllers-555f4ffcbc-ks7r5    1/1     Running   0          10s
kube-system      calico-node-mvqms                           1/1     Running   0          18m
kube-system      calico-node-rcztl                           1/1     Running   0          19m
kube-system      cloud-controller-manager-8d7d987f8-jpx4n    1/1     Running   0          13s
kube-system      cloud-node-manager-ltz8t                    1/1     Running   0          8m32s
kube-system      cloud-node-manager-msnw6                    1/1     Running   0          8m32s
kube-system      coredns-645c5d6f5b-cfkt2                    1/1     Running   0          9m36s
kube-system      coredns-6c4b58d497-685fl                    0/1     Pending   0          12s
kube-system      coredns-6c4b58d497-kw87j                    0/1     Running   0          12s
kube-system      csi-azuredisk-controller-54ff6d4cb7-rrm4n   6/6     Running   0          8m20s
kube-system      csi-azuredisk-controller-54ff6d4cb7-rs7mf   6/6     Running   0          8m20s
kube-system      csi-azuredisk-controller-7c45dc7f7f-twc89   0/6     Pending   0          13s
kube-system      csi-azuredisk-node-vlc2b                    3/3     Running   0          8m20s
kube-system      csi-azuredisk-node-zsfdj                    3/3     Running   0          8m20s
kube-system      konnectivity-agent-pxrv2                    1/1     Running   0          9m34s
kube-system      konnectivity-agent-x5spn                    1/1     Running   0          9m34s
kube-system      kube-proxy-59rb9                            1/1     Running   0          18m
kube-system      kube-proxy-n5wp6                            1/1     Running   0          18m
kube-system      metrics-server-5b9b76db47-tqk67             0/1     Running   0          12s
kube-system      metrics-server-78c4ccbc7f-w8phh             1/1     Running   0          7m11s
projectsveltos   sveltos-agent-manager-7c967bfdd5-7c4d9      1/1     Running   0          28m

Maintenant tout est Okubectl !

5.4 Test du cluster créé

KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl  create deploy web --image nginx -n default
KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl  expose deploy web --type LoadBalancer -n default --port 80

KUBECONFIG=001-kcm-k8s-hosted-cp.conf kubectl  get deploy,svc -n default

# Résultats :
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   1/1     1            1           3m22s

NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
service/kubernetes   ClusterIP      10.96.0.1       <none>          443/TCP        34m
service/web          LoadBalancer   10.101.53.225   4.208.216.226   80:32732/TCP   2m14s

Le cloud controller fonctionne bien il a créé un loadbalancer qui pointe sur les vm du cluster kubernetes

5.5 Test de l'accès au service web

curl -s -o /dev/null -I -w "%{http_code}" 4.208.216.226 

200%

Le déprovisionnement fonctionne aussi très bien le loadbalancer ainsi que l'adresse ip publique sont bien supprimés

5.6 Cleaning

# Très important !  

kubectl patch azurecluster 001-kcm-k8s-hosted-cp  --type=merge --patch 'metadata: {finalizers: [manual]}'

kubectl delete clusterdeployment 001-kcm-k8s-hosted-cp

# CA PREND DU TEMPS ! (Nettoyage de toutes les ressources Azure)


# Libérer la resource pour sa suppression 

kubectl patch azurecluster 001-kcm-k8s-hosted-cp --type=json -p='[{"op": "remove", "path": "/metadata/finalizers/0"}]'

6. Conclusions

k0rdent (kcm) démontre sa capacité à simplifier considérablement le déploiement et la gestion de clusters Kubernetes sur Azure. Que ce soit pour des clusters AKS entièrement managés, des clusters k0s autonomes, ou des clusters avec un plan de contrôle hébergé, k0rdent offre une abstraction puissante grâce à l'intégration de Cluster API.

L'automatisation fournie par k0rdent réduit la complexité, accélère les déploiements, et permet aux équipes de se concentrer sur leurs applications plutôt que sur l'infrastructure sous-jacente.

L'utilisation de templates préconfigurés et la gestion centralisée des identifiants facilitent grandement l'adoption de Kubernetes sur Azure.

Découvrez les technologies d'alter way