July 3, 2019

Azure Container InstancesのGraceful Shutdown事情

何の話か Azure Container Instances(ACI)はサクッとコンテナーを作れるところが幸せポイントですが、停止処理どうしてますか。クライアントとのコネクションをぶっちぎってもいい、何かしらの書き込み処理が中途半端に終わっても問題ない、という人でなければ読む価値があります。 ACIはKubernetesで言うところのポッドを1つから使えるサービスです。概念や用語もKubernetesに似ています。家族や親戚という感じではありますが、”Kubernetesである”とは明言されていないので、その違いは意識しておいたほうがいいでしょう。この記事ではコンテナーの停止、削除処理に絞って解説します。 Kubernetesのポッド停止処理 Kubernetesのポッド停止については、@superbrothersさんの素晴らしい解説記事があります。 Kubernetes: 詳解 Pods の終了 書籍 みんなのDocker/KubernetesのPart2 第3章でも最新の動向を交えて説明されています。しっかり理解したい人に、おすすめです。 ざっくりまとめると、ポッドをGraceful Shutdownする方法は次の2つです。 PreStop処理を書いて、コンテナー停止に備える コンテナー停止時に送られるシグナルを、適切に扱う ACIでは現在PreStop処理を書けません。なので、シグナルをどう扱うかがポイントです。 DockerのPID 1問題 シグナルハンドリングの前に、DockerのPID 1問題について触れておきます。 Docker and the PID 1 zombie reaping problem Unix/LinuxではプロセスIDの1番はシステム起動時にinit(systemd)へ割り当てられます。そして親を失ったプロセスの代理親となったり、終了したプロセスを管理テーブルから消したりします。いわゆるゾンビプロセスのお掃除役も担います。 しかしDockerでは、コンテナーではじめに起動したプロセスにPID 1が割り当てられます。それはビルド時にDockerfileのENTRYPOINTにexec形式で指定したアプリであったり、シェル形式であれば/bin/sh -cだったりします。 この仕様には、次の課題があります。 コンテナーにゾンビプロセスのお掃除をするinitがいない docker stopを実行するとPID 1のプロセスに対してSIGTERMが、一定時間の経過後(既定は10秒)にSIGKILLが送られる。PID 1はLinuxで特別な扱いであり、SIGTERMのハンドラーがない場合、それを無視する。ただしinitの他はSIGKILLを無視できない。つまりPID 1で動いたアプリは待たされた挙句、強制終了してしまう。また、転送しなければ子プロセスにSIGTERMが伝わらない 前者が問題になるかは、コンテナーでどれだけプロセスを起動するかにもよります。いっぽうで後者は、PID 1となるアプリで意識してSIGTERMを処理しなければ、常に強制終了されることを意味します。穏やかではありません。 解決の選択肢 シグナルハンドリングについては、解決の選択肢がいくつかあります。 SIGTERMを受け取って、終了処理をするようアプリを書く PID 1で動く擬似initを挟み、その子プロセスとしてアプリを動かす PID 1で動く擬似initを挟み、その子プロセスとしてアプリを動かす (シグナル変換) Docker APIを触れる環境であれば、docker run時に–initオプションをつければ擬似init(tini)をPID 1で起動できます。ですがACIはコンテナーの起動処理を抽象化しているため、ユーザーから–initオプションを指定できません。なので別の方法で擬似initを挟みます。 それぞれのやり方と動き ではそれぞれのやり方と動きを見てみましょう。シグナルの送られ方がわかるように、Goで簡単なアプリを作りました。 package main import ( "log" "os" "os/signal" "syscall" ) func main() { sigs := make(chan os. Read more

© Copyright 2019 Toru Makabe

Powered by Hugo & Kiss.