はじめに
こんにちは!
本記事は「本気で学ぶKubernetes」シリーズの第2回です。このシリーズでは、Kubernetesの基礎から実践まで、段階的に学んでいきます。
前回の記事では、Kubernetesの全体像を見てきました。
今回は、k8sの重要な概念である「Pod」「Deployment」「Service」に焦点を当てて、図示しながら確認していきます。
この記事は人間がKubernetesの公式ドキュメントを読み漁りながら、人間の手で書いていますのでご安心ください!
前提知識
- Kubernetesの全体像を理解している方
- Pod、Deployment、Serviceという言葉は知っているが、具体的にどう動くか分からない方
- YAMLファイルの基本的な読み方を知っている方
1. Podとは
Pod(ポッド)は、Kubernetesにおけるコンピューティングの最小構成単位です。
Kubernetesにおいては主に2つの用途で使用されます。
- 単一のコンテナを実行する
- 連携して動作させるコンテナを実行する
アプリケーションの単一インスタンスを起動する箱として稼働させ、もしアプリケーションを水平スケールさせる場合は複数のPodを起動します。
以下はPodを含めたクラスター概念を抽象化したイメージです。
KubernetesとしてはPodが最小単位で動作しており、その中でユーザーが用意したコンテナが動作するようになっています。
いくつか特徴がありますのでまとめました。
Podの特徴
1. ユニークなIPアドレス割り当て
各Podごとに一意のIPアドレスが割り当てられて、Pod内の全てのコンテナはIPアドレスやポート情報などのネットワーク情報を共有します。
つまりPodごとにIPアドレス経由でアプリケーションにアクセすることが可能です。
ただしPod自体は使い捨て可能なエンティティとして設計されており、Podが再作成されるに伴いIPアドレスも再割り当てされます。
そのため後述するServiceを作成して使用することが不可欠となってきます。
2. 同じPod内のコンテナはlocalhostで通信可能
Pod内には複数のコンテナを稼働することできます。
以下は通信のイメージです。
この場合、web-appコンテナとlog-collectorコンテナは同じPod内にいる(=同じネットワークネームスペースを共有する)ため、localhostで通信することができます。
3. Podは一時的
Podは以下のような場合に削除・再作成されることがあるようです。
- ノード単位の障害
- リソース不足
- スケジューリングの最適化
- アプリケーションのアップデート
Pod自体は手動で作成して運用することはほとんどなく、Deployment、ReplicaSetなど機能によってワークロードの中で作成されます。
Podのマニフェスト例
以下は公式ドキュメント記載のYAMLマニフェストの例です。
docker-composeのYAMLを書いたことがある方なら、すんなりと理解できるのではないでしょうか。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
コンテナのポート80でnginxをPodで構成していることがわかります。
Podには複数のコンテナを含められますので、以下のように定義することも可能です。
apiVersion: v1
kind: Pod
metadata:
name: two-containers
spec:
restartPolicy: Never
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: nginx-container
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: debian-container
image: debian
volumeMounts:
- name: shared-data
mountPath: /pod-data
command: ["/bin/sh"]
args: ["-c", "echo Hello from the debian container > /pod-data/index.html"]
出典: Kubernetes公式ドキュメント - 共有ボリュームを使用して同じPod内のコンテナ間で通信する
2. Deploymentとは
Deploymentは、Podを「あるべき状態」に維持する機能です。
あらかじめYAMLファイルで宣言的に設定された状態を維持するためにPodの数やコンテナイメージを作成したり更新して自動管理できるようにする仕組みです。
Deploymentの主な役割としては以下があげられます。
- レプリカ管理:「Podを常に3つ動かす」という宣言を維持
- 自己修復(Self-healing):Podがクラッシュしたら自動で再作成
- ローリングアップデート:新バージョンを段階的にデプロイ
- ロールバック:Podに問題があれば前のバージョンに戻す
Podの章で「手動で作成することはほとんどない」と記載しましたが、DeploymentでPodの状態を宣言して運用する中でPodが作成されて利用することが可能になります。
「Deployment」でPodの状態を管理する上で欠かせない概念が「ReplicaSet」です。
ReplicaSetとは
ReplicaSetはKubernetesクラスター内に安定したPodの数を維持するために宣言、定義するための概念です。
こちらもYAML形式で定義することができます。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5
Kubernetesクラスターに適用すると、ReplicaSetとそれが管理するPodが作成されます。この例ではレプリカ数が3になっているのでPodが3つ作成されます。
Deploymentはより上位の概念で、ReplicaSetの定義をもとにレプリカ管理や自己修復などを行なっていきます。
整理すると以下のような構成になります。
- kubectl apply:Kubernetesクラスターに適用
- Deployment:レプリカ管理、ローリングアップデートを担当
- ReplicaSet:指定されたレプリカ数を維持
- Pod:実際にアプリが動く
ローリングアップデートを行う場合
Deploymentの仕組みを使うことで例えばイメージのバージョンを更新すると、段階的にPodが入れ替えることができます。
# イメージを nginx:1.25 から nginx:1.26 に更新
kubectl set image deployment/nginx-deployment nginx=nginx:1.26
更新の流れ
- 新しいバージョン(nginx:1.26)のPodを1つ起動
- 正常に起動したら、古いバージョンのPodを1つ削除
- これを繰り返して、すべてのPodを新バージョンに入れ替え
Deploymentのマニフェスト例
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
上記からreplicasのパラメータも指定可能なことが分かりますが、明示的にReplicaSetを宣言しなくともDeploymentで宣言することで内部的にReplicaSetが作成され適用されることとなります。
つまりDeploymentはPod自体を管理するのではなく、ReplicaSetを管理する概念とも言えますね。
Deploymentを定義する場合、冗長管理になるためReplicaSetを自分で作らないことが基本です。
出典: Kubernetes公式ドキュメント - Deployments
3. Serviceとは
Service は、Podへのアクセスを抽象化するための機能です。
主な仕組みは以下が挙げられます。
- 固定IPアドレスを提供(Cluster IP)
- 固定DNS名を提供(サービス名での名前解決)
- 複数のPodに負荷分散
なぜServiceが必要なのか?
ここまでの話からPodはDeploymentの機能で再作成されることがあり、これに伴いIPアドレスも再割り当てされるということが分かりました。
例えば、
- 最初のPod IP:
10.244.0.5 - クラッシュして再作成 → 新しいPod IP:
10.244.0.12
もしPodのIPアドレスを直接指定していた場合、再作成のたびに設定を変更する必要があります。
- Service IP:
10.96.0.10(固定) - Service DNS:
nginx-service(固定)
Serviceを使うと、Podが再作成されてIPアドレスが変わってもServiceのIPやDNS経由でアクセスすることが可能になります。
Serviceのマニフェスト例
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Serviceはラベル、セレクタを使ってPodを自動的に見つけます。
Deploymentで作成されたPodのラベル
labels:
app: nginx
Serviceのセレクタ
selector:
app: nginx
上記の場合app: nginxというラベルを持つPodすべてが、このServiceの負荷分散対象になります。
Serviceによる負荷分散
例えば3つのPodが動いている場合、Serviceは自動的に負荷分散します。
サービスタイプには大きく4つの種類があります。
- ClusterIP: クラスタ内部でのみアクセス可能なデフォルトのServiceタイプ
- NodePort: 各ノードの特定ポートを開放して外部からアクセスできるようにする
- LoadBalancer: ロードバランサーを自動作成して外部公開する
- ExternalName: 外部のDNS名(CNAME)にマッピングする特殊なServiceタイプ
長くなりそうなので詳細や挙動は別の記事でまとめて解説しようと思います。
出典: Kubernetes公式ドキュメント - Service
まとめと次回予告
- Pod:アプリケーションを載せる最小実行単位。一時的でIPアドレスが変わる
- ReplicaSet: Podの数を宣言した数に維持する
- Deployment:ReplicaSetを管理し、Podを「あるべき状態」に維持
- Service:Podへのアクセスを抽象化。ラベルセレクタでPodを判別し負荷分散が可能
次回は、「Docker → Kubernetesへの移行」をテーマに、作成したコンテナをk8sにのせて動作させるところまでを確認していきたいと思います!
それでは、また明日!



