Kubernetes · Cheatsheet 03

Manifiestos YAML

En Kubernetes no se crean las cosas con clics ni con comandos sueltos: se describen en archivos de texto (manifiestos) en formato YAML y se aplican con kubectl apply -f <archivo>. Esta página explica cómo se escribe cada tipo de objeto, con plantillas para copiar basadas en una app Node llamada chanchito y su base de datos monguito.

Términos de esta página

Manifiesto
Un archivo .yaml que describe uno o más objetos. Es el “estado deseado” en texto.
YAML
Formato de texto con sangría de espacios: lo que está más a la derecha pertenece a la línea de arriba. clave: valor es un dato y - marca un elemento de lista.
apiVersion / kind
Qué tipo de objeto es (kind: Deployment) y qué versión de la API de Kubernetes lo define (apps/v1).
metadata
Datos de identificación: el nombre, el namespace y las labels.
spec
La especificación: lo que querés que pase (cuántas réplicas, qué imagen, qué puertos).
status
Lo que realmente está pasando. Lo escribe Kubernetes, vos nunca.
Label / selector
Una label es una etiqueta en un objeto (app: chanchito); un selector es un filtro que busca objetos por sus labels. Así se conectan, por ejemplo, un Service y sus Pods.
template
Dentro de un Deployment, el “molde” con el que se crea cada Pod.
Probe
Un chequeo automático (por ejemplo, pedir /health) que Kubernetes hace para saber si el contenedor está vivo o listo.
requests / limits
Cuánta CPU y memoria se reserva para el contenedor y cuánto puede usar como máximo. 100m = una décima de núcleo de CPU; 128Mi = 128 megabytes.
Base64
Una forma de escribir datos como texto. No es cifrado: cualquiera puede decodificarlo.
1

Anatomía de un manifiesto

Siempre los mismos 4 bloques.

Los 4 campos raíz

apiVersion: apps/v1     # versión de la API para este tipo
kind: Deployment        # QUÉ objeto es
metadata:               # CÓMO se llama y cómo se etiqueta
  name: chanchito
  namespace: default
  labels:
    app: chanchito
spec:                   # LO QUE QUERÉS (estado deseado)
  replicas: 2
  # ...
# status:               # lo que HAY: lo completa Kubernetes, no se escribe
i

Indentación con espacios (2 es lo habitual). Un error de sangría cambia el significado sin dar error de sintaxis.

apiVersion de cada kind

kindapiVersion
Pod, Service, ConfigMap, Secret, PersistentVolumeClaim, Namespacev1
Deployment, StatefulSet, DaemonSet, ReplicaSetapps/v1
Job, CronJobbatch/v1
Ingressnetworking.k8s.io/v1
HorizontalPodAutoscalerautoscaling/v2
✓

¿No te acordás? kubectl explain <kind> muestra la versión y los campos. O generá la base con --dry-run=client -o yaml.

2

Labels y selectors: cómo se encuentran los objetos

Nada se conecta por nombre: se conecta por labels. Si no coinciden, no funciona (y no da error).

Deployment chanchito selector: matchLabels: app: chanchito template: metadata: labels: app: chanchito spec: containers: … iguales Pod app: chanchito Pod app: chanchito Pod app: chanchito Pod app: monguito crea Pods con ese label Service chanchito selector: app: chanchito port: 80 targetPort: 3000 ✕ no coincide, no recibe tráfico
1

selector.matchLabels del Deployment tiene que ser igual a template.metadata.labels. Si no, apply lo rechaza.

2

El selector del Service elige a qué Pods mandar tráfico. Verificalo con kubectl get endpoints chanchito.

!

El selector de un Deployment no se puede cambiar después de creado: hay que borrarlo y recrearlo.

3

Deployment

Tu app corriendo con N réplicas.

chanchito-deployment.yaml

k8s/chanchito-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: chanchito
  labels:
    app: chanchito
spec:
  replicas: 2
  selector:
    matchLabels:
      app: chanchito            # debe = template.metadata.labels
  template:                     # molde de cada Pod
    metadata:
      labels:
        app: chanchito
    spec:
      containers:
        - name: chanchito
          image: chanchito:1    # tag fijo, nunca latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3000
          env:
            - name: NODE_ENV
              value: production
          envFrom:
            - configMapRef:
                name: chanchito-config
            - secretRef:
                name: mongo-secret
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits:   { memory: 256Mi }
          readinessProbe:
            httpGet: { path: /, port: 3000 }
            initialDelaySeconds: 5

Campo por campo

CampoQué es
replicasCuántos Pods iguales
selectorQué Pods “son suyos” (por label)
templateEl molde del Pod: labels + contenedores
containers[].imageImagen (≈ image: del compose)
imagePullPolicyIfNotPresent: usa la local si existe. Always: siempre baja. Never: solo local
containerPortPuerto donde escucha la app (informativo, como EXPOSE)
envVariables sueltas
envFromTodas las claves de un ConfigMap/Secret como variables
resourcesCPU/RAM reservada (requests) y máxima (limits)
readinessProbeCuándo el Pod está listo para recibir tráfico
strategyRollingUpdate (por defecto) o Recreate
!

Con image: chanchito:latest Kubernetes usa imagePullPolicy: Always y va a intentar bajarla de Docker Hub → ImagePullBackOff con imágenes locales. Usá tags con versión.

4

Service

Nombre DNS e IP fija delante de los Pods. Detalle de tipos y puertos en Red, config y datos.

ClusterIP (interno, por defecto)

k8s/chanchito-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: chanchito        # nombre DNS: http://chanchito
spec:
  type: ClusterIP
  selector:
    app: chanchito       # a qué Pods manda tráfico
  ports:
    - port: 80           # puerto del Service
      targetPort: 3000   # puerto del contenedor

NodePort (accesible desde tu PC)

apiVersion: v1
kind: Service
metadata:
  name: chanchito
spec:
  type: NodePort
  selector:
    app: chanchito
  ports:
    - port: 80
      targetPort: 3000
      nodePort: 30080    # 30000-32767 → localhost:30080
i

En Docker Desktop entrás por http://localhost:30080. En minikube: minikube service chanchito --url.

5

ConfigMap y Secret

Sacan la configuración de la imagen (≈ environment: / .env del compose).

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: chanchito-config
data:
  MONGO_HOST: monguito          # nombre del Service de Mongo
  MONGO_DB: miapp
  LOG_LEVEL: info

Secret

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
type: Opaque
stringData:                     # texto plano; se guarda en base64
  MONGO_USER: mati
  MONGO_PASSWORD: <password>
kubectl create secret generic mongo-secret \
  --from-literal=MONGO_USER=mati \
  --from-literal=MONGO_PASSWORD=<password>
Crea el mismo Secret directamente con un comando, sin archivo YAML. Cada --from-literal agrega una clave con su valor. Así la contraseña no queda escrita en ningún archivo del repositorio; la contra es que hay que repetir el comando en cada cluster nuevo.
✕

No subas YAML de Secrets con valores reales a git: base64 no es cifrado.

6

PersistentVolumeClaim

Disco que sobrevive a los Pods (≈ volumes: mongo-data:).

Pedir el disco

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongo-data
spec:
  accessModes:
    - ReadWriteOnce        # un nodo a la vez
  resources:
    requests:
      storage: 1Gi
  # storageClassName: standard   # opcional: usa la default

Montarlo en el contenedor

spec:
  template:
    spec:
      containers:
        - name: monguito
          image: mongo:7
          volumeMounts:
            - name: datos          # nombre interno
              mountPath: /data/db  # mismo path que en Docker
      volumes:
        - name: datos
          persistentVolumeClaim:
            claimName: mongo-data  # el PVC
i

Dos pasos: volumes (a nivel Pod) declara de dónde sale; volumeMounts (en el contenedor) dice dónde se monta. Se unen por name.

7

Ingress

Entrada HTTP por dominio/path. Requiere un Ingress controller instalado (ej. Traefik).

chanchito.localhost → Service chanchito

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: chanchito
spec:
  ingressClassName: traefik
  rules:
    - host: chanchito.localhost
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: chanchito
                port:
                  number: 80

Notas

  • *.localhost resuelve a tu PC sin tocar el archivo hosts en la mayoría de navegadores.
  • Varios paths o hosts → varios Services detrás de una sola entrada (ej. /api al backend y / al frontend).
  • Para HTTPS se agrega tls: con un Secret de tipo kubernetes.io/tls.
  • Gateway API (Gateway + HTTPRoute) es el reemplazo moderno de Ingress; el controller ingress-nginx fue retirado en 2026.
kubectl get ingress
kubectl get ingressclass
La primera línea lista los Ingress: sus hosts, rutas y la dirección asignada (si ADDRESS queda vacío, no hay un controller atendiéndolos). La segunda lista las IngressClass: qué Ingress controllers hay instalados. Sin ninguno, los Ingress existen pero no hacen nada.
8

Probes y recursos

Cómo sabe Kubernetes si tu app está viva y cuánto le puede dar.

Probes

ProbeSi falla…
readinessProbeSe saca el Pod del Service (no recibe tráfico). No lo reinicia.
livenessProbeReinicia el contenedor.
startupProbeDa tiempo extra a apps lentas antes de evaluar las otras dos.
livenessProbe:
  httpGet: { path: /health, port: 3000 }   # o tcpSocket / exec
  initialDelaySeconds: 10
  periodSeconds: 10
  failureThreshold: 3
!

Una livenessProbe mal configurada (path inexistente, poco delay) mata la app en loop → CrashLoopBackOff.

Recursos

CampoSignificado
requests.cpuCPU reservada para ubicar el Pod. 100m = 0,1 núcleo
requests.memoryRAM reservada. 128Mi
limits.cpuTope de CPU (si lo pasa, se ralentiza)
limits.memoryTope de RAM (si lo pasa → OOMKilled)
i

Si los requests son más de lo que tiene libre algún nodo, el Pod queda Pending.

9

Organizar los archivos

Un archivo por objeto o varios en uno separados con ---.

Estructura sugerida

mi-proyecto/
├── Dockerfile
├── docker-compose.yml
└── k8s/
    ├── chanchito-config.yaml      # ConfigMap
    ├── mongo-secret.yaml          # Secret (fuera de git)
    ├── mongo-pvc.yaml
    ├── monguito.yaml              # Deployment + Service
    ├── chanchito.yaml             # Deployment + Service
    └── ingress.yaml
kubectl apply -f k8s/
Aplica la carpeta entera. Si algo depende de otro objeto, Kubernetes reintenta hasta que exista.

Varios objetos en un archivo

apiVersion: apps/v1
kind: Deployment
metadata:
  name: monguito
# ...
---                     # separador de documentos
apiVersion: v1
kind: Service
metadata:
  name: monguito
# ...
✓

Juntá en un archivo lo que va siempre unido (Deployment + su Service). La migración completa está en De Compose a K8s.