あなたのK8sクラスターが外部API、マーケットプレイス、広告プラットフォームにリクエストを送信する場合、遅かれ早かれIPによるブロックに直面することになります。Ingress Controllerは、受信トラフィックを管理しますが、ポッドを介した送信リクエストには別のプロキシスキームが必要です。この記事では、プロキシのタイプの選択から、NGINX IngressとTraefikの具体的なYAML設定まで、正しい設定方法を解説します。
Kubernetesにおけるプロキシの必要性:実際のシナリオ
Kubernetesはオーケストレーターであり、ほとんどの関連記事は受信トラフィックについて述べています:Ingressの設定、TLS証明書の発行、サービスへのリクエストのルーティング。しかし、もう一つの側面があります:ポッドからの送信トラフィックです。ここでIPによるブロック、地理的制限、IP制限の問題が発生します。
K8sクラスターでプロキシが必要となる具体的なタスクを考えてみましょう:
- 価格のパースとモニタリング。 あなたのクラスターは15分ごとにCronJobを実行し、Wildberries、Ozon、Amazonからデータを収集します。IPのローテーションなしでは、2〜3時間後にクラウドプロバイダーのIP範囲全体がブロックされます。
- 広告APIとの連携。 Facebook Marketing API、TikTok Ads API、Google Ads APIはすべてリクエストのソースを追跡します。数十のポッドが同じデータセンターのIPからリクエストを送信すると、自動ブロックのトリガーとなります。
- ジオロケーションテスト。 あなたのサービスは異なる国のユーザーに異なるコンテンツを表示する必要があります。プロキシを介してポッドは必要な地域からのリクエストを模倣し、自動テストを行うことができます。
- 企業の制限を回避。 一部のインフラストラクチャでは、すべての送信トラフィックが企業プロキシを経由する必要があります。これはコンプライアンスの要件です。
- ホワイトリストIPのパートナーAPIとの連携。 パートナーが特定のIPからのリクエストのみを許可し、あなたのクラスターがスケールアップしてアドレスを変更する場合、静的IPを持つプロキシが問題を解決します。
アーキテクチャの分離を理解することが重要です:Ingress Controllerは受信トラフィックを管理します(ユーザーからあなたのサービスへ)、そして送信リクエストのためのプロキシは別のタスクです。それでも、両者は関連しています:プロキシの設定はしばしば同じIngress Controllerのレベルまたはそれが読み取るアノテーションで設定されます。
💡 重要な区分
この記事では、2つのシナリオを検討します:(1)外部アップストリームサーバーへのリバースプロキシとしてのIngress Controllerの設定、(2)ポッドから外部プロキシサーバーを介した送信トラフィックのルーティング。どちらのシナリオも本番環境で見られます。
K8sクラスターに適したプロキシの選択
プロキシのタイプの選択は、クラスターがブロックなしでどれだけ長く動作できるかに直接影響します。データセンターのIPは最も安価ですが、特定されやすく、ブロックされやすいです。居住者IPとモバイルIPは高価ですが、実際のユーザーを模倣する必要があるタスクにははるかに信頼性があります。
| プロキシタイプ | 速度 | ブロックリスク | K8sでの最適なシナリオ |
|---|---|---|---|
| データセンター | 高い | 高い | 内部API、企業のコンプライアンス、ホワイトリスト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で最も一般的な選択肢です。2つのシナリオを考えてみましょう:プロキシサーバーを介して外部アップストリームへのリバースプロキシとしてNGINXを設定すること、そしてコントローラー自体のための送信プロキシのグローバル設定です。
アップストリームへのリクエストをプロキシするためのアノテーション
NGINX Ingressは、プロキシの動作を管理するためのアノテーションをサポートしています。Ingressが外部サービスへのリクエストを中間プロキシを介して転送する必要がある場合は、カスタム設定を持つConfigMapを使用します:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
data:
# NGINXの送信リクエスト用のグローバルHTTPプロキシ
http-snippet: |
proxy_connect_timeout 10s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
# プロキシを介したアップストリームの設定
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自体が外部プロキシを介して送信リクエストを行う必要がある場合(例えば、外部エンドポイントのヘルスチェックのため)、コントローラーの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は、特にHelmやマネージドクラスター(k3s、Docker Swarm、Nomad)と組み合わせて使用される人気のあるNGINX Ingressの代替手段です。Traefikは、CRD(カスタムリソース定義)を介した独自の設定システムと静的/動的設定を持っています。
プロキシを使用した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
プロキシヘッダーを追加するためのミドルウェア
Traefikでは、リクエストを転送する際にヘッダーを追加または変更するミドルウェアを作成できます。これは、プロキシチェーンを介してクライアントの実際の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を介して行います:
# Traefik Helmチャートのためのvalues.yaml
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
すべてのポッドがプロキシを使用する必要がある企業クラスターでは、すべての作成されるポッドにプロキシの環境変数を自動的に追加するミューテイティングアドミッションWebhookを設定できます。このソリューションは、すべての送信トラフィックが企業プロキシを経由することを要求するコンプライアンスがあるエンタープライズインフラストラクチャで使用されます。このようなWebhookの実装はこの記事の範囲を超えますが、その存在を知っておくことは重要です。
K8sにおけるIPのローテーションとプロキシプールの管理
静的プロキシは企業のコンプライアンスには良いですが、ブロックを回避する必要があるタスクには不向きです。50のポッドが同じIPを介してリクエストを送信すると、そのIPは非常に早くブロックされます。解決策はプロキシのローテーションです。
プロキシサイドカーのスキーム
一つのパターンは、プロキシエージェントをメインアプリケーションの隣にサイドカーコンテナとして起動することです。サイドカーは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"
# サイドカー:ローカルプロキシエージェントとローテーション
- 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"
中央プロキシサービスのスキーム
代替アプローチは、クラスター内の単一のプロキシサービスで、すべてのポッドがそれにアクセスします。これにより管理が簡素化されます。プロキシの認証情報を含むSecretを1つ更新するだけで、すべてのポッドが自動的に新しいデータを使用し始めます。
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におけるプロキシの認証情報の保存
認証情報の安全な保存は、すべての本番クラスターにおける必須要件です。決して、Gitリポジトリに保存されるYAMLマニフェストにプロキシのユーザー名/パスワードを直接挿入しないでください。
プロキシ用の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
SecretのYAMLマニフェスト
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"
DeploymentでのSecretの使用
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
外部シークレットストレージとの統合
エンタープライズ環境では、HashiCorp Vault、AWS Secrets Manager、またはAzure Key Vaultからのシークレットを同期するためにExternal Secrets Operatorを使用することが推奨されます。これにより、手動での介入やポッドの再起動なしにプロキシの認証情報を自動的に更新できます:
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変数が設定されていないことです。
標準のK8sクラスターに必要な最小限のNO_PROXYの値は次のとおりです:
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:HTTPSプロキシ使用時のTLSエラー
プロキシが自己署名証明書または企業CAを使用している場合、アプリケーションはTLS検証エラーを受け取ります。解決策は、プロキシのCA証明書を信頼されたものに追加することです:
# CA証明書を持つConfigMapを作成
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を介した静的設定とヘッダー管理のためのミドルウェアを組み合わせてください。
- ポッドの場合 — Secretsを介した標準の
HTTP_PROXY/HTTPS_PROXYの使用が最も汎用的で安全なアプローチです。 - 常にNO_PROXYを設定してください — そうしないと、クラスター内トラフィックが壊れます。
- 認証情報を決して平文で保存しないでください — マニフェストやGitに保存しないでください。
- 本番環境では — 認証情報の自動ローテーションのためにExternal Secrets Operatorを使用してください。
あなたのK8sクラスターがIPの安定性とブロックのリスクを最小限に抑える必要があるタスクを実行している場合(パース、広告APIとの連携、ジオテストなど)、居住者プロキシの使用をお勧めします。これにより、実際の家庭ユーザーのIPが提供され、保護アルゴリズムはそれを正当なトラフィックとして認識します。速度とブロックリスクが最小限に抑えられるモバイルプラットフォーム向けのタスクには、モバイルプロキシが最適です。これらは、実際の4G/5Gネットワークを介して動作します。
```