GeekFactory

int128.hatenablog.com

Dockerコンテナの起動や停止をトリガーにして処理を実行する

Dockerホストで新しいコンテナが起動したり既存のコンテナが停止したタイミングで何らかの処理を実行したい場合があります。例えば、リバースプロキシの設定を反映したり、コンテナのURLをレビュアに通知したりといった用途が考えられます。

本記事ではdockerコマンドやRemote APIでイベントを取得して処理する方法を説明します。

docker eventsコマンドを使う

docker eventsコマンドを実行すると、イベントが発生した場合に以下のような行が出力されます。

[2014-10-05 03:18:08 +0900 JST] 9f732da00641498f383779b58168b5e84aa21b5130bd7b9ed196220dea6d428b: (from centos:centos7) create
[2014-10-05 03:18:08 +0900 JST] 9f732da00641498f383779b58168b5e84aa21b5130bd7b9ed196220dea6d428b: (from centos:centos7) start
[2014-10-05 03:18:09 +0900 JST] 9f732da00641498f383779b58168b5e84aa21b5130bd7b9ed196220dea6d428b: (from centos:centos7) die
[2014-10-05 03:18:10 +0900 JST] 9f732da00641498f383779b58168b5e84aa21b5130bd7b9ed196220dea6d428b: (from centos:centos7) destroy

何も引数を付けなければ実行以降のイベントが、--since=という引数を付けた場合は指定した日時以降のイベントが出力されます。

docker eventsコマンドのフォーマットはあまり機械処理には向いていませんが、頑張ればシェルスクリプトでも処理できます。 とりあえずコンセプトを実証したい場合は、以下のようなシェルスクリプトでさくっと作ってしまうとよいと思います。

#!/bin/bash
docker events "$@" | while read line; do
  container_id="$(echo $line | sed -e 's/^.*] \(\w*\): .*$/\1/g')"
  event="$(echo $line | sed -e 's/^.* \(\w*\)$/\1/g')"
  case "$event" in
    start)
      container_name="$(docker inspect -f '{{.Name}}' "$container_id" 2> /dev/null)"
      container_ip="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' "$container_id" 2> /dev/null)"
      echo "$container_id: started as $container_name at $container_ip";;
    die | kill)
      echo "$container_id: stopped";;
    destroy)
      echo "$container_id: removed";;
  esac
done

Remote APIにアクセスする

Docker Remote APIMonitor Docker's events でイベントを取得できます。

Node.jsで動作するDocker Remote APIライブラリのdockerodeを使った例を以下に示します。

# app.coffee
Docker      = require 'dockerode'
JSONStream  = require 'JSONStream'

docker = new Docker socketPath: '/var/run/docker.sock'
docker.getEvents {}, (error, stream) ->
  throw error if error
  stream?.pipe JSONStream.parse().on 'root', (event) ->
    switch event.status
      when 'start'
        console.info "#{event.time}: #{event.status}: #{event.id} from #{event.from}"
      when 'die', 'kill'
        console.info "#{event.time}: #{event.status}: #{event.id} from #{event.from}"
      when 'destroy'
        console.info "#{event.time}: #{event.status}: #{event.id} from #{event.from}"

dockerodeのAPIは非同期になっており、コールバックで結果が返ってきます。 getEventsのコールバックの中でinspect()を実行すればコンテナ名などの詳細情報を取得できます。

slack-docker ではdockerodeで取得したイベントをSlackに連携しています。 参考になれば幸いです。