Construir un Cluster Kubernetes

Avanzado | 180 min de lectura | 2025.12.02

Lo que Aprenderas en este Tutorial

  • Construir un cluster Kubernetes local con minikube
  • Conceptos basicos de Pod, Deployment y Service
  • Como escribir manifiestos YAML
  • Despliegue y exposicion de aplicaciones
  • Escalado y rolling updates
  • Uso de ConfigMap, Secret y Namespace
  • Mejores practicas para entornos de produccion

Prerrequisitos: Docker Desktop debe estar instalado. Se requiere la instalacion de kubectl y minikube.


Historia y Contexto de Kubernetes

Por que nacio Kubernetes

Kubernetes (tambien escrito como K8s) es una plataforma de orquestacion de contenedores que Google lanzo como codigo abierto en 2014. Su origen esta en los sistemas de gestion de contenedores a gran escala “Borg” y “Omega” que Google opero internamente durante mas de 10 anos.

“Kubernetes is based on a decade and a half of experience at Google running production workloads at scale, combined with best-of-breed ideas and practices from the community.”

Documentacion Oficial de Kubernetes

Se dice que Google inicia miles de millones de contenedores cada semana, y el conocimiento obtenido de esa experiencia operativa esta consolidado en Kubernetes.

Origen del nombre Kubernetes

“Kubernetes” significa “timonel” o “piloto” en griego. Tiene el significado de pilotar el “barco” de contenedores, y el logo esta inspirado en el timon de un barco. La abreviatura “K8s” proviene de que hay 8 caracteres (ubernete) entre K y s.

Necesidad de Orquestacion de Contenedores

La tecnologia de contenedores (Docker) ha simplificado dramaticamente el empaquetado y distribucion de aplicaciones. Sin embargo, surgen nuevos desafios en entornos de produccion:

DesafioDescripcion
EscaladoAjustar dinamicamente el numero de contenedores segun el trafico
Recuperacion de fallosReinicio automatico cuando un contenedor falla
Balanceo de cargaDistribucion del trafico entre multiples contenedores
Descubrimiento de serviciosGestion de direcciones IP de contenedores que cambian dinamicamente
Rolling updatesActualizacion de aplicaciones sin tiempo de inactividad
Gestion de secretosDistribucion segura de contrasenas y claves API

Kubernetes resuelve estos desafios con configuracion declarativa (definiendo el estado deseado).

CNCF y el Ecosistema Cloud Native

En 2015, Google dono Kubernetes a CNCF (Cloud Native Computing Foundation). CNCF es una organizacion bajo Linux Foundation que promueve la difusion y estandarizacion de tecnologias cloud native.

Actualmente, CNCF incluye proyectos importantes como:

  • Kubernetes - Orquestacion de contenedores
  • Prometheus - Monitoreo y alertas
  • Envoy - Proxy de servicios
  • Helm - Gestor de paquetes
  • Argo - Flujos de trabajo GitOps

Referencia: CNCF Cloud Native Interactive Landscape


Descripcion General de la Arquitectura de Kubernetes

Un cluster Kubernetes se compone de Control Plane (master) y Worker Nodes.

Componentes del Control Plane

flowchart TB
    subgraph ControlPlane["Control Plane"]
        API["API Server"]
        Sched["Scheduler"]
        CM["Controller Manager"]
        etcd["etcd<br/>(Almacen clave-valor distribuido)"]
    end
ComponenteRol
kube-apiserverPunto de entrada para todas las operaciones API al cluster
etcdBase de datos distribuida que almacena el estado del cluster
kube-schedulerDecide en que nodo colocar los Pods
kube-controller-managerEjecuta varios controladores (ReplicaSet, Node, etc.)

Componentes de los Worker Nodes

flowchart TB
    subgraph WorkerNode["Worker Node"]
        kubelet["kubelet"]
        kproxy["kube-proxy"]
        runtime["Container Runtime"]
        subgraph Pods["Pods"]
            P1["Pod"]
            P2["Pod"]
            P3["Pod"]
            P4["Pod"]
        end
    end
ComponenteRol
kubeletAgente que gestiona los Pods en el nodo
kube-proxyGestiona reglas de red y realiza la funcion de Service
Container RuntimeEjecuta contenedores (containerd, CRI-O, etc.)

Step 1: Iniciar minikube

minikube es una herramienta que facilita la construccion de un cluster Kubernetes en tu entorno local. Es ideal para aprendizaje y desarrollo.

# Iniciar cluster minikube
# Puedes especificar el driver con la opcion --driver (docker, virtualbox, hyperkit, etc.)
minikube start

# Iniciar con memoria y CPU especificos (para reproducir un entorno similar a produccion)
minikube start --memory=4096 --cpus=2

# Verificar estado del cluster
minikube status

# Verificar conexion de kubectl
kubectl cluster-info

# Verificar informacion del nodo
kubectl get nodes -o wide

Otras herramientas de entorno local: kind (Kubernetes in Docker), k3s (Kubernetes ligero) tambien son populares. Elige segun tu caso de uso.


Step 2: Conceptos Basicos de Kubernetes

Comprendamos los principales recursos de Kubernetes. Documentacion oficial de conceptos tiene explicaciones detalladas.

Relacion de Recursos Principales

flowchart BT
    External["Trafico Externo"]
    Service["Service<br/>(LB)"]

    External --> Service

    subgraph Deployment["Deployment<br/>(Gestiona replicas, estrategia de actualizacion, rollback)"]
        subgraph ReplicaSet["ReplicaSet<br/>(Mantiene el numero especificado de replicas de Pod)"]
            Pod1["Pod<br/>(Contenedor)"]
            Pod2["Pod<br/>(Contenedor)"]
            Pod3["Pod<br/>(Contenedor)"]
            Pod4["Pod<br/>(Contenedor)"]
        end
    end

    Service --> Pod1
    Service --> Pod2
    Service --> Pod3
    Service --> Pod4

Detalle de Cada Recurso

RecursoDescripcionCaso de Uso
PodUnidad minima de despliegue. Contiene uno o mas contenedoresUna instancia de aplicacion individual
ReplicaSetMantiene el numero especificado de replicas de PodNormalmente gestionado automaticamente por Deployment
DeploymentGestion de replicas de Pod y rolling updatesAplicaciones stateless
StatefulSetGestion ordenada de Pods y almacenamiento persistenteBases de datos, sistemas distribuidos
DaemonSetColoca un Pod en cada nodoRecoleccion de logs, agentes de monitoreo
ServiceAbstrae el acceso de red a los PodsBalanceo de carga, descubrimiento de servicios
IngressEnrutamiento HTTP/HTTPS y terminacion TLSExposicion externa, enrutamiento basado en rutas
ConfigMapAlmacena datos de configuracionVariables de entorno, archivos de configuracion
SecretAlmacena datos confidencialesContrasenas, claves API, certificados
NamespaceSeparacion logica de recursosSeparacion de entornos (dev/staging/prod)

Step 3: Desplegar tu Primer Pod

Crear Directamente desde Linea de Comandos (para desarrollo/depuracion)

# Crear Pod nginx
kubectl run my-nginx --image=nginx:latest

# Verificar estado del Pod
# Esperar hasta que STATUS sea Running
kubectl get pods

# Monitorear estado en tiempo real
kubectl get pods -w

# Verificar detalles del Pod (eventos, uso de recursos, etc.)
kubectl describe pod my-nginx

# Verificar logs del Pod
kubectl logs my-nginx

# Eliminar Pod
kubectl delete pod my-nginx

Consejo: Los Pods creados con kubectl run no se recrean automaticamente cuando se eliminan. Siempre usa Deployment en entornos de produccion.

Depuracion Dentro del Pod

# Iniciar shell dentro del Pod
kubectl exec -it my-nginx -- /bin/bash

# Ejecutar comando especifico
kubectl exec my-nginx -- cat /etc/nginx/nginx.conf

# Verificar red desde dentro del Pod
kubectl exec my-nginx -- curl -s localhost

Step 4: Desplegar con Manifiestos YAML

En entornos de produccion, define recursos en archivos YAML siguiendo el principio de Infrastructure as Code. Esto asegura control de versiones, revision y reproducibilidad.

“Store the declarative configuration in source control. This allows you to roll back and roll forward configurations.”

Mejores Practicas de Kubernetes

Manifiesto de Deployment

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
    # Usa etiquetas para organizar recursos
    environment: development
    version: v1.0.0
spec:
  replicas: 3  # Mantener 3 replicas de Pod
  selector:
    matchLabels:
      app: my-app
  # Configuracion de estrategia de actualizacion
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # Numero de Pods adicionales que se pueden crear durante la actualizacion
      maxUnavailable: 0  # Numero de Pods que pueden estar no disponibles durante la actualizacion
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: nginx:1.24
        ports:
        - containerPort: 80
        # Limites de recursos (mejor practica esencial)
        resources:
          requests:  # Recursos a asegurar en el scheduling
            memory: "64Mi"
            cpu: "250m"    # 250 milicores = 0.25 CPU
          limits:    # Limite superior (OOMKilled o throttling si se excede)
            memory: "128Mi"
            cpu: "500m"
        # Liveness Probe: Verifica si el Pod esta vivo
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
        # Readiness Probe: Verifica si puede aceptar trafico
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3

Aplicar el Deployment

# Aplicar manifiesto (--record registra historial de rollout)
kubectl apply -f deployment.yaml

# Verificar estado del Deployment
kubectl get deployments

# Verificar ReplicaSet tambien (creado automaticamente por Deployment)
kubectl get replicasets

# Verificar estado de los Pods (filtrar por selector de etiqueta)
kubectl get pods -l app=my-app

# Salida detallada en formato YAML
kubectl get deployment my-app -o yaml

Importancia de los Health Checks (Probes)

Los Probes de Kubernetes son un mecanismo para verificar la salud de las aplicaciones.

ProbePropositoComportamiento en Fallo
livenessProbeVerifica si el Pod esta vivoReinicia el contenedor
readinessProbeVerifica si puede aceptar solicitudesElimina de los endpoints del Service
startupProbeVerifica si el inicio se completoDeshabilita liveness/readiness hasta que se complete el inicio

Precaucion: Si verificas la conexion a la BD en livenessProbe, un fallo de BD puede causar un fallo en cascada con reinicios infinitos de Pods.


Step 5: Exponer la App con Service

Service proporciona acceso de red estable a los Pods. Los Pods se crean y eliminan dinamicamente y sus direcciones IP cambian, pero Service proporciona un nombre DNS e IP fijos.

Tipos de Service

TipoUsoAlcance de Acceso
ClusterIPPor defecto. Solo interno al clusterComunicacion entre microservicios internos
NodePortExposicion externa a traves del puerto del nodoEntornos de desarrollo/pruebas
LoadBalancerAprovisionamiento automatico de LB en la nubeExposicion externa en produccion
ExternalNameAlias a servicios externosConexion a BD externa

Manifiesto de Service

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
  labels:
    app: my-app
spec:
  type: NodePort  # Para desarrollo. Usa LoadBalancer en produccion
  selector:
    app: my-app   # Reenviar trafico a Pods con esta etiqueta
  ports:
  - name: http
    protocol: TCP
    port: 80         # Puerto del Service
    targetPort: 80   # Puerto del Pod
    nodePort: 30080  # Puerto del nodo (30000-32767)

Aplicar y Verificar Service

# Crear Service
kubectl apply -f service.yaml

# Verificar Service
kubectl get services

# Detalles del Service (verificar IPs de Pods en Endpoints)
kubectl describe service my-app-service

# Verificar Endpoints directamente
kubectl get endpoints my-app-service

# Obtener URL de acceso en minikube
minikube service my-app-service --url

# Abrir en navegador
minikube service my-app-service

Ejemplo de Service ClusterIP (para comunicacion interna)

apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  type: ClusterIP  # Por defecto
  selector:
    app: backend
  ports:
  - port: 8080
    targetPort: 8080

Se puede acceder desde dentro del cluster como backend-service.default.svc.cluster.local o simplemente backend-service.


Step 6: Escalado

Una de las caracteristicas poderosas de Kubernetes es el escalado flexible.

Escalado Manual

# Cambiar numero de replicas
kubectl scale deployment my-app --replicas=5

# Verificar que los Pods han aumentado
kubectl get pods -l app=my-app

# Verificar estado del Deployment
kubectl get deployment my-app

Horizontal Pod Autoscaler (HPA)

HPA ajusta automaticamente el numero de Pods basado en uso de CPU o metricas personalizadas.

# Configurar autoescalado basado en CPU
# Escalar cuando el uso de CPU exceda 50%
kubectl autoscale deployment my-app --min=2 --max=10 --cpu-percent=50

# Verificar estado de HPA
kubectl get hpa

# Verificar detalles
kubectl describe hpa my-app

Manifiesto YAML de HPA

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  # Controlar comportamiento de escalado detalladamente
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # Escalar hacia abajo despues de 5 minutos de estabilidad

Nota: Para usar HPA, Metrics Server debe estar instalado en el cluster. En minikube, habilitalo con minikube addons enable metrics-server.


Step 7: Rolling Updates

Los rolling updates de Kubernetes permiten actualizar aplicaciones sin tiempo de inactividad.

Ejecutar Actualizacion

# Actualizar imagen
kubectl set image deployment/my-app my-app=nginx:1.25

# O, editar el manifiesto y aplicar
kubectl apply -f deployment.yaml

# Verificar estado del rollout en tiempo real
kubectl rollout status deployment/my-app

# Verificar historial de rollout
kubectl rollout history deployment/my-app

# Verificar detalles de revision especifica
kubectl rollout history deployment/my-app --revision=2

Rollback

# Rollback a version anterior
kubectl rollout undo deployment/my-app

# Rollback a revision especifica
kubectl rollout undo deployment/my-app --to-revision=1

# Pausar rollout (para canary releases, etc.)
kubectl rollout pause deployment/my-app

# Reanudar rollout
kubectl rollout resume deployment/my-app

Estrategias de Actualizacion

Puedes especificar la estrategia de actualizacion en el campo strategy del Deployment:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%        # Porcentaje de Pods adicionales que se pueden crear durante la actualizacion
      maxUnavailable: 25%  # Porcentaje de Pods que pueden detenerse durante la actualizacion
ConfiguracionEfecto
maxSurge: 1, maxUnavailable: 0Prioridad de seguridad (detener Pod antiguo despues de iniciar el nuevo)
maxSurge: 0, maxUnavailable: 1Ahorro de recursos (detener Pod antiguo primero)

Step 8: ConfigMap y Secret

Externalizar la configuracion y la informacion sensible de la aplicacion permite cambiar la configuracion sin reconstruir las imagenes. Esto sigue el principio de The Twelve-Factor App de “almacenar configuracion en variables de entorno”.

ConfigMap

Almacena datos de configuracion en formato clave-valor.

configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  # Formato clave-valor
  APP_ENV: "production"
  LOG_LEVEL: "info"
  MAX_CONNECTIONS: "100"
  # Incrustado como archivo
  nginx.conf: |
    server {
      listen 80;
      location / {
        root /usr/share/nginx/html;
      }
    }

Secret

Almacena datos confidenciales. Los valores estan codificados en base64.

secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  # Valor codificado en base64
  # echo -n "password123" | base64 → cGFzc3dvcmQxMjM=
  DB_PASSWORD: cGFzc3dvcmQxMjM=
  API_KEY: c2VjcmV0LWFwaS1rZXk=

Advertencia de Seguridad: Los Secrets de Kubernetes solo estan codificados en base64 por defecto, no encriptados. Para entornos de produccion, considera lo siguiente:

Usar ConfigMap/Secret en Pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: my-app
        image: nginx:1.24
        # Inyectar como variables de entorno
        env:
        - name: APP_ENVIRONMENT
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_ENV
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: DB_PASSWORD
        # Inyectar todas las claves como variables de entorno
        envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secret
        # Montar como archivo
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/conf.d
          readOnly: true
      volumes:
      - name: config-volume
        configMap:
          name: app-config
          items:
          - key: nginx.conf
            path: default.conf

Step 9: Aislamiento de Recursos con Namespace

Usa Namespace para aislar recursos logicamente.

Crear y Usar Namespace

# Crear Namespace
kubectl create namespace development
kubectl create namespace staging
kubectl create namespace production

# Verificar Namespaces existentes
kubectl get namespaces

# Crear recursos en un Namespace especifico
kubectl apply -f deployment.yaml -n development

# Verificar recursos especificando Namespace
kubectl get pods -n development

# Verificar recursos en todos los Namespaces
kubectl get pods --all-namespaces
kubectl get pods -A  # Forma abreviada

Cambiar Namespace por Defecto

# Verificar contexto actual
kubectl config current-context

# Cambiar Namespace por defecto
kubectl config set-context --current --namespace=development

# Verificar cambio
kubectl config view --minify | grep namespace

ResourceQuota por Namespace

Puedes limitar el uso de recursos por equipo o entorno.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: development-quota
  namespace: development
spec:
  hard:
    requests.cpu: "4"
    requests.memory: "8Gi"
    limits.cpu: "8"
    limits.memory: "16Gi"
    pods: "20"
    services: "10"

Comandos kubectl Utiles

Verificar Recursos

# Mostrar todos los recursos
kubectl get all

# Formato de salida amplio
kubectl get pods -o wide

# Salida en formato YAML/JSON
kubectl get deployment my-app -o yaml
kubectl get deployment my-app -o json

# Salida con columnas personalizadas
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase

# Watch de recursos (actualizacion en tiempo real)
kubectl get pods -w

Depuracion y Solucion de Problemas

# Ejecutar comando dentro del Pod
kubectl exec -it pod-name -- /bin/sh

# Para multiples contenedores, especificar contenedor
kubectl exec -it pod-name -c container-name -- /bin/sh

# Port forward (acceso directo desde local al Pod)
kubectl port-forward pod/my-app-xxx 8080:80

# Port forward a Service
kubectl port-forward service/my-app-service 8080:80

# Verificar eventos del recurso
kubectl get events --sort-by='.lastTimestamp'

# Eventos de Pod especifico
kubectl describe pod my-app-xxx | grep -A 10 Events

Eliminar Recursos

# Eliminar desde manifiesto
kubectl delete -f deployment.yaml

# Eliminar en lote por etiqueta
kubectl delete pods -l app=my-app

# Eliminar Namespace completo (precaucion: elimina todos los recursos dentro)
kubectl delete namespace development

# Eliminacion forzada (para Pods atascados, etc.)
kubectl delete pod my-app-xxx --force --grace-period=0

Mejores Practicas para Entornos de Produccion

1. Configurar Limites de Recursos

Establece requests y limits para todos los contenedores.

resources:
  requests:
    memory: "64Mi"
    cpu: "250m"
  limits:
    memory: "128Mi"
    cpu: "500m"

Por que es importante: Sin limites de recursos, un Pod puede usar todos los recursos del nodo, afectando a otros Pods.

2. Implementar Health Checks (Probes)

Siempre configura livenessProbe y readinessProbe.

3. Pod Disruption Budget (PDB)

Mantiene un numero minimo de Pods incluso durante mantenimiento.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
spec:
  minAvailable: 2  # O maxUnavailable: 1
  selector:
    matchLabels:
      app: my-app

4. Configuracion Anti-Affinity

Distribuye Pods en diferentes nodos para mejorar la disponibilidad.

spec:
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: my-app
          topologyKey: kubernetes.io/hostname

5. NetworkPolicy

Restringe el trafico de red de los Pods.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

6. Security Context

Configura permisos minimos para los contenedores.

spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 1000
  containers:
  - name: my-app
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL

Errores Comunes y Antipatrones

Lo que se Debe Evitar

AntipatronProblemaSolucion
Usar etiqueta latestSin reproducibilidad, actualizaciones inesperadasUsar etiquetas de version explicitas
Sin limites de recursosAgotamiento de recursos, caida de nodoSiempre configurar requests/limits
Sin ProbesRetraso en deteccion de fallosConfigurar liveness/readinessProbe
Hardcodear SecretsRiesgo de seguridadUsar ConfigMap/Secret
Ejecutar como rootRiesgo de seguridadConfigurar runAsNonRoot: true
Replica unicaPunto unico de falloMantener minimo 2 replicas

Practicas Recomendadas

# Buen ejemplo
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: my-app
        image: my-app:1.2.3  # Version explicita
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
        securityContext:
          runAsNonRoot: true
          readOnlyRootFilesystem: true

Limpieza

# Eliminar recursos
kubectl delete -f service.yaml
kubectl delete -f deployment.yaml
kubectl delete -f configmap.yaml
kubectl delete -f secret.yaml

# O eliminacion en lote
kubectl delete -f .

# Eliminar Namespace (tambien elimina los recursos dentro)
kubectl delete namespace development

# Detener minikube
minikube stop

# Eliminar minikube completamente
minikube delete

# Eliminar todos los perfiles
minikube delete --all

Proximos Pasos

Basandote en los fundamentos aprendidos en este tutorial, te recomendamos avanzar a los siguientes temas:

Temas Avanzados


Enlaces de Referencia

Documentacion Oficial

Recursos de Aprendizaje

Mejores Practicas

Herramientas

  • Lens - IDE de Kubernetes
  • k9s - UI de Kubernetes basada en terminal
  • kubectx/kubens - Herramienta de cambio de contexto/Namespace
  • stern - Visualizacion de logs de multiples Pods

Certificaciones

← Volver a la lista