# GKE — Google Kubernetes Engine: Patrones de Producción

Referencia de patrones para clusters GKE con Workload Identity, HPA y configuraciones de seguridad.

---

## 1. Crear cluster GKE con configuración segura

```bash
# Cluster con Workload Identity habilitado (OBLIGATORIO para acceder a servicios GCP)
gcloud container clusters create mi-cluster \
    --region=us-central1 \
    --machine-type=e2-standard-4 \
    --num-nodes=3 \
    --min-nodes=1 \
    --max-nodes=10 \
    --enable-autoscaling \
    --workload-pool=$PROJECT_ID.svc.id.goog \
    --enable-ip-alias \
    --enable-private-nodes \
    --master-ipv4-cidr=172.16.0.0/28 \
    --enable-network-policy \
    --release-channel=regular
```

**Opciones clave:**
- `--workload-pool`: habilita Workload Identity (reemplaza claves SA montadas como archivos)
- `--enable-private-nodes`: nodos sin IP pública (acceso solo desde red privada)
- `--enable-network-policy`: permite NetworkPolicy de Kubernetes para aislar pods
- `--release-channel=regular`: parches de seguridad automáticos con estabilidad probada

---

## 2. Node Pools — separación de cargas de trabajo

```bash
# Node pool para cargas de producción (alta disponibilidad)
gcloud container node-pools create produccion \
    --cluster=mi-cluster \
    --region=us-central1 \
    --machine-type=e2-standard-8 \
    --num-nodes=2 \
    --min-nodes=2 \
    --max-nodes=20 \
    --enable-autoscaling \
    --node-taints=env=produccion:NoSchedule \
    --node-labels=env=produccion

# Node pool para jobs/workers (puede escalar a cero)
gcloud container node-pools create workers \
    --cluster=mi-cluster \
    --region=us-central1 \
    --machine-type=e2-standard-4 \
    --num-nodes=0 \
    --min-nodes=0 \
    --max-nodes=10 \
    --enable-autoscaling \
    --node-taints=workload=batch:NoSchedule \
    --node-labels=workload=batch
```

---

## 3. Workload Identity — acceso seguro a servicios GCP desde pods

Workload Identity vincula una Kubernetes Service Account (KSA) con una Google Service Account (GSA).
Los pods usan la KSA y GCP autentica usando la GSA vinculada. Sin claves de SA como archivos.

```bash
# 1. Crear Google Service Account para el servicio
gcloud iam service-accounts create mi-api-gsa \
    --display-name="GSA para mi-api en GKE"

# 2. Otorgar permisos necesarios a la GSA
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:mi-api-gsa@$PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

# 3. Permitir que la KSA actúe como la GSA
gcloud iam service-accounts add-iam-policy-binding \
    mi-api-gsa@$PROJECT_ID.iam.gserviceaccount.com \
    --role="roles/iam.workloadIdentityUser" \
    --member="serviceAccount:$PROJECT_ID.svc.id.goog[mi-namespace/mi-api-ksa]"
```

```yaml
# Kubernetes Service Account con anotación de Workload Identity
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mi-api-ksa
  namespace: mi-namespace
  annotations:
    iam.gke.io/gcp-service-account: mi-api-gsa@PROJECT_ID.iam.gserviceaccount.com
```

```yaml
# Deployment que usa la KSA
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mi-api
  namespace: mi-namespace
spec:
  selector:
    matchLabels:
      app: mi-api
  template:
    metadata:
      labels:
        app: mi-api
    spec:
      serviceAccountName: mi-api-ksa  # Referencia a la KSA anotada
      containers:
        - name: api
          image: gcr.io/PROJECT_ID/mi-api:latest
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"
```

---

## 4. Horizontal Pod Autoscaler (HPA)

```yaml
# HPA basado en CPU y memoria
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: mi-api-hpa
  namespace: mi-namespace
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mi-api
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # Evita flapping al escalar hacia abajo
      policies:
        - type: Percent
          value: 25
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0    # Escala hacia arriba inmediatamente
      policies:
        - type: Percent
          value: 100
          periodSeconds: 30
```

---

## 5. NetworkPolicy — aislar namespaces

```yaml
# Permitir tráfico solo desde el ingress y desde otros pods del mismo namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: aislar-namespace
  namespace: mi-namespace
spec:
  podSelector: {}  # Aplica a todos los pods del namespace
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
        - podSelector: {}  # Tráfico dentro del mismo namespace
  egress:
    - to:
        - namespaceSelector: {}  # Permitir todo egress (ajustar según necesidad)
    - ports:
        - protocol: UDP
          port: 53   # DNS obligatorio
```

---

## 6. Checklist de seguridad GKE

- [ ] Workload Identity habilitado en el cluster (`--workload-pool`)
- [ ] Nodos privados (`--enable-private-nodes`) en entornos de producción
- [ ] NetworkPolicy habilitada (`--enable-network-policy`)
- [ ] Node pools separados para producción y workers/batch
- [ ] Todos los Deployments tienen `resources.requests` y `resources.limits`
- [ ] HPA configurado con `minReplicas >= 2` para servicios críticos
- [ ] Ningún pod usa la service account `default` sin anotación de Workload Identity
- [ ] Imágenes de contenedor con versión explícita (nunca `:latest` en producción)

---

## 7. Comandos frecuentes

```bash
# Ver estado del cluster
kubectl get nodes -o wide
kubectl top nodes

# Ver pods con su node y service account
kubectl get pods -n mi-namespace -o wide

# Ver logs en tiempo real
kubectl logs -f deployment/mi-api -n mi-namespace

# Verificar que Workload Identity está funcionando
kubectl exec -it pod/mi-api-xxx -n mi-namespace -- \
    curl -H "Metadata-Flavor: Google" \
    http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email
```
