Unité 3.2 : Déploiement et exploitation de Kubernetes
Introduction
Vous avez conteneurisé TaskBoard's API, frontend et worker dans l'Unité 3.1 et les avez poussés vers Private Container Registry avec des étiquettes git-SHA. Maintenant, vous avez besoin d'un endroit pour les exécuter. Dans cette unité, vous allez provisionner un Managed Kubernetes (MKS) Cluster en tant que code, connecter les informations d'identification du registre dans le Cluster afin qu'il puisse extraire vos images, et déployer 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 influencent chaque déploiement que vous écrivez. Premièrement, un Service de type LoadBalancer sur MKS ne provisionne pas un véritable Load Balancer externe, donc l'entrée de production est gérée par un Application Load Balancer (ALB) provisionné séparément. Deuxièmement, les événements de plan de contrôle que vous pourriez attendre dans un flux de journal centralisé ne sont pas là, ce qui change la façon dont vous déboguez. Vous allez écrire du code pour ces deux réalités, et non les contourner après qu'elles vous ont posé des problèmes en production.
1. Provisionnement du Cluster avec Terraform
Un Managed Kubernetes Cluster sur IONOS est constitué de deux ressources distinctes : le Cluster (le plan de contrôle géré) et une ou plusieurs Node Pools (le calcul des workers que vous payez). Le plan de contrôle lui-même est gratuit ; vous ne payez que pour le calcul sous-jacent du Node Pool et les volumes Block Storage que votre Pods met en place. Créez d'abord le Cluster, puis attachez les Node Pools qui le référencent.
1.1 Ressources du Cluster et du Node Pool
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 Worker Nodes à l'intérieur d'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 Kubernetes prises en charge sont 1.34, 1.33, 1.32, et 1.31. Épinglez une version k8s_version explicite plutôt que de suivre la dernière version, car chaque mise à niveau du Node Pool est exécutée pendant la fenêtre de maintenance et peut provoquer des déconnexions. Les Node Pools acceptent à la fois les types de serveurs DedicatedCore et vCPU, vous pouvez donc dimensionner le pool d'applications de TaskBoard sur Dedicated Core pour des performances prévisibles.
1.2 Récupération du kubeconfig à partir de l'état
Vous ne téléchargez pas le kubeconfig à partir d'une interface utilisateur. La ressource Cluster expose la configuration directement, de sorte que Terraform puisse l'écrire sur le disque pour que kubectl et CI puissent la consommer.
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 kubeconfig est également récupérable via le API à 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 de charges de travail sur MKS
Une fois que kubectl atteint le Cluster, MKS se comporte comme un Kubernetes standard en amont. Il n'y a pas de dialecte de manifeste spécifique à IONOS. Vous appliquez des déploiements, des services, des ConfigMaps et des Secrets exactement comme vous le feriez sur n'importe quel Cluster conforme. Le CNI est Calico et est fixe, donc la création de stratégies de réseau suit les sémantiques de Calico sans option pour échanger le plugin.
2.1 Déploiement, ConfigMap et Secret
La TaskBoard API nécessite une configuration non secrète et des informations d'identification secrètes. Séparez-les : une ConfigMap pour l'hôte de base de données et les indicateurs de fonctionnalités, 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 à REST dans MKS, mais les Secrets Kubernetes ne sont que codés en base64 dans le manifeste, donc gardez toujours les valeurs sources en dehors de Git et injectez-les à partir de la sortie Terraform au moment du déploiement. La sonde de prêt est importante car les mises à jour progressives attendent qu'elle soit terminée avant de modifier le trafic.
2.2 Téléchargement d'images avec imagePullSecrets
Private Container Registry nécessite une authentification pour chaque téléchargement, et il s'agit d'une authentification basée sur le jeton Docker, sans RBAC et sans répertoires par équipe. Kubernetes nécessite un Secret dockerconfigjson construit à partir d'un jeton d'enregistrement, référencé comme 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 omittez la référence imagePullSecrets, ou si vous limitez le Secret à un espace de noms incorrect, Pods sera bloqué dans ImagePullBackOff. Le Secret est limité à un espace de noms, donc créez-le dans chaque espace de noms qui exécute des images d'enregistrement. Dans CI, vous générez le jeton d'enregistrement une seule fois et le stockez comme secret de pipeline, puis créez le Secret Kubernetes comme étape de déploiement.
3. Exposition du trafic : la réalité du LoadBalancer
Ceci est le fait le plus important spécifique à IONOS dans cette unité. Un Service de type LoadBalancer sur MKS ne provisionne pas un véritable Load Balancer externe. IONOS Cloud réserve une adresse publique statique IP et l'attribue en tant qu'adresse secondaire IP à un worker Node, qui devient le Node d'entrée, et kube-proxy NAT ensuite le trafic vers le pod cible.
3.1 Ce que cela signifie pour vos manifests
Deux conséquences découlent directement. La source client IP est perdue à moins que vous ne définissiez externalTrafficPolicy: Local, et le débit est limité à 2 Gbit/s, le plafond public de ce seul Node d'entrée, car tout le trafic passe par un seul Node. Il n'y a pas d'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 seul Node, vous réservez plusieurs adresses LB IP et les distribuez sur plusieurs nœuds d'entrée en utilisant DNS pour l'équilibrage de charge. Puisque seuls les Node Pools publics prennent en charge le type de service LoadBalancer (les Node Pools privés ne le font pas), gardez votre contrôleur d'entrée orienté internet sur un pool public. N'exposez que le contrôleur d'entrée en tant que LoadBalancer, et non un Service par application.
3.2 Frontage du Cluster avec un ALB provisionné séparément
Pour la production TaskBoard, provisionnez un Application Load Balancer séparément via Terraform. L'ALB n'est pas créé automatiquement à partir d'un manifeste Kubernetes, il n'y a donc aucune annotation de contrôleur d'entrée qui le crée. Vous le provisionnez en tant qu'infrastructure et pointez ses règles de transfert vers les adresses IP Node 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 du serveur-NIC, et non à l'ALB géré ou à MKS, vous contrôlez donc le trafic d'entrée via les règles de transfert ALB et les règles de sécurité sur les NICs de worker Node, et non en attachant un NSG au Load Balancer.
4. Node Pool Operations
Les Node Pools sont la surface opérationnelle que vous gérez pendant la durée de vie du Cluster : mise à l'échelle pour la charge, mise à jour des versions de Kubernetes, et isolation des charges de travail. Les nœuds eux-mêmes sont immuables, donc les modifications de configuration qui touchent un Node le remplacent plutôt que de le modifier en 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 le API. Un pool de Node peut contenir jusqu'à 100 nœuds (20 recommandés), un Cluster peut contenir jusqu'à 500 Node Pools (50 recommandés) et jusqu'à 5000 nœuds au total, et chaque Node peut exécuter jusqu'à 110 Pods avec jusqu'à 20 volumes attachés. Utilisez des pools séparés pour isoler les charges de travail, par exemple un pool de Dedicated Core pour les API sensibles à la latence et un pool de vCPU pour les travailleurs 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 travailleur sur ce pool avec un nodeSelector correspondant au pool, en le gardant hors des nœuds API.
4.2 Mises à jour de version
Augmentez la version k8s_version sur le pool de Node pour effectuer une mise à jour. L'opération aligne les ressources dans le centre de données cible et le pool revient à Active lorsqu'il est terminé, mais il s'exécute pendant la maintenance et peut causer des déconnexions, donc faites-le délibérément. Gardez la version mineure du plan de contrôle et les versions du pool de Node dans les écarts de version pris en charge, et mettez à jour le plan de contrôle avant les Node Pools.
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 IONOS CSI (provisionneur cloud.ionos.com) pris en charge par Block Storage, donc les Pods avec des PVC peuvent être replanifiés sur des nœuds de remplacement pendant une mise à jour sans perdre de données.
5. Débogage des charges de travail sur MKS
Lorsqu'un déploiement se comporte de manière anormale, travaillez à partir du pod vers l'extérieur. La chaîne standard de triage kubectl s'applique, mais une lacune de plateforme change votre stratégie : les événements de contrôle de Kubernetes ne transitent pas par le Logging Service d'IONOS, donc ne vous attendez pas à trouver des journaux de planificateur ou de API-serveur ici.
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 où ImagePullBackOff, les échecs de planification et les échecs de sonde apparaissent, donc lisez-le avant de chercher des journaux. Pour l'observabilité au niveau de l'application, transmettez explicitement vos propres journaux de conteneur au Logging Service, car la plateforme ne capturera pas les signaux de contrôle pour vous.
5.2 Connaître la limite de la plateforme
Si vous supposez que les événements de contrôle sont enregistrés de manière centralisée, vous perdrez des heures à rechercher un flux qui ne les contient jamais. Configurez la transmission de journaux au niveau Cluster (par exemple, un DaemonSet Fluent Bit qui envoie des journaux de pod au Logging Service) pour les journaux d'application que vous contrôlez, et comptez sur kubectl get events pour la visibilité de la couche de contrôle. Associez ceci aux sondes de prêt et de vivacité de la Section 2, de sorte que le Cluster redémarre et réorganise automatiquement les Pods non sains pendant que vous investigatez.
API Référence Quick Card
Points de terminaison clés API pour Managed Kubernetes :
| Méthode | Point de terminaison | Description |
|---|---|---|
GET |
/k8s |
Liste tous les clusters Kubernetes |
POST |
/k8s |
Crée un nouveau Cluster |
GET |
/k8s/{k8sClusterId}/kubeconfig |
Récupère le kubeconfig Cluster |
POST |
/k8s/{k8sClusterId}/nodepools |
Crée un pool Node |
PUT |
/k8s/{k8sClusterId}/nodepools/{nodepoolId} |
Met à l'échelle ou met à niveau un pool Node |
URL de base : https://api.ionos.com/cloudapi/v6
Authentification : Authorization: Bearer <token>
Laboratoire de code
Objectif : Mettre en place un MKS Cluster avec Terraform, déployer TaskBoard's API à partir de Private Container Registry, et y accéder via un contrôleur d'entrée.
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 : Mettre en place le pool Cluster et Node
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 un espace de noms et un secret de tirage de 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 le API, ConfigMap et 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 train de tirer et d'exécuter
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 : Confirmer que le point de terminaison répond
curl -sk https://<reserved-ip>/healthz
Sortie attendue :
{"status":"ok"}
Liste de validation :
- [ ] Le pool Cluster et Node atteint
Activeet les nœuds sontReady - [ ] Les API Pods sont
Running, et nonImagePullBackOff - [ ] L'entrée IP renvoie une réponse saine à partir du 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: LoadBalancervous donne une véritable adresse Load Balancer externe- Problème : Vous exposez chaque Service en tant que
LoadBalancer, vous attendez une haute disponibilité entre les nœuds, et les adresses IP sources affichent toutes une seule adresse Node. - Pourquoi cela se produit : Sur MKS, un Service
LoadBalancerréserve une adresse IP statique et la relie à un worker Node comme adresse IP secondaire ; kube-proxy effectue une traduction d'adresses 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 le trafic de production devant un ALB provisionné séparément :
spec: type: LoadBalancer externalTrafficPolicy: Local - Problème : Vous exposez chaque Service en tant que
-
ImagePullBackOffen raison d'un secret de tirage manquant ou mal étendu- Problème : Les Pods ne démarrent jamais ;
kubectl describe podafficheFailed to pull image ... no basic auth credentials. - Pourquoi cela se produit : Private Container Registry nécessite une authentification à chaque tirage, et le secret
dockerconfigjsonest étendu à l'échelle des noms d'espace. Un secret dansdefaultne fait rien pour les Pods danstaskboard. - Correction : Créez le secret d'enregistrement dans l'espace de noms de la charge de travail et référez-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 les Logging Service pour les événements de plan de contrôle
- Problème : Un pod ne peut pas être planifié et vous passez une heure à rechercher des erreurs de planificateur dans les journaux centralisés qui ne sont pas là.
- Pourquoi cela se produit : Les événements de plan de contrôle Kubernetes ne passent pas par les Logging Service d'IONOS.
- Correction : Lisez les signaux de plan de contrôle avec
kubectl, et transmettez uniquement 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 maintenant provisionner un Managed Kubernetes Cluster et Node Pools entièrement en code, récupérer le kubeconfig à partir de l'état de Terraform, et déployer des services conteneurisés qui tirent de Private Container Registry. Vous connaissez également les deux réalités IONOS qui séparent un déploiement MKS fonctionnel d'un déploiement cassé : le type de service LoadBalancer n'est pas un véritable Load Balancer externe, donc le trafic de production est géré par un ALB provisionné séparément, et les événements de plan de contrôle ne sont pas enregistrés centralement, donc la débogage se fait via kubectl plus votre propre transfert de journaux.
Avec TaskBoard's API, frontend et worker s'exécutant sur MKS derrière un ALB, vous avez une cible déployable. La prochaine unité automatisera le chemin d'un commit Git à ce Cluster en cours d'exécution.
Points clés :
- Le plan de contrôle MKS est gratuit ; vous payez uniquement pour le calcul du Node Pool 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 adresse IP statique à un worker Node et n'est pas un véritable Load Balancer externe ; mettez en production avec un ALB provisionné séparément - Tirez des images privées avec un secret
docker-registryréférencé commeimagePullSecrets - Les événements de plan de contrôle Kubernetes ne parviennent pas au Logging Service d'IONOS ; déboguez avec
kubectlet transférez vous-même les journaux d'application
Terminologie importante :
- Node Pool : Un groupe de Worker Nodes d'un type de serveur dans un centre de données, mis à l'échelle et amélioré en tant qu'unité (jusqu'à 100 nœuds, 20 recommandés)
- kubeconfig : Le fichier d'informations d'identification et de connexion pour
kubectl, exposé par la ressource Cluster et traité comme un secret - imagePullSecrets : Une référence de spécification de pod à un secret
dockerconfigjsonqui authentifie les tirages de Private Container Registry - externalTrafficPolicy : Local : Un paramètre de service qui préserve l'adresse IP source du client en gardant le trafic sur le nœud récepteur Node au lieu de le réacheminer
- Provisionneur CSI (
cloud.ionos.com) : Le pilote de stockage IONOS qui prend en charge les revendications de volume persistant avec Block Storage afin que les données survivent au remplacement du Node
Prochaines étapes
Continuer l'apprentissage : Unité 3.3 : CI/CD Pipelines pour IONOS
Sujets connexes :