kubernetes

全ての Pod を一発でリロードさせる方法

前提条件:

  • Deployment を使ってアプリケーションのデプロイ管理を行っている

tl;dr

PodTemplateSpec の Label か Annotation (.spec.template.metadata.[labels|annotations]) に適当な key-value を追加・上書きする。
value はタイムスタンプにでもしておくと便利。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: awesome-app
  labels:
    name: awesome-app
    role: web
spec:
  minReadySeconds: 30
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 50%
      maxUnavailable: 0
  replicas: 20
  template:
    metadata:
      name: awesome-app
      labels:
        name: awesome-app
        role: web
      annotations:
        reloaded-at: "20171217190756" # <========== これ

シェルコマンド一発でやるなら以下。エイリアス作っておくと便利。

# "frontend" Deployment 配下の Pod を全部リロードする
$ kubectl patch deployment frontend -p \
  "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"reloaded-at\":\"`date +'%Y%m%d%H%M%S'`\"}}}}}"

Why

Kubernetes で Pod に設定を注入するには ConfigMap や Secret が主に使われます。
これらの中身は Pod 起動時に Pod へコピーされる仕組みとなっているため、アプリケーション起動中に中身を変更してもそれが即反映されるわけではありません。
Pod を作りなおす必要があります。

じゃあどうするか?

今動いている Pod を消す

Running Pod を消せば、ReplicaSet の設定に基づいて Pod が必要な数だけ再作成されます。
…が、当然ながら相当乱暴なやり方です。

Deployment の仕組みに則ってデプロイする

通常のデプロイだと、kubectl set image などで PodTemplateSpec にある Docker image tag を更新して新しい Pod をデプロイします。
しかし、Kubernetes では差分のない PodTemplateSpec を再度デプロイすることはできません。
つまり、通常のオペレーションでは同じ Docker image をデプロイすることができません。

What

PodTemplateSpec に差分が発生すれば新しい ReplicaSet が作られて Pod がデプロイされます。
なので Docker image や環境変数以外のアプリケーション動作に影響しない Pod spec、つまり Label や Annotation を編集すればよいのです。

いつリロードしたのかわかりやすいように、注入する値はタイムスタンプにでもしておくとよいでしょう。

Deployment の設定に基づいて Pod の再作成が行われるので、(設定をちゃんとしていれば)パフォーマンス劣化やダウンタイムが発生することもない graceful restart となります。

Ref