Skip to content

Resiliencia y alta disponibilidad de EKS

Versiones compatibles: EKS 1.28+, Istio 1.20+, Karpenter 1.0+ Última actualización: February 23, 2026

Descripción general de la resiliencia

La resiliencia es la capacidad de minimizar el impacto durante las fallas mientras se recupera un estado normal o se mantiene el servicio. Va más allá de la simple alta disponibilidad (HA) y representa una filosofía de diseño que anticipa las fallas y se prepara para ellas.

Modelo de madurez de la resiliencia

NivelNombreAlcanceTecnologías claveObjetivo de RTO
1BásicoPodProbes, Resource Limits, PDBMinutos
2Multi-AZAvailability ZoneTopology Spread, ARC Zonal ShiftSegundos
3Basado en CellUnidad de ServiceShuffle Sharding, Cell RouterSegundos (parcial)
4Multi-RegionRegionGlobal Accelerator, Data ReplicationCasi cero

No todos los servicios requieren el Nivel 4. Elija el nivel adecuado según los requisitos de SLA, las regulaciones y el presupuesto.


Nivel 1: resiliencia básica (nivel de Pod)

Liveness/Readiness/Startup Probes

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: app
        image: web-app:1.0
        ports:
        - containerPort: 8080
        startupProbe:
          httpGet:
            path: /healthz
            port: 8080
          failureThreshold: 30
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 0
          periodSeconds: 10
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          periodSeconds: 5
          failureThreshold: 3
        resources:
          requests:
            cpu: "250m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"

PodDisruptionBudget (PDB)

PDB garantiza una disponibilidad mínima durante interrupciones voluntarias.

yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-app-pdb
spec:
  # Method 1: Minimum available Pods
  minAvailable: 2
  # Method 2: Maximum unavailable Pods (use only one)
  # maxUnavailable: 1
  selector:
    matchLabels:
      app: web-app
bash
# Check PDB status
kubectl get pdb web-app-pdb
# NAME          MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
# web-app-pdb   2               N/A               1                     5m

Graceful Shutdown

yaml
spec:
  terminationGracePeriodSeconds: 60
  containers:
  - name: app
    lifecycle:
      preStop:
        exec:
          command: ["/bin/sh", "-c", "sleep 5"]

La razón para esperar 5 segundos en preStop: si el Pod termina antes de que se propague la eliminación del endpoint, se produce pérdida de tráfico. La espera garantiza tiempo para la propagación.


Nivel 2: estrategia Multi-AZ

Pod Topology Spread Constraints

Distribuya los Pods de manera uniforme entre las availability zones.

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 6
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      topologySpreadConstraints:
      # Hard constraint: Maximum 1 difference between AZs
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: web-app
        minDomains: 3
      # Soft constraint: Even distribution across nodes
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: ScheduleAnyway
        labelSelector:
          matchLabels:
            app: web-app
      containers:
      - name: app
        image: web-app:1.0
ParámetroDescripción
maxSkewDiferencia máxima en el recuento de Pods entre dominios de topología
topologyKeyBase de distribución (zone, hostname, etc.)
whenUnsatisfiableDoNotSchedule (Hard) o ScheduleAnyway (Soft)
minDomainsNúmero mínimo de dominios (3 para 3 AZs)

Karpenter Multi-AZ NodePool

yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
      - key: topology.kubernetes.io/zone
        operator: In
        values: ["ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c"]
      - key: karpenter.sh/capacity-type
        operator: In
        values: ["on-demand", "spot"]
      - key: node.kubernetes.io/instance-type
        operator: In
        values: ["m6i.xlarge", "m6i.2xlarge", "m7i.xlarge", "m7i.2xlarge"]
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    budgets:
    - nodes: "20%"    # Maximum 20% disrupted simultaneously
    - nodes: "0"
      schedule: "0 9 * * 1-5"   # No disruption during business hours
      duration: 8h

ARC Zonal Shift

AWS Application Recovery Controller (ARC) Zonal Shift redirige automáticamente el tráfico fuera de una AZ con fallas.

bash
# Start Zonal Shift (manual)
aws arc-zonal-shift start-zonal-shift \
  --resource-identifier arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:loadbalancer/app/my-alb/abc123 \
  --away-from ap-northeast-2a \
  --expires-in 1h \
  --comment "AZ-a experiencing issues"

# Enable Zonal Autoshift (automatic)
aws arc-zonal-shift create-practice-run-configuration \
  --resource-identifier $ALB_ARN \
  --outcome-alarms '[{"alarmIdentifier": {"alarmName": "my-alarm", "region": "ap-northeast-2"}, "type": "CLOUDWATCH"}]'

Consideraciones de almacenamiento

Prevención de problemas de bloqueo de AZ con EBS:

yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer  # Create volume after Pod scheduling
parameters:
  type: gp3

Acceso entre AZ con EFS:

yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: fs-12345
  directoryPerms: "700"

Istio Locality-Aware Routing

Priorizar el tráfico dentro de la misma AZ reduce los costos de transferencia entre AZ en un 60-80%.

yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: web-app-dr
spec:
  host: web-app.default.svc.cluster.local
  trafficPolicy:
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 30s
    connectionPool:
      tcp:
        maxConnections: 100
  # Locality-aware routing is handled automatically by Istio
  # Based on Pod's topology.kubernetes.io/zone label

Nivel 3: arquitectura basada en Cell

Concepto de Cell

Una Cell es una unidad de servicio autónoma con su propio almacén de datos, caché y cola. Aísla el radio de impacto de las fallas a una Cell específica.

Estrategias de particionamiento de Cell

EstrategiaDescripciónAdecuado para
Basada en clientesAsignar Cell por hash de ID de clienteSaaS multi-tenant
Basada en RegionParticionar por ubicación geográficaServicios globales
Basada en capacidadNueva Cell cuando se alcanza la capacidadDistribución uniforme de carga
Basada en nivelCell por nivel de servicioDiferenciación Premium/Standard

Implementación de Cell basada en Namespace

yaml
# Cell A Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: cell-a
  labels:
    cell: a
    tier: standard
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: cell-a-quota
  namespace: cell-a
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: cell-isolation
  namespace: cell-a
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          cell: a
    - namespaceSelector:
        matchLabels:
          role: cell-router
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          cell: a
    - namespaceSelector:
        matchLabels:
          role: shared-services

Shuffle Sharding

Asignar cada cliente a una combinación de Cells seleccionada aleatoriamente minimiza los clientes afectados por una falla de una sola Cell.

With 2 Cell combinations from a pool of 8 Cells:
- Customer A → Cell 1, Cell 5
- Customer B → Cell 2, Cell 7
- Customer C → Cell 1, Cell 3

When Cell 1 fails:
- Customer A → Automatically switches to Cell 5 ✅
- Customer B → Not affected ✅
- Customer C → Automatically switches to Cell 3 ✅

Número de combinaciones: C(8,2) = 28, lo que hace que la probabilidad de que dos clientes compartan la misma combinación sea muy baja.


Nivel 4: Multi-Cluster / Multi-Region

Comparación de patrones de arquitectura

PatrónRTORPOCostoComplejidad
Active-Active~0~02x+Muy alta
Active-PassiveMin~HoursMinutos1.5xAlta
Regional IsolationN/AN/A1x por regionMedia
Hub-SpokeMinutosMinutos1.3xMedia

Despliegue Multi-Cluster con ArgoCD ApplicationSet

yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: web-app-set
  namespace: argocd
spec:
  generators:
  # Cluster Generator: Based on cluster labels
  - clusters:
      selector:
        matchLabels:
          environment: production
  template:
    metadata:
      name: 'web-app-{{name}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/k8s-manifests.git
        targetRevision: main
        path: 'apps/web-app/overlays/{{metadata.labels.region}}'
      destination:
        server: '{{server}}'
        namespace: web-app
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

Integración con Global Accelerator

bash
# Create Global Accelerator
aws globalaccelerator create-accelerator \
  --name prod-accelerator \
  --ip-address-type IPV4

# Add endpoint groups (each region)
aws globalaccelerator create-endpoint-group \
  --listener-arn $LISTENER_ARN \
  --endpoint-group-region ap-northeast-2 \
  --endpoint-configurations "EndpointId=$NLB_ARN_APNE2,Weight=50" \
  --health-check-path /healthz

Federación Istio Multi-Primary

yaml
# Cross-cluster service discovery
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: web-app-remote
spec:
  hosts:
  - web-app.default.svc.cluster.local
  location: MESH_INTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  endpoints:
  - address: web-app.remote-cluster.example.com
    locality: us-west-2/us-west-2a
    ports:
      http: 80

Chaos Engineering

Chaos Engineering es una metodología para inyectar fallas intencionalmente en entornos de producción con el fin de descubrir de forma proactiva las debilidades del sistema.

AWS Fault Injection Service (FIS)

json
{
  "description": "AZ Failure Simulation",
  "targets": {
    "eks-pods": {
      "resourceType": "aws:eks:pod",
      "selectionMode": "ALL",
      "parameters": {
        "clusterIdentifier": "production-cluster",
        "namespace": "default",
        "selectorType": "labelSelector",
        "selectorValue": "app=web-app"
      }
    }
  },
  "actions": {
    "delete-pods": {
      "actionId": "aws:eks:pod-delete",
      "parameters": {},
      "targets": { "Pods": "eks-pods" }
    }
  },
  "stopConditions": [
    {
      "source": "aws:cloudwatch:alarm",
      "value": "arn:aws:cloudwatch:ap-northeast-2:123456789012:alarm:error-rate-high"
    }
  ]
}

Litmus Chaos (CNCF Incubating)

yaml
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
  name: pod-delete-chaos
  namespace: default
spec:
  appinfo:
    appns: default
    applabel: app=web-app
    appkind: deployment
  chaosServiceAccount: litmus-admin
  experiments:
  - name: pod-delete
    spec:
      components:
        env:
        - name: TOTAL_CHAOS_DURATION
          value: "30"
        - name: CHAOS_INTERVAL
          value: "10"
        - name: FORCE
          value: "false"

Chaos Mesh

yaml
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
  name: network-delay
spec:
  action: delay
  mode: all
  selector:
    namespaces:
    - default
    labelSelectors:
      app: web-app
  delay:
    latency: "100ms"
    jitter: "50ms"
    correlation: "25"
  duration: "5m"

Marco de Game Day

FaseActividadEntregable
1. Registrar estado estableRecopilar líneas base de métricasCaptura del dashboard
2. Inyectar fallaEjecutar experimentos FIS/LitmusLogs del experimento
3. Observar recuperaciónMonitorear el proceso de recuperación automáticaMedición del tiempo de recuperación
4. Analizar impactoAnalizar tasa de errores y cambios de latenciaInforme de impacto
5. Revisión post-mortemIdentificar mejoras, Action ItemsPlan de mejora

Checklist de implementación

Nivel 1 básico

  • [ ] Configurar Liveness/Readiness Probe para todos los contenedores
  • [ ] Configurar requests/limits de recursos
  • [ ] Configurar PodDisruptionBudget
  • [ ] Implementar Graceful shutdown (hook preStop)
  • [ ] Configurar terminationGracePeriodSeconds adecuado

Nivel 2 Multi-AZ

  • [ ] Aplicar Pod Topology Spread Constraints
  • [ ] Configurar distribución en 3 AZ en Karpenter NodePool
  • [ ] Configurar WaitForFirstConsumer en StorageClass
  • [ ] Habilitar ARC Zonal Shift
  • [ ] Monitorear costos de tráfico Cross-AZ

Nivel 3 basado en Cell

  • [ ] Definir límites de Cell (Namespace o Cluster)
  • [ ] Implementar Cell Router
  • [ ] Aislar Cells con NetworkPolicy
  • [ ] Implementar Shuffle Sharding
  • [ ] Configurar ResourceQuota por Cell

Nivel 4 Multi-Region

  • [ ] Decidir el patrón de arquitectura Multi-Region
  • [ ] Configurar Global Accelerator
  • [ ] Desplegar multi-cluster con ArgoCD ApplicationSet
  • [ ] Establecer estrategia de replicación de datos
  • [ ] Mantener coherencia con GitOps

Consideraciones de costo

ElementoImpacto en costoEstrategia de reducción de costos
Multi-Region Active-Active2x+ comparado con una sola regionReducir Passive en 50-70% con Active-Passive
Tráfico Cross-AZ$0.01/GB (dentro de la misma region)Reducir 60-80% con Locality-aware routing
Spot Instance60-90% de ahorro comparado con On-DemandAplicar a workloads sin estado
Chaos EngineeringCostos de experimentos FISROI mediante prevención de fallas

Próximos pasos