この記事は Kubernetes 1.5.2 で確認した情報を元に記載しています。
Deployment
Deployment
はローリングアップデートやロールバックといったデプロイ管理の仕組みを提供するものです。
Deployment の仕組み
下記の図のようにDeployment
はReplicaSet
を生成・管理し、ReplicaSet
はPod
を生成・管理します。
ReplicaSet
(ReplicationController
の後継)はPodTemplate
と呼ばれるPod
のテンプレートをもとに、Pod
を指定された数(レプリカ数)に調整・管理を行う仕組みです。Pod
がレプリカ数より足りない場合はPod
を追加し、多い場合はをPod
を削除します。この仕組みによってノードの障害やアプリケーションのクラッシュでPod
が足りなくなった際も自動的にPod
が追加され、セルフヒーリングが実現されています。
Deployment
はコンテナイメージのバージョンアップなどアップデートがあった場合、新しい仕様のReplicaSet
を作成し、新旧の全体Pod
数を調整しながら新しい仕様のPod
に置き換えていきます。これによりローリングアップデートが実現されます。ただし、レプリカ数のみ変更の場合は新しいReplicaSet
は作成せず、現在のReplicaSet
のレプリカ数を変更します。新旧のPod
ともに共通するラベルを持っておりローリングアップデート中はService
を通して新旧のバージョンが混ざってサービス提供される形になります。
リソース | 役割 |
---|---|
Deployment |
ReplicaSet を生成、管理しローリングアップデートやロールバックといったデプロイ管理を行います。 |
ReplicaSet |
同じ仕様のPod のレプリカ数を管理します。ReplicationController の後継に当たるものです。 |
Pod |
アプリケーションを動かすための最小単位。1つ以上のコンテナと共有されたボリュームで構成されます。 |
ローリングアップデートが終わった後もアップデート前のReplicaSet
は一定数保持されます。これによりロールバックが可能になっています。
Deployment の定義
以下はDeployment
の定義例になります。下記の内容をdeployment-example.yaml
という名前で保存したとします。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
# Deploymentの名前。Namespace内ではユニークである必要があります
name: deployment-example
spec:
# レプリカ数の指定
replicas: 2
# Podのテンプレート(PodTemplate)
template:
metadata:
labels:
# ラベル指定は必須
app: deployment-example
spec:
containers:
- name: nginx
image: nginx:1.10
ports:
- containerPort: 80
.spec.template
はPodTemplate
と呼ばれるPod
のテンプレートになります。このPodTemplate
をもとにReplicaSet
がレプリカ数分のPod
を生成・管理します。またDeployment
が配下のReplicaSet
とReplicaSet
が管理するPod
を管理するためにラベルが必要となり、.spec.template.metadata.labels
で指定する必要があります。
Deployment のデプロイ
定義したDeployment
をデプロイをしてみます。ここでは操作履歴を残すために--record
オプションを指定してkubectl
のコマンドをアノテーションに保存するように指定しています。
$ kubectl create -f deployment-example.yaml --record
deployment "deployment-example" created
デプロイできたか確認してみます。
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment-example 2 2 2 2 22m
--selector
オプションで設定したラベルを指定して関連リソースを見てます。
$ kubectl get deployments,replicasets,pods --selector app=deployment-example
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/deployment-example 2 2 2 2 30s
NAME DESIRED CURRENT READY AGE
rs/deployment-example-2748039730 2 2 2 30s
NAME READY STATUS RESTARTS AGE
po/deployment-example-2748039730-k5c5j 1/1 Running 0 30s
po/deployment-example-2748039730-p85gg 1/1 Running 0 30s
Deployment の変更
次にDeployment
の情報を変更してみます。ここでは nginx のバージョンを変更してみます。先程のdeployment-example.yaml
を編集し、nginx のバージョンを 1.11 にしてみます。
# 省略...
spec:
containers:
- name: nginx
image: nginx:1.11 # 1.10から1.11に変更
ports:
- containerPort: 80
変更を反映させます。
$ kubectl apply -f deployment-example.yaml --record
deployment "deployment-example" configured
変更されたか見てみます。ローリングアップデートで新旧のPod
の数を調整しながらアップデートされていきます。
$ kubectl get deployments,replicasets,pods --selector app=deployment-example
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/deployment-example 2 2 2 2 7m
NAME DESIRED CURRENT READY AGE
rs/deployment-example-2748039730 0 0 0 7m # 古いバージョンのReplicaSet。レプリカ数が0に
rs/deployment-example-2829304371 2 2 2 27s # 新しいバージョンのReplicaset。レプリカ数が2に
NAME READY STATUS RESTARTS AGE
po/deployment-example-2829304371-33x2x 1/1 Running 0 27s # Podは再生成される
po/deployment-example-2829304371-szbxm 1/1 Running 0 27s
アップデート中は下記の図のような状態になっています。アップデートが終わっても古いバージョンのReplicaSet
は履歴管理のために残ります。
Pod
のコンテナのバージョンが新しくなっていることを確認してみます。
$ kubectl describe pods --selector=app=deployment-example
...
Controllers: ReplicaSet/deployment-example-2829304371
Containers:
nginx:
Container ID: docker://a7adf603e653826d4092d8b1340f985584767080c47a5d23895c438ed5d4d813
Image: nginx:1.11 # コンテナのバージョンが新しくなっていれば成功
Image ID: docker://sha256:01f818af747d88b4ebca7cdabd0c581e406e0e790be72678d257735fad84a15f
Port: 80/TCP
...
ロールバック
Deployment
の特徴にロールバックがあります。デプロイの履歴を見てみます。
$ kubectl rollout history deployment deployment-example
deployments "deployment-example"
REVISION CHANGE-CAUSE
1 kubectl create -f deployment-example.yaml --record
2 kubectl apply -f deployment-example.yaml --record
リビジョンの詳細は下記のコマンドで確認できます。
$ kubectl rollout history deployment deployment-example --revision=2
deployments "deployment-example" with revision #2
Labels: app=deployment-example
pod-template-hash=2829304371
Annotations: kubernetes.io/change-cause=kubectl apply -f deployment-example.yaml --record
Containers:
nginx:
Image: nginx:1.11
Port: 80/TCP
Volume Mounts: <none>
Environment Variables: <none>
No volumes.
リビジョンを指定してロールバックしてみます。--to-revision
オプションを指定しない場合は直前のリビジョンになります。
$ kubectl rollout undo deployment deployment-example --to-revision=1
deployment "deployment-example" rolled back
nginx コンテナのバージョンが 1.11 から 1.10 にロールバックされていることを確認します。ロールバックまで少し時間がかかる場合があります。
$ kubectl describe pods --selector=app=deployment-example
...
Containers:
nginx:
Container ID: docker://fae4d04753243119bf5840fefd820353766eddfd9dd75a628ea1e56673cf3828
Image: nginx:1.10 # 1.10に戻っている
Image ID: docker://sha256:c2d83d8cde8d6b13e774170f85d87829736e6614a8be33479bb7f8bd7f12dd06
Port: 80/TCP
デプロイの履歴を見てみます。リビジョン1の行がなくなり、リビジョン3(最新)になっていることがわかります。
$ kubectl rollout history deployment deployment-example
deployments "deployment-example"
REVISION CHANGE-CAUSE
2 kubectl apply -f deployment-example.yaml --record
3 kubectl create -f deployment-example.yaml --record # 1から3(最新)に変更された
なおデプロイの履歴は内部的には過去のReplicaSet
で管理されており、ロールバックは過去のReplicaSet
の切り替えることで行われています。リビジョンやコマンドの履歴といった情報はReplicaSet
のアノテーションとして保存されています。
補足: Deployment のラベル
Deployment
ではspec.template.metadata.labels
設定したラベルが自動的にDeployment
のセレクタ(.spec.selector.matchLabels
)に設定されるようになっています。
$ kubectl get deployment deployment-example -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
...
spec:
replicas: 2
selector:
# 自動的に設定される
matchLabels:
app: deployment-example
...
template:
metadata:
creationTimestamp: null
labels:
# マニフェストで設定した値
app: deployment-example
...
Deployment
のspec.template.metadata.labels
の値はReplicaSet
のラベルとセレクタの一部とPod
のラベルに使われています。またReplicaSet
ごとに配下のPod
を識別するためにpod-template-hash
というPodTemplate
から生成したハッシュ値を持っています。
$ kubectl get replicaset -l app=deployment-example -o yaml
...
- apiVersion: extensions/v1beta1
kind: ReplicaSet
spec:
replicas: 2
selector:
# このセレクタでPodを選択する
matchLabels:
# deploymentで指定したラベル
app: deployment-example
# Podを識別するためのPodTemplateから作られたハッシュ値
pod-template-hash: "2748039730"
template:
metadata:
creationTimestamp: null
labels:
# セレクタと同じ値
app: deployment-example
pod-template-hash: "2748039730"
Pod
のReplicaSet
が持つセレクタと同じラベルが設定されています。
$ kubectl get pods -l app=deployment-example -o yaml
...
- apiVersion: v1
kind: Pod
metadata:
...
labels:
app: deployment-example
pod-template-hash: "2748039730"
下記の図ではDeployment
のspec.template.metadata.labels
がapp=myapp
だった場合のラベルの付け方を説明しています。新旧のPod
ともに共通のapp=myapp
というラベルがあるためローリングアップデート中もService
を通して断続なくサービス提供でき、新旧で異なるpod-template-hashというラベルがあるため個別にも管理
できる仕組みになっています。
まとめ
-
Deployment
はローリングアップデートやロールバックといったデプロイ管理の仕組みを提供します - 同じ仕様の
Pod
を管理するReplicaSet
とアプリケーションを動作させる最小単位のPod
で構成されています - 履歴が管理されておりロールバックが可能です