OpenShiftのサービスとPodを全て安全に停止する

Red HatでOpenShiftのサポートをしているid:nekopです。OpenShift 全部俺 Advent Calendar 2018 - Qiitaの17日目のエントリです。

レアなユースケースですが、クラスタを全停止したい、というケースがあります。単にホストをシャットダウンした場合は安全な停止手段であるdrainなどは行われず、単なるdockerサービスの停止になってしまい、デフォルトのdocker stopの挙動であるTERM送信10秒タイムアウトKILL送信強制終了となります。Podに定義されている安全な停止タイムアウトなどは無視されます。データ書き込み途中で強制killされて次回データ不整合で起動しない、といった事象で泣かない人は直接ホストをシャットダウンしたりdockerサービスを停止したりしてもいいかもしれません。

OpenShift 3.11の通常のAnsibleでのセットアップでの完全停止は以下のような手順となります。この手順は手動実行でのおおまかな流れを示すものであり、前コマンドの結果確認などを一切含んでいません。そのままスクリプト化して実行すると危険なので注意してください。

# Stop all non-DaemonSet pods
oc adm drain -l "a!=" --delete-local-data --ignore-daemonsets
# Stop master api, controllers and etcd
ansible masters -m shell -a "mv /etc/origin/node/pods /etc/origin/node/pods.stop"
# Stop atomic-openshift-node service
ansible nodes -m shell -a "systemctl stop atomic-openshift-node"
# Stop DaemonSet containers
ansible nodes -m shell -a "docker ps -q | xargs docker stop --time 120"
# Stop docker service
ansible nodes -m shell -a "systemctl stop docker"

Ansibleコマンドについてはもちろんより適切なmoduleを利用することもできますが、慣れていない方もストレートに読めるようにここではあえてshellモジュールで記述しています。

一番重要なのはoc adm drainです。このdrainによりノード上のワークロードpodが通常終了して他ノードに退避されます。drain以外のステップはあまり重要ではなく、オプショナルと言ってもいいでしょう。drainさえ行なえば大抵そのまま停止とかリブートとかしても大丈夫です。

ノードセレクタに-l "a!="という一見奇妙な指定がありますが、否定条件を記述することで全てのノードがマッチする、というハックです。本来なら空のセレクタが全てにマッチするのですが、oc adm drainoc adm cordonは空のセレクタ指定を受け付けません。

OpenShift 3.11ではmaster api, controllers, etcdはstatic podなので、停止するにはstatic podの定義ファイルをmvする必要があります。

Kubernetes 1.11 (OpenShift 3.11)まではDaemonSetは通常のスケジューラではなくDaemonSet Controllerによる特殊なスケジューリングがされますので、drainとPod削除では対応できず別に扱う必要があります。Kubernetes 1.12からはDaemonSetも通常のスケジューリングがされるのでschedulableフラグで制御できます。

上記の例ではDaemonSetは面倒なのでdocker stopで直接停止しています。念の為タイムアウトは長めの設定にしています。もっと正攻法でDaemonSetを停止したい、という場合はDaemonSetのnodeSelectorかnodeのラベルを書き換えてpodを削除して再デプロイされないようにする、というような手順が必要です。

PodDisruptionBudgetを設定している場合は当然PodのReady数が確保できずdrainはタイムアウトするので、PodDisruptionBudgetを削除したりoc delete podするなどの対応が必要となります。

再開する場合は逆順です。

ansible nodes -m shell -b -a "systemctl start docker"
ansible nodes -m shell -b -a "systemctl start atomic-openshift-node"
ansible masters -m shell -b -a "mv /etc/origin/node/pods.stop /etc/origin/node/pods"
oc adm uncordon -l "a!="

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。