Unité 3.2 : Déploiement et exploitation de Kubernetes
Introduction
Vous avez conteneurisé l'API, le front-end et le worker de TaskBoard dans l'unité 3.1 et les avez poussés vers Private Container Registry avec des étiquettes git-SHA. Vous avez maintenant besoin d'un endroit pour les exécuter. Dans cette unité, vous provisionnez un cluster Managed Kubernetes (MKS) en tant que code, vous configurez les identifiants du registre dans le cluster afin qu'il puisse récupérer vos images, et vous déployez les trois services en tant que ressources Kubernetes standard.
Le plan de contrôle MKS est géré pour vous, mais deux réalités spécifiques à IONOS CLOUD influencent chaque déploiement que vous écrivez. Premièrement, un Service de type LoadBalancer sur MKS ne provisionne pas un équilibreur de charge externe réel, de sorte que l'ingress de production est géré par un Application Load Balancer (ALB) provisionné séparément. Deuxièmement, les événements du plan de contrôle que vous pourriez attendre dans un flux de journaux centralisé ne sont pas présents, ce qui modifie la manière dont vous effectuez le débogage. Vous écrirez du code pour ces deux réalités, au lieu de chercher des contournements après qu'ils vous aient causé des problèmes en production.
1. Provisionnement du Cluster avec Terraform
Un cluster Managed Kubernetes sur IONOS CLOUD est constitué de deux ressources distinctes : le cluster (le plan de contrôle géré) et un ou plusieurs pools de nœuds (le calcul des workers que vous payez). Le plan de contrôle lui-même est gratuit ; vous ne payez que le calcul des pools de nœuds sous-jacents et les volumes Block Storage que vos pods provisionnent. Créez d'abord le cluster, puis attachez des pools de nœuds qui y font référence.
1.1 Ressources Cluster et Pool de nœuds
La ressource ionoscloud_k8s_cluster définit le plan de contrôle et sa version Kubernetes. La ressource ionoscloud_k8s_node_pool définit les nœuds de travail dans un centre de données spécifique.
resource "ionoscloud_k8s_cluster" "taskboard" {
name = "taskboard-prod"
k8s_version = "1.34"
maintenance_window {
day_of_the_week = "Sunday"
time = "03:00:00Z"
}
}
resource "ionoscloud_k8s_node_pool" "app" {
name = "taskboard-app-pool"
k8s_cluster_id = ionoscloud_k8s_cluster.taskboard.id
datacenter_id = ionoscloud_datacenter.taskboard.id
k8s_version = ionoscloud_k8s_cluster.taskboard.k8s_version
cpu_family = "INTEL_SKYLAKE"
server_type = "DedicatedCore"
node_count = 3
cores_count = 4
ram_size = 8192
availability_zone = "AUTO"
storage_type = "SSD"
storage_size = 100
}
Les versions de Kubernetes prises en charge sont 1.34, 1.33, 1.32 et 1.31. Fixez une valeur explicite pour k8s_version au lieu de suivre la version la plus récente, car chaque mise à niveau de pool de Node est exécutée pendant la fenêtre de maintenance et peut provoquer des déconnexions. Les pools de Node acceptent les types de serveur DedicatedCore et vCPU, il est donc recommandé de dimensionner le pool d'application de TaskBoard sur Dedicated Core pour des performances prévisibles.
1.2 Récupération du kubeconfig depuis l'état
Le kubeconfig peut être téléchargé depuis l'interface utilisateur DCD, mais la ressource cluster expose également la configuration directement, ce qui permet à Terraform de l'écrire sur le disque pour kubectl et pour qu'elle soit consommée par les pipelines CI.
output "kubeconfig" {
value = ionoscloud_k8s_cluster.taskboard.kube_config
sensitive = true
}
resource "local_file" "kubeconfig" {
content = ionoscloud_k8s_cluster.taskboard.kube_config
filename = "${path.module}/kubeconfig.yaml"
file_permission = "0600"
}
export KUBECONFIG=$(pwd)/kubeconfig.yaml
kubectl get nodes
Le fichier kubeconfig est également accessible via l'API à l'adresse GET /k8s/{k8sClusterId}/kubeconfig et via ionosctl k8s kubeconfig get --cluster-id <id>. Traitez-le comme un secret : il accorde un accès complet au cluster. Marquez la sortie Terraform sensitive et ne commitez jamais le fichier généré.
2. Déploiement des charges de travail sur MKS
Une fois que kubectl atteint le cluster, MKS se comporte comme un Kubernetes amont standard. Il n'existe pas de dialecte de manifeste spécifique à IONOS CLOUD. Vous appliquez les Deployments, Services, ConfigMaps et Secrets exactement comme vous le feriez sur n'importe quel cluster conforme. Le CNI est Calico et est fixe, donc la création des politiques réseau suit la sémantique de Calico, sans possibilité de changer le plugin.
2.1 Deployment, ConfigMap et Secret
L'API de TaskBoard nécessite une configuration non confidentielle et des identifiants secrets. Séparez-les : un ConfigMap pour l'hôte de la base de données et les drapeaux de fonctionnalité, et un Secret pour le mot de passe de connexion.
apiVersion: v1
kind: ConfigMap
metadata:
name: taskboard-config
namespace: taskboard
data:
DB_HOST: "pg-cluster.taskboard.internal"
CACHE_TTL: "300"
---
apiVersion: v1
kind: Secret
metadata:
name: taskboard-db
namespace: taskboard
type: Opaque
stringData:
DB_PASSWORD: "REPLACED_FROM_TERRAFORM_OUTPUT"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: taskboard-api
namespace: taskboard
spec:
replicas: 3
selector:
matchLabels:
app: taskboard-api
template:
metadata:
labels:
app: taskboard-api
spec:
imagePullSecrets:
- name: registry-cred
containers:
- name: api
image: <registry-name>.cr.de-fra.ionos.com/taskboard-api:<git-sha>
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: taskboard-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: taskboard-db
key: DB_PASSWORD
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
Les données secrètes sont chiffrées au repos dans MKS, mais les Secrets Kubernetes ne sont que des valeurs encodées en base64 dans le manifeste. Il convient donc de ne pas conserver les valeurs source dans Git et de les injecter à partir de la sortie Terraform au moment du déploiement. La sonde de disponibilité est importante car les mises à jour progressives en dépendent avant de rediriger le trafic.
2.2 Tirage des images à l'aide de imagePullSecrets
Private Container Registry exige une authentification pour chaque tirage. Il s'agit uniquement d'une connexion docker basée sur des jetons, sans RBAC et sans dépôts par équipe. Kubernetes nécessite un Secret dockerconfigjson construit à partir d'un jeton de registre, référencé en tant que imagePullSecrets dans la spécification du pod ci-dessus.
kubectl create namespace taskboard
kubectl create secret docker-registry registry-cred \
--namespace taskboard \
--docker-server=<registry-name>.cr.de-fra.ionos.com \
--docker-username=<token-name> \
--docker-password=<registry-token>
Si vous omettez la référence imagePullSecrets, ou si vous associez le Secret à l'espace de noms incorrect, les pods restent bloqués dans ImagePullBackOff. Le Secret étant lié à un espace de noms, créez-le dans chaque espace de noms qui exécute des images de registre. Dans les pipelines CI, vous générez le jeton de registre une seule fois et le stockez en tant que secret de pipeline, puis vous créez le Secret Kubernetes en tant qu'étape de déploiement.
3. Exposition du trafic : la réalité de LoadBalancer
C'est le fait le plus important spécifique à IONOS CLOUD dans cette unité. Un Service de type LoadBalancer sur MKS ne provisionne pas un équilibreur de charge externe véritable. IONOS CLOUD réserve une IP publique statique et l'assigne en tant qu'IP secondaire à un nœud worker, qui devient le nœud d'entrée, et kube-proxy effectue ensuite le NAT du trafic vers le pod cible.
3.1 Ce que cela implique pour vos manifests
Deux conséquences en découlent directement. L'IP source du client est perdue à moins que vous ne définissiez externalTrafficPolicy: Local, et le débit est limité au plafond public de 2 Gbit/s de ce seul nœud d'entrée, car tout le trafic transite par un unique nœud. Il n'y a pas de haute disponibilité automatique entre les nœuds pour cette IP.
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app: ingress-nginx
ports:
- port: 443
targetPort: 8443
Pour mettre à l'échelle le trafic au-delà d'un nœud unique, vous réservez plusieurs adresses IP LB et les répartissez sur plusieurs nœuds d'entrée à l'aide de l'équilibrage de charge DNS. Comme seuls les pools de nœuds publics prennent en charge le type de Service LoadBalancer (les pools de nœuds privés ne le prennent pas en charge), conservez votre contrôleur d'entrée orienté vers Internet sur un pool public. Exposez uniquement le contrôleur d'entrée en tant que LoadBalancer, et non un Service par application.
3.2 Placer un ALB provisionné séparément devant le Cluster
Pour TaskBoard en production, provisionnez un Application Load Balancer séparément via Terraform. L'ALB n'est pas créé automatiquement à partir de tout manifeste Kubernetes, il n'existe donc aucune annotation de contrôleur d'entrée qui en crée un. Vous le provisionnez en tant qu'infrastructure et orientez ses règles de transfert vers les adresses IP des nœuds qui servent le contrôleur d'entrée.
resource "ionoscloud_application_loadbalancer" "taskboard" {
name = "taskboard-alb"
datacenter_id = ionoscloud_datacenter.taskboard.id
listener_lan = ionoscloud_lan.public.id
ips = [ionoscloud_ipblock.alb.ips[0]]
target_lan = ionoscloud_lan.app.id
}
resource "ionoscloud_application_loadbalancer_forwardingrule" "https" {
datacenter_id = ionoscloud_datacenter.taskboard.id
application_loadbalancer_id = ionoscloud_application_loadbalancer.taskboard.id
name = "https-rule"
protocol = "HTTP"
listener_ip = ionoscloud_ipblock.alb.ips[0]
listener_port = 443
}
Notez que les règles NSG ne s'appliquent pas à l'ALB. Les Network Security Groups sont liés au niveau de l'interface réseau du serveur, et non à l'ALB managé ou à MKS. Vous contrôlez donc le trafic entrant via les règles de transfert de l'ALB et les règles de sécurité des interfaces réseau des nœuds de travail, et non en associant un NSG à l'équilibreur de charge.
4. Opérations sur les pools de Node
Les pools de Node constituent la surface opérationnelle que vous gérez tout au long du cycle de vie du cluster : mise à l'échelle en fonction de la charge, mise à niveau des versions de Kubernetes et isolation des charges de travail. Les Node eux-mêmes sont immuables, de sorte que les modifications de configuration qui concernent un Node le remplacent au lieu de le modifier sur place.
4.1 Mise à l'échelle et isolation des charges de travail
La mise à l'échelle d'un pool est une modification node_count appliquée via Terraform ou l'API. Un pool de Node peut contenir jusqu'à 100 Node (20 recommandés), un cluster peut contenir jusqu'à 500 pools de Node (50 recommandés) et jusqu'à 5000 Node au total, et chaque Node exécute jusqu'à 110 pods avec jusqu'à 20 volumes attachés. Utilisez des pools distincts pour isoler les charges de travail, par exemple un pool Dedicated Core pour l'API sensible à la latence et un pool vCPU pour le travailleur en arrière-plan.
resource "ionoscloud_k8s_node_pool" "worker" {
name = "taskboard-worker-pool"
k8s_cluster_id = ionoscloud_k8s_cluster.taskboard.id
datacenter_id = ionoscloud_datacenter.taskboard.id
k8s_version = ionoscloud_k8s_cluster.taskboard.k8s_version
server_type = "vCPU"
node_count = 2
cores_count = 2
ram_size = 4096
storage_type = "SSD"
storage_size = 50
}
Planifiez le déploiement du worker sur ce pool en utilisant un nodeSelector correspondant au pool, afin de le maintenir hors des nœuds API.
4.2 Mises à niveau de version
Augmentez k8s_version sur le pool de nœuds pour effectuer la mise à niveau. Cette opération aligne les ressources dans le centre de données cible et le pool repasse à Active une fois terminée, mais elle s'exécute pendant la maintenance et peut provoquer des déconnexions ; effectuez-la donc délibérément. Maintenez la version mineure du control-plane et les versions des pools de nœuds dans la plage de dérive prise en charge, et mettez à niveau le control plane avant les pools de nœuds.
ionosctl k8s nodepool update \
--cluster-id <cluster-id> \
--nodepool-id <nodepool-id> \
--k8s-version 1.34
Les volumes persistants sont provisionnés par le pilote CSI IONOS CLOUD (provisionneur cloud.ionos.com) adossé à Block Storage, de sorte que les pods dotés de PVC sont replanifiés sur des Node de remplacement lors d'une mise à niveau sans perte de données.
5. Débogage des charges de travail sur MKS
Lorsqu'un déploiement présente un dysfonctionnement, travaillez à partir du pod vers l'extérieur. La chaîne de triage standard kubectl s'applique, mais une lacune de la plateforme modifie votre stratégie : les événements du plan de contrôle Kubernetes ne transitent pas par le Logging Service d'IONOS CLOUD, il ne faut donc pas s'attendre à y trouver les journaux du scheduler ou de l'API-server.
5.1 La chaîne de triage
# pod status and restart counts
kubectl get pods -n taskboard -o wide
# why a pod is stuck (events at the bottom)
kubectl describe pod taskboard-api-7d9f -n taskboard
# application stdout/stderr, including the previous crashed container
kubectl logs taskboard-api-7d9f -n taskboard --previous
# cluster-scoped events, newest last
kubectl get events -n taskboard --sort-by=.lastTimestamp
# shell into a running container to test connectivity
kubectl exec -it taskboard-api-7d9f -n taskboard -- sh
kubectl describe est l'endroit où ImagePullBackOff, les échecs de planification et les échecs de sondage apparaissent, il est donc recommandé de le consulter avant de recourir aux journaux. Pour une observabilité au niveau de l'application, transmettez explicitement vos propres journaux de conteneur au Logging Service, car la plateforme ne capture pas les signaux du plan de contrôle à votre place.
5.2 Connaître la limite de la plateforme
Si vous supposez que les événements du plan de contrôle sont journalisés de manière centralisée, vous perdrez des heures à chercher dans un flux qui ne les a jamais contenues. Configurez la transmission des journaux au niveau du cluster (par exemple, un DaemonSet Fluent Bit envoyant les journaux des pods au Logging Service) pour les journaux d'application que vous contrôlez, et fiez-vous à kubectl get events pour la visibilité sur le plan de contrôle. Associez cela aux sondes de disponibilité et de vitalité de la section 2 afin que le cluster redémarre et reprogramme automatiquement les pods non sains pendant que vous menez vos investigations.
Fiche de référence rapide de l'API
Points d'accès API principaux pour Managed Kubernetes :
| Méthode | Point d'accès | Description |
|---|---|---|
GET |
/k8s |
Lister tous les clusters Kubernetes |
POST |
/k8s |
Créer un nouveau cluster |
GET |
/k8s/{k8sClusterId}/kubeconfig |
Récupérer le kubeconfig du cluster |
POST |
/k8s/{k8sClusterId}/nodepools |
Créer un pool de nœuds |
PUT |
/k8s/{k8sClusterId}/nodepools/{nodepoolId} |
Redimensionner ou mettre à niveau un pool de nœuds |
URL de base : https://api.ionos.com/cloudapi/v6
Authentification : Authorization: Bearer <token>
Atelier de code
Objectif : Provisionner un cluster MKS avec Terraform, déployer l'API de TaskBoard depuis le Private Container Registry, et y accéder via un contrôleur d'ingress.
Prérequis :
- Compte IONOS CLOUD avec jeton API (
IONOS_TOKENexporté) - Terraform et le fournisseur
ionos-cloud/ionoscloud kubectletionosctlinstallés- Un Private Container Registry avec l'image
taskboard-apipoussée (Unité 3.1)
Étape 1 : Provisionner le cluster et le pool de nœuds
terraform init
terraform apply -auto-approve
Sortie attendue :
ionoscloud_k8s_cluster.taskboard: Creation complete
ionoscloud_k8s_node_pool.app: Creation complete
Apply complete! Resources: 2 added.
Étape 2 : Écrire le kubeconfig et se connecter
terraform output -raw kubeconfig > kubeconfig.yaml
chmod 600 kubeconfig.yaml
export KUBECONFIG=$(pwd)/kubeconfig.yaml
kubectl get nodes
Sortie attendue :
NAME STATUS ROLES AGE VERSION
taskboard-app-pool-1 Ready <none> 2m v1.34.x
taskboard-app-pool-2 Ready <none> 2m v1.34.x
taskboard-app-pool-3 Ready <none> 2m v1.34.x
Étape 3 : Créer l'espace de noms et le secret de récupération du registre
kubectl create namespace taskboard
kubectl create secret docker-registry registry-cred \
--namespace taskboard \
--docker-server=<registry-name>.cr.de-fra.ionos.com \
--docker-username=<token-name> \
--docker-password=<registry-token>
Sortie attendue :
namespace/taskboard created
secret/registry-cred created
Étape 4 : Déployer l'API, la ConfigMap et le Secret
kubectl apply -f taskboard-api.yaml
kubectl rollout status deployment/taskboard-api -n taskboard
Sortie attendue :
deployment "taskboard-api" successfully rolled out
Étape 5 : Vérifier que les pods sont en cours de récupération et d'exécution
kubectl get pods -n taskboard
Sortie attendue :
NAME READY STATUS RESTARTS AGE
taskboard-api-7d9f8c-abcde 1/1 Running 0 40s
taskboard-api-7d9f8c-fghij 1/1 Running 0 40s
taskboard-api-7d9f8c-klmno 1/1 Running 0 40s
Étape 6 : Exposer le contrôleur d'entrée et lire son IP
kubectl apply -f ingress.yaml
kubectl get svc ingress-nginx -n ingress
Sortie attendue :
NAME TYPE EXTERNAL-IP PORT(S)
ingress-nginx LoadBalancer <reserved-ip> 443:3xxxx/TCP
Étape 7 : Vérifier que le point d'accès répond
curl -sk https://<reserved-ip>/healthz
Sortie attendue :
{"status":"ok"}
Liste de contrôle de validation :
- [ ] Le Cluster et le pool de nœuds atteignent
Activeet les nœuds sontReady - [ ] Les pods API sont
Running, et nonImagePullBackOff - [ ] L'IP d'entrée renvoie une réponse saine de l'API
Nettoyage :
kubectl delete namespace taskboard
terraform destroy -auto-approve
Erreurs courantes
Erreurs de développement à éviter lors du déploiement sur MKS :
-
S'attendre à ce que
type: LoadBalancerfournisse un équilibreur de charge externe réel- Problème : Vous exposez chaque Service en tant que
LoadBalancer, vous vous attendez à une haute disponibilité entre les nœuds, et toutes les adresses IP sources apparaissent comme une seule adresse de nœud. - Pourquoi cela se produit : Sur MKS, un Service
LoadBalancerréserve une adresse IP statique et l'associe à un nœud worker unique en tant qu'adresse IP secondaire ; kube-proxy effectue une conversion NAT vers le pod et l'adresse IP source est perdue. - Correction : Exposez uniquement le contrôleur d'entrée en tant que
LoadBalancer, définissezexternalTrafficPolicy: Localpour conserver l'adresse IP source, et placez un ALB provisionné séparément devant le trafic de production :
spec: type: LoadBalancer externalTrafficPolicy: Local - Problème : Vous exposez chaque Service en tant que
-
ImagePullBackOffdû à un secret de tirage manquant ou mal défini- Problème : Les Pods ne démarrent jamais ;
kubectl describe podafficheFailed to pull image ... no basic auth credentials. - Cause : Private Container Registry exige une authentification pour chaque tirage, et le Secret
dockerconfigjsonest lié à un espace de noms. Un Secret dansdefaultn'a aucun effet sur les pods danstaskboard. - Correction : Créez le Secret du registre dans l'espace de noms de la charge de travail et référencez-le sous
imagePullSecrets:
kubectl create secret docker-registry registry-cred -n taskboard \ --docker-server=<registry-name>.cr.de-fra.ionos.com \ --docker-username=<token-name> --docker-password=<registry-token> - Problème : Les Pods ne démarrent jamais ;
-
Recherche dans le Logging Service des événements du plan de contrôle
- Problème : Un pod n'est pas planifié et vous passez une heure à rechercher dans les journaux centralisés des erreurs du planificateur qui n'y figurent pas.
- Cause : Les événements du plan de contrôle de Kubernetes ne transitent pas par le Logging Service d'IONOS CLOUD.
- Solution : Lisez les signaux du plan de contrôle avec
kubectl, et n'envoyez que les journaux d'application que vous contrôlez :
kubectl get events -n taskboard --sort-by=.lastTimestamp kubectl describe pod <pod> -n taskboard
Résumé
Vous pouvez désormais provisionner un cluster Managed Kubernetes et des pools de Node entièrement en tant que code, récupérer le kubeconfig à partir de l'état Terraform, et déployer des services conteneurisés qui tirent leurs images depuis le Private Container Registry. Vous connaissez également les deux réalités IONOS CLOUD qui distinguent un déploiement MKS fonctionnel d'un déploiement défaillant : le type de Service LoadBalancer n'est pas un équilibreur de charge externe véritable, de sorte que le trafic de production est géré par un ALB provisionné séparément, et les événements du plan de contrôle ne sont pas journalisés de manière centralisée, de sorte que le débogage s'effectue via kubectl ainsi que votre propre transfert de journaux.
Avec l'API, le frontend et le worker de TaskBoard exécutés sur MKS derrière un ALB, vous disposez d'une cible déployable. L'unité suivante automatise le parcours allant d'un commit Git à ce cluster en cours d'exécution.
Points clés :
- Le plan de contrôle MKS est gratuit ; vous ne payez que pour le calcul des pools de Node et les volumes Block Storage
- Récupérez le kubeconfig à partir de l'attribut
kube_configde la ressourceionoscloud_k8s_cluster, marqué comme sensible - Un Service
type: LoadBalancerassocie une IP statique à un seul worker Node et n'est pas un LB externe véritable ; placez un ALB provisionné séparément devant la production - Tirez les images privées à l'aide d'un Secret
docker-registryavec espace de noms, référencé en tant queimagePullSecrets - Les événements du plan de contrôle Kubernetes n'atteignent pas le Logging Service IONOS CLOUD ; déboguez avec
kubectlet transférez vous-même les journaux applicatifs
Terminologie importante :
- Pool de Node : Un groupe de worker Nodes d'un même type de serveur dans un même centre de données, mis à l'échelle et mis à niveau en tant qu'unité (jusqu'à 100 Nodes, 20 recommandés)
- kubeconfig : Le fichier d'identifiants et de connexion pour
kubectl, exposé par la ressource du cluster et traité comme un secret - imagePullSecrets : Une référence dans la spécification d'un pod à un Secret
dockerconfigjsonqui authentifie les tirages depuis le Private Container Registry - externalTrafficPolicy: Local : Un paramètre de Service qui préserve l'IP source du client en conservant le trafic sur le Node récepteur au lieu de le rediriger
- Provisionneur CSI (
cloud.ionos.com) : Le pilote de stockage IONOS CLOUD qui sous-tend les PersistentVolumeClaims avec du Block Storage afin que les données survivent au remplacement d'un Node
Prochaines étapes
Continuer l'apprentissage : Unité 3.3 : Pipelines CI/CD pour IONOS CLOUD
Sujets connexes :