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 で扱っています。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲