17 min de lectura

Objetivos de aprendizaje

Al final de este módulo, podrás:

  • Aprovisionar un clúster de Managed Kubernetes y grupos de nodos con Terraform y recuperar el kubeconfig directamente desde el estado
  • Desplegar Deployments, Services, ConfigMaps y Secrets en MKS, obteniendo imágenes desde Private Container Registry con `imagePullSecrets`
  • Exponer el tráfico de la aplicación de manera correcta, dado que el tipo de Service `LoadBalancer` en MKS no es un balanceador de carga externo genuino, y colocar un Application Load Balancer aprovisionado por separado como front del clúster
  • Gestionar grupos de nodos de forma programática: escalar el número de nodos, ejecutar actualizaciones de versión e aislar cargas de trabajo en varios grupos
  • Depurar cargas de trabajo en ejecución con `kubectl logs`, `exec` y eventos, sabiendo qué señales la plataforma IONOS CLOUD expone y cuáles no

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_TOKEN exportado)
  • Terraform y el proveedor ionos-cloud/ionoscloud
  • kubectl y ionosctl instalados
  • Un Private Container Registry con la imagen taskboard-api publicada (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 Active y los nodos están Ready
  • [ ] Los pods de la API están Running, no ImagePullBackOff
  • [ ] 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:

  1. Esperar que type: LoadBalancer proporcione 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 LoadBalancer reserva 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, configure externalTrafficPolicy: Local para preservar la IP de origen, y coloque un ALB aprovisionado por separado delante del tráfico de producción:
    spec:
      type: LoadBalancer
      externalTrafficPolicy: Local
    
  2. ImagePullBackOff debido a un pull secret ausente o con un alcance incorrecto

    • Problema: Los Pods nunca se inician; kubectl describe pod muestra Failed to pull image ... no basic auth credentials.
    • Por qué ocurre: Private Container Registry requiere autenticación en cada pull, y el Secret dockerconfigjson está limitado a un namespace. Un Secret en default no tiene ningún efecto para los pods en taskboard.
    • 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>
    
  3. 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_config del recurso ionoscloud_k8s_cluster, marcado como confidencial
  • Un Service type: LoadBalancer fija 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-registry referenciado como imagePullSecrets
  • Los eventos del plano de control de Kubernetes no llegan al Logging Service de IONOS CLOUD; depure con kubectl y 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 dockerconfigjson que 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: