🖥️

【4-3】Kubernetes実践編:Service(ClusterIP, NodePort, LoadBalancer)でPodにアクセス

に公開

Kubernetes実践編:Service(ClusterIP, NodePort, LoadBalancer)でPodにアクセスする

はじめに

前回の記事では、Deploymentを使ってPodを自動で管理し、「自己修復」や「ローリングアップデート」といったKubernetesの強力な機能を体験しました。
https://zenn.dev/koikoi_infra/articles/b3a785733a31a4

しかし、まだ大きな問題が残っています。

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)で解決した手順については、長くなるため別記事にまとめました。同じ問題に直面した方は、ぜひこちらをご覧ください。

参考記事:
https://zenn.dev/koikoi_infra/articles/240093b8167928

実践①: 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.yamltemplate.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大要素が揃いました。

次の記事では、いよいよこのDeploymentServiceを組み合わせて、Docker Composeで構築したWordPress環境をKubernetesに完全移行します。

Discussion