Artículo

Contenedorización con Docker y Kubernetes

Contenedorización con Docker y Kubernetes

La contenedorización ha revolucionado la forma en que construimos, enviamos y ejecutamos software. Al empaquetar aplicaciones con sus dependencias en unidades portátiles y livianas, los contenedores resuelven el problema de "funciona en mi máquina" y permiten una implementación consistente en entornos de desarrollo, pruebas y producción.

3 min de lecturaIdioma: ES EspañolGratis0 aplausos0 comentarios
TecnologíaArtículos de ingenieríaDevOpsDockerKubernetesTechnologyEngineering ArticlesContainerization
Opciones de lectura

Introducción

La contenedorización ha revolucionado la forma en que construimos, enviamos y ejecutamos software. Al empaquetar aplicaciones con sus dependencias en unidades portátiles y livianas, los contenedores resuelven el problema de "funciona en mi máquina" y permiten una implementación consistente en entornos de desarrollo, pruebas y producción.

Docker hizo que los contenedores fueran accesibles. Kubernetes los hizo manejables a escala. Juntos, forman la columna vertebral de la implementación moderna de aplicaciones nativas de la nube.


¿Qué son los contenedores?

Contenedores versus máquinas virtuales

┌───────────────────────┐  ┌───────────────────────┐
│    Virtual Machine     │  │      Container         │
├───────────────────────┤  ├───────────────────────┤
│  ┌─────────────────┐  │  │  ┌─────────────────┐  │
│  │   Application   │  │  │  │   Application   │  │
│  ├─────────────────┤  │  │  ├─────────────────┤  │
│  │   Guest OS      │  │  │  │   Dependencies   │  │
│  │   (full kernel) │  │  │  ├─────────────────┤  │
│  ├─────────────────┤  │  │  │   Container      │  │
│  │   Hypervisor    │  │  │  │   Runtime        │  │
│  ├─────────────────┤  │  │  ├─────────────────┤  │
│  │   Host OS       │  │  │  │   Host OS        │  │
│  └─────────────────┘  │  │  │   Kernel (shared)│  │
└───────────────────────┘  │  └─────────────────┘  │
                           └───────────────────────┘
Característica máquina virtual Recipiente
Tiempo de arranque Minutos Milisegundos
Tamaño GB MB
Sobrecarga del sistema operativo SO completo por VM Núcleo compartido
Aislamiento Fuerte (nivel de hardware) Nivel de proceso
Actuación Casi nativo Casi nativo
Portabilidad Bien Excelente
Densidad Bajo (10-100 por host) Alto (100-1000 por host)

Docker: la plataforma de contenedores

Conceptos clave

Concepto Descripción
Imagen Una plantilla de solo lectura con instrucciones para crear un contenedor
Recipiente Una instancia ejecutable de una imagen.
archivo Docker Un archivo de texto con instrucciones para construir una imagen.
Registro Almacenamiento y distribución de imágenes (Docker Hub, ECR, GCR)
Volumen Almacenamiento de datos persistente fuera del sistema de archivos contenedor
Red Comunicación entre contenedores y el mundo exterior.
Componer Definir y ejecutar aplicaciones de múltiples contenedores

Mejores prácticas de Dockerfile

# 1. Use specific base images (not 'latest')
FROM node:20-alpine AS builder

# 2. Set working directory
WORKDIR /app

# 3. Copy dependency files first (leverage layer caching)
COPY package*.json ./
RUN npm ci --production

# 4. Copy application code last
COPY . .

# 5. Use multi-stage builds
FROM node:20-alpine AS production
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist

# 6. Run as non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

# 7. Expose only necessary ports
EXPOSE 3000

# 8. Use exec form of CMD
CMD ["node", "dist/server.js"]

Hoja de referencia de comandos de Docker

# Build image
docker build -t myapp:1.0 .

# Run container
docker run -d --name myapp -p 3000:3000 myapp:1.0

# Execute command in running container
docker exec -it myapp bash

# View logs
docker logs -f myapp

# List containers
docker ps -a

# Stop and remove
docker stop myapp && docker rm myapp

# Volumes (persistent data)
docker volume create data-volume
docker run -v data-volume:/app/data myapp:1.0

# Compose (multi-service)
docker compose up -d
docker compose logs -f
docker compose down

Redes acoplables

# docker-compose.yml
version: '3.8'
services:
  web:
    image: myapp:latest
    ports:
      - "3000:3000"
    networks:
      - frontend
      - backend
    depends_on:
      - api
      - db

  api:
    image: api:latest
    networks:
      - backend
    environment:
      - DB_HOST=db

  db:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - backend
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

networks:
  frontend:
  backend:

volumes:
  postgres_data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Kubernetes: orquestación de contenedores

Kubernetes (K8s) automatiza la implementación, el escalado y la gestión de aplicaciones en contenedores en un clúster.

Arquitectura

┌──────────────────────────────────────────────┐
│            Kubernetes Control Plane          │
│  ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│  │ API      │ │ Scheduler│ │ Controller   │ │
│  │ Server   │ │          │ │ Manager      │ │
│  └──────────┘ └──────────┘ └──────────────┘ │
│  ┌─────────────────────────────────────────┐│
│  │ etcd (distributed key-value store)      ││
│  └─────────────────────────────────────────┘│
└─────────────────┬────────────────────────────┘
                  │
┌─────────────────▼────────────────────────────┐
│                Worker Nodes                   │
│  ┌──────────────────────────────────────────┐│
│  │ Node 1                                   ││
│  │  ┌──────┐ ┌──────┐ ┌──────┐             ││
│  │  │ Pod  │ │ Pod  │ │ Pod  │             ││
│  │  └──────┘ └──────┘ └──────┘             ││
│  │  ┌────────────────────────────────────┐ ││
│  │  │ kubelet ││ kube-proxy ││ container │ ││
│  │  │         ││            ││  runtime  │ ││
│  │  └────────────────────────────────────┘ ││
│  └──────────────────────────────────────────┘│
│  ┌──────────────────────────────────────────┐│
│  │ Node 2 (same structure)                  ││
│  └──────────────────────────────────────────┘│
└──────────────────────────────────────────────┘

Objetos principales de Kubernetes

Pod: unidad desplegable más pequeña

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
    - name: myapp-container
      image: nginx:1.25
      ports:
        - containerPort: 80
      resources:
        requests:
          memory: "128Mi"
          cpu: "250m"
        limits:
          memory: "256Mi"
          cpu: "500m"

Implementación: gestión declarativa de pods

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myapp:1.0
          ports:
            - containerPort: 3000
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 3
            periodSeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1

Servicio: acceso estable a la red

apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 3000
      protocol: TCP
  type: ClusterIP  # Internal access only
---
# For external access:
apiVersion: v1
kind: Service
metadata:
  name: myapp-loadbalancer
spec:
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 3000
  type: LoadBalancer

Ingreso: enrutamiento HTTP/HTTPS

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80

ConfigMap y secreto: configuración

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: production
  DB_HOST: postgres-service
  LOG_LEVEL: info
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  DB_PASSWORD: c3VwZXJzZWNyZXQ=  # base64 encoded

Implementación de una aplicación

# Apply configurations
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml

# Check status
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get ingress

# View logs
kubectl logs -f deployment/myapp-deployment

# Scale
kubectl scale deployment/myapp-deployment --replicas=5

# Rollout update
kubectl set image deployment/myapp-deployment myapp=myapp:2.0
kubectl rollout status deployment/myapp-deployment

# Rollback if needed
kubectl rollout undo deployment/myapp-deployment

Funciones avanzadas de Kubernetes

Escalador automático de pods horizontales (HPA)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp-deployment
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

Volúmenes persistentes

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard
---
apiVersion: v1
kind: Pod
metadata:
  name: postgres
spec:
  containers:
    - name: postgres
      image: postgres:16-alpine
      volumeMounts:
        - mountPath: /var/lib/postgresql/data
          name: postgres-storage
  volumes:
    - name: postgres-storage
      persistentVolumeClaim:
        claimName: data-claim

Espacios de nombres

# Create namespaces for environment isolation
kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace production

# Deploy to specific namespace
kubectl apply -f deployment.yaml -n production

# Resource quotas per namespace
kubectl create quota prod-quota --hard=cpu=40,memory=80Gi,pods=50 -n production

Docker versus Kubernetes: cuándo usar qué

Guión Docker solo Agregar Kubernetes
Desarrollo local ✅ Sí ❌ Exceso
Implementación de un único servidor ✅ Sí ❌ Exceso
2-3 microservicios ✅ Composición acoplable ❌ Generalmente exagerado
Se requiere alta disponibilidad ❌ Conmutación por error manual ✅ Autocuración
Se necesita escalado automático ❌ manuales ✅ HPA
Clúster de múltiples nodos ❌ Limitado ✅ Incorporado
Actualizaciones continuas ❌ manuales ✅ Incorporado
Implementaciones canarias ❌ Complejo ✅ Soporte nativo
Multinube ❌ No portátil ✅ Portátil

Marco de decisión:

  1. Comience con Docker: siempre. Los contenedores son la base.
  2. Utilice Docker Compose: para desarrollo local, CI e implementaciones de host único.
  3. Adopte Kubernetes cuando: Necesita HA, escalamiento, múltiples nodos u orquestación compleja.
  4. Utilice Kubernetes administrado (EKS, AKS, GKE): evite la autoadministración del plano de control.

Mejores prácticas

Construcción de imágenes

  • Utilice etiquetas de imagen base específicas (node:20-alpine, no node:latest).
  • Implemente compilaciones de varias etapas para minimizar el tamaño de la imagen.
  • Escanee imágenes en busca de vulnerabilidades: docker scan myapp:1.0.
  • Imágenes de signos: signo de cosign --key cosign.key myapp:1.0.

Seguridad

  • Ejecute contenedores como usuarios no root.
  • Establezca sistema de archivos raíz de solo lectura: readOnlyRootFilesystem: true.
  • Utilice secretos para datos confidenciales, no para variables de entorno.
  • Implemente políticas de red para restringir el tráfico entre pods.
  • Habilite RBAC para el acceso a la API de Kubernetes.

Gestión de recursos

  • Establezca siempre solicitudes y límites de recursos.
  • Utilice cuotas de recursos por espacio de nombres.
  • Implemente HPA para escalado automático.
  • Utilice PodDisruptionBudget para conocer la disponibilidad durante el mantenimiento.

Monitoreo y observabilidad

# Sidecar pattern for logging
spec:
  containers:
    - name: app
      image: myapp:latest
    - name: log-collector
      image: fluentd:latest
      volumeMounts:
        - name: logs
          mountPath: /var/log/app

Canalización de CI/CD

# GitHub Actions — Build + Deploy to Kubernetes
name: CI/CD
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker image
        run: docker build -t registry.example.com/myapp:${{ github.sha }} .
      - name: Push to registry
        run: docker push registry.example.com/myapp:${{ github.sha }}
      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/myapp-deployment \
            myapp=registry.example.com/myapp:${{ github.sha }}

El ecosistema

Categoría Herramientas
Tiempo de ejecución del contenedor Docker, en contenedor, CRI-O
Orquestación Kubernetes, Nomad, Docker Swarm
Administrador de paquetes Timón, personalizar
Malla de servicio Istio, Linkerd, Cilio
Escucha Prometeo + Grafana, Datadog
Explotación florestal ELK Stack, Grafana Loki, Fluentd
Seguridad Trivy, Falco, OPA/Gatekeeper, Kyverno
GitOps ArgoCD, flujo
Herramientas para desarrolladores Skaffold, Inclinación, DevSpace
Almacenamiento Torre/Ceph, Longhorn, Portworx
Sin servidor en K8 Knativo, OpenFaaS, KEDA

Conclusión

Docker y Kubernetes juntos proporcionan una plataforma poderosa para crear, implementar y escalar aplicaciones modernas:

  1. Comience con Docker: contenedorice aplicaciones, domine Dockerfiles y Compose.
  2. Conozca los fundamentos de Kubernetes: pods, implementaciones, servicios, ConfigMaps.
  3. Utilice Kubernetes administrado: deje que los proveedores de la nube se encarguen del plano de control.
  4. Adopte GitOps: ArgoCD o Flux para implementaciones declarativas con control de versiones.
  5. Invierta en observabilidad: el monitoreo, el registro y el rastreo son esenciales a escala.

La inversión en el aprendizaje de la contenerización y la orquestación rinde dividendos en términos de confiabilidad de la implementación, eficiencia operativa y portabilidad de las aplicaciones entre entornos.

Artículos destacados

6 patrones de programación que aprendí de ingenieros senior
EditorialES
5 minGratis

6 patrones de programación que aprendí de ingenieros senior

TecnologíaCodeProgrammingCoding
0 aplausos
Leer
Crea un asistente privado de notas con IA
DestacadoES
9 minGratis

Crea un asistente privado de notas con IA

Convierte notas Markdown en un asistente consultable sin exponer borradores privados.

TecnologíaGuías de plataformaEscritura con IAAIAutomationData
0 aplausos
Leer
Automatiza la extracción de datos de facturas con OCR
EditorialES
8 minGratis

Automatiza la extracción de datos de facturas con OCR

Crea un flujo que lee facturas, extrae campos y marca valores dudosos para revisión.

TecnologíaArtículos de ingenieríaEscritura con IAAIAutomationData
0 aplausos
Leer

Comentarios

0 comentarios

Todavía no hay comentarios aprobados. Las respuestas nuevas pueden esperar moderación.