それとなくKubernetesを使っているのですが、ちゃんと基本概念を知っておくかということでメモ
まずはワークロードから確認していきましょう。
Pod
Podとは
- コンテナをまとめて実行する最小単位
- Kubernetesにおけるデプロイ可能な最小単位がPodです。
- 通常は1つのコンテナを含むことが多いですが、特定のケースでは複数のコンテナを同一Pod内で稼働させることもあります(例えばサイドカーコンテナなど)
- 同じネットワーク名前空間を共有
- 同一Pod内のコンテナは、同じ
localhost
ネットワーク名前空間を共有します。つまり、同じIPアドレス空間を使って通信が可能です。
- 同一Pod内のコンテナは、同じ
Podの具体例
apiVersion: v1
kind: Pod
metadata:
name: sample-pod
spec:
containers:
- name: sample-container
image: nginx:1.19
ports:
- containerPort: 80
- 上記は、nginxを実行するシンプルなPodの例です。
kubectl apply -f
で適用すれば、Podが作成されます。
Deployment
Deploymentとは
- ステートレスアプリケーションを管理するためのコントローラ
- Podテンプレートを指定し、複数のレプリカを作成・管理します。
- ローリングアップデートやロールバックなどの機能が備わっており、継続的デリバリーの実現に役立ちます。
- Podの更新やスケーリングが容易
- 実行中のアプリケーションを停止させることなくバージョンアップを行うローリングアップデートが代表的な機能です。
Deploymentの具体例
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deployment
spec:
replicas: 3
selector:
matchLabels:
app: sample
template:
metadata:
labels:
app: sample
spec:
containers:
- name: sample-container
image: nginx:1.19
ports:
- containerPort: 80
replicas: 3
は、同じPodを3つ実行することを意味します。
kubectl set image deployment/sample-deployment sample-container=nginx:1.20
のように実行することで、コンテナイメージを更新しつつローリングアップデートが行われます。
StatefulSet
StatefulSetとは
- ステートフルなアプリケーションを管理するためのコントローラ
- データを保持するようなシステム(例: データベース、分散データストアなど)では、Podの永続的な識別(ordinal index)や安定したネットワークIDなどが必要なケースがあります。
- StatefulSetを使用すると、Pod名やストレージをある程度固定化しながらレプリカの作成・運用が可能になります。
- 安定したネットワークID
- 各Podに対して
<StatefulSet名>-<ordinal>
のホスト名を割り当て、クラスタ内でユニークなアドレスを持ち続けられます。
- 各Podに対して
- 順序立てたデプロイ/スケーリング/終了処理
- Podを起動・停止する際、必ず「順番」に従い制御されます。例えば、Pod-0が起動してからPod-1が起動する、といった具合です。
StatefulSetの具体例
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sample-statefulset
spec:
serviceName: "sample-statefulset-service"
replicas: 3
selector:
matchLabels:
app: sample-stateful
template:
metadata:
labels:
app: sample-stateful
spec:
containers:
- name: sample-stateful-container
image: mysql:5.7
ports:
- containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "gp2" # (例: AWS EBSを想定したStorageClass)
resources:
requests:
storage: 10Gi
それぞれのPodはsample-statefulset-0
, sample-statefulset-1
, sample-statefulset-2
のように命名され、専用のPersistentVolumeが割り当てられます。
データが永続化されることで、Podの再スケジュールがあってもデータロストを防ぎやすくなります(ただしストレージとの組み合わせに注意)。
ReplicaSet
ReplicaSetとは
- 指定した数のPodレプリカを常に稼働させるコントローラ
- Deploymentと同様、ある数のPodが常に存在するように監視・制御します。
- ただし現在では、多くの場合ReplicaSetを直接扱わず、Deploymentを通して運用するのが一般的です(Deploymentが内部でReplicaSetを生成・管理する仕組み)。
- ReplicationControllerの後継
- ReplicaSetは、旧来のReplicationControllerを置き換える存在として位置づけられていますが、機能面ではほぼ同等です。
ReplicaSetの具体例
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: sample-replicaset
spec:
replicas: 2
selector:
matchLabels:
app: sample-rs
template:
metadata:
labels:
app: sample-rs
spec:
containers:
- name: sample-rs-container
image: nginx:1.19
ports:
- containerPort: 80
指定したreplicas: 2
の数だけPodが稼働します。
Deploymentを使わない場合、こちらのReplicaSetリソースを直接定義してもよいですが、多くのシーンではローリングアップデートなどが便利なDeploymentを利用します。
DaemonSet
DaemonSetとは
- クラスタ内の各ノードで必ず1つのPodを稼働させるためのコントローラ
- ログ収集エージェントや監視エージェントなど、全ノードで動かす必要があるアプリケーションに適しています。
- ノード追加時にも自動でPodが配置される
- ノードがスケールアウトされると、自動的に新たなノード上にもPodが作成されます。
- 特定のノードプールに限定も可能
nodeSelector
やtolerations
などを使って、特定のラベルを持つノードだけに配置することも可能です。
DaemonSetの具体例
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: sample-daemonset
spec:
selector:
matchLabels:
app: sample-daemon
template:
metadata:
labels:
app: sample-daemon
spec:
containers:
- name: log-agent
image: fluentd:latest
ports:
- containerPort: 24224
全ノードでFluentdコンテナを起動し、ログを収集するようなユースケースを想定した例です。
ノードが増えれば、そのノード上にも自動でFluentdのPodが立ち上がります。
Job
Jobとは
- 一度きりの処理・バッチジョブを実行するためのコントローラ
- 長期間常駐するサービスではなく、特定のタスクやバッチ処理を一度走らせ、完了したらPodを停止させるようなユースケースに使われます。
- Jobは「完了(成功)状態」のPodが指定数分(通常1つ)達成されると終了します。
- 並列実行や再試行などが柔軟に設定可能
completions
やparallelism
を指定することで、同時実行数や成功完了数をコントロールできます。
Jobの具体例
apiVersion: batch/v1
kind: Job
metadata:
name: sample-job
spec:
completions: 1
parallelism: 1
template:
metadata:
name: sample-job-pod
spec:
restartPolicy: Never
containers:
- name: batch-container
image: busybox
command: ["sh", "-c", "echo 'Hello from Job'; sleep 5"]
上記例では、BusyBoxコンテナを実行して「Hello from Job」というメッセージを表示し、5秒後に終了します。
completions: 1
とparallelism: 1
により、単一のPodが成功完了すればジョブ全体が終了します。
ワークロードリソースの比較
いろいろ出てきてなんのこっちゃってなったので比較していきます。
リソース | 主な用途 | ポッドのID管理 | ローリングアップデート | レプリカ数の制御 | ユースケース例 |
---|---|---|---|---|---|
Deployment | ステートレスアプリケーションの管理 | 匿名的(Pod名は流動的) | サポート(ローリング更新、ロールバック機能あり) | サポート(replicasで指定) | Webアプリケーション、APIサーバなど |
StatefulSet | ステートフルアプリケーションの管理 | 固定的(<名前>-<番号>) | 一部サポート(順序立てた更新) | サポート(replicasで指定) | データベース、分散キャッシュなど |
ReplicaSet | 指定数のPodレプリカを常に維持 | 匿名的(Pod名は流動的) | 部分的(Deploymentほど柔軟でない) | サポート(replicasで指定) | Deployment内部で使用、手動運用はまれ |
DaemonSet | 全ノードでPodを1つずつ実行 | 匿名的(Pod名は流動的) | 原則なし(段階更新は工夫が必要) | ノード数に依存 | ログ収集、監視エージェントなど |
Job | 一度きりのタスクやバッチ処理 | 匿名的(Pod名は流動的) | 該当なし(完了したら終了) | サポート(completionsなどで指定) | バッチ処理、バックアップ、移行スクリプトなど |
簡単な補足
- PodのID管理
- DeploymentやReplicaSet、DaemonSet、Jobなどは、Pod名が常に一定ではなく再作成時に変化しやすいです。
- StatefulSetでは、Pod名に通し番号(ordinal)が含まれるため、ステートフルなデータを扱う際に便利です。
- ローリングアップデート
- Deployment はロールバック機能も含め、もっとも充実したステートレス運用が可能です。
- StatefulSet でも順序立てたアップデートは可能ですが、途中でエラーが発生すると後続が進まないなど、少し動作が異なります。
- DaemonSet や Job は、概念上ローリングアップデートは想定していません(DaemonSetで段階的に更新する方法はあるが、明示的な機能としては限定的)。
- レプリカ数の制御
- Deployment や ReplicaSet、StatefulSet は、
spec.replicas
の数を変更することでスケールアップ/ダウンが容易です。 - DaemonSet は、ノード数に合わせて自動的にPod数が決まるため、ユーザーが
replicas
を指定する必要はありません。 - Job には
parallelism
やcompletions
といったパラメータがあり、タスクの並列実行や完了数などを制御できます。
- Deployment や ReplicaSet、StatefulSet は、
- ユースケース例
- Deployment は最も一般的なステートレスワークロード向け。
- StatefulSet はデータベースや分散ストレージなど、Podの永続IDが重要なケースで利用。
- ReplicaSet はDeploymentの内部で生成されることがほとんどで、単独で使う場面は少なめ。
- DaemonSet はノードごとに必ず動かす必要のあるエージェント系で使用。
- Job はバッチ的処理、単発・定期実行のタスク(定期実行はCronJob)で使用。
理解しやすかったですね、次にサービスについてみていきます。
Service
Serviceとは
- Podへの永続的なアクセスを提供する仕組み
- Podは名前をつけて直接アクセスするには不安定です。Podのレプリカが増減したり、再起動したりするため、常に同じPodが存在するわけではありません。
- ロードバランシング機能
- Serviceを介してアクセスすることで、裏側でPodが増減しても問題なく負荷分散されます。
Serviceのタイプ
- ClusterIP(デフォルト)
- クラスター内部のみで通信を受け付けたい場合に使用。Serviceに対して仮想的なIPアドレスが割り当てられる。
- NodePort
- ノードの特定ポート(静的なポート)を外部に公開し、そこからServiceへとトラフィックを転送するタイプ。(<NodeIP>:<NodePort>にアクセスすることによってServiceにアクセスできるようになります。)
- LoadBalancer
- クラウドプロバイダのロードバランサと連携し、外部にも公開するタイプ。(MetalLBなどオンプレミスでも利用可能になるロードバランサーもあります。)
- ExternalName
- DNSのCNAMEレコードを返すことで外部サービスを内部から参照できるようにするタイプ。
Serviceの具体例
apiVersion: v1
kind: Service
metadata:
name: sample-service
spec:
selector:
app: sample
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
selector
により、「app=sample
」というラベルを持つPodがバックエンドとして紐付けられます。
複数のPodに同じラベルをつけておけば、Pod群にトラフィックが負荷分散されます。
Ingress
Ingressとは
- HTTP/HTTPS経由の外部アクセスを制御するための仕組み
- ServiceはKubernetes内部もしくはNodePort/LoadBalancerで外部に公開できますが、複雑なルーティングやSSL/TLS終端などを扱う場合はIngressを使用します。
- Ingress Controllerが必要
- 実際にトラフィックを転送するのはIngress Controller(例:NGINX Ingress Controller、Traefikなど)で、Ingressリソースで記載されたルールに従い、トラフィックをServiceへ振り分けます。
Ingressの具体例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sample-ingress
spec:
rules:
- host: sample.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: sample-service
port:
number: 80
host: sample.example.com
に対するリクエストは、sample-service
のポート80へ転送されます。- Ingressを利用するには、クラスタ上に対象のIngress Controllerが正しくデプロイされている必要があります。
サービスはもっとありますがいったん確認したいことは終わったので一旦終わります。また更新します。