はじめに
Kubernetesについての初心者向けまとめ兼自分のメモです。なお、この記事は「Docker/Kubernetes 実践コンテナ開発入門」という技術書の内容に則っています。
Kubernetesとは
KubernetesはGoogle社主導で開発された、コンテナの運用を自動化するためのコンテナオーケストレーションシステムです。コンテナオーケストレーションを実現・管理するための統合的なシステムであり、その操作のためのAPIやCLIツールも併せて提供されています。
Kubernetesの概念
Kubernetesで実行されるアプリケーションは様々なリソースと協調して動作することで成立しています。Kubernetesのリソースとは、アプリケーションのデプロイ構成するための部品のようなもので以下のようなものがあります。
リソース名 | 用途 |
---|---|
Node | Kubernetesクラスタで実行するコンテナを配置するためのサーバ |
Namespace | Kubernetesクラスタ内で作る仮想的なクラスタ |
Pod | コンテナ集合体の単位で、コンテナを実行する方法を定義する |
ReplicaSet | 同じ仕様のPodを複数生成・管理する |
Deployment | ReplicaSetの世代を管理する |
Service | Podの集合にアクセスするための経路を定義する |
Ingress | ServiceをKubernetesクラスタの外に公開する |
ConfigMap | 設定情報を定義し、Podに供給する |
PersistentVolume | Podが利用するストレージのサイズや種別を定義する |
PersistentVolumeClaim | PersistentVolumeを動的に確保する |
StorageClass | PersistentVolumeが確保するストレージの種類を定義する |
StatefulSet | 同じ仕様で一貫性のあるPodを複数生成・管理する |
Job | 常駐目的ではない複数のPodを作成し、正常終了することを保証する |
CronJob | cron記法でスケジューリングして実行されるJob |
Secret | 認証情報等の機密データを定義する |
Role | Namespace内で操作可能なKubernetesリソースのルールを定義する |
RoleBinding | RoleとKubernetesリソースを利用するユーザーを紐づける |
ClusterRole | Cluster全体で操作可能なKubernetesリソースのルールを定義する |
ClusterRoleBinding | ClusterRoleとKubernetesリソースを利用するユーザーを紐づける |
ServiceAccount | PodにKubernetesリソースを操作させる際に利用するユーザー |
KubernetesクラスタとNode
KubenetesクラスタはKubernetesの様々なリソースを管理する集合体のことを指します。NodeはKubernetesクラスタの管理下に登録されているDockerホストのことでKubernetesでコンテナをデプロイするために利用されます。Kubernetesクラスタは以下のようにMasterとNode郡によって構成されます。
Master Nodeにデプロイされるコンポーネントの役割は以下のようになっています。
コンポーネント名 | 役割 |
---|---|
kube apiserver | KubernetesのAPIを公開するコンポーネント。kubectlからのリソース操作を受け付ける |
etcd | 高可用性を備えた分散キーバリューストアでKubernetesクラスタのバッキングストアとして利用される |
kube scheduler | Nodeを監視し、コンテナを配置する最適なNodeを選択する |
kube controller manager | リソースを制御するコントローラーを実行する |
Namespace
kubernetesはクラスタの中に入れ子となる仮想的なクラスタを作成できます。これがNamespaceという概念です。クラスタを構築するとあらかじめdefault,docker,kube-public,kube-systemというNamespaceが用意されます。Namespaceごとに操作権限を用意できるのでより堅牢で細やかな権利制御を実現できます。
Pod
Podの概要
Podはコンテナの集合体の単位で、少なくとも1つのコンテナを持ちます。Podは以下のようにどこかのNodeに配置されるようになっています。同じPodを複数のNodeに配置する、1つのNodeに複数配置することも可能です。
Podの作成
作成するPodは以下のようにyamlファイル(マニフェストファイル)で定義します。ここでは例としてプロキシの役割をもつNginxとアプリケーションであるechoで構成されるPodを定義します。(イメージは既に作成済みとします)
apiVersion: v1
kind: Pod # リソースの種類の指定
metadate:
name: echo # リソース名
spec: # kind属性の値次第でspec以下のスキーマが変わる
containers: # コンテナ郡の指定
- name: nginx # コンテナ名
image: example/nginx:latest # イメージ保存先
env: # 環境変数の指定
- name: BACKEND_HOST
value: localhost:8080
ports: # EXPOSEするポートの指定
- containerPort: 80
- name: echo
image: example/echo:latest
ports:
- containerPort: 8080
このファイルで定義したPodをKubernetesクラスタに反映させるには以下のコマンドを実行します。
$ kubectl apply -f echo.yaml
pod "echo" created
以降に紹介するリソースも同様のコマンドで反映させることができます。
Podの操作
Podの状態の確認
Podの状態は以下のコマンドを実行することで一覧取得できます。STATUSがRunningになっていればPod内の全てのコンテナが実行状態になったことを示します。READYの分母はPodに定義されたコンテナ数、分子は実行状態になったコンテナ数を表します。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
echo 2/2 Running 0 11m
コンテナ内でのコマンド実行
以下のコマンドでコンテナ内でコマンドを実行することができます。
# kubectl exec -it Pod名 コマンド -c コンテナ名
$ kubectl exec -it echo sh -c nginx
#
コンテナの標準出力表示
# kubectl logs -f Pod名 -c コンテナ名
$ kubectl logs -f echo -c echo
Podの削除
# kubectl delete pod Pod名
$ kubectl delete pod echo
# kubectl delete -f マニフェストファイル名
$ kubectl delete -f echo.yaml
PodとPod内コンテナのアドレス
Podにはそれぞれ固有の仮想IPアドレスが割り振られます。Podに割り振られた仮想IPアドレスはそのPod内の全てのコンテナと共有されます。
ReplicaSet
ReplicaSetは同じ仕様のPodを複数生成・管理するためのリソースです。例としてReplicaSetを記述したマニフェストファイルecho-replicaset.yamlを示します。
apiVersion: apps/v1
kind: ReplicaSet # リソースの種類の指定
metadate:
name: echo # リソース名
labels:
app: echo
spec: # kind属性の値次第でspec以下のスキーマが変わる
replicas: 3 # Pod数
selector:
matchLabels:
app: echo
template:
metadate:
labels:
app: echo
spec:
containers: # コンテナ郡の指定
- name: nginx # コンテナ名
image: example/nginx:latest # イメージ保存先
env: # 環境変数の指定
- name: BACKEND_HOST
value: localhost:8080
ports: # EXPOSEするポートの指定
- containerPort: 80
- name: echo
image: example/echo:latest
ports:
- containerPort: 8080
ReplicaSetを操作してPodの数を減らすと、減らした分のPodは削除されます。削除されたPodを復元することはできません。そのためWebアプリケーションのようなステートレスな性質を持つPodの利用に向いています。
Deployment
ReplicaSetより上位のリソースとしてDeploymentというリソースがあります。Deploymentはアプリケーションデプロイの基本単位となるリソースです。DeploymentはReplicaSetを管理・操作するために提供されているリソースです。例としてDeploymentを記述したマニフェストファイルecho-deployment.yamlを示します。
apiVersion: apps/v1
kind: Deployment # リソースの種類の指定
metadate:
name: echo # リソース名
labels:
app: echo
spec: # kind属性の値次第でspec以下のスキーマが変わる
replicas: 3 # Pod数
selector:
matchLabels:
app: echo
template:
metadate:
labels:
app: echo
spec:
containers: # コンテナ郡の指定
- name: nginx # コンテナ名
image: example/nginx:latest # イメージ保存先
env: # 環境変数の指定
- name: BACKEND_HOST
value: localhost:8080
ports: # EXPOSEするポートの指定
- containerPort: 80
- name: echo
image: example/echo:latest
ports:
- containerPort: 8080
Deploymentの定義はReplicaSetと大差ありません。違いはDeploymentがReplicaSetの世代管理を可能にする点です。Deploymentのリビジョンは以下のコマンドで確認できます。
$ kubectl rollout history deployment echo
deployments "echo"
REVISION CHANGE-CASE
1 kubectl apply --filename=echo-deployment.yaml --record=true
Service
Serviceはkubernetesクラスタ内において、Podの集合(主にReplicaSet)に対する経路やサービスディスカバリを提供するためのリソースです。例として2つのReplicaSetを記述したマニフェストファイルecho-ReplicaSet-with-label.yamlを示します。
apiVersion: apps/v1
kind: ReplicaSet # リソースの種類の指定
metadate:
name: echo # リソース名
labels:
app: echo
release: spring # ラベル
spec: # kind属性の値次第でspec以下のスキーマが変わる
replicas: 1 # Pod数
selector:
matchLabels:
app: echo
release: spring
template:
metadate:
labels:
app: echo
release: spring
spec:
containers: # コンテナ郡の指定
- name: nginx # コンテナ名
image: example/nginx:latest # イメージ保存先
env: # 環境変数の指定
- name: BACKEND_HOST
value: localhost:8080
ports: # EXPOSEするポートの指定
- containerPort: 80
- name: echo
image: example/echo:latest
ports:
- containerPort: 8080
---
apiVersion: apps/v1
kind: ReplicaSet # リソースの種類の指定
metadate:
name: echo # リソース名
labels:
app: echo
release: summer # ラベル
spec: # kind属性の値次第でspec以下のスキーマが変わる
replicas: 2 # Pod数
selector:
matchLabels:
app: echo
release: summer
template:
metadate:
labels:
app: echo
release: summer
spec:
containers: # コンテナ郡の指定
- name: nginx # コンテナ名
image: example/nginx:latest # イメージ保存先
env: # 環境変数の指定
- name: BACKEND_HOST
value: localhost:8080
ports: # EXPOSEするポートの指定
- containerPort: 80
- name: echo
image: example/echo:latest
ports:
- containerPort: 8080
release=summerを持つPodだけにアクセスできるようなServiceを定義したマニフェストファイルを以下のように作成します。
apiVersion: v1
kind: Service
metadate:
name: echo
spec:
selector:
app: echo
release: summer
ports:
- name: http
port: 80
このServiceとラベル付で区別されたPodとの関係を表しているのが次の図です。
Ingress
kubenetesクラスタの外にServiceを公開するためにはServiceをNodePortで公開することで可能ですが、この手法はあくまでL4層レベルまでしか扱えないため、HTTP/HTTPSのようにパスベースで転送先のServiceを切り替えるといったL7層レベルの制御までは行えません。これを解決するためのリソースがIngressです。ServiceのKubernetesクラスタの外への公開と、パスベースでの高度なHTTPルーティングを両立します。例として以下のServiceを考えます。
apiService: v1
kind: Service
metadata:
name: echo
spec:
selector:
app: echo
ports:
- name: http
port: 80
このServiceをKubernetesクラスタの外へ公開するためのIngressは以下のように定義できます。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echo
spec:
rules:
- host: example.local
http:
paths:
- path: /
backend:
serviceName: echo
servicePort: 80
PersistentVolumeとPersistentVolumeClaim
kubernetesではストレージを確保するためにPersistentVolumeとPersistentVolumeClaimというリソースが提供されています。これらはクラスタが提供されているプラットフォームnに対応した永続ボリュームを作成するためのリソースです。PersistentVolumeはストレージの実体(GCPではGCEPersistentDisk)で、PersistentVolumeClaimはPersistentVolumeに対して必要な容量を動的に確保できます。PersistentVolumeClaimのマニフェストファイルのイメージは次のようなものです。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes: # ストレージへのマウントポリシー
- ReadWriteOnce
storageClassName: ssd # StorageClassリソースの名前
resources:
requests:
storage: 4Gi
StorageClass
StorageClassはPersistentVolumeが確保するストレージの種類を定義できるリソースです。StorageClassのマニフェストファイルのイメージは次のようなものです。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ssd
annotation:
storageclass.kubernetes.io/is-default-class: "false"
labels:
kubernetes.io/cluster-service: "true"
provisioner: kubernetes.io/gce-pd # GCPの永続ストレージであるGCEPersistentDiskに対応したVolumePlugin
parameters:
type: pd-ssd
StatefulSet
Deploymentは定義されたPod仕様に基づきPodを作成するリソースで、一意性を持つPodや永続かデータを持つ必要がないステートレスなアプリケーションをデプロイするのに向いています。対して、StatefulSetはデータストアのように継続的にデータを永続化するステートフルなアプリケーションの管理に向いたリソースです。DeploymentではPodにランダムな識別子が付与されますが、StatefulSetではpod-0,pod-1,pod-2のような連番で一意な識別子でPodを作成します。マニュフェストファイルの定義はReplicaSetとほとんど同じです。
Job
Jobは1つ以上のPodを作成し、指定された数のPodが正常に完了するまでを管理するためのリソースです。Jobによる全てのPodが正常に終了しても、Podは削除されずに保持されるため、終了後にPodのログや実行結果を分析できます。そのため、Webアプリケーション等の常駐型アプリケーションではなく大規模な計算やバッチ指向のアプリケーションに向いています。Jobのマニフェストファイルのイメージは次のようなものです。
apiVersion: batch/v1
kind: Job
metadata:
name: pingpong
labels:
app: pingpong
spec:
parallelism: 3 # 同時に実行するPod数
template:
metadata:
labels:
app: pingpong
spec:
containers:
- name: pingpong
image: example/alpine:bash
command: ["/bin/sh"]
args:
- "-c"
- |
echo ['date'] ping!
sleep 10
echo ['date'] pong!
restartPolicy: Never # Pod終了時の再実行の設定
Podの状態を確認すると終了したPodはSTATUS=Completedとして表示されます。
CronJob
Jobは一度きりのPodの実行ですが、CronJobリソースを利用するとスケジューリングして定期的にPodを実行できます。CronJobのマニフェストファイルのイメージは次のようなものです。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: pingpong
spec:
schedule: "*/1 * * * *" # Jobのスケジュール(cron記法)
jobTemplate:
spec:
template:
metadata:
labels:
app: pingpong
spec:
containers:
- name: pingpong
image: example/alpine:bash
command: ["/bin/sh"]
args:
- "-c"
- |
echo ['date'] ping!
sleep 10
echo ['date'] pong!
restartPolicy: OnFailure # Pod終了時の再実行の設定
Secret
KubernetesではSecretリソースを定義すると、機密情報の文字列をBase64エンコードした状態で扱えます。Secretのマニフェストファイルのイメージは次のようなものです。
apiVersion: v1
kind: Secret
matadata:
name: example-secret
type: Opaque
data:
.htpasswd: Base64エンコードした機密情報の文字列
Secretリソースを確認すると、Base64を複合した状態のファイルとしてダッシュボードからその内容を確認できます。
(Cluster)Roleと(Cluster)RoleBinding
KubernetesにおけるRBACの仕組み
RBACでの権限制御は、Kubernetes APIのどの操作が可能であるかを定義したロールと、認証ユーザー・グループ・ServiceAccountとロールの紐付けの2つの要素で成立します。2つの要素の関係は以下のような図で表すことができます。
RBACでの権限制御を実現するために、次のようなKubernetesリソースが提供されています。
リソース名 | 内容 |
---|---|
Role | Kubernetes APIへの操作許可のルールを定義し、指定のNamespace内でのみ有効 |
RoleBinding | 認証ユーザー・グループ・ServiceAccountとRoleの紐付けを定義する |
ClusterRole | Kubernetes APIへの操作許可のルールを定義し、クラスタ全体で有効 |
ClusterRoleBinding | 認証ユーザー・グループ・ServiceAccountとClusterRoleの紐付けを定義する |
マニフェストファイル
ClusterRoleとClusterRoleBindingのマニフェストファイルは以下のように記述する。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-reader-binding
subjects: # Roleを紐付ける対象の認証ユーザー
- kind: ServiceAccount
name: user
namespace: default
roleRef: # Role
kind: ClusterRole
name: pod-reader
apiGroup: rbac.authorization.k8s.io