先日、「sam local start-api
から実行されるコンテナの
/var/task
の中を確認しようとしたところ、コンテナがすぐに終了してしまうのでちょっとむずかしい」という状況があった.
という訳で、Dockerのイベント(コンテナがスタートした等)に対して何らかのアクションを自動的に実行するような仕組みがあれば便利かな、と思ったので試してみた.
イベントの監視には、以下の docker events
を使う.
試しに $ sudo docker events
を実行し、適当にコンテナの操作を行うことでイベントが表示されることを確認.
今回は $ sam local start-api
から実行されるコンテナの開始を捕捉したいので、以下のようにフィルターを指定する.
- タイプは
container
- イベントは
start
- イメージは
lambci/lambda
$ sudo docker events --filter type=container --filter event=start --filter image=lambci/lambda
アクション(今回は docker exec
)の実行時にコンテナの ID を利用したいので、以下のように ID のみ表示するフォーマットを指定する.
$ sudo docker events --filter type=container --filter event=start --filter image=lambci/lambda --format '{{.Actor.ID}}'
コンテナの ID を受け取って docker exec
を実行する場合は以下のようにする.
$ sudo sh -c "docker events --filter type=container --filter event=start --filter image=lambci/lambda --format '{{.Actor.ID}}' | xargs -I{} docker exec -t '{}' ls -l /var/task"
これで、lambci/lambda
を元にしたコンテナが開始される毎に指定したコマンドが実行されるようになる.
上記の例の場合だとコンテナが稼働している時間が短いので、以下のような結果となることも多い (他のエラーメッセージのパターンもあるが、ようはコンテナが動いてないと返ってくる).
Error response from daemon: Container 3fb957... is not running
あとは、パイプを他のコマンドに繋いだり、複数使ったりするとうまく出力されないことがある.
awk
を挟む場合は system("")
を使ったり、その他では stdbuf -i0 -o0
を使うと回避できることもあるので、おそらくバッファ関連の問題かと推測しているのだけれども、根本的な原因と解決策はよくわかっていない.
上記の例では順次アクションを実行しているが、そこがボトルネックになる可能性がある.
これについては、xargs
を間に挟む場合は -P
で同時に実行できるプロセス(アクション)数を指定できるようなので、
効率が気になる場合は -P
を試してみるとよいかもしれない.
標準入力の内容を通知するコマンド(今回の例では some_notify
)を利用する場合、以下のようにする.
$ sudo docker events --filter type=image --filter event=tag --format '{{.Actor.Attributes.name}}' | xargs -I{} -P 3 -- sh -c "echo -e '\ntagged: {}\n' | some_notify"
この例では、xargs
に -P
を指定しているので、通知は同時に3つまで実行されるはず
(同時実行される状況を試していないのであまり自信はない).
標準入力の内容を通知するコマンド(foo
)があるとした場合、以下のようにする.
$ sudo docker events --filter type=container --filter event=die --format '{{.Actor.Attributes.image}},{{.Actor.Attributes.exitCode}}' | awk -F',' '/^sha/ && $2!=0{print $2; system("")}' | xargs -I{} -P 3 -- sh -c "echo -e '\ncontainer stopped. exit code={}\n' | some_notify"
この例では docker events
のフィルター指定だけでは難しかったので、
awk
を間に挟んでいる.
ちなみに、これを実行していると docker build
がエラーで終了したときが大雑把に把握できる
(実際には Dockerfile
の構文エラー等は通知されない等、完全に把握はできないのだが).
ワンライナー版でもお手軽で良い感じかなと思っているのだけれども、いろいろ拡張できるかなと思って Python でも試してみた.
よければ、そちらもどうぞ.