Volver al blog

Proxies para el Controlador de Ingress de Kubernetes: configuración completa en un clúster K8s con ejemplos de configuraciones

Analizamos cómo configurar correctamente un servidor proxy en el controlador de ingreso de Kubernetes, desde la configuración básica de NGINX hasta la rotación de IP residenciales para eludir bloqueos.

📅10 de agosto de 2026
```html

Si su clúster de K8s realiza solicitudes externas — a API de socios, a marketplaces, a plataformas publicitarias — tarde o temprano se encontrará con bloqueos por IP. El Ingress Controller por sí mismo gestiona el tráfico entrante, pero para las solicitudes salientes a través de los pods se necesita un esquema separado con un proxy. En este artículo analizamos cómo configurarlo correctamente: desde la elección del tipo de proxy hasta configuraciones YAML específicas para NGINX Ingress y Traefik.

¿Por qué un proxy en Kubernetes: escenarios reales?

Kubernetes es un orquestador, y la mayoría de los artículos sobre él hablan del tráfico entrante: cómo configurar Ingress, cómo emitir un certificado TLS, cómo enrutar solicitudes a los servicios. Pero hay otro lado: el tráfico saliente de los pods. Aquí es donde surgen problemas con bloqueos, restricciones geográficas y límites por IP.

Consideremos tareas específicas donde un proxy en el clúster de K8s se vuelve una necesidad:

  • Raspado y monitoreo de precios. Su clúster ejecuta un CronJob cada 15 minutos y recopila datos de Wildberries, Ozon, Amazon. Sin rotación de IP, después de 2–3 horas recibirá un bloqueo en todo el rango de IP de su proveedor de nube.
  • Trabajo con API publicitarias. Facebook Marketing API, TikTok Ads API, Google Ads API — todos ellos rastrean el origen de las solicitudes. Si decenas de pods envían solicitudes desde una sola IP de un centro de datos, eso es un disparador para un bloqueo automático.
  • Pruebas de geolocalización. Su servicio debe mostrar contenido diferente para usuarios de diferentes países. A través de un proxy, los pods pueden simular solicitudes desde las regiones necesarias para pruebas automáticas.
  • Elusión de restricciones corporativas. En algunas infraestructuras, todo el tráfico saliente debe pasar a través de un proxy corporativo — este es un requisito de cumplimiento.
  • Trabajo con API de socios con lista blanca de IP. Cuando un socio permite solicitudes solo desde IP específicas, y su clúster se escala y cambia direcciones — un proxy con IP estáticas resuelve el problema.

Es importante entender la separación arquitectónica: Ingress Controller gestiona el tráfico entrante (de los usuarios a sus servicios), y el proxy para las solicitudes salientes es una tarea separada. Sin embargo, están relacionados: la configuración del proxy a menudo se establece a nivel del mismo Ingress Controller o a través de anotaciones que lee.

💡 División clave

En este artículo analizamos dos escenarios: (1) configuración de Ingress Controller como un proxy inverso para servidores upstream externos, y (2) enrutamiento del tráfico saliente de los pods a través de un servidor proxy externo. Ambos escenarios se encuentran en producción.

Qué tipo de proxy elegir para el clúster de K8s

La elección del tipo de proxy afecta directamente cuánto tiempo podrá funcionar su clúster sin bloqueos. Las IP de centros de datos son las más baratas, pero son fáciles de identificar y bloquear. Las IP residenciales y móviles son más caras, pero significativamente más confiables para tareas donde es importante simular un usuario real.

Tipo de proxy Velocidad Riesgo de bloqueo Mejor escenario en K8s
Centros de datos Alta Alta API internas, cumplimiento corporativo, integraciones de socios con lista blanca de IP
Residenciales Media Bajo Raspado de marketplaces, trabajo con API publicitarias, pruebas geográficas
Móviles Media Mínimo Facebook Ads API, TikTok API, tareas de alta carga con riesgo de bloqueo

Para la mayoría de las tareas en el clúster de K8s relacionadas con el raspado o el trabajo con plataformas publicitarias, la elección óptima son los proxies residenciales con rotación. Proporcionan IP reales de usuarios domésticos, y los algoritmos de protección de sitios perciben tales solicitudes como tráfico normal de navegador.

Desde el punto de vista del protocolo, el más versátil para K8s es el proxy HTTP/HTTPS — es compatible con todos los clientes HTTP populares en cualquier lenguaje de programación a través de las variables de entorno estándar HTTP_PROXY y HTTPS_PROXY. SOCKS5 solo es necesario para protocolos no estándar o cuando se requiere proxy no solo para HTTP.

Configuración de proxy a través de NGINX Ingress Controller

NGINX Ingress Controller es la opción más común en K8s. Analicemos dos escenarios: la configuración de NGINX como un proxy inverso a un upstream externo a través de un servidor proxy, y la configuración global de un proxy saliente para el propio controlador.

Anotaciones para el proxy de solicitudes a upstream

NGINX Ingress admite anotaciones para gestionar el comportamiento del proxy. Si necesita que Ingress envíe solicitudes a un servicio externo a través de un proxy intermedio, utilice un ConfigMap con una configuración personalizada:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
data:
  # Proxy HTTP global para solicitudes salientes de NGINX
  http-snippet: |
    proxy_connect_timeout 10s;
    proxy_read_timeout 30s;
    proxy_send_timeout 30s;
  # Configuración de upstream a través de proxy
  use-proxy-protocol: "false"
  proxy-real-ip-cidr: "0.0.0.0/0"

Recurso Ingress con anotaciones para proxy

Para un recurso Ingress separado, se pueden establecer parámetros de proxy a través de anotaciones. Esto es útil cuando diferentes servicios requieren diferentes tiempos de espera y configuraciones:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-service-ingress
  namespace: production
  annotations:
    kubernetes.io/ingress.class: "nginx"
    # Tiempos de espera del proxy
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
    # Tamaño del búfer
    nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
    nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
    # Transmisión de la IP real del cliente
    nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
    nginx.ingress.kubernetes.io/forwarded-for-header: "X-Forwarded-For"
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80

Configuración de un proxy externo para solicitudes salientes del pod NGINX

Si el propio NGINX Ingress Controller debe realizar solicitudes salientes a través de un proxy externo (por ejemplo, para verificar la salud de los endpoints externos), se deben establecer variables de entorno en el Deployment del controlador:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  template:
    spec:
      containers:
      - name: controller
        image: registry.k8s.io/ingress-nginx/controller:v1.9.4
        env:
        - name: HTTP_PROXY
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: http-proxy-url
        - name: HTTPS_PROXY
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: https-proxy-url
        - name: NO_PROXY
          value: "localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.cluster.local"

Preste atención a la variable NO_PROXY — es críticamente importante. Sin ella, todo el tráfico intra-cluster también pasará a través del proxy externo, lo que romperá la interacción entre servicios. En NO_PROXY siempre incluya los rangos RFC-1918 y el sufijo .cluster.local.

Configuración de proxy en Traefik Ingress Controller

Traefik es una alternativa popular a NGINX Ingress, especialmente en combinación con Helm y en clústeres gestionados (k3s, Docker Swarm, Nomad). Traefik tiene su propio sistema de configuración a través de CRD (Definiciones de Recursos Personalizados) y configuraciones estáticas/dinámicas.

Configuración estática de Traefik con proxy

apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik-config
  namespace: traefik
data:
  traefik.yaml: |
    # Configuración estática de Traefik
    entryPoints:
      web:
        address: ":80"
      websecure:
        address: ":443"
    
    # Configuraciones para trabajar detrás de un proxy
    serversTransport:
      insecureSkipVerify: false
      maxIdleConnsPerHost: 200
      dialTimeout: 10s
      responseHeaderTimeout: 30s
    
    # Registro para diagnóstico de proxy
    log:
      level: INFO
    
    accessLog:
      fields:
        headers:
          defaultMode: keep
          names:
            X-Forwarded-For: keep
            X-Real-IP: keep

Middleware para agregar encabezados de proxy

En Traefik se puede crear un Middleware que agregue o modifique encabezados al transmitir solicitudes. Esto es útil para la correcta transmisión de la IP real del cliente a través de la cadena de proxies:

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: proxy-headers
  namespace: production
spec:
  headers:
    customRequestHeaders:
      X-Forwarded-Proto: "https"
    # Eliminamos encabezados que pueden revelar la infraestructura
    customResponseHeaders:
      X-Powered-By: ""
      Server: ""
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: my-app-route
  namespace: production
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`myapp.example.com`)
    kind: Rule
    middlewares:
    - name: proxy-headers
    services:
    - name: my-service
      port: 80

Variables de entorno para el Deployment de Traefik

Al igual que con NGINX, para Traefik se establecen variables de entorno a través de los valores de Helm o directamente en el Deployment. Al usar el chart de Helm, esto se hace a través de values.yaml:

# values.yaml para el chart de Helm de Traefik
deployment:
  enabled: true
  kind: Deployment
  
env:
  - name: HTTP_PROXY
    valueFrom:
      secretKeyRef:
        name: proxy-credentials
        key: http-proxy-url
  - name: HTTPS_PROXY
    valueFrom:
      secretKeyRef:
        name: proxy-credentials
        key: https-proxy-url
  - name: NO_PROXY
    value: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/16,.cluster.local,.svc"

Proxy a través de variables de entorno en los pods

La forma más versátil de configurar un proxy saliente para cualquier pod es a través de las variables de entorno estándar. Este método funciona independientemente del lenguaje de programación y el marco: Python requests, Go net/http, Node.js axios, Java HttpClient — todos ellos leen HTTP_PROXY y HTTPS_PROXY automáticamente.

Opción 1: Directamente en el Pod Spec

apiVersion: v1
kind: Pod
metadata:
  name: scraper-pod
  namespace: production
spec:
  containers:
  - name: scraper
    image: mycompany/scraper:latest
    env:
    - name: HTTP_PROXY
      value: "http://username:[email protected]:8080"
    - name: HTTPS_PROXY
      value: "http://username:[email protected]:8080"
    - name: NO_PROXY
      value: "localhost,127.0.0.1,10.0.0.0/8,.cluster.local"
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "500m"

⚠️ ¡No almacene credenciales en texto claro!

El ejemplo anterior se muestra para ilustración. En producción, las credenciales del proxy siempre deben almacenarse en Kubernetes Secret y transmitirse a través de secretKeyRef. Más detalles en la sección sobre Secrets a continuación.

Opción 2: A través de ConfigMap para varios pods

Si varios Deployments utilizan el proxy, es conveniente extraer la configuración en un ConfigMap y conectarlo a través de envFrom:

apiVersion: v1
kind: ConfigMap
metadata:
  name: proxy-config
  namespace: production
data:
  NO_PROXY: "localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,.cluster.local,.svc.cluster.local"
  PROXY_TIMEOUT: "30"
  PROXY_MAX_RETRIES: "3"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: price-monitor
  namespace: production
spec:
  replicas: 5
  selector:
    matchLabels:
      app: price-monitor
  template:
    metadata:
      labels:
        app: price-monitor
    spec:
      containers:
      - name: monitor
        image: mycompany/price-monitor:v2.1
        envFrom:
        - configMapRef:
            name: proxy-config
        - secretRef:
            name: proxy-credentials
        ports:
        - containerPort: 8080

Opción 3: Mutating WebhookAdmissionController

Para clústeres corporativos, donde todos los pods deben utilizar un proxy, se puede configurar un webhook de admisión mutante que agregue automáticamente las variables de entorno del proxy a todos los pods que se creen. Esta solución se utiliza en infraestructuras empresariales donde el cumplimiento requiere que todo el tráfico saliente pase a través de un proxy corporativo. La implementación de dicho webhook está más allá del alcance de este artículo, pero vale la pena saber de su existencia.

Rotación de IP y gestión del grupo de proxies en K8s

Un proxy estático es bueno para el cumplimiento corporativo, pero malo para tareas donde se necesita evitar bloqueos. Si 50 de sus pods envían solicitudes a través de la misma IP, esa IP será bloqueada muy rápidamente. La solución es la rotación de proxies.

Esquema con Proxy Sidecar

Uno de los patrones es ejecutar un agente proxy como un contenedor sidecar junto a la aplicación principal. El sidecar recibe solicitudes en localhost:8080 y las reenvía a través de un grupo rotatorio de proxies externos:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: scraper-with-proxy-sidecar
  namespace: production
spec:
  replicas: 10
  selector:
    matchLabels:
      app: scraper
  template:
    metadata:
      labels:
        app: scraper
    spec:
      containers:
      # Aplicación principal
      - name: scraper
        image: mycompany/scraper:latest
        env:
        - name: HTTP_PROXY
          value: "http://localhost:8080"
        - name: HTTPS_PROXY
          value: "http://localhost:8080"
        - name: NO_PROXY
          value: "localhost,127.0.0.1,.cluster.local"
      
      # Sidecar: agente proxy local con rotación
      - name: proxy-rotator
        image: mycompany/proxy-rotator:latest
        ports:
        - containerPort: 8080
        env:
        - name: PROXY_LIST_URL
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: api-endpoint
        - name: ROTATION_INTERVAL
          value: "60"  # rotación cada 60 segundos
        resources:
          requests:
            memory: "64Mi"
            cpu: "50m"
          limits:
            memory: "128Mi"
            cpu: "200m"

Esquema con Proxy Service central

Un enfoque alternativo es un único Proxy Service dentro del clúster, al que se dirigen todos los pods. Esto es más fácil de gestionar: basta con actualizar un Secret con las credenciales del proxy, y todos los pods comenzarán automáticamente a utilizar los nuevos datos.

apiVersion: v1
kind: Service
metadata:
  name: proxy-gateway
  namespace: proxy-system
spec:
  selector:
    app: proxy-gateway
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  - name: socks5
    port: 1080
    targetPort: 1080
  type: ClusterIP
---
# Los pods utilizan el proxy a través de DNS interno
# HTTP_PROXY=http://proxy-gateway.proxy-system.svc.cluster.local:8080

Para tareas donde la anonimidad y el riesgo mínimo de bloqueos son críticos (por ejemplo, raspado de marketplaces o trabajo con API publicitarias), recomendamos utilizar proxies residenciales con rotación — proporcionan IP reales de usuarios domésticos, lo que hace que el tráfico de su clúster sea indistinguible del tráfico normal de navegador.

Almacenamiento de credenciales de proxy en Kubernetes Secrets

El almacenamiento seguro de credenciales es un requisito obligatorio para cualquier clúster de producción. Nunca inserte el nombre de usuario/contraseña del proxy directamente en los manifiestos YAML que se almacenan en el repositorio de Git.

Creación de Secret para el proxy

# Creación a través de kubectl (los valores se codifican en base64 automáticamente)
kubectl create secret generic proxy-credentials \
  --namespace=production \
  --from-literal=http-proxy-url='http://user:[email protected]:8080' \
  --from-literal=https-proxy-url='http://user:[email protected]:8080' \
  --from-literal=socks5-proxy-url='socks5://user:[email protected]:1080'

# Verificación del Secret creado
kubectl get secret proxy-credentials -n production -o yaml

YAML-manifiesto de Secret

apiVersion: v1
kind: Secret
metadata:
  name: proxy-credentials
  namespace: production
  labels:
    app: proxy-config
    managed-by: ops-team
type: Opaque
# Los valores están codificados en base64
# echo -n 'http://user:pass@proxy:8080' | base64
stringData:
  # stringData permite especificar valores en texto claro
  # Kubernetes los codifica automáticamente en base64
  http-proxy-url: "http://user:[email protected]:8080"
  https-proxy-url: "http://user:[email protected]:8080"
  proxy-host: "gate.proxycove.com"
  proxy-port: "8080"
  proxy-username: "user"
  proxy-password: "password"

Uso de Secret en Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-worker
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-worker
  template:
    metadata:
      labels:
        app: api-worker
    spec:
      containers:
      - name: worker
        image: mycompany/api-worker:latest
        env:
        - name: HTTP_PROXY
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: http-proxy-url
        - name: HTTPS_PROXY
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: https-proxy-url
        - name: NO_PROXY
          value: "localhost,127.0.0.1,10.0.0.0/8,.cluster.local"
        # Para aplicaciones que leen host/puerto por separado
        - name: PROXY_HOST
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: proxy-host
        - name: PROXY_PORT
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: proxy-port

Integración con almacenes de secretos externos

En un entorno empresarial, se recomienda utilizar el External Secrets Operator para sincronizar secretos desde HashiCorp Vault, AWS Secrets Manager o Azure Key Vault. Esto permite actualizar automáticamente las credenciales del proxy sin intervención manual y reinicio de pods:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: proxy-credentials-ext
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: proxy-credentials
    creationPolicy: Owner
  data:
  - secretKey: http-proxy-url
    remoteRef:
      key: secret/proxy/proxycove
      property: http_proxy_url
  - secretKey: https-proxy-url
    remoteRef:
      key: secret/proxy/proxycove
      property: https_proxy_url

Diagnóstico y errores comunes al configurar proxies en K8s

Incluso con una configuración correcta, pueden surgir problemas. Analicemos los más comunes y las formas de diagnóstico.

Problema 1: El tráfico intra-cluster pasa a través del proxy

Síntoma: los pods dejan de verse entre sí, la resolución DNS dentro del clúster se rompe, los servicios no responden. Causa — la variable NO_PROXY no está configurada.

El valor mínimo necesario para NO_PROXY para un clúster K8s estándar es:

NO_PROXY=localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.cluster.local,.svc,.svc.cluster.local,kubernetes.default.svc

Problema 2: El proxy no se aplica a un pod específico

Diagnóstico: entre al pod y verifique las variables de entorno:

# Verificación de variables de entorno en el pod
kubectl exec -it <pod-name> -n production -- env | grep -i proxy

# Prueba de conexión a través del proxy desde el pod
kubectl exec -it <pod-name> -n production -- curl -v --proxy http://proxy:8080 https://httpbin.org/ip

# Verificación de que el Secret se monta correctamente
kubectl exec -it <pod-name> -n production -- env | grep PROXY

Problema 3: Errores de TLS al usar un proxy HTTPS

Si el proxy utiliza un certificado autofirmado o un CA corporativo, las aplicaciones recibirán errores de verificación TLS. La solución es agregar el certificado CA del proxy a los confiables:

# Creación de ConfigMap con el certificado CA
kubectl create configmap proxy-ca-cert \
  --from-file=proxy-ca.crt=./proxy-ca.crt \
  -n production

# Montaje en el pod
spec:
  containers:
  - name: app
    volumeMounts:
    - name: proxy-ca
      mountPath: /etc/ssl/certs/proxy-ca.crt
      subPath: proxy-ca.crt
  volumes:
  - name: proxy-ca
    configMap:
      name: proxy-ca-cert

Problema 4: Solicitudes lentas a través del proxy

Si las solicitudes a través del proxy son significativamente más lentas que las directas — verifique:

  • Resolución DNS: asegúrese de que las solicitudes DNS no pasen a través del proxy (agregue a NO_PROXY)
  • Conexiones Keep-alive: configure el grupo de conexiones al servidor proxy
  • Ubicación geográfica: el servidor proxy debe estar físicamente cerca del recurso objetivo
  • Tipo de proxy: para tareas de alta velocidad, considere proxies de centros de datos — proporcionan la menor latencia

Comandos útiles para diagnóstico

# Verificar los registros del Ingress Controller
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=100

# Verificar eventos del pod
kubectl describe pod <pod-name> -n production

# Prueba de conexión proxy desde el pod
kubectl run test-proxy --image=curlimages/curl --rm -it --restart=Never -- \
  curl -x http://user:pass@proxy:8080 -v https://httpbin.org/ip

# Verificar que el Secret existe y contiene las claves necesarias
kubectl get secret proxy-credentials -n production -o jsonpath='{.data}' | python3 -c "
import sys, json, base64
data = json.load(sys.stdin)
for k, v in data.items():
    print(f'{k}: {base64.b64decode(v).decode()[:20]}...')
"

Conclusión y recomendaciones

Configurar un proxy en Kubernetes no es una tarea única, sino parte de la arquitectura de seguridad de red del clúster. Resumamos:

  • Para NGINX Ingress Controller — use anotaciones para configurar los parámetros del proxy a nivel de recursos Ingress individuales, y variables de entorno en el Deployment para configuraciones globales del tráfico saliente.
  • Para Traefik — combine la configuración estática a través de ConfigMap con Middleware para gestionar encabezados.
  • Para los pods — las variables estándar HTTP_PROXY / HTTPS_PROXY a través de Secrets — el enfoque más versátil y seguro.
  • Siempre configure NO_PROXY — de lo contrario, el tráfico intra-cluster se romperá.
  • Nunca almacene credenciales del proxy en texto claro en manifiestos o en Git.
  • Para producción — utilice el External Secrets Operator para la rotación automática de credenciales.

Si su clúster de K8s realiza tareas donde la estabilidad de IP y el riesgo mínimo de bloqueos son críticos — raspado, trabajo con API publicitarias, pruebas geográficas — recomendamos utilizar proxies residenciales. Proporcionan IP reales de usuarios domésticos, que los algoritmos de protección perciben como tráfico legítimo. Para tareas con altas demandas de velocidad y riesgos mínimos de bloqueos por parte de plataformas móviles, son ideales los proxies móviles — funcionan a través de redes reales 4G/5G de operadores.

```