2026年9月4日
2026年9月4日
Kubernetesの基本概念 Pod・Deployment・Serviceの役割と関係をマニフェストで理解する
Kubernetes でアプリを動かすとき、最初に押さえるべきオブジェクトが Pod・Deployment・Service の3つです。この記事では、それぞれの役割と、3つが「ラベル」と「セレクター」でどうつながるかを、手元のクラスターでそのまま試せるマニフェストで説明します。
3つのオブジェクトの役割
| オブジェクト | 役割 | 直接作ることは |
|---|---|---|
| Pod | 1つ以上のコンテナをまとめた、Kubernetes が動かす最小の単位。Pod 内のコンテナは IP アドレスとポートを共有する | 学習用以外ではほとんどない |
| Deployment | 「この Pod をいくつ動かすか」「どのイメージで動かすか」を宣言し、数の維持・ローリング更新・ロールバックを受け持つ(内部で ReplicaSet を作る) | 通常はこれを作る |
| Service | ラベルで選んだ Pod の集まりに、変わらない名前と IP アドレスを与えて通信を振り分ける | Deployment と組で作る |
Pod は作り直されるたびに IP アドレスが変わります。そこで Deployment が Pod の数を保ち、Service が「今動いている Pod」へ通信を届ける、という分担になります。
3つをつなぐのは名前ではなくラベルです。Deployment は自分が作る Pod に app: myapp のようなラベルを付け、Service は selector で同じラベルを持つ Pod を探します。ラベルの綴りが1文字でも違うと、Service はどの Pod にもつながりません。
準備するもの
- 動いている Kubernetes クラスター(学習用なら minikube、kind、k3s など)
- クラスターに接続できる
kubectl
接続できているかは次で確かめます。
kubectl cluster-info
kubectl get nodes
VPS 1台にクラスターを用意する手順は VPSにk3sでKubernetesを導入する を参照してください。
Pod を単体で動かしてみる
まず Pod を1つだけ作り、Pod がどういうものかを確かめます。次の内容を pod.yaml として保存します。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp-test
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
適用して状態を確認します。
kubectl apply -f pod.yaml
kubectl get pods -o wide
kubectl describe pod myapp-pod
kubectl logs myapp-pod
STATUS が Running になれば起動しています。確認できたら削除します。
kubectl delete -f pod.yaml
単体で作った Pod は、削除されたりノードが止まったりしても作り直されません。実際の運用では、次の Deployment に Pod を作らせます。
Deployment で Pod を管理する
次の内容を deployment.yaml として保存します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
spec.selector.matchLabels と spec.template.metadata.labels は同じ値にします。食い違っていると適用時にエラーになります。
kubectl apply -f deployment.yaml
kubectl rollout status deployment/myapp
kubectl get deployments
kubectl get replicasets
kubectl get pods -l app=myapp
Pod が3つ動いていることを確認したら、そのうち1つを削除してみます。
kubectl delete pod "$(kubectl get pods -l app=myapp -o jsonpath='{.items[0].metadata.name}')"
kubectl get pods -l app=myapp
すぐに新しい Pod が作られ、3つに戻ります。これが Deployment(実際にはその下の ReplicaSet)による数の維持です。
台数を変える
kubectl scale deployment/myapp --replicas=5
kubectl scale はその場の変更です。次に deployment.yaml を kubectl apply すると replicas の値に戻るので、残したい変更はマニフェストに書いて適用します。
イメージを更新し、戻す
deployment.yaml の image を nginx:1.28 に書き換えて適用すると、Pod が少しずつ新しいものに入れ替わります(既定の更新方式はローリングアップデート)。
kubectl apply -f deployment.yaml
kubectl rollout status deployment/myapp
kubectl rollout history deployment/myapp
更新後に問題が出たら、1つ前の状態に戻せます。
kubectl rollout undo deployment/myapp
undo はクラスター側の状態だけを戻します。手元の deployment.yaml は書き換わらないので、戻した内容に合わせてファイルも直しておきます。
Service で Pod にアクセスする
次の内容を service.yaml として保存します。selector は Deployment の Pod に付けたラベル app: myapp と同じにします。
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
port は Service が受けるポート、targetPort は Pod 側のコンテナが待ち受けるポートです。type を書かないと ClusterIP(クラスター内だけで使えるアドレス)になります。
kubectl apply -f service.yaml
kubectl get services
kubectl get endpointslices -l kubernetes.io/service-name=myapp
EndpointSlice に Pod の IP アドレスが並んでいれば、Service と Pod がつながっています。手元のパソコンから試すには、ポートフォワードを使います。
kubectl port-forward service/myapp 8080:80
別のターミナルで curl http://localhost:8080/ を実行し、nginx の応答が返れば成功です。クラスター内の別の Pod からは、http://myapp(同じ名前空間の場合)という名前で届きます。
Service の種類
| type | 届く範囲 |
|---|---|
| ClusterIP(既定) | クラスター内だけ |
| NodePort | 各ノードの IP アドレスと決まったポート(既定では 30000〜32767 の範囲)で外から届く |
| LoadBalancer | 外部のロードバランサーを割り当てる。クラウドの連携機能や、k3s の ServiceLB・MetalLB のような仕組みが必要 |
| ExternalName | クラスター外の DNS 名への別名 |
自作のイメージを使うときの注意
手元で docker build したイメージは、そのままではクラスターのノードから見えません。マニフェストの image には、ノードが取得できる場所にあるイメージを指定します。
- コンテナレジストリ(Docker Hub など)に push して、そのイメージ名を書く
- kind なら
kind load docker-image myapp:1.0.3、minikube ならminikube image load myapp:1.0.3でノードに読み込む
latest タグは中身が変わっても名前が同じなため、どの版が動いているか分からなくなります。nginx:1.27 や myapp:1.0.3 のように版の分かるタグを付けておくと、ロールバックもしやすくなります。
つまずきやすい状態と確かめ方
表の POD_NAME と SERVICE_NAME は、kubectl get pods と kubectl get services で表示される名前に置き換えます。
| 症状 | よくある原因 | 確かめるコマンド |
|---|---|---|
Pod が ImagePullBackOff |
イメージ名・タグの誤り、非公開レジストリの認証が無い | kubectl describe pod POD_NAME の Events |
Pod が CrashLoopBackOff |
コンテナの起動直後にアプリが終了している | kubectl logs POD_NAME --previous |
Pod が Pending のまま |
ノードの CPU・メモリが足りない | kubectl describe pod POD_NAME の Events |
| Service につないでも応答が無い | selector と Pod のラベルが一致していない、targetPort の誤り |
kubectl get endpointslices -l kubernetes.io/service-name=SERVICE_NAME と kubectl get pods --show-labels |
片付け
kubectl delete -f service.yaml
kubectl delete -f deployment.yaml
まとめ
- Pod はコンテナを動かす最小の単位で、単体では作り直されない
- Deployment は Pod の数と版を管理し、ローリング更新と
kubectl rollout undoによる巻き戻しを受け持つ - Service はラベルで選んだ Pod に固定の名前と IP アドレスを与える
- 3つはラベルとセレクターでつながるので、つながらないときはまずラベルの一致を確かめる
設定値やパスワードを Pod に渡す方法は KubernetesのConfigMapとSecret、データを残す方法は KubernetesのPersistentVolume で扱っています。