Si votre cluster K8s effectue des requêtes externes — vers des API partenaires, des places de marché, des plateformes publicitaires — tôt ou tard, vous serez confronté à des blocages par IP. L'Ingress Controller gère le trafic entrant, mais pour les requêtes sortantes via des pods, un schéma distinct avec un proxy est nécessaire. Dans cet article, nous examinons comment le configurer correctement : du choix du type de proxy aux configurations YAML spécifiques pour NGINX Ingress et Traefik.
Pourquoi un proxy dans Kubernetes : scénarios réels
Kubernetes est un orchestrateur, et la plupart des articles à son sujet parlent du trafic entrant : comment configurer l'Ingress, comment délivrer un certificat TLS, comment router les requêtes vers les services. Mais il y a un autre aspect : le trafic sortant des pods. C'est ici que surgissent les problèmes de blocages, de géo-restrictions et de limites par IP.
Examinons des tâches spécifiques où un proxy dans un cluster K8s devient une nécessité :
- Parsing et surveillance des prix. Votre cluster exécute un CronJob toutes les 15 minutes et collecte des données de Wildberries, Ozon, Amazon. Sans rotation des IP, après 2–3 heures, vous recevrez un ban sur toute la plage IP de votre fournisseur de cloud.
- Travail avec des API publicitaires. Facebook Marketing API, TikTok Ads API, Google Ads API — tous suivent la source des requêtes. Si des dizaines de pods envoient des requêtes depuis une seule IP de datacenter, c'est un déclencheur pour un blocage automatique.
- Tests de géolocalisation. Votre service doit afficher un contenu différent pour les utilisateurs de différents pays. Via un proxy, les pods peuvent simuler des requêtes des régions nécessaires pour les tests automatiques.
- Contourner les restrictions d'entreprise. Dans certaines infrastructures, tout le trafic sortant doit passer par un proxy d'entreprise — c'est une exigence de conformité.
- Travail avec des API partenaires avec liste blanche d'IP. Lorsque le partenaire autorise les requêtes uniquement depuis des IP spécifiques, et que votre cluster se met à l'échelle et change d'adresses — un proxy avec des IP statiques résout le problème.
Il est important de comprendre la séparation architecturale : L'Ingress Controller gère le trafic entrant (des utilisateurs vers vos services), tandis qu'un proxy pour les requêtes sortantes est une tâche distincte. Néanmoins, ils sont liés : la configuration du proxy est souvent définie au niveau du même Ingress Controller ou via des annotations qu'il lit.
💡 Distinction clé
Dans cet article, nous examinons deux scénarios : (1) configurer l'Ingress Controller comme un proxy inverse pour des serveurs upstream externes, et (2) router le trafic sortant des pods via un serveur proxy externe. Les deux scénarios se rencontrent en production.
Quel type de proxy choisir pour un cluster K8s
Le choix du type de proxy influence directement la durée pendant laquelle votre cluster pourra fonctionner sans blocages. Les IP de datacenter sont les moins chères, mais elles sont faciles à identifier et à bloquer. Les IP résidentes et mobiles sont plus chères, mais beaucoup plus fiables pour les tâches où l'imitation d'un utilisateur réel est importante.
| Type de proxy | Vitesse | Risque de blocage | Meilleur scénario dans K8s |
|---|---|---|---|
| Datacenter | Élevée | Élevé | APIs internes, conformité d'entreprise, intégrations partenaires avec liste blanche d'IP |
| Résidentiel | Moyenne | Faible | Parsing de places de marché, travail avec des APIs publicitaires, tests géographiques |
| Mobile | Moyenne | Minimale | Facebook Ads API, TikTok API, tâches à forte charge avec risque de ban |
Pour la plupart des tâches dans un cluster K8s, liées au parsing ou au travail avec des plateformes publicitaires, le choix optimal est des proxies résidentiels avec rotation. Ils fournissent de vraies IP d'utilisateurs domestiques, et les algorithmes de protection des sites perçoivent ces requêtes comme un trafic de navigateur ordinaire.
En termes de protocole pour K8s, le plus universel est le proxy HTTP/HTTPS — il est pris en charge par tous les clients HTTP populaires dans n'importe quel langage de programmation via les variables d'environnement standard HTTP_PROXY et HTTPS_PROXY. SOCKS5 n'est nécessaire que pour des protocoles non standards ou lorsque vous devez proxyfier autre chose qu'HTTP.
Configuration du proxy via NGINX Ingress Controller
NGINX Ingress Controller est l'option la plus répandue dans K8s. Examinons deux scénarios : configurer NGINX comme un proxy inverse vers un upstream externe via un serveur proxy, et configurer globalement le proxy sortant pour le contrôleur lui-même.
Annotations pour proxyfier les requêtes vers l'upstream
NGINX Ingress prend en charge les annotations pour gérer le comportement du proxy. Si vous avez besoin que l'Ingress transmette des requêtes à un service externe via un proxy intermédiaire, utilisez un ConfigMap avec une configuration personnalisée :
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
data:
# Proxy HTTP global pour les requêtes sortantes NGINX
http-snippet: |
proxy_connect_timeout 10s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
# Configuration de l'upstream via un proxy
use-proxy-protocol: "false"
proxy-real-ip-cidr: "0.0.0.0/0"
Ressource Ingress avec annotations pour le proxy
Pour une ressource Ingress distincte, vous pouvez définir les paramètres du proxy via des annotations. Cela est utile lorsque différents services nécessitent des délais d'attente et des configurations différents :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-service-ingress
namespace: production
annotations:
kubernetes.io/ingress.class: "nginx"
# Délais d'attente du 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"
# Taille du buffer
nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
# Transmission de la vraie IP du client
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
Configuration d'un proxy externe pour les requêtes sortantes du pod NGINX
Si le NGINX Ingress Controller lui-même doit effectuer des requêtes sortantes via un proxy externe (par exemple, pour vérifier la santé des points de terminaison externes), vous devez définir des variables d'environnement dans le déploiement du contrôleur :
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"
Notez la variable NO_PROXY — elle est critique. Sans elle, tout le trafic intra-cluster passera également par le proxy externe, ce qui rompra l'interaction entre les services. Dans NO_PROXY, incluez toujours les plages RFC-1918 et le suffixe .cluster.local.
Configuration du proxy dans Traefik Ingress Controller
Traefik est une alternative populaire à NGINX Ingress, surtout en combinaison avec Helm et dans des clusters gérés (k3s, Docker Swarm, Nomad). Traefik a son propre système de configuration via CRD (Custom Resource Definitions) et des configurations statiques/dynamiques.
Configuration statique de Traefik avec proxy
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config
namespace: traefik
data:
traefik.yaml: |
# Configuration statique de Traefik
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
# Paramètres pour fonctionner derrière un proxy
serversTransport:
insecureSkipVerify: false
maxIdleConnsPerHost: 200
dialTimeout: 10s
responseHeaderTimeout: 30s
# Journalisation pour le diagnostic du proxy
log:
level: INFO
accessLog:
fields:
headers:
defaultMode: keep
names:
X-Forwarded-For: keep
X-Real-IP: keep
Middleware pour ajouter des en-têtes de proxy
Dans Traefik, vous pouvez créer un Middleware qui ajoutera ou modifiera des en-têtes lors de la transmission des requêtes. Cela est utile pour transmettre correctement la vraie IP du client à travers la chaîne de proxies :
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: proxy-headers
namespace: production
spec:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
# Supprimez les en-têtes qui pourraient révéler l'infrastructure
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 d'environnement pour le déploiement Traefik
De même que pour NGINX, pour Traefik, définissez des variables d'environnement via les valeurs Helm ou directement dans le déploiement. Lors de l'utilisation du chart Helm, cela se fait via values.yaml :
# values.yaml pour le chart 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 via des variables d'environnement dans les pods
La manière la plus universelle de configurer un proxy sortant pour n'importe quel pod est via des variables d'environnement standard. Cette méthode fonctionne indépendamment du langage de programmation et du framework : Python requests, Go net/http, Node.js axios, Java HttpClient — tous lisent HTTP_PROXY et HTTPS_PROXY automatiquement.
Option 1 : Directement dans la spécification du pod
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"
⚠️ Ne stockez pas les informations d'identification en clair !
L'exemple ci-dessus est montré pour des raisons de clarté. En production, les informations d'identification du proxy doivent toujours être stockées dans Kubernetes Secret et transmises via secretKeyRef. Plus de détails dans la section sur les Secrets ci-dessous.
Option 2 : Via ConfigMap pour plusieurs pods
Si plusieurs déploiements utilisent le proxy, il est pratique de déplacer les paramètres dans un ConfigMap et de les connecter via 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
Option 3 : Mutating WebhookAdmissionController
Pour les clusters d'entreprise, où tous les pods doivent utiliser un proxy, vous pouvez configurer un webhook d'admission mutateur qui ajoute automatiquement des variables d'environnement proxy à tous les pods créés. Cette solution est utilisée dans des infrastructures d'entreprise, où la conformité exige que tout le trafic sortant passe par un proxy d'entreprise. La mise en œuvre d'un tel webhook dépasse le cadre de cet article, mais il est bon d'en connaître l'existence.
Rotation des IP et gestion du pool de proxies dans K8s
Un proxy statique est bon pour la conformité d'entreprise, mais mauvais pour les tâches où il faut éviter les blocages. Si 50 de vos pods envoient des requêtes via la même IP, cette IP sera rapidement bloquée. La solution est la rotation des proxies.
Schéma avec Proxy Sidecar
Un des modèles consiste à exécuter un agent proxy en tant que conteneur sidecar à côté de l'application principale. Le sidecar reçoit des requêtes sur localhost:8080 et les redirige via un pool rotatif de proxies externes :
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:
# Application principale
- 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 : agent proxy local avec rotation
- 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" # rotation toutes les 60 secondes
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
Schéma avec un service Proxy central
Une approche alternative consiste à avoir un service Proxy unique à l'intérieur du cluster, auquel tous les pods se connectent. C'est plus facile à gérer : il suffit de mettre à jour un Secret avec les informations d'identification du proxy, et tous les pods commenceront automatiquement à utiliser les nouvelles données.
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
---
# Les pods utilisent le proxy via le DNS interne
# HTTP_PROXY=http://proxy-gateway.proxy-system.svc.cluster.local:8080
Pour les tâches où l'anonymat est critique et le risque de blocages doit être minimisé (par exemple, le parsing de places de marché ou le travail avec des APIs publicitaires), nous recommandons d'utiliser des proxies résidentiels avec rotation — ils fournissent de vraies IP d'utilisateurs domestiques, ce qui rend le trafic de votre cluster indiscernable d'un trafic de navigateur ordinaire.
Stockage des informations d'identification du proxy dans Kubernetes Secrets
Le stockage sécurisé des informations d'identification est une exigence obligatoire pour tout cluster de production. Ne jamais insérer le login/mot de passe du proxy directement dans les manifests YAML qui sont stockés dans un dépôt Git.
Création d'un Secret pour le proxy
# Création via kubectl (les valeurs sont automatiquement encodées en 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'
# Vérification du Secret créé
kubectl get secret proxy-credentials -n production -o yaml
Manifest YAML du Secret
apiVersion: v1
kind: Secret
metadata:
name: proxy-credentials
namespace: production
labels:
app: proxy-config
managed-by: ops-team
type: Opaque
# Les valeurs sont encodées en base64
# echo -n 'http://user:pass@proxy:8080' | base64
stringData:
# stringData permet de spécifier des valeurs en clair
# Kubernetes les encode automatiquement 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"
Utilisation du Secret dans le déploiement
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"
# Pour les applications qui lisent l'hôte/le port séparément
- name: PROXY_HOST
valueFrom:
secretKeyRef:
name: proxy-credentials
key: proxy-host
- name: PROXY_PORT
valueFrom:
secretKeyRef:
name: proxy-credentials
key: proxy-port
Intégration avec des stockages secrets externes
Dans un environnement d'entreprise, il est recommandé d'utiliser External Secrets Operator pour synchroniser les secrets depuis HashiCorp Vault, AWS Secrets Manager ou Azure Key Vault. Cela permet de mettre à jour automatiquement les informations d'identification du proxy sans intervention manuelle et sans redémarrer les 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
Diagnostic et erreurs courantes lors de la configuration du proxy dans K8s
Même avec une configuration correcte, des problèmes peuvent survenir. Examinons les plus fréquents et les moyens de les diagnostiquer.
Problème 1 : Le trafic intra-cluster passe par le proxy
Symptôme : les pods ne se voient plus, la résolution DNS à l'intérieur du cluster échoue, les services ne répondent pas. La cause — la variable NO_PROXY n'est pas configurée.
La valeur minimale requise pour NO_PROXY pour un cluster K8s standard :
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
Problème 2 : Le proxy ne s'applique pas à un pod spécifique
Diagnostic : entrez dans le pod et vérifiez les variables d'environnement :
# Vérification des variables d'environnement dans le pod
kubectl exec -it <pod-name> -n production -- env | grep -i proxy
# Test de connexion via le proxy depuis le pod
kubectl exec -it <pod-name> -n production -- curl -v --proxy http://proxy:8080 https://httpbin.org/ip
# Vérification que le Secret est monté correctement
kubectl exec -it <pod-name> -n production -- env | grep PROXY
Problème 3 : Erreurs TLS lors de l'utilisation de proxies HTTPS
Si le proxy utilise un certificat auto-signé ou un CA d'entreprise, les applications recevront des erreurs de vérification TLS. La solution consiste à ajouter le certificat CA du proxy aux approuvés :
# Création d'un ConfigMap avec le certificat CA
kubectl create configmap proxy-ca-cert \
--from-file=proxy-ca.crt=./proxy-ca.crt \
-n production
# Montage dans le 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
Problème 4 : Requêtes lentes via le proxy
Si les requêtes via le proxy sont significativement plus lentes que les directes — vérifiez :
- Résolution DNS : assurez-vous que les requêtes DNS ne passent pas par le proxy (ajoutez-les à
NO_PROXY) - Connexions Keep-alive : configurez le pool de connexions vers le serveur proxy
- Localisation géographique : le serveur proxy doit être physiquement proche de la ressource cible
- Type de proxy : pour des tâches à haute vitesse, envisagez des proxies de datacenter — ils offrent une latence minimale
Commandes utiles pour le diagnostic
# Vérifier les logs de l'Ingress Controller
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=100
# Vérifier les événements du pod
kubectl describe pod <pod-name> -n production
# Tester la connexion proxy depuis le pod
kubectl run test-proxy --image=curlimages/curl --rm -it --restart=Never -- \
curl -x http://user:pass@proxy:8080 -v https://httpbin.org/ip
# Vérifier que le Secret existe et contient les clés nécessaires
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]}...')
"
Conclusion et recommandations
La configuration du proxy dans Kubernetes n'est pas une tâche ponctuelle, mais fait partie de l'architecture de sécurité réseau du cluster. Résumons :
- Pour NGINX Ingress Controller — utilisez des annotations pour configurer les paramètres du proxy au niveau des ressources Ingress individuelles, et des variables d'environnement dans le déploiement pour les paramètres globaux du trafic sortant.
- Pour Traefik — combinez la configuration statique via ConfigMap avec Middleware pour gérer les en-têtes.
- Pour les pods — les variables standard
HTTP_PROXY/HTTPS_PROXYvia Secrets — c'est l'approche la plus universelle et sécurisée. - Configurez toujours NO_PROXY — sinon, le trafic intra-cluster sera rompu.
- Ne stockez jamais les informations d'identification du proxy en clair dans les manifests ou dans Git.
- Pour la production — utilisez External Secrets Operator pour la rotation automatique des informations d'identification.
Si votre cluster K8s effectue des tâches où la stabilité des IP et le risque minimal de blocages sont critiques — parsing, travail avec des APIs publicitaires, tests géographiques — nous recommandons d'utiliser des proxies résidentiels. Ils fournissent de vraies IP d'utilisateurs domestiques, que les algorithmes de protection perçoivent comme un trafic légitime. Pour les tâches avec des exigences élevées en matière de vitesse et un risque minimal de blocages de la part des plateformes mobiles, les proxies mobiles sont idéaux — ils fonctionnent via de véritables réseaux 4G/5G d'opérateurs.
```