【4-3】Kubernetes実践編:Service(ClusterIP, NodePort, LoadBalancer)でPodにアクセス
Kubernetes実践編:Service(ClusterIP, NodePort, LoadBalancer)でPodにアクセスする
はじめに
前回の記事では、Deploymentを使ってPodを自動で管理し、「自己修復」や「ローリングアップデート」といったKubernetesの強力な機能を体験しました。
しかし、まだ大きな問題が残っています。
Deploymentが作ったPodは、IPアドレスがいつ変わるか分かりませんし、port-forwardは一時的なデバッグ用です。どうすれば、このPodたちに安定してアクセスできるのでしょうか?
その答えが、今回学ぶServiceリソースです。
Serviceは、複数のPodに対して 「固定のIPアドレス」 と 「DNS名」 を提供する、Kubernetesネットワークの「玄関口」の役割を果たします。
学習の準備(と、さっそくのトラブル)
Serviceの動作を確認するため、まずは前回作成したバックエンドとなるNginxのPodを3つ起動しておきましょう。
nginx-deploymentを起動します。
# Phase2で作成したDeploymentを適用
k apply -f nginx-deployment.yaml
# 3つのPodがRunningになることを確認
k get pods -l app=nginx
ところが、私の環境ではk get podsを実行しても、PodがPendingのまま一向に起動しませんでした。
k describe podで原因を調査したところ、**disk-pressure(ディスク圧迫)**が原因であることが判明。
このトラブルシューティングの全容と、VMのディスク拡張(LVM)で解決した手順については、長くなるため別記事にまとめました。同じ問題に直面した方は、ぜひこちらをご覧ください。
参考記事:
実践①: ClusterIP(クラスター内部専用の玄関口)
ClusterIPは、クラスター内部専用のIPアドレスをServiceに割り当てる、最も基本的なタイプです。
クラスターの外(ブラウザなど)からはアクセスできませんが、Pod同士が通信するため(例:WordPressがMySQLに接続する)に使われます。
1. ClusterIPマニフェストの作成
cat > nginx-service-clusterip.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: ClusterIP
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
-
kind: Service: リソースの種類は
Serviceです。 - type: ClusterIP: 内部専用のIPを割り当てます(実はこれはデフォルトなので省略可能です)。
-
selector:{app: nginx}: これが最重要です。 このServiceは、
app: nginxというラベルを持つPod(Deploymentが作成したPod)を探し出し、トラフィックを自動で振り分けます。nginx-deployment.yamlのtemplate.metadata.labelsと一致していることが重要です。 - port: 80: Service自体が公開するポートです。
- targetPort: 80: Serviceが転送する先のPod(Nginxコンテナ)が待機しているポートです。
2. Serviceの作成と確認
# Serviceを適用
k apply -f nginx-service-clusterip.yaml
# Serviceの一覧を表示
k get services
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-service ClusterIP 10.43.122.147 <none> 80/TCP 92m
# Serviceが正しくPodを認識しているか詳細を確認
k describe service nginx-service
k describeの結果のEndpoints:という欄に、Running状態のNginx Pod(3つ)のIPアドレスがリストアップされていれば成功です。
3. クラスター内からのアクセステスト
ClusterIPは外部からアクセスできないため、テスト用のPodをクラスター内部で一時的に起動し、そこからアクセスします。
# busyboxイメージを使い、対話的(-it)に実行し、終了後に自動削除(--rm)する
k run test-pod --image=busybox -it --rm
#--- コンテナ内部のシェルが起動したら ---
# wgetでService名にアクセス!
/ # wget -qO- nginx-service
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
(NginxのHTMLが返ってくれば成功)
# exitでPodを終了・削除
/ # exit
nginx-serviceというServiceの名前だけでPodにアクセスできることが確認できました。これがKubernetes内部のDNS(サービスディスカバリー) の力です。
実践②: NodePort(外部公開用のテスト窓口)
NodePortは、ClusterIPの機能(内部IP)に加え、全てのワーカーノード(物理サーバー) の特定のポート(例:30080)を外部に公開します。
手っ取り早く外部からアクセスしたい開発・テストでよく使われます。
1. NodePortマニフェストの作成
cat > nginx-service-nodeport.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
EOF
- type: NodePort: タイプをNodePortに指定します
- nodePort: 30080: ノード(192.168.3.101)の30080番ポートを公開します
2. Serviceの作成とブラウザ確認
k apply -f nginx-service-nodeport.yaml
k get services
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-nodeport NodePort 10.43.104.211 <none> 80:30080/TCP 3m14s
PORT(S)が80:30080/TCPとなりました。これは「Serviceの80番ポートが、ノードの30080番ポートにマッピングされた」ことを意味します。
PCのブラウザから、k3sサーバーのIPアドレスとnodePortにアクセスします。
ブラウザで開くURL: http://192.168.3.101:30080
「Welcome to nginx!」の画面が表示されれば成功です!
実践③: LoadBalancer(本番用の自動玄関)
LoadBalancerタイプは、NodePortの機能に加え、AWS, GCP, Azureなどのクラウドプロバイダーが提供する本物のロードバランサーを自動でプロビジョニングし、グローバルなEXTERNAL-IP(外部IPアドレス)を取得するのが本来の役割です。
k3sでの動作
k3sには簡易的な組み込みLB(Klipper)が搭載されています。type: LoadBalancerを指定すると、NodePortの動作に加えてEXTERNAL-IP欄にノードのIPアドレスを自動で割り当てようとします。
cat > nginx-service-lb.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
k apply -f nginx-service-lb.yaml
k get services
私の環境では、EXTERNAL-IPは<pending>(保留中)のままでした。これは、ホスト側(192.168.3.101)のポート80が他のプログラムに既に使用されており、k3sのLBがポートを確保できなかったためです。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 43h
nginx-loadbalancer LoadBalancer 10.43.59.248 <pending> 80:32168/TCP 25s
nginx-nodeport NodePort 10.43.104.211 <none> 80:30080/TCP 3m14s
nginx-service ClusterIP 10.43.122.147 <none> 80/TCP 92m
しかし、PORT(S)を見ると80:32168/TCPとなっており、LoadBalancerタイプでもNodePort(ポート32168)は自動で有効になっていることがわかります。
curl http://localhost:32168でアクセスできることも確認できました。
まとめ
KubernetesのServiceリソースには、3つの主要なタイプがあることを学びました。
| Type | 主な用途 | アクセス元 | IP/ポート |
|---|---|---|---|
| ClusterIP | クラスター内部通信 (Pod間) | クラスター内部のPod | 内部IP (10.x.x.x:80) |
| NodePort | 開発・テスト用の外部公開 | クラスター外部(ブラウザ) | ノードIP (192.168.3.101:30080) |
| LoadBalancer | 本番環境の外部公開(クラウド) | クラスター外部(ブラウザ) | 専用の外部IP ([LBのIP]:80) |
これで、Kubernetes上で本格的なアプリケーションを動かすための2大要素が揃いました。
次の記事では、いよいよこのDeploymentとServiceを組み合わせて、Docker Composeで構築したWordPress環境をKubernetesに完全移行します。
Discussion