Kubernetes の Deployments を安全にロールバックするラッパーコマンドを書いた

Posted on

Kubernetes の Deployments はリビジョンを保持しているので、簡単にロールバックすることができます。 CLI で実行するなら kubectl rollout undo を実行するだけです。

Kubernetes の宣言的な API のコンセプトを踏まえると、命令的なオペレーションであるロールバックは緊急時以外に行うべきではありませんが、いざという時にすぐにロールバックできるのは開発者にとって安心感があります(望ましい方法は直前のデプロイで入った Pull Request を Revert してデプロイし直すことです)。

先日とあるマイクロサービスをデプロイしたところ、そのデプロイが起因となって MySQL の負荷が上がり CPU が 100% に張り付きました。幸いユーザーにはまだ公開していない機能だったので障害にはなりませんでしたが、アラートが飛んでいる状況で冷静にロールバックすることは難しかったです。

具体的には、次のような点が難しかったです。

  • 普段使うことのない kubectl のサブコマンドを正確に覚えていない
  • ロールバック先のリビジョン内容を確認してからロールバックしたい

というわけで、簡単なラッパーコマンドを書きました。

ロールバックを試してみる

nginx の Docker イメージを使った Deployments を書いて、バージョン番号をインクリメントしながら kubectl apply していきます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
      annotations:
        kubernetes.io/change-cause: nginx 1.15.4
    spec:
      containers:
      - name: nginx
        image: nginx:1.15.4
        ports:
        - containerPort: 80
$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         nginx 1.15.4
2         nginx 1.15.5
3         nginx 1.15.6
4         nginx 1.15.7

1.15.4 から 1.15.7 までのリビジョンができました。 kubernetes.io/change-cause というアノテーションを追加すれば CHANGE-CAUSE に表示されます。

先ほどのラッパーコマンドに -n namespace-d deployment を引数で渡せば、ロールバック先の Deployments を表示してユーザーのアクションを待ちます。問題なければ enter/return でロールバックを実行します。

$ ./rollback -n default -d nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         nginx 1.15.4
2         nginx 1.15.5
3         nginx 1.15.6
4         nginx 1.15.7

Previous revision:  3
Current revision:   4

deployments "nginx-deployment" with revision #3
Pod Template:
  Labels:   app=nginx
    pod-template-hash=3855055088
  Annotations:  kubernetes.io/change-cause=nginx 1.15.6
  Containers:
   nginx:
    Image:  nginx:1.15.6
    Port:   80/TCP
    Host Port:  0/TCP
    Environment:    <none>
    Mounts: <none>
  Volumes:  <none>

Are you okay? Hit enter:
deployment.apps "nginx-deployment"

履歴を見てみると、もともとリビジョン 3 だったものがなくなってリビジョン 5 になっていますね。

$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         nginx 1.15.4
2         nginx 1.15.5
4         nginx 1.15.7
5         nginx 1.15.6

ロールバックはロールアウトと逆の動きをするだけなので、そのリビジョン番号がなくなって最新のリビジョンとして登録され直すようです。

まとめ

Kubernetes のマネージドサービスも増えて簡単に使い始められるようになりましたが、いざという時に慌てないためにも改めて Deep dive しようと思いました。