企業環境やファイアウォールの背後でKubernetesを展開する際、外部リソースへのアクセスのためにプロキシサーバーを設定する必要が生じることがよくあります。これは、コンテナイメージのダウンロード、パッケージの更新、外部APIとの相互作用にとって非常に重要です。このガイドでは、Kubernetesにおけるプロキシの設定のすべてのレベルを、ノードの構成から個々のポッドまで詳しく説明します。
Kubernetesクラスターにおけるプロキシの必要性
企業環境におけるKubernetesクラスターは、インターネットへのアクセスが制限された隔離されたネットワークで動作することがよくあります。プロキシサーバーは、いくつかの重要なタスクを解決します:
- コンテナイメージのダウンロード — Docker Hub、Google Container Registry、プライベートレジストリは外部アクセスを必要とします
- パッケージの更新 — コンテナ内でのapt、yum、pipを介した依存関係のインストール
- 外部APIへのアクセス — クラウドサービス、モニタリング、ロギングとの統合
- セキュリティ — トラフィックの制御、ドメインのフィルタリング、リクエストのロギング
- キャッシング — 同じリソースへの再リクエストの高速化
プロキシが正しく設定されていないと、アプリケーションをデプロイしようとしたときに「image pull failed」、「connection timeout」または「network unreachable」といったエラーに直面することになります。特に、CI/CDパイプラインの自動化においては、ダウンタイムの1秒がコストに影響します。
重要:企業クラスターには、高い帯域幅と安定した接続を持つデータセンタープロキシの使用を推奨します。これにより、インフラ全体の機能が保証されます。
Kubernetesにおけるプロキシ設定のレベル
Kubernetesは多層アーキテクチャを持っており、プロキシはタスクに応じて各レベルで設定する必要があります:
| レベル | 設定内容 | 目的 |
|---|---|---|
| オペレーティングシステム | システム環境変数 | ユーティリティへのアクセス(curl、wget、apt) |
| Container Runtime (Docker/containerd) | デーモンの構成 | コンテナイメージのダウンロード |
| kubelet | kubeletの起動オプション | APIサーバーとの相互作用 |
| ポッド(Pods) | マニフェスト内の環境変数 | アプリケーションの外部APIへのアクセス |
| kubectl | クライアントの環境変数 | プロキシ経由でのクラスター管理 |
各レベルは個別に設定が必要であり、いずれかを見逃すと問題が発生する可能性があります。たとえば、Dockerのプロキシのみを設定し、ポッドのプロキシを設定しないと、イメージはダウンロードされますが、コンテナ内のアプリケーションは外部APIにアクセスできません。
Dockerおよびcontainerdのためのプロキシ設定
コンテナランタイムは、外部レジストリからコンテナイメージをダウンロードする責任を持つ最初のコンポーネントです。両方の人気のあるランタイムの設定を見てみましょう。
Dockerのためのプロキシ設定
Dockerには、Dockerサービスに環境変数を追加するsystemdドロップインファイルを作成する必要があります:
# 設定用のディレクトリを作成
sudo mkdir -p /etc/systemd/system/docker.service.d
# プロキシ設定ファイルを作成
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.cluster.local,.svc"
EOF
# systemdの設定を再読み込み
sudo systemctl daemon-reload
# Dockerを再起動
sudo systemctl restart docker
# 設定が適用されたことを確認
sudo systemctl show --property=Environment docker
これでDockerはプロキシサーバーを経由してイメージをダウンロードできるようになります。動作を確認するには、次のコマンドを使用します:
docker pull nginx:latest
containerdのためのプロキシ設定
containerdは、現代のKubernetesクラスターで主要なコンテナランタイムとして使用されます。プロキシの設定は少し異なります:
# 設定用のディレクトリを作成
sudo mkdir -p /etc/systemd/system/containerd.service.d
# プロキシ設定ファイルを作成
sudo tee /etc/systemd/system/containerd.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.cluster.local,.svc"
EOF
# 設定を再読み込み
sudo systemctl daemon-reload
sudo systemctl restart containerd
# ステータスを確認
sudo systemctl status containerd
アドバイス:プライベートコンテナレジストリを使用している場合は、NO_PROXYにそのドメインを追加して、余分な遅延やSSL証明書の問題を回避してください。
kubeletのためのプロキシ構成
kubeletは、クラスターの各ノードで動作するKubernetesエージェントです。APIサーバーや外部リソースへのアクセスも必要です。設定はKubernetesのインストール方法によって異なります。
kubeadmクラスターの場合
kubeadmを使用している場合は、systemdを介してプロキシを設定します:
# kubeletの設定用ディレクトリを作成
sudo mkdir -p /etc/systemd/system/kubelet.service.d
# プロキシ設定ファイルを作成
sudo tee /etc/systemd/system/kubelet.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/16,.cluster.local,.svc"
EOF
# kubeletを再起動
sudo systemctl daemon-reload
sudo systemctl restart kubelet
マネージドKubernetes(EKS、GKE、AKS)の場合
マネージドKubernetesサービスでは、kubeletの設定は通常、ノードの起動パラメータやユーザーデータスクリプトを介して行われます。たとえば、AWS EKSの場合:
#!/bin/bash
# EKSワーカーノード用のユーザーデータスクリプト
# システムのプロキシ設定
cat <<EOF >> /etc/environment
HTTP_PROXY=http://proxy.company.com:8080
HTTPS_PROXY=http://proxy.company.com:8080
NO_PROXY=localhost,127.0.0.1,169.254.169.254,.ec2.internal,.cluster.local
EOF
# kubelet用の設定
mkdir -p /etc/systemd/system/kubelet.service.d
cat <<EOF > /etc/systemd/system/kubelet.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,169.254.169.254,.ec2.internal,.cluster.local"
EOF
systemctl daemon-reload
systemctl restart kubelet
169.254.169.254をNO_PROXYに追加することに注意してください。これはAWSのメタデータサービスのアドレスで、プロキシなしでアクセス可能である必要があります。
ポッドレベルでのプロキシ設定
Dockerとkubeletのプロキシを設定しても、ポッド内のアプリケーションは自動的にプロキシを使用しません。Kubernetesのマニフェスト内で環境変数を明示的に指定する必要があります。
Deploymentマニフェストを介した設定
最も簡単な方法は、コンテナの仕様に環境変数を追加することです:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-company/my-app:latest
env:
- name: HTTP_PROXY
value: "http://proxy.company.com:8080"
- name: HTTPS_PROXY
value: "http://proxy.company.com:8080"
- name: NO_PROXY
value: "localhost,127.0.0.1,.cluster.local,.svc,10.0.0.0/8"
ports:
- containerPort: 8080
ConfigMapを使用した中央集権的な設定
各Deploymentにプロキシ設定を重複させないために、ConfigMapを作成します:
apiVersion: v1
kind: ConfigMap
metadata:
name: proxy-config
namespace: default
data:
HTTP_PROXY: "http://proxy.company.com:8080"
HTTPS_PROXY: "http://proxy.company.com:8080"
NO_PROXY: "localhost,127.0.0.1,.cluster.local,.svc,10.0.0.0/8"
次に、このConfigMapをDeploymentで使用します:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: my-company/my-app:latest
envFrom:
- configMapRef:
name: proxy-config
このアプローチは管理を簡素化します:プロキシのアドレスを変更する場合、ConfigMapを更新するだけで、ポッドを再起動すると新しい設定が自動的に適用されます。
MutatingWebhookを介した自動インジェクション
すべてのポッドにプロキシ変数を自動的に追加するには、MutatingAdmissionWebhookを使用できます。これは高度なアプローチであり、独自のWebhookサービスを開発する必要がありますが、アプリケーションのマニフェストを変更せずに設定を中央集権的に管理できます。
NO_PROXYの正しい構成
NO_PROXY変数は、プロキシサーバーをバイパスする必要があるアドレスやドメインを定義します。NO_PROXYの設定ミスは、Kubernetesクラスターでの問題の最も一般的な原因です。
Kubernetesのための必須の例外
次のアドレスと範囲は、常にNO_PROXYに含める必要があります:
| アドレス/範囲 | 目的 |
|---|---|
localhost, 127.0.0.1 |
ローカル接続 |
.cluster.local |
クラスターの内部DNS |
.svc |
Kubernetesサービス |
10.0.0.0/8 |
ポッドネットワーク(CNIに依存) |
10.96.0.0/12 |
サービスネットワーク(デフォルト) |
172.16.0.0/12 |
プライベートDockerネットワーク |
192.168.0.0/16 |
プライベートローカルネットワーク |
NO_PROXYの完全な構成の例
NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,10.96.0.0/12,.cluster.local,.svc,.default.svc,.default.svc.cluster.local,kubernetes.default.svc,kubernetes.default.svc.cluster.local
注意:一部のアプリケーションはNO_PROXYでCIDR表記をサポートしていません。その場合は、ワイルドカードを使用してください:10.*を10.0.0.0/8の代わりに使用します。
プロキシ経由でのkubectlの設定
プロキシの背後にあるワークステーションからクラスターを管理する場合、kubectlのために環境変数を設定します:
# Linux/macOSの場合 - ~/.bashrcまたは~/.zshrcに追加
export HTTP_PROXY=http://proxy.company.com:8080
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,kubernetes.default.svc,.cluster.local
# Windows PowerShellの場合
$env:HTTP_PROXY="http://proxy.company.com:8080"
$env:HTTPS_PROXY="http://proxy.company.com:8080"
$env:NO_PROXY="localhost,127.0.0.1,kubernetes.default.svc,.cluster.local"
これでkubectlはプロキシを介してクラスターのAPIサーバーに接続できるようになります。動作を確認してください:
kubectl cluster-info
kubectl get nodes
認証付きプロキシの設定
プロキシサーバーが認証を要求する場合、URLに資格情報を追加します:
export HTTP_PROXY=http://username:password@proxy.company.com:8080
export HTTPS_PROXY=http://username:password@proxy.company.com:8080
セキュリティ:設定ファイルにパスワードを平文で保存しないでください。環境変数やKubernetesのシークレットを使用してプロキシの資格情報を保存してください。
一般的な問題の診断と解決
正しく設定されていても、問題が発生することがあります。最も一般的なエラーとその解決方法を見てみましょう。
イメージのダウンロード時の「ImagePullBackOff」エラー
症状:ポッドが起動せず、イベントに「Failed to pull image」または「connection timeout」と表示されます。
診断:
# ポッドのイベントを確認
kubectl describe pod <pod-name>
# Docker/containerdのプロキシ設定を確認
sudo systemctl show --property=Environment docker
sudo systemctl show --property=Environment containerd
# ノードで手動でイメージをダウンロードしてみる
sudo docker pull nginx:latest
sudo crictl pull nginx:latest
解決策:コンテナランタイムのためにプロキシが設定されていることを確認し、イメージレジストリのドメインがNO_PROXYに含まれていないことを確認してください。
クラスター内のDNS解決の問題
症状:ポッドがDNS名(例:service-name.namespace.svc.cluster.local)で互いにアクセスできません。
診断:
# ポッドからDNSを確認
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default
# ポッド内のプロキシ変数を確認
kubectl exec -it <pod-name> -- env | grep PROXY
解決策:NO_PROXYに.cluster.localと.svcを追加してください。
外部APIへのアクセス時の遅延またはタイムアウト
症状:アプリケーションが遅く動作するか、外部サービスへのリクエストでタイムアウトが発生します。
診断:
# ポッドからプロキシの可用性を確認
kubectl exec -it <pod-name> -- curl -v -x http://proxy.company.com:8080 https://www.google.com
# レスポンスタイムを測定
kubectl exec -it <pod-name> -- time curl -x http://proxy.company.com:8080 https://api.example.com
解決策:問題はプロキシサーバーのパフォーマンスにある可能性があります。遅延を減らすために、地理的に近いレジデンシャルプロキシの使用を検討してください。
プロキシ経由でのSSL/TLSエラー
症状:「certificate verify failed」や「SSL handshake failed」といったエラーが発生します。
原因:一部のプロキシサーバーはSSLインスペクション(HTTPSトラフィックの復号化)を実行し、プロキシのルート証明書をインストールする必要があります。
解決策:
# プロキシの証明書でConfigMapを作成
kubectl create configmap proxy-ca-cert --from-file=ca.crt=/path/to/proxy-ca.crt
# 証明書をポッドにマウントし、システムストレージに追加
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
volumeMounts:
- name: proxy-ca
mountPath: /usr/local/share/ca-certificates/proxy-ca.crt
subPath: ca.crt
volumes:
- name: proxy-ca
configMap:
name: proxy-ca-cert
本番環境におけるプロキシのベストプラクティス
企業環境でのKubernetesクラスターの運用経験に基づいて、プロキシを信頼性高く運用するための推奨事項を以下に示します:
1. 高可用性のプロキシサーバーを使用する
プロキシはクラスター全体の単一障害点となります。ロードバランサーの背後に複数のプロキシサーバーを設定してください:
HTTP_PROXY=http://proxy-lb.company.com:8080
ここで、proxy-lb.company.comは複数のプロキシサーバーの前にあるロードバランサーです。
2. 設定の中央集権的管理
各マニフェストにハードコーディングするのではなく、ConfigMapやSecretを使用してプロキシ設定を保存します:
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-proxy-config
namespace: kube-system
data:
HTTP_PROXY: "http://proxy-lb.company.com:8080"
HTTPS_PROXY: "http://proxy-lb.company.com:8080"
NO_PROXY: "localhost,127.0.0.1,.cluster.local,.svc,10.0.0.0/8"
3. 監視とアラート設定
プロキシサーバーの可用性を監視し、問題が発生した場合にアラートを設定します:
- プロキシの応答時間(ローカルプロキシの場合は100ms未満であるべき)
- プロキシへの接続エラーの数
- クラスター内のImagePullBackOffイベントの数
- プロキシサーバーのCPUおよびネットワークの負荷
4. NO_PROXYの例外を文書化する
NO_PROXYに追加されたドメインやIPアドレスとその理由を文書化してください。これにより、トラブルシューティングやセキュリティ監査が容易になります。
5. dev環境での変更をテストする
本番環境でプロキシ設定を変更する前に、必ずdev/stagingクラスターでテストしてください:
# プロキシ確認用のテストポッド
apiVersion: v1
kind: Pod
metadata:
name: proxy-test
spec:
containers:
- name: test
image: curlimages/curl:latest
command: ["sleep", "3600"]
env:
- name: HTTP_PROXY
value: "http://new-proxy.company.com:8080"
- name: HTTPS_PROXY
value: "http://new-proxy.company.com:8080"
# 外部リソースへのアクセスを確認
kubectl exec -it proxy-test -- curl -v https://registry.k8s.io
kubectl exec -it proxy-test -- curl -v https://docker.io
6. 異なるタスクに異なるタイプのプロキシを使用する
重要なコンポーネント(イメージのダウンロード、クラスターAPI)には高速なデータセンタープロキシを使用し、地理的に多様なIPを必要とするアプリケーションにはレジデンシャルまたはモバイルプロキシを使用してください。
7. NO_PROXYリストを定期的に更新する
新しいサービスを追加したりネットワークトポロジーを変更した場合は、NO_PROXYを更新してください。これをHelmチャートやKustomizeを通じて自動化します:
# Helmチャートのvalues.yaml
proxy:
enabled: true
http: "http://proxy.company.com:8080"
https: "http://proxy.company.com:8080"
noProxy:
- localhost
- 127.0.0.1
- .cluster.local
- .svc
- 10.0.0.0/8
- internal-service.company.com
結論
Kubernetesクラスターにおけるプロキシの設定は、多層的なタスクであり、オペレーティングシステムやコンテナランタイムから個々のポッドまで、各レベルでの詳細に注意を払う必要があります。正しい構成は、クラスターの円滑な運用、外部リソースへの安全なアクセス、企業のセキュリティポリシーへの準拠を保証します。
覚えておくべき重要なポイント:
- すべてのレベルでプロキシを設定する:OS、コンテナランタイム、kubelet、ポッド
- NO_PROXYを正しく構成し、クラスターのすべての内部ネットワークを含める
- ConfigMapを通じて中央集権的な管理を使用する
- プロキシサーバーの可用性とパフォーマンスを監視する
- 本番環境に適用する前に変更をテストする
重要なKubernetesクラスターには、高可用性と低遅延を持つ信頼性の高いデータセンタープロキシの使用を推奨します。これにより、インフラの安定した運用が保証され、ネットワークアクセスの問題によるダウンタイムのリスクが最小限に抑えられます。
問題が発生した場合は、システマティックなアプローチで診断を行い、各レベルでの設定を確認し、ログやイベントを分析し、手動で接続をテストしてください。Kubernetesにおけるプロキシの問題の大半は、環境変数やNO_PROXYの正しい設定によって解決されます。