Service:短命な Pod のための安定したネットワーキング
Pod に安定したアドレスを与え、クラスターの内外に公開し、誰が誰と通信できるかを制限します。
すべての Pod は独自の IP アドレスを持ちますが、Pod は現れては消え、そのアドレスも一緒に消えます。Service は、変化し続ける Pod の集合の前に、安定したアドレスを提供します。このガイドでは、前のガイドの web Deployment を基に、Service、クラスターの外への公開、Ingress、ネットワークポリシーを説明します。
問題:Pod の IP は変わる
kubectl get pods -l app=web -o wide
kubectl delete pod POD_NAME
kubectl get pods -l app=web -o wide
代わりの Pod は、異なる IP を持ち、別のノード上にあることもあります。古いアドレスをハードコードしていたものは、すべて壊れ、レプリカが現れては消える中で、アドレスを手作業で追跡することはできません。
ClusterIP の Service を作成する
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
selector は、Deployment で見たのと同じラベルを使って、Service を支える Pod を選びます。port は Service がリッスンするポートで、targetPort は転送先の Pod のポートで、コンテナのポートと一致している必要があります。type を設定していないため、これは ClusterIP の Service です。クラスターの内部からのみ、安定した仮想 IP で到達できます。
kubectl apply -f service.yaml
kubectl get service web
kubectl get endpointslices -l kubernetes.io/service-name=web
EndpointSlice は、現在 Service の背後にある Pod の IP を一覧表示します。Deployment をスケールアップまたはダウンすると自動的に更新されますが、Service 自体のアドレスは変わりません。(古いクラスターやチュートリアルでは、同じ情報のために kubectl get endpoints web を使います。最近のバージョンでは、その API は EndpointSlice に置き換えられ、非推奨になっています。)
クラスター内では、Service には DNS 名も付きます。同じ namespace からは web、どこからでも web.NAMESPACE.svc.cluster.local です。使い捨ての Pod からテストします。
kubectl run tmp --rm -it --image=busybox:1.36 --restart=Never -- wget -qO- http://web
nginx のウェルカムページが表示されるはずです。各ノードでは、kube-proxy が、Service の準備完了の Pod に接続を分散させるルールを維持しています。一般的な iptables モードでは、これは厳密なラウンドロビンではなく、実質的にランダムで、readiness チェックに失敗した Pod はローテーションから外されます。
Service をクラスターの外に公開する
Service のタイプはさらに 2 つあり、それぞれが前のものの上に構築されています。
- NodePort は、さらにすべてのノードでポート(30000 〜 32767)を開きます。ノードの IP に到達できるものは何でも、そのポートで Service に到達できます。
- LoadBalancer は、さらにそれらのノードポートを指す外部ロードバランサーを、環境に要求します。クラウドプロバイダーでは自動的に行われます。ベアメタルでは、MetalLB のようなものが必要です。
apiVersion: v1
kind: Service
metadata:
name: web-public
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080
nodePort を省略すると、Kubernetes が空いているものを選びます。Docker ドライバーを使った minikube では、ノードの IP にノート PC から直接到達できないことが多いため、minikube に開いてもらいます。
minikube service web-public --url
minikube の LoadBalancer の Service には、別のターミナルで minikube tunnel を実行します。
Ingress で HTTP をルーティングする
Service ごとに LoadBalancer を持つとコストがかさみ、しかも生のトラフィックしか処理できません。Ingress を使うと、単一のエントリポイントを通じて、ホストとパスで多くの Service に HTTP(S) トラフィックをルーティングし、そこで TLS を終端できます。Ingress はルールを記述するだけです。それに基づいて動作するには、クラスターで動作している ingress コントローラーが必要です(minikube では minikube addons enable ingress)。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
ingressClassName: nginx
rules:
- host: web.example.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
web.example.local へのリクエストは、web Service に送られます。ホストの証明書は、cert-manager のようなツールで自動化できます。
NetworkPolicy でトラフィックを制限する
デフォルトでは、すべての Pod が他のすべての Pod と通信できます。NetworkPolicy は、Pod を選択し、許可されるトラフィックを列挙します。いずれかのポリシーが ingress について Pod を選択すると、明示的に許可されていないものはすべて拒否されます。まず、namespace 内のすべての受信トラフィックを拒否することから始めます。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
空の podSelector は、namespace 内のすべての Pod を選択します。そして、必要なものだけを許可します。たとえば、role: client ラベルを持つ Pod から web Pod へのトラフィックです。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-client-to-web
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: client
ports:
- protocol: TCP
port: 80
ネットワークポリシーは namespace に属し、クラスターのネットワークプラグイン(たとえば Calico や Cilium)がサポートしている場合にのみ適用されます。一部の最小限のローカル構成は、オブジェクトを受け付けても、黙って無視します。そのため、拒否された接続が実際にブロックされていることをテストしてください。
人気のガイド
-
Kubernetes とは何か、そしてそれが解決する問題 コンテナだけではスケールしなくなる理由と、Kubernetes がマシンの集まりを 1 つのプラットフォームに変える方法。 -
Kubernetes クラスターの仕組み:コントロールプレーンとノード クラスターを動かすコンポーネントと、kubectl apply から実行中のコンテナまでの間に何が起きるか。 -
Deployment:スケーリング、自己修復、ローリングアップデート Pod のレプリカを実行し、ダウンタイムなしで更新し、リリースがうまくいかなかったときにロールバックします。 -
失敗する Pod をデバッグする:describe、logs、exec、port-forward Pod が Pending のまま、クラッシュする、応答しない原因を突き止めるための、繰り返し使えるチェックリスト。