Если ваш K8s-кластер делает внешние запросы — к API партнёров, к маркетплейсам, к рекламным платформам — рано или поздно вы столкнётесь с блокировками по IP. Ingress Controller сам по себе управляет входящим трафиком, но для исходящих запросов через поды нужна отдельная схема с прокси. В этой статье разбираем, как это настроить правильно: от выбора типа прокси до конкретных YAML-конфигов для NGINX Ingress и Traefik.
Зачем прокси в Kubernetes: реальные сценарии
Kubernetes — это оркестратор, и большинство статей про него говорят про входящий трафик: как настроить Ingress, как выдать TLS-сертификат, как маршрутизировать запросы к сервисам. Но есть другая сторона: исходящий трафик из подов. Именно здесь возникают проблемы с блокировками, геоограничениями и лимитами по IP.
Рассмотрим конкретные задачи, где прокси в K8s-кластере становится необходимостью:
- Парсинг и мониторинг цен. Ваш кластер запускает CronJob каждые 15 минут и собирает данные с Wildberries, Ozon, Amazon. Без ротации IP через 2–3 часа вы получите бан по всему диапазону IP вашего облачного провайдера.
- Работа с рекламными API. Facebook Marketing API, TikTok Ads API, Google Ads API — все они отслеживают источник запросов. Если десятки подов шлют запросы с одного IP дата-центра, это триггер для автоматической блокировки.
- Геолокационное тестирование. Ваш сервис должен показывать разный контент для пользователей из разных стран. Через прокси поды могут имитировать запросы из нужных регионов для автотестов.
- Обход корпоративных ограничений. В некоторых инфраструктурах весь исходящий трафик должен идти через корпоративный прокси — это требование compliance.
- Работа с партнёрскими API с белым списком IP. Когда партнёр разрешает запросы только с конкретных IP, а ваш кластер масштабируется и меняет адреса — прокси со статическими IP решает проблему.
Важно понимать архитектурное разделение: Ingress Controller управляет входящим трафиком (от пользователей к вашим сервисам), а прокси для исходящих запросов — это отдельная задача. Тем не менее, они связаны: конфигурация прокси часто задаётся на уровне того же Ingress Controller или через аннотации, которые он читает.
💡 Ключевое разграничение
В этой статье мы разбираем два сценария: (1) настройка Ingress Controller как обратного прокси для внешних upstream-серверов, и (2) маршрутизация исходящего трафика из подов через внешний прокси-сервер. Оба сценария встречаются в продакшне.
Какой тип прокси выбрать для K8s-кластера
Выбор типа прокси напрямую влияет на то, насколько долго ваш кластер сможет работать без блокировок. Дата-центровые IP — самые дешёвые, но их легко идентифицировать и заблокировать. Резидентные и мобильные IP — дороже, но значительно надёжнее для задач, где важна имитация реального пользователя.
| Тип прокси | Скорость | Риск блокировки | Лучший сценарий в K8s |
|---|---|---|---|
| Дата-центровые | Высокая | Высокий | Внутренние API, корпоративный compliance, партнёрские интеграции с белым списком IP |
| Резидентные | Средняя | Низкий | Парсинг маркетплейсов, работа с рекламными API, геотестирование |
| Мобильные | Средняя | Минимальный | Facebook Ads API, TikTok API, высоконагруженные задачи с риском бана |
Для большинства задач в K8s-кластере, связанных с парсингом или работой с рекламными платформами, оптимальный выбор — резидентные прокси с ротацией. Они предоставляют реальные IP домашних пользователей, и алгоритмы защиты сайтов воспринимают такие запросы как обычный браузерный трафик.
С точки зрения протокола для K8s наиболее универсален HTTP/HTTPS-прокси — его поддерживают все популярные HTTP-клиенты в любом языке программирования через стандартные переменные окружения HTTP_PROXY и HTTPS_PROXY. SOCKS5 нужен только для нестандартных протоколов или когда требуется проксировать не только HTTP.
Настройка прокси через NGINX Ingress Controller
NGINX Ingress Controller — самый распространённый вариант в K8s. Рассмотрим два сценария: настройка NGINX как обратного прокси к внешнему upstream через прокси-сервер, и глобальная настройка исходящего прокси для самого контроллера.
Аннотации для проксирования запросов к upstream
NGINX Ingress поддерживает аннотации для управления поведением прокси. Если вам нужно, чтобы Ingress передавал запросы к внешнему сервису через промежуточный прокси, используйте ConfigMap с кастомным конфигом:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
data:
# Глобальный HTTP-прокси для исходящих запросов NGINX
http-snippet: |
proxy_connect_timeout 10s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
# Настройка upstream через прокси
use-proxy-protocol: "false"
proxy-real-ip-cidr: "0.0.0.0/0"
Ingress-ресурс с аннотациями для прокси
Для отдельного Ingress-ресурса можно задать параметры прокси через аннотации. Это полезно, когда разные сервисы требуют разных таймаутов и настроек:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-service-ingress
namespace: production
annotations:
kubernetes.io/ingress.class: "nginx"
# Таймауты прокси
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
# Размер буфера
nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
# Передача реального IP клиента
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
Настройка внешнего прокси для исходящих запросов NGINX-пода
Если сам NGINX Ingress Controller должен делать исходящие запросы через внешний прокси (например, для health-check внешних эндпоинтов), нужно задать переменные окружения в Deployment контроллера:
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"
Обратите внимание на переменную NO_PROXY — она критически важна. Без неё весь внутрикластерный трафик тоже пойдёт через внешний прокси, что сломает взаимодействие между сервисами. В NO_PROXY всегда включайте RFC-1918 диапазоны и суффикс .cluster.local.
Настройка прокси в Traefik Ingress Controller
Traefik — популярная альтернатива NGINX Ingress, особенно в связке с Helm и в managed-кластерах (k3s, Docker Swarm, Nomad). Traefik имеет свою систему конфигурации через CRD (Custom Resource Definitions) и статический/динамический конфиги.
Статическая конфигурация Traefik с прокси
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config
namespace: traefik
data:
traefik.yaml: |
# Статическая конфигурация Traefik
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
# Настройки для работы за прокси
serversTransport:
insecureSkipVerify: false
maxIdleConnsPerHost: 200
dialTimeout: 10s
responseHeaderTimeout: 30s
# Логирование для диагностики прокси
log:
level: INFO
accessLog:
fields:
headers:
defaultMode: keep
names:
X-Forwarded-For: keep
X-Real-IP: keep
Middleware для добавления заголовков прокси
В Traefik можно создать Middleware, который будет добавлять или модифицировать заголовки при передаче запросов. Это полезно для корректной передачи реального IP клиента через цепочку прокси:
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: proxy-headers
namespace: production
spec:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
# Удаляем заголовки, которые могут раскрыть инфраструктуру
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
Переменные окружения для Traefik Deployment
Аналогично NGINX, для Traefik задаём переменные окружения через Helm values или напрямую в Deployment. При использовании Helm-чарта это делается через values.yaml:
# values.yaml для Traefik Helm chart
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"
Прокси через переменные окружения в подах
Самый универсальный способ настроить исходящий прокси для любого пода — через стандартные переменные окружения. Этот метод работает независимо от языка программирования и фреймворка: Python requests, Go net/http, Node.js axios, Java HttpClient — все они читают HTTP_PROXY и HTTPS_PROXY автоматически.
Вариант 1: Прямо в 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"
⚠️ Не храните учётные данные в открытом виде!
Пример выше показан для наглядности. В продакшне учётные данные прокси всегда должны храниться в Kubernetes Secret и передаваться через secretKeyRef. Подробнее — в разделе про Secrets ниже.
Вариант 2: Через ConfigMap для нескольких подов
Если прокси используют несколько Deployment, удобно вынести настройки в ConfigMap и подключать его через 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
Вариант 3: Мутирующий WebhookAdmissionController
Для корпоративных кластеров, где все поды обязаны использовать прокси, можно настроить мутирующий admission webhook, который автоматически добавляет переменные окружения прокси ко всем создаваемым подам. Это решение используется в enterprise-инфраструктурах, где compliance требует, чтобы весь исходящий трафик шёл через корпоративный прокси. Реализация такого webhook выходит за рамки этой статьи, но стоит знать о его существовании.
Ротация IP и управление прокси-пулом в K8s
Статический прокси — это хорошо для корпоративного compliance, но плохо для задач, где нужно избегать блокировок. Если 50 ваших подов шлют запросы через один и тот же IP, этот IP заблокируют очень быстро. Решение — ротация прокси.
Схема с Proxy Sidecar
Один из паттернов — запускать прокси-агент как sidecar-контейнер рядом с основным приложением. Sidecar принимает запросы на localhost:8080 и пересылает их через ротирующийся пул внешних прокси:
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:
# Основное приложение
- 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: локальный прокси-агент с ротацией
- 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" # ротация каждые 60 секунд
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
Схема с центральным Proxy Service
Альтернативный подход — единый Proxy Service внутри кластера, к которому обращаются все поды. Это проще в управлении: достаточно обновить один Secret с учётными данными прокси, и все поды автоматически начнут использовать новые данные.
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
---
# Поды используют прокси через внутренний DNS
# HTTP_PROXY=http://proxy-gateway.proxy-system.svc.cluster.local:8080
Для задач, где критична анонимность и минимальный риск блокировок (например, парсинг маркетплейсов или работа с рекламными API), рекомендуем использовать резидентные прокси с ротацией — они предоставляют реальные IP домашних пользователей, что делает трафик из вашего кластера неотличимым от обычного браузерного.
Хранение учётных данных прокси в Kubernetes Secrets
Безопасное хранение учётных данных — обязательное требование для любого продакшн-кластера. Никогда не вставляйте логин/пароль прокси напрямую в YAML-манифесты, которые хранятся в Git-репозитории.
Создание Secret для прокси
# Создание через kubectl (значения кодируются в base64 автоматически)
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'
# Проверка созданного Secret
kubectl get secret proxy-credentials -n production -o yaml
YAML-манифест Secret
apiVersion: v1
kind: Secret
metadata:
name: proxy-credentials
namespace: production
labels:
app: proxy-config
managed-by: ops-team
type: Opaque
# Значения закодированы в base64
# echo -n 'http://user:pass@proxy:8080' | base64
stringData:
# stringData позволяет указывать значения в открытом виде
# Kubernetes автоматически кодирует их в 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"
Использование Secret в 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"
# Для приложений, которые читают хост/порт отдельно
- name: PROXY_HOST
valueFrom:
secretKeyRef:
name: proxy-credentials
key: proxy-host
- name: PROXY_PORT
valueFrom:
secretKeyRef:
name: proxy-credentials
key: proxy-port
Интеграция с внешними хранилищами секретов
В enterprise-среде рекомендуется использовать External Secrets Operator для синхронизации секретов из HashiCorp Vault, AWS Secrets Manager или Azure Key Vault. Это позволяет автоматически обновлять учётные данные прокси без ручного вмешательства и перезапуска подов:
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
Диагностика и типичные ошибки при настройке прокси в K8s
Даже при правильной конфигурации могут возникать проблемы. Разберём самые частые из них и способы диагностики.
Проблема 1: Внутрикластерный трафик идёт через прокси
Симптом: поды перестают видеть друг друга, DNS-резолюция внутри кластера ломается, сервисы не отвечают. Причина — не настроена переменная NO_PROXY.
Минимально необходимое значение NO_PROXY для стандартного K8s-кластера:
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
Проблема 2: Прокси не применяется к конкретному поду
Диагностика: зайдите в под и проверьте переменные окружения:
# Проверка переменных окружения в поде
kubectl exec -it <pod-name> -n production -- env | grep -i proxy
# Тест подключения через прокси из пода
kubectl exec -it <pod-name> -n production -- curl -v --proxy http://proxy:8080 https://httpbin.org/ip
# Проверка что Secret смонтирован корректно
kubectl exec -it <pod-name> -n production -- env | grep PROXY
Проблема 3: TLS-ошибки при использовании HTTPS-прокси
Если прокси использует самоподписанный сертификат или корпоративный CA, приложения будут получать ошибки верификации TLS. Решение — добавить CA-сертификат прокси в доверенные:
# Создание ConfigMap с CA-сертификатом
kubectl create configmap proxy-ca-cert \
--from-file=proxy-ca.crt=./proxy-ca.crt \
-n production
# Монтирование в под
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
Проблема 4: Медленные запросы через прокси
Если запросы через прокси значительно медленнее прямых — проверьте:
- DNS-резолюция: убедитесь, что DNS-запросы не идут через прокси (добавьте в
NO_PROXY) - Keep-alive соединения: настройте пул соединений к прокси-серверу
- Географическое расположение: прокси-сервер должен быть физически близко к целевому ресурсу
- Тип прокси: для высокоскоростных задач рассмотрите прокси дата-центров — они обеспечивают минимальную задержку
Полезные команды для диагностики
# Проверить логи Ingress Controller
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=100
# Проверить события пода
kubectl describe pod <pod-name> -n production
# Тест прокси-соединения из пода
kubectl run test-proxy --image=curlimages/curl --rm -it --restart=Never -- \
curl -x http://user:pass@proxy:8080 -v https://httpbin.org/ip
# Проверить что Secret существует и содержит нужные ключи
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]}...')
"
Заключение и рекомендации
Настройка прокси в Kubernetes — это не разовая задача, а часть архитектуры сетевой безопасности кластера. Подведём итоги:
- Для NGINX Ingress Controller — используйте аннотации для настройки параметров прокси на уровне отдельных Ingress-ресурсов, и переменные окружения в Deployment для глобальных настроек исходящего трафика.
- Для Traefik — комбинируйте статическую конфигурацию через ConfigMap с Middleware для управления заголовками.
- Для подов — стандартные переменные
HTTP_PROXY/HTTPS_PROXYчерез Secrets — самый универсальный и безопасный подход. - Всегда настраивайте NO_PROXY — иначе внутрикластерный трафик сломается.
- Никогда не храните учётные данные прокси в открытом виде в манифестах или в Git.
- Для продакшна — используйте External Secrets Operator для автоматической ротации учётных данных.
Если ваш K8s-кластер выполняет задачи, где критична стабильность IP и минимальный риск блокировок — парсинг, работа с рекламными API, геотестирование — рекомендуем использовать резидентные прокси. Они обеспечивают реальные IP домашних пользователей, которые алгоритмы защиты воспринимают как легитимный трафик. Для задач с высокими требованиями к скорости и минимальными рисками блокировок со стороны мобильных платформ отлично подойдут мобильные прокси — они работают через реальные 4G/5G-сети операторов.