【Kubernetes超入門#04】ReplicaSet、Deployment

Kubernetes超入門04 tech

こんにちは、Mashです。

本記事は、近年大注目されているコンテナオーケストレーション技術である Kubernetes について、図解と実機確認例を交えて解説するシリーズとなります。

今回は第4回。プロダクション環境で求められるPodの冗長化や世代管理についてご紹介します。

Podってなに? というかたがいらっしゃれば前回記事をご参照ください。

今回のゴール
  • Podの冗長化を管理するリソース「ReplicaSet」を理解する
  • ReplicaSetを世代管理するリソース「Deployment」を理解する
  • プロダクション環境で求められる「Podの冗長化」「ローリングアップデート/ロールバック」が実現できるようになる

※本シリーズはLinuxコマンドやネットワーク、Dockerの基礎知識がある方を前提としています。

それではいきましょう!

環境

私の検証環境はこのようになっています。

  • 検証環境はUbuntu Server 20.04 LTSのサーバ1台構成(MasterとNodeを兼任)
  • 検証マシンへSSH接続済み
  • kubectlコマンドでK8sクラスタを操作
  • ノードがインターネットに接続していること
  • Kubernetesバージョンは1.19.4

イメージはこのような状態↓です。

検証環境イメージ図

ReplicaSet

まずはReplicaSetリソースについて。

ReplicaSetとは

ReplicaSet

前回、K8sでコンテナを展開するためにはPodというリソースとして扱う必要があることを学びました。

また、Podの仕様をマニフェストで定義して立ち上げる方法も習得しました。

しかし、これだけではPodに障害が発生した場合にはシステム管理者がまた手動でPodを立ち上げる必要があります

めっちゃ面倒ですよね。

安心してください。K8sにはPodを冗長化する機能があります。

それが ReplicaSet です。

ReplicaSetマニフェストとPodの複製展開

それでは実際にReplicaSetのマニフェストを作成しながらご説明します。

まずはYAMLファイルを作成します。

$ vi nginx-replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
       containers:
       - name: nginx
         image: mash4work/mash-k8s-nginx:1.0
         env:
         - name: TEST_ENV_VALUE1
           value: "01"
         - name: TEST_ENV_VALUE2
           value: "02"
         ports:
         - containerPort: 80

こちらがReplicaSetのマニフェストです。kind「ReplicaSet」と宣言しています。

注目していただきたいのが「template」 以降のセクション。前回使用したPodのマニフェストとほぼ同じ内容になっている点です。

ReplicaSetは「Podがいくつ存在するべきか」を管理する概念なので、ReplicaSetとPodは包含関係にある ということをここで抑えてください。

ReplicaSetの概念

ReplicaSetのマニフェストがあれば、Podのマニフェストは使いません。

それではReplicaSetのマニフェストを使ってPodを展開してみます。

# ReplicaSetマニフェストからPodを展開
$ kubectl apply -f nginx-replicaset.yaml
replicaset.apps/nginx created

# ReplicaSetの状況を確認
$ kubectl get replicasets
NAME               DESIRED   CURRENT   READY   AGE
nginx-c9fff459     3         3         3       8h

# Podの状況を確認
$ kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP             NODE           NOMINATED NODE   READINESS GATES
nginx-mr5nf   1/1     Running   0          16s   10.42.32.142   k8s-master01   <none>           <none>
nginx-rcgpb   1/1     Running   0          16s   10.42.32.143   k8s-master01   <none>           <none>
nginx-z48tn   1/1     Running   0          16s   10.42.32.140   k8s-master01   <none>           <none>

Podが3つ作成されていることが確認できます。

そしてここからがReplicaSetの重要ポイント。
Podをわざと削除してPod障害を起こしてみましょう。

# Podの状況確認
$ kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP             NODE           NOMINATED NODE   READINESS GATES
nginx-mr5nf   1/1     Running   0          65s   10.42.32.142   k8s-master01   <none>           <none>
nginx-rcgpb   1/1     Running   0          65s   10.42.32.143   k8s-master01   <none>           <none>
nginx-z48tn   1/1     Running   0          65s   10.42.32.140   k8s-master01   <none>           <none>

# Podをわざと削除
mash@k8s-master01:~$ kubectl delete pods nginx-mr5nf
pod "nginx-mr5nf" deleted

# 再度Podの状況を確認
mash@k8s-master01:~$ kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE    IP             NODE           NOMINATED NODE   READINESS GATES
nginx-5gn6g   1/1     Running   0          35s    10.42.32.141   k8s-master01   <none>           <none>
nginx-rcgpb   1/1     Running   0          2m1s   10.42.32.143   k8s-master01   <none>           <none>
nginx-z48tn   1/1     Running   0          2m1s   10.42.32.140   k8s-master01   <none>           <none>
-> 新しいPod(nginx-5gn6g)が作成されている!

# いったん環境をお掃除
$ kubectl delete -f nginx-replicaset.yaml

削除したPodのかわりにまた別のPodが起動して、3つの状態を維持してくれています!

これがReplicaSetの特徴、Podの冗長化機能です。

ReplicaSetマニフェスト内で定義したレプリカ数は「Podの個数に関するあるべき姿」で、Podに障害などが発生するとK8sが「あるべき姿」に自動的に戻してくれるわけですね。

これがオートヒーリング機能になります。

Deployment

さて、ReplicaSetでPodのオートヒーリングを実現することができました。これだけでプロダクション環境を運用するには十分でしょうか。

いえ、まだ足りないんです(泣)

つづいてDeploymentリソースについてご説明します。

Deploymentとは

deploy

Deploymentは、ReplicaSetより上位の概念でReplicaSetの世代を管理します。

実際のシステム運用現場では、アプリケーションコードの修正などによりコンテナをバージョンアップしたり、また不具合がみつかった場合にはコンテナをロールバックする必要がでてきます。

こういった作業の度にサービスが全停止していてはお客様に迷惑がかかってしまうので、極力システムに影響を出さずにコンテナを差し替えたいです。

そこで登場するのが Deployment です。

第1回目でK8sは「ローリングアップデート機能」や「ロールバック機能」を持っていることをご紹介しましたが、あれはまさにDeploymentで提供される機能になります。

DeploymentマニフェストとPot展開の世代管理

それではDeploymentのマニフェストを作成します。

$ vi nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
       containers:
       - name: nginx
         image: mash4work/mash-k8s-nginx:1.0
         env:
         - name: TEST_ENV_VALUE1
           value: "01"
         - name: TEST_ENV_VALUE2
           value: "02"
         ports:
         - containerPort: 80

実はDeploymentのマニフェストはReplicaSetとほぼかわりません。kind 指定が変わっているだけです。

これは、DeploymentはReplicaSetの世代を管理するリソースだからです。

Deploymentの概念

ここまでもったいぶってきましたが、Podを展開する場合は基本的にこのDeploymentで管理していきます。

PodやReplicaSetのマニフェストを使うことはありません

それではDeploymentマニフェストからPodを展開します。

$ kubectl apply -f nginx-deployment.yaml --record=true
deployment.apps/nginx created

$ kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE
nginx-c9fff459-bgtdq   1/1     Running   0          31s
nginx-c9fff459-cdtpj   1/1     Running   0          31s
nginx-c9fff459-pj45h   1/1     Running   0          31s

# PodのIPアドレスにcurl
$ curl http://10.42.32.186
<p>Hostname of this container is nginx-c9fff459-bgtdq</p>
<p>version 1.0</p>

# Deploymentの展開履歴を確認
$ kubectl rollout history deploy nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=nginx-deployment.yaml --record=true

さて、ここからがご注目

nginx-deployment.yamlを以下の通り編集してください。

nginxコンテナイメージを2.0にバージョンアップしています。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
       containers:
       - name: nginx
         image: mash4work/mash-k8s-nginx:2.0
         env:
         - name: TEST_ENV_VALUE1
           value: "01"
         - name: TEST_ENV_VALUE2
           value: "02"
         ports:
         - containerPort: 80

Deploymentをアップデートします。

難しいことはなく、これまで実施してきた kubectl apply コマンドでOKです。

# 更新したdeploymentマニフェストを適用
$ kubectl apply -f nginx-deployment.yaml --record=true
deployment.apps/nginx configured

# 1秒ごとに kubectl get pods の結果を表示
$ watch -n 1 'kubectl get pods'

「watch」コマンドはLinuxの基本コマンドで、引数指定したコマンドの結果を定期的に表示してくれます。ここでは kubectl get pods の結果を1秒おきに表示させています。

Podがローリングアップデートされる様子をご覧ください。

おわかりいただけますでしょうか。

新しいPodがRunningになるにつれて古いPodがTerminatingとなり、最終的には新しいPod3つだけが残りました。

Deploymentを使えば、このようにPodを更新したい場合もサービス提供を停止せずにローリングアップデートを実現することが可能になります。

最後にロールバックしてみましょう。

# Podの状況を確認
$ kubectl get pods
NAME                     READY   STATUS        RESTARTS   AGE
nginx-57f7546dc4-8q7ww   1/1     Running       0          24s
nginx-57f7546dc4-hq49d   1/1     Running       0          25s
nginx-57f7546dc4-tvtj5   1/1     Running       0          21s

# PodのIPアドレスにcurl
# バージョンが2.0になっている
$ curl http://10.42.32.191
<p>Hostname of this container is nginx-57f7546dc4-8q7ww</p>
<p>version 2.0</p>

# Deploymentの展開履歴を確認
# 2世代保持していることがわかる
$ kubectl rollout history deployment
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=nginx-deployment.yaml --record=true
2         kubectl apply --filename=nginx-deployment.yaml --record=true

# 現在REVISON2なので、REVISON1へロールバック
$ kubectl rollout undo deployment nginx --to-revision=1
deployment.apps/nginx rolled back

# PodのIPアドレスにcurl
# バージョンが1.0にロールバックできている
$ curl http://10.42.32.132
<p>Hostname of this container is nginx-c9fff459-2rg89</p>
<p>version 1.0</p>

無事にNginxイメージのバージョンが1.0に巻き戻ってくれています。ロールバック成功ですね。

このようにDeploymentはREVISIONというかたちで過去の展開を世代管理していて、ロールバックも非常にかんたんにおこなうことができるようになっています。

もちろんサービス停止はありません。すごい!

まとめ

今回はReplicaSetによるPodの冗長化、DeploymentによるPodの世代管理をご紹介しました。

さきほど触れましたが、Podの展開については基本的にDeploymentで管理します。Podや
ReplicaSetで管理することはありません。

Deployment > ReplicaSet > Pod という包含関係を覚えておきましょう。

さて、ここまででPodをいいかんじに複数展開できるようになったわけですが、PodのIPアドレスは再起動のたびに毎回変わってしまいます。

プロダクション環境でPodのIPを確認して接続して、、、なんてやってられません。

ネットワークの課題

そこで登場するのが Service です。

次回からK8sのネットワークや通信の負荷分散を司るServiceリソースについて学習していきます。

今回は以上です。

それじゃあまたね。

タイトルとURLをコピーしました