# Kubernetes — Manifiestos Completos de Referencia

Manifiestos YAML completos para Deployment, Service, Ingress, ConfigMap, Secrets,
HPA, PDB, NetworkPolicy, Helm y troubleshooting.

---

## Deployment Productivo Completo

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-nomina
  namespace: produccion
  labels:
    app: api-nomina
    version: "1.5.2"
    team: rrhh
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-nomina
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: api-nomina
        version: "1.5.2"
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8000"
        prometheus.io/path: "/metrics"
    spec:
      serviceAccountName: api-nomina-sa
      securityContext:
        runAsNonRoot: true
        runAsUser: 1001
        runAsGroup: 1001
        fsGroup: 1001
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: api
          image: registry.empresa.com/api-nomina:1.5.2
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8000
              protocol: TCP
          env:
            - name: PORT
              value: "8000"
            - name: LOG_LEVEL
              valueFrom:
                configMapKeyRef:
                  name: api-nomina-config
                  key: log_level
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: api-nomina-secrets
                  key: database_url
          resources:
            requests:
              cpu: "100m"
              memory: "256Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
          livenessProbe:
            httpGet:
              path: /health/live
              port: http
            initialDelaySeconds: 30
            periodSeconds: 10
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health/ready
              port: http
            initialDelaySeconds: 10
            periodSeconds: 5
            failureThreshold: 3
          startupProbe:
            httpGet:
              path: /health/live
              port: http
            failureThreshold: 30
            periodSeconds: 10
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]
          volumeMounts:
            - name: tmp-dir
              mountPath: /tmp
      volumes:
        - name: tmp-dir
          emptyDir: {}
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app
                      operator: In
                      values: [api-nomina]
                topologyKey: kubernetes.io/hostname
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: api-nomina
```

---

## Service e Ingress

```yaml
apiVersion: v1
kind: Service
metadata:
  name: api-nomina-svc
  namespace: produccion
spec:
  selector:
    app: api-nomina
  ports:
    - name: http
      port: 80
      targetPort: http
      protocol: TCP
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-nomina-ingress
  namespace: produccion
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/rate-limit-window: "1m"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.empresa.com.mx
      secretName: api-nomina-tls
  rules:
    - host: api.empresa.com.mx
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-nomina-svc
                port:
                  name: http
```

---

## ConfigMaps y Secrets

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: api-nomina-config
  namespace: produccion
data:
  log_level: "INFO"
  max_workers: "4"
  cache_ttl: "300"
  allowed_origins: "https://app.empresa.com.mx"

---
apiVersion: v1
kind: Secret
metadata:
  name: api-nomina-secrets
  namespace: produccion
type: Opaque
# En producción: gestionar con External Secrets Operator
```

```bash
kubectl create secret generic api-nomina-secrets \
  --from-env-file=.env.prod \
  --namespace=produccion \
  --dry-run=client -o yaml | kubectl apply -f -
```

---

## HPA

```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-nomina-hpa
  namespace: produccion
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-nomina
  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
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "100"
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Pods
          value: 1
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 30
      policies:
        - type: Pods
          value: 4
          periodSeconds: 60
```

---

## NetworkPolicy — Zero-trust

```yaml
# Negar todo por defecto
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: produccion
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

---
# Permitir tráfico específico
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-nomina-netpol
  namespace: produccion
spec:
  podSelector:
    matchLabels:
      app: api-nomina
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
      ports:
        - port: 8000
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - port: 5432
    - to:
        - podSelector:
            matchLabels:
              app: redis
      ports:
        - port: 6379
    - ports:
        - port: 53
          protocol: UDP
```

---

## Blue-Green Deployment

```bash
# 1. Desplegar versión Green
kubectl apply -f deployment-green.yaml
# 2. Verificar que Green está sano
kubectl rollout status deployment/api-nomina-green --timeout=300s
# 3. Smoke tests
kubectl run test --rm -it --image=curlimages/curl -- \
  curl http://api-nomina-green-svc/health
# 4. Switch instantáneo
kubectl patch service api-nomina-svc \
  -p '{"spec":{"selector":{"version":"1.5.2"}}}'
# 5. Rollback si falla
kubectl patch service api-nomina-svc \
  -p '{"spec":{"selector":{"version":"1.5.1"}}}'
# 6. Eliminar Blue después de observación
kubectl delete deployment api-nomina-blue
```

---

## Canary Deployment

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-nomina-canary
  namespace: produccion
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api-nomina
      track: canary
  template:
    metadata:
      labels:
        app: api-nomina
        track: canary
        version: "1.6.0-beta.1"
    spec:
      containers:
        - name: api
          image: registry.empresa.com/api-nomina:1.6.0-beta.1

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-nomina-canary-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  # ... misma configuración que el ingress principal
```

---

## Helm — Chart Completo

```yaml
# Chart.yaml
apiVersion: v2
name: api-nomina
description: API de Nómina de Recursos Humanos
version: 1.5.2
appVersion: "1.5.2"
dependencies:
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled
```

```yaml
# values.yaml
replicaCount: 3
image:
  repository: registry.empresa.com/api-nomina
  tag: ""
  pullPolicy: IfNotPresent
service:
  type: ClusterIP
  port: 80
ingress:
  enabled: true
  className: nginx
  host: api.empresa.com.mx
resources:
  requests:
    cpu: 100m
    memory: 256Mi
  limits:
    cpu: 500m
    memory: 512Mi
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
```

```bash
helm lint ./charts/api-nomina
helm template api-nomina ./charts/api-nomina -f values-prod.yaml
helm upgrade --install api-nomina ./charts/api-nomina \
  --namespace produccion --create-namespace \
  -f values-prod.yaml --set image.tag=1.5.2 --wait --timeout 5m
helm history api-nomina --namespace produccion
helm rollback api-nomina 3 --namespace produccion
```

---

## Troubleshooting

```bash
kubectl describe pod <pod-name> -n produccion
kubectl logs <pod-name> -n produccion --previous
kubectl logs <pod-name> -n produccion -f
kubectl top nodes
kubectl top pods -n produccion --sort-by=memory
kubectl exec -it <pod-name> -n produccion -- /bin/sh
kubectl port-forward pod/<pod-name> 8080:8000 -n produccion
kubectl get events -n produccion --sort-by='.lastTimestamp'
kubectl run debug --rm -it --image=nicolaka/netshoot -- bash
```
