Unidad 3.2: Despliegue y operaciones de Kubernetes
Introducción
En la Unidad 3.1, contenerizó la API, el frontend y el worker de TaskBoard, y los subió a Private Container Registry con etiquetas git-SHA. Ahora necesita un lugar para ejecutarlos. En esta unidad, aprovisiona un clúster de Managed Kubernetes (MKS) como código, configura las credenciales del registro en el clúster para que pueda obtener sus imágenes, e implementa los tres servicios como recursos estándar de Kubernetes.
El plano de control de MKS se gestiona por usted, pero dos realidades específicas de IONOS CLOUD condicionan cada implementación que escriba. Primero, un Service de tipo LoadBalancer en MKS no aprovisiona un balanceador de carga externo real, por lo que el ingreso de producción se gestiona mediante un Application Load Balancer (ALB) aprovisionado por separado. Segundo, los eventos del plano de control que podría esperar en un flujo de registros centralizado no están presentes, lo que cambia la forma en que se depura. Escribirá código para ambas realidades, en lugar de buscar soluciones alternativas después de que le causen problemas en producción.
1. Aprovisionamiento del Cluster con Terraform
Un cluster de Managed Kubernetes en IONOS CLOUD consta de dos recursos distintos: el cluster (el plano de control administrado) y uno o varios grupos de Node (la capacidad de cómputo de trabajo que usted paga). El plano de control en sí es gratuito; usted solo paga por el cómputo subyacente de los grupos de Node y por los volúmenes de Block Storage que sus pods aprovisionan. Cree primero el cluster y luego adjunte grupos de Node que hagan referencia a él.
1.1 Recursos de Cluster y grupo de Node
El recurso ionoscloud_k8s_cluster define el plano de control y su versión de Kubernetes. El recurso ionoscloud_k8s_node_pool define los Node de trabajo dentro de un centro de datos específico.
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
}
Las versiones de Kubernetes compatibles son 1.34, 1.33, 1.32 y 1.31. Fije un k8s_version explícito en lugar de seguir la versión más reciente, ya que cada actualización de un grupo de nodos se ejecuta durante la ventana de mantenimiento y puede provocar desconexiones. Los grupos de nodos aceptan tanto tipos de servidor DedicatedCore como vCPU, por lo que debe dimensionar el grupo de aplicaciones de TaskBoard en Dedicated Core para obtener un rendimiento predecible.
1.2 Recuperación del kubeconfig desde el Estado
El kubeconfig puede descargarse desde la interfaz de usuario de DCD, pero el recurso del clúster también expone la configuración directamente, de modo que Terraform puede escribirla en el disco para que kubectl y CI la consuman.
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
El kubeconfig también se puede obtener a través de la API en GET /k8s/{k8sClusterId}/kubeconfig y mediante ionosctl k8s kubeconfig get --cluster-id <id>. Trátelo como un secreto: otorga acceso completo al clúster. Marque la salida de Terraform sensitive y nunca commite el archivo generado.
2. Despliegue de Workloads en MKS
Una vez que kubectl llega al clúster, MKS se comporta como un Kubernetes estándar de upstream. No existe un dialecto de manifiestos específico de IONOS CLOUD. Se aplican Deployments, Services, ConfigMaps y Secrets exactamente como se haría en cualquier clúster conforme. El CNI es Calico y es fijo, por lo que la creación de políticas de red sigue la semántica de Calico sin opción de cambiar el complemento.
2.1 Deployment, ConfigMap y Secret
La API de TaskBoard requiere configuración no secreta y credenciales secretas. Sepárelas: un ConfigMap para el host de la base de datos y las banderas de función, y un Secret para la contraseña de conexión.
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
Los datos de secretos se cifran en reposo en MKS, pero los Secrets de Kubernetes solo se codifican en base64 en el manifiesto, por lo que se deben mantener los valores de origen fuera de Git e inyectarlos desde la salida de Terraform en el momento de la implementación. La sonda de preparación es importante porque las actualizaciones graduales esperan a que se complete antes de cambiar el tráfico.
2.2 Obtención de imágenes con imagePullSecrets
Private Container Registry requiere autenticación para cada extracción, y se basa únicamente en tokens de docker login, sin RBAC y sin repositorios por equipo. Kubernetes necesita un Secret dockerconfigjson creado a partir de un token del registro y referenciado como imagePullSecrets en la especificación del pod anterior.
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 omite la referencia imagePullSecrets, o asigna el Secret al espacio de nombres incorrecto, los pods se quedan atascados en ImagePullBackOff. El Secret está asociado a un espacio de nombres, por lo que debe crearlo en cada espacio de nombres que ejecute imágenes del registro. En CI, genera el token del registro una sola vez y lo almacena como un secreto de la pipeline, y luego crea el Secret de Kubernetes como un paso de despliegue.
3. Exposición de tráfico: la realidad de LoadBalancer
Este es el hecho más importante y específico de IONOS CLOUD en la unidad. Un Service de tipo LoadBalancer en MKS no aprovisiona un equilibrador de carga externo real. IONOS CLOUD reserva una IP pública estática y la asigna como IP secundaria a un nodo de trabajo, que se convierte en el nodo de entrada, y kube-proxy aplica NAT al tráfico hacia el pod de destino.
3.1 Implicaciones para sus manifiestos
De esto se derivan dos consecuencias directas. La IP de origen del cliente se pierde a menos que configure externalTrafficPolicy: Local, y el rendimiento se limita al límite público de 2 Gbit/s de ese único nodo de entrada, ya que todo el tráfico se canaliza a través de un solo nodo. No existe alta disponibilidad automática entre nodos para esa 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
Para escalar el tráfico más allá de un solo nodo, reserva varias direcciones IP de LB y distribúyelas entre varios nodos de entrada mediante equilibrio de carga de DNS. Dado que solo los grupos de nodos públicos admiten el tipo de Service LoadBalancer (los grupos de nodos privados no lo admiten en absoluto), mantén tu controlador de entrada orientado a internet en un grupo público. Expón únicamente el controlador de entrada como LoadBalancer, nunca un Service por aplicación.
3.2 Fronting the Cluster with a Separately Provisioned ALB
Para TaskBoard de producción, aprovisiona un Application Load Balancer de forma independiente mediante Terraform. El ALB no se crea automáticamente a partir de ningún manifiesto de Kubernetes, por lo que no existe ninguna anotación de controlador de entrada que lo genere. Lo aprovisionas como infraestructura y diriges sus reglas de reenvío hacia las direcciones IP de los nodos que sirven el controlador de entrada.
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
}
Tenga en cuenta que las reglas de NSG no se aplican a ALB. Los Network Security Groups se asocian a nivel de NIC del servidor, no a Managed ALB ni a MKS, por lo que controla el tráfico de entrada a través de las reglas de reenvío de ALB y las reglas de seguridad en las NIC de los nodos de trabajo, no al adjuntar un NSG al equilibrador de carga.
4. Operaciones de Node Pool
Los Node Pool son la superficie operativa que usted administra a lo largo del ciclo de vida del clúster: escalado para la carga, actualización de versiones de Kubernetes y aislamiento de Workload. Los Node son inmutables, por lo que los cambios de configuración que afectan a un Node lo reemplazan en lugar de modificarlo in situ.
4.1 Escalado y Aislamiento de Workload
El escalado de un pool es un cambio de node_count aplicado a través de Terraform o la API. Un Node Pool admite hasta 100 Node (se recomiendan 20), un clúster admite hasta 500 Node Pool (se recomiendan 50) y hasta 5000 Node en total, y cada Node ejecuta hasta 110 pods con hasta 20 volúmenes adjuntos. Utilice pools separados para aislar Workload, por ejemplo, un pool Dedicated Core para la API sensible a la latencia y un pool de vCPU para el worker en segundo plano.
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
}
Programe el Deployment del worker en este pool con un nodeSelector que coincida con el pool, manteniéndolo fuera de los nodos API.
4.2 Actualizaciones de versión
Aumente k8s_version en el pool de nodos para actualizar. La operación alinea los recursos en el centro de datos de destino y el pool vuelve a Active al completarse, pero se ejecuta durante el mantenimiento y puede causar desconexiones, por lo que debe realizarse de manera deliberada. Mantenga la versión menor del control-plane y las versiones de los pools de nodos dentro del desfase admitido, y actualice el control plane antes que los pools de nodos.
ionosctl k8s nodepool update \
--cluster-id <cluster-id> \
--nodepool-id <nodepool-id> \
--k8s-version 1.34
Los volúmenes persistentes se aprovisionan mediante el controlador CSI de IONOS CLOUD (aprovisionador cloud.ionos.com) respaldado por Block Storage, de modo que los pods con PVC se reprograman en nodos de reemplazo durante una actualización sin perder datos.
5. Depuración de Workloads en MKS
Cuando una implementación presenta un comportamiento incorrecto, trabaje desde el pod hacia el exterior. Se aplica la cadena de triaje estándar de kubectl, pero una brecha de la plataforma cambia su estrategia: los eventos del plano de control de Kubernetes no fluyen a través del IONOS CLOUD Logging Service, por lo que no espere encontrar registros del programador o del API-server allí.
5.1 La cadena de triaje
# 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 es donde se manifiestan ImagePullBackOff, los errores de programación y las fallas de sondas, por lo que debe leerlo antes de recurrir a los registros. Para la observabilidad a nivel de aplicación, transfiera sus propios registros de contenedores al Logging Service de forma explícita, ya que la plataforma no capturará las señales del plano de control por usted.
5.2 Conocer el límite de la plataforma
Si asume que los eventos del plano de control se registran de forma centralizada, perderá horas buscando en un flujo que nunca los contuvo. Configure la transferencia de registros a nivel de clúster (por ejemplo, un DaemonSet de Fluent Bit que envía los registros de los pods al Logging Service) para los registros de aplicación que usted controla, y confíe en kubectl get events para la visibilidad del plano de control. Combine esto con las sondas de preparación y de supervivencia de la Sección 2 para que el clúster reinicie y reprograma automáticamente los pods no saludables mientras usted investiga.
Tarjeta rápida de referencia de API
Puntos finales de API clave para Managed Kubernetes:
| Método | Punto final | Descripción |
|---|---|---|
GET |
/k8s |
Listar todos los clústeres de Kubernetes |
POST |
/k8s |
Crear un nuevo clúster |
GET |
/k8s/{k8sClusterId}/kubeconfig |
Obtener el kubeconfig del clúster |
POST |
/k8s/{k8sClusterId}/nodepools |
Crear un grupo de nodos |
PUT |
/k8s/{k8sClusterId}/nodepools/{nodepoolId} |
Escalar o actualizar un grupo de nodos |
URL base: https://api.ionos.com/cloudapi/v6
Autenticación: Authorization: Bearer <token>
Laboratorio de código
Objetivo: Aprovisionar un clúster MKS con Terraform, desplegar la API de TaskBoard desde Private Container Registry y acceder a ella a través de un controlador de entrada.
Requisitos previos:
- Cuenta de IONOS CLOUD con token de API (
IONOS_TOKENexportado) - Terraform y el proveedor
ionos-cloud/ionoscloud kubectlyionosctlinstalados- Un Private Container Registry con la imagen
taskboard-apipublicada (Unidad 3.1)
Paso 1: Aprovisionar el clúster y el grupo de nodos
terraform init
terraform apply -auto-approve
Salida esperada:
ionoscloud_k8s_cluster.taskboard: Creation complete
ionoscloud_k8s_node_pool.app: Creation complete
Apply complete! Resources: 2 added.
Paso 2: Escriba el kubeconfig y conéctese
terraform output -raw kubeconfig > kubeconfig.yaml
chmod 600 kubeconfig.yaml
export KUBECONFIG=$(pwd)/kubeconfig.yaml
kubectl get nodes
Salida esperada:
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
Paso 3: Crear el espacio de nombres y el secreto de extracción del registro
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>
Salida esperada:
namespace/taskboard created
secret/registry-cred created
Paso 4: Despliegue de la API, el ConfigMap y el Secret
kubectl apply -f taskboard-api.yaml
kubectl rollout status deployment/taskboard-api -n taskboard
Salida esperada:
deployment "taskboard-api" successfully rolled out
Paso 5: Verificar que los pods están siendo descargados y en ejecución
kubectl get pods -n taskboard
Salida esperada:
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
Paso 6: Exponer el controlador de entrada y leer su IP
kubectl apply -f ingress.yaml
kubectl get svc ingress-nginx -n ingress
Salida esperada:
NAME TYPE EXTERNAL-IP PORT(S)
ingress-nginx LoadBalancer <reserved-ip> 443:3xxxx/TCP
Paso 7: Confirmar que el punto de extremo responde
curl -sk https://<reserved-ip>/healthz
Salida esperada:
{"status":"ok"}
Lista de verificación:
- [ ] El Cluster y el pool de nodos alcanzan
Activey los nodos estánReady - [ ] Los pods de la API están
Running, noImagePullBackOff - [ ] La IP de entrada devuelve una respuesta saludable de la API
Limpieza:
kubectl delete namespace taskboard
terraform destroy -auto-approve
Errores comunes
Errores de los desarrolladores que deben evitarse al implementar en MKS:
-
Esperar que
type: LoadBalancerproporcione un equilibrador de carga externo real- Problema: Expone cada Service como
LoadBalancer, espera alta disponibilidad entre nodos, y todas las direcciones IP de origen aparecen como una única dirección de nodo. - Por qué ocurre: En MKS, un Service
LoadBalancerreserva una IP estática y la asigna a un solo nodo de trabajo como IP secundaria; kube-proxy realiza NAT hacia el pod y la IP de origen se pierde. - Solución: Exponga solo el controlador de entrada como
LoadBalancer, configureexternalTrafficPolicy: Localpara preservar la IP de origen, y coloque un ALB aprovisionado por separado delante del tráfico de producción:
spec: type: LoadBalancer externalTrafficPolicy: Local - Problema: Expone cada Service como
-
ImagePullBackOffdebido a un pull secret ausente o con un alcance incorrecto- Problema: Los Pods nunca se inician;
kubectl describe podmuestraFailed to pull image ... no basic auth credentials. - Por qué ocurre: Private Container Registry requiere autenticación en cada pull, y el Secret
dockerconfigjsonestá limitado a un namespace. Un Secret endefaultno tiene ningún efecto para los pods entaskboard. - Solución: Cree el Secret del registro en el namespace de la carga de trabajo y refiérase a él bajo
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> - Problema: Los Pods nunca se inician;
-
Búsqueda de eventos del plano de control en el Logging Service
- Problema: Un pod no se programa y se pierde una hora buscando en los registros centralizados errores del programador que no están presentes.
- Por qué ocurre: Los eventos del plano de control de Kubernetes no fluyen a través del Logging Service de IONOS CLOUD.
- Solución: Lea las señales del plano de control con
kubectl, y reenvíe únicamente los registros de la aplicación que usted controla:
kubectl get events -n taskboard --sort-by=.lastTimestamp kubectl describe pod <pod> -n taskboard
Resumen
Ahora puede aprovisionar un clúster de Managed Kubernetes y pools de Node completamente como código, recuperar el kubeconfig desde el estado de Terraform e implementar servicios contenerizados que obtienen imágenes desde Private Container Registry. También conoce las dos realidades de IONOS CLOUD que distinguen una implementación de MKS funcional de una rota: el tipo de Service LoadBalancer no es un equilibrador de carga externo real, por lo que el tráfico de producción se dirige a un ALB aprovisionado por separado, y los eventos del plano de control no se registran de forma centralizada, por lo que la depuración se realiza mediante kubectl más su propio reenvío de registros.
Con la API, el frontend y el worker de TaskBoard ejecutándose en MKS detrás de un ALB, tiene un destino implementable. La siguiente unidad automatiza el camino desde un commit de Git hasta este clúster en ejecución.
Puntos clave:
- El plano de control de MKS es gratuito; solo paga por el cómputo del pool de Node y los volúmenes de Block Storage
- Recupere el kubeconfig del atributo
kube_configdel recursoionoscloud_k8s_cluster, marcado como confidencial - Un Service
type: LoadBalancerfija una IP estática a un solo Node de trabajo y no es un LB externo real; dirija la producción a un ALB aprovisionado por separado - Obtenga imágenes privadas mediante un Secret con espacio de nombres
docker-registryreferenciado comoimagePullSecrets - Los eventos del plano de control de Kubernetes no llegan al Logging Service de IONOS CLOUD; depure con
kubectly reenvíe usted mismo los registros de la aplicación
Terminología importante:
- Pool de Node: Un grupo de nodos de trabajo de un solo tipo de servidor en un solo centro de datos, escalado y actualizado como una unidad (hasta 100 nodos, 20 recomendados)
- kubeconfig: El archivo de credenciales y conexión para
kubectl, expuesto por el recurso del clúster y tratado como un secreto - imagePullSecrets: Una referencia en la especificación del pod a un Secret
dockerconfigjsonque autentica las obtenciones desde Private Container Registry - externalTrafficPolicy: Local: Una configuración de Service que preserva la IP de origen del cliente manteniendo el tráfico en el Node receptor en lugar de reencaminarlo
- Provisionador CSI (
cloud.ionos.com): El controlador de almacenamiento de IONOS CLOUD que respalda los PersistentVolumeClaims con Block Storage para que los datos sobrevivan a la sustitución del Node
Próximos pasos
Siga aprendiendo: Unidad 3.3: Pipelines de CI/CD para IONOS CLOUD
Temas relacionados: