Kubernetes の Pod とは?コンテナを動かす最小単位を整理する
- 公開日
- カテゴリ:Kubernetes
- タグ:Kubernetes,学習メモ

Kubernetes では、コンテナを Pod という単位に入れて動かす。Docker で docker run nginx としていたところを、Kubernetes では「nginx のコンテナを入れた Pod を作る」という形にする。
この記事では、その Pod をローカルのクラスタで実際に作り、状態を見て、消すところまでを整理する。クラスタの構成要素(Control Plane、Node、kubelet など)については「Kubernetes のアーキテクチャを整理する:Control Plane と Node の構成要素」を参照。
この記事でやること:
- kind でローカルのクラスタを作る
- Pod の YAML を読む
kubectl applyで Pod を作るkubectl get/describe/logs/port-forwardで Pod を見るkubectl deleteで Pod を消す- コンテナを2つ入れた Pod で、コンテナ同士が
localhostでつながることを確かめる
Pod の中身を図にしたものは「Kubernetes の仕組みを図で整理する」にまとめている。
contents
環境:kind でクラスタを作る
Kubernetes を触るにはクラスタが必要で、本来は複数台のマシンで構成する。手元の Mac 1台でそれを再現するために kind(Kubernetes IN Docker)を使う。kind は、Docker コンテナ1つを Node(マシン1台)に見立ててクラスタを作るツール。
Mac
└── Docker Desktop
├── コンテナ「k8s-study-control-plane」 ← Node 1台のふり(クラスタを管理する側)
├── コンテナ「k8s-study-worker」 ← Node 1台のふり(Pod を載せる側)
└── コンテナ「k8s-study-worker2」 ← Node 1台のふり(Pod を載せる側)
kind の役目はクラスタを作る・消すことだけで、作ったあとの操作は kubectl で行う。
インストールは Homebrew。
brew install kind
Control Plane 1台 + Worker 2台の構成にするため、設定ファイルを用意する。
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
kind create cluster --name k8s-study --config kind-config.yaml
Node が3つ Ready になっていれば準備完了。
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-study-control-plane Ready control-plane 1m v1.37.0
k8s-study-worker Ready <none> 1m v1.37.0
k8s-study-worker2 Ready <none> 1m v1.37.0
- 環境: macOS(Apple Silicon)、Docker Desktop 29.8.0、kind v0.33.0、Kubernetes v1.37.0、kubectl v1.36.1
- kubectl は kube-apiserver の ±1 マイナーバージョンまでサポートされるので、v1.36 の kubectl で v1.37 のクラスタを操作できる
- クラスタを消すときは
kind delete cluster --name k8s-study
Pod とは
公式ドキュメントでは、Pod は「Kubernetes 内で作成・管理できるコンピューティングの最小のデプロイ可能なユニット」と定義されている。
- Pod は 1つ以上のコンテナをまとめたもので、ストレージとネットワークを共有する
- Kubernetes が管理するのはコンテナではなく Pod。コンテナ単体を作る操作はなく、コンテナは必ず Pod の中に書く
- 最も一般的なのは「1 Pod 1 コンテナ」の構成。この場合、Pod はコンテナ1つを包む薄いラッパーと考えられる
Docker: docker run ──▶ コンテナ
Kubernetes: kubectl apply ──▶ Pod ──▶ コンテナ(Pod の中に入っている)
Pod の YAML
nginx のコンテナを1つ入れた Pod の定義。公式ドキュメントの例と同じ内容。
# nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
| フィールド | 意味 |
|---|---|
apiVersion / kind | 何を作るか。Pod なら v1 と Pod の組み合わせで固定 |
metadata | 名前などの識別情報。name は kubectl get や delete で指定するときに使う |
spec | どんな Pod にしたいか。自分で決めるのはここ |
spec.containers | Pod に入れるコンテナの一覧(1つ以上)。image が docker run に渡すイメージ名にあたる |
spec.containers[].ports | コンテナが待ち受けるポートの情報。書かなくても通信はできる |
Kubernetes のリソースは、Pod 以外もすべて apiVersion / kind / metadata / spec の4つの塊でできている。
Pod を作る
kubectl apply -f nginx-pod.yaml
pod/nginx created
kubectl apply -f <ファイル> は、ファイルの内容を Kubernetes に渡すコマンド。ここから先は Kubernetes が、Pod を置く Node を決め、その Node でイメージを取得してコンテナを起動する。
Pod を見る
kubectl get pods
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 30s
| 列 | 意味 |
|---|---|
READY | 動いているコンテナ数 / Pod に入っているコンテナ数 |
STATUS | Pod の状態。作った直後は ContainerCreating、動き出すと Running |
RESTARTS | コンテナが再起動された回数 |
AGE | 作ってからの経過時間 |
-o wide を付けると、どの Node に置かれたかと、Pod に付いた IP が見える。
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 15s 10.244.2.5 k8s-study-worker2 <none> <none>
NODEはk8s-study-worker2。Pod を置く Node は Kubernetes が決めるもので、YAML には書いていない。Control Plane の Node には kubeadm の既定で普通の Pod が置かれないため、Worker のどちらかになるIPは Pod に1つ付く。コンテナではなく Pod が IP を持つ
kubectl describe pod
kubectl describe pod nginx
出力は長いが、見るのは Node: / IP:、Containers: の下の State:、一番下の Events: の3か所。Events: には、この Pod に何が起きたかが時系列で記録されている。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 114s default-scheduler Successfully assigned default/nginx to k8s-study-worker2
Normal Pulling 114s kubelet spec.containers{nginx}: Pulling image "nginx:1.14.2"
Normal Pulled 109s kubelet spec.containers{nginx}: Successfully pulled image "nginx:1.14.2" in 4.531s (4.531s including waiting). Image size: 41901077 bytes.
Normal Created 109s kubelet spec.containers{nginx}: Container created
Normal Started 109s kubelet spec.containers{nginx}: Container started
上から順に「Node が決まった → イメージを取りに行った → 取れた → コンテナを作った → 起動した」。kubectl apply のあとに Kubernetes が裏で行っていたことが、ここに並ぶ。
From列は、それを行った担当。Scheduledだけがdefault-scheduler(Node を決める係)で、Pulling以降はその Node のkubelet(Node 上でコンテナを動かす係)PullingとPulledの間の 5 秒が、イメージ(約 42MB)のダウンロードにかかった時間- Pod がうまく動かないときも、まずここを見る。イメージ名を間違えると
Failed to pull imageのような行が出る
同じ Node でもう一度 Pod を作ると、イメージはすでに Node にあるため Pulling の行がなくなり、Pulled の内容が「already present on machine」に変わる。
Normal Scheduled 38s default-scheduler Successfully assigned default/nginx to k8s-study-worker2
Normal Pulled 38s kubelet spec.containers{nginx}: Container image "nginx:1.14.2" already present on machine and can be accessed by the pod
Normal Created 38s kubelet spec.containers{nginx}: Container created
Normal Started 38s kubelet spec.containers{nginx}: Container started
イメージは Node ごとに保存されるので、次にもう一方の Worker に置かれたときは、また Pulling から始まる。
kubectl logs
kubectl logs nginx
コンテナが標準出力に書いたものが出る。docker logs にあたる。
kubectl port-forward
Pod の IP はクラスタの中のものなので、Mac から直接はつながらない。port-forward で Mac のポートを Pod のポートにつなぐ。
kubectl port-forward pod/nginx 8080:80
別のターミナルから curl http://localhost:8080 を実行すると nginx のトップページの HTML が返り、kubectl logs nginx にアクセスログが1行増える。確認したら Ctrl+C で port-forward を止める。
port-forward を止めないままにすると、Pod を消したあとも Mac のポート 8080 は kubectl が握ったままになる。ブラウザのキャッシュで nginx の画面が表示され続けることもあるので、Pod が消えたかどうかは kubectl get pods で確認する。
Pod を消す
kubectl delete pod nginx
# => pod "nginx" deleted
kubectl get pods
# => No resources found in default namespace.
Pod を単体で作った場合、消したら終わりで、誰も作り直さない。「消えたら自動で作り直してほしい」「同じ Pod を3つ動かしたい」を実現するのは Pod ではなく、Pod を見張って数を保つ担当である Deployment という別のリソースになる。
コンテナが落ちた場合とは動きが違う。コンテナが落ちたときは、同じ Pod の中で kubelet がコンテナを再起動する(RESTARTS が増える)。Pod は残ったまま、中のコンテナだけが入れ替わる。
| 起きたこと | 何が起きるか | 誰がやるか |
|---|---|---|
| コンテナが落ちた | 同じ Pod の中でコンテナを再起動する | kubelet |
| Pod が削除された | 何も起きない。単体で作った Pod は作り直されない | 担当がいない |
コンテナを2つ入れた Pod
Pod にはコンテナを2つ以上入れられる。同じ Pod のコンテナは 同じ IP とポート空間を共有し、localhost でお互いに届く。これを確かめるため、nginx(web)と、5 秒ごとに localhost:80 にアクセスして結果を出力するだけのコンテナ(checker)を1つの Pod に入れる。
# multi-container-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: web-and-checker
spec:
containers:
- name: web
image: nginx:1.14.2
ports:
- containerPort: 80
- name: checker
image: busybox:1.28
command:
- sh
- -c
- |
while true; do
if wget -q -O /dev/null http://localhost:80; then
echo "ok $(date)"
else
echo "ng $(date)"
fi
sleep 5
done
kubectl apply -f multi-container-pod.yaml
kubectl get pods
READY が 2/2 になる。コンテナが複数ある Pod では、kubectl logs に -c <コンテナ名> を付けてどのコンテナのログかを指定する。
kubectl logs web-and-checker -c checker # ok <日時> が 5 秒ごとに並ぶ
kubectl logs web-and-checker -c web # 127.0.0.1 からのアクセスが記録されている
web のアクセスログに 127.0.0.1 からのリクエストが並ぶのは、checker が同じ Pod の中から localhost でアクセスしているため。Pod の IP は1つで、待ち受けているのは web だけ。
この Pod の中身を図にすると次のようになる。
- 同じ Pod に nginx を2つ入れることはできない。ポートも共有しているので、2つ目がポート 80 を取れずに起動に失敗する
- nginx を2つ動かしたい場合は Pod を2つ作る。それを行うのが Deployment
- 2つ目のコンテナを入れる実際の用途は、ログの転送や通信の中継のように、アプリ本体を手伝う役目のもの。
checkerは動作を確かめるためだけのもの
kubectl delete pod web-and-checker
用語メモ
| 用語 | 読み方 | 意味 |
|---|---|---|
| Pod | ポッド | コンテナを入れて動かす箱。Kubernetes が扱う最小の単位 |
| kind | カインド | Docker の上に学習用のクラスタを作るツール |
| Node | ノード | Pod を載せるマシン。kind では Docker コンテナ1つ |
| Events | イベンツ | Pod に何が起きたかの記録。kubectl describe pod の一番下に出る |
まとめ
- Kubernetes では、コンテナは Pod という箱に入れて動かす。人間が作るのは Pod で、コンテナ単体を作る操作はない
- Pod の YAML は
apiVersion/kind/metadata/specの4つの塊。自分で決めるのはspec(何のコンテナを入れるか) - 作る:
kubectl apply -f、見る:kubectl get pods(-o wideで Node と IP)、kubectl describe pod(Events:に経緯)、kubectl logs、消す:kubectl delete pod - Pod を置く Node は Kubernetes が決める。IP はコンテナではなく Pod に付く
- 単体で作った Pod は、消したら作り直されない。作り直す担当を付けるのが Deployment

