UbuntuでUpstartを使ってECS Agentをサービス化する

さて、先日Docker1.8がリリースされました。なんといっても目玉はLogging DriverのFluentd対応ですが、ウチのプロジェクトでもこれの対応を見越して早速Docker1.8にバージョンをあげています。

Docker1.8で何が変わるかは以下のエントリを抑えておくとよいでしょう。

Announcing Docker 1.8: Content Trust, Toolbox, and Updates to Registry and Orchestration

で、本題なのですが、今まではECSを利用するのにAWSが提供しているECS Optimized AMI(ベースはAmazon Linux)を利用していました。でもUbuntuの方がDockerを積極的にアップデートしやすそうってのと、そもそもECS Agent自体Dockerコンテナとして動くので、プラットフォームなんてどうでもいいだろうっていう考えで移行しました。

ECS Optimized AMI

Amazon ECS-Optimized Amazon Linux AMI on AWS Marketplace

そもそもECS Optimized AMIを使うメリットはなんでしょうか。userdata(インスタンスLaunch時に実行するスクリプト)にインスタンスをジョインさせるECSクラスタ名さえ記述すれば、勝手にECS Agentコンテナが起動して、任意のクラスタにジョインされるとこまでよろしくやってくれることにあると勝手に解釈しています。

ECS Optimized AMI ではamazon-ecs-initというツールでこのあたりの制御が行われているようです。Ubuntuにしてもこれを使ってみようとしたけど、どうやらRPM対応のみみたいなので別の仕組みで実現してみました。

userdataでキックするスクリプトを作る

userdataはEC2が初回Launch時にのみ実行される処理を記述するもので、ECSならばECS Agentコンテナの初回Runにもってこいです。以下のように引数にECSクラスタ名を指定するようなスクリプトを用意します。ECS Agentの起動には ECS_CLUSTER の指定が必須なのでこのようにしてます。

#!/bin/bash

ECS_CLUSTER=$1
AGENT_NAME=ecs-agent

if [ -z "$ECS_CLUSTER" ]; then
  echo "not specified ecs cluster name" 1>&2
  exit 1
fi

docker run --name=$AGENT_NAME \
--detach=true \
--volume=/var/run/docker.sock:/var/run/docker.sock \
--volume=/var/log/ecs/:/log \
--volume=/var/lib/ecs/data:/data \
--publish=127.0.0.1:51678:51678 \
--env=ECS_LOGFILE=/log/ecs-agent.log \
--env=ECS_LOGLEVEL=info \
--env=ECS_DATADIR=/data \
--env=ECS_CLUSTER=$ECS_CLUSTER \
amazon/amazon-ecs-agent:latest

ただ、userdataだと再起動時にECS Agentのコンテナを自動で立ち上げるということまではできません。ECS Agentのコンテナはちゃんとサービス化しておきたいところ。

UpstartでECS Agentをサービス化する

サービス化といえばchkconfigが定番でしたが、実は最近のUbuntuではデフォルトでインストールされてません。というわけで今回はUpstartを使ってみます。

chkconfigより優れてるところは、ゴリゴリとinitスクリプトを書かなくて済むという点に集約されます。pidを制御をしたり、etc/init.d/functions で消耗したりってことから開放されます。

Upstartでは以下の /etc/init/ecs-agent.conf を追加するだけ。

description "ECS Agent container"
author "foobar"
start on filesystem and started docker
stop on runlevel [!2345]
respawn
script
  /usr/bin/docker start -a ecs-agent
end script

これを有効にするには initctl start して、 initctl reload-configuration すればOKです。これはuserdataで実行するスクリプトに入れちゃえばよいでしょう。つまり、スクリプトの完成形は以下のようになります。

#!/bin/bash

ECS_CLUSTER=$1
AGENT_NAME=ecs-agent

if [ -z "$ECS_CLUSTER" ]; then
  echo "not specified ecs cluster name" 1>&2
  exit 1
fi

docker run --name=$AGENT_NAME \
--detach=true \
--volume=/var/run/docker.sock:/var/run/docker.sock \
--volume=/var/log/ecs/:/log \
--volume=/var/lib/ecs/data:/data \
--publish=127.0.0.1:51678:51678 \
--env=ECS_LOGFILE=/log/ecs-agent.log \
--env=ECS_LOGLEVEL=info \
--env=ECS_DATADIR=/data \
--env=ECS_CLUSTER=$ECS_CLUSTER \
amazon/amazon-ecs-agent:latest

# UpstartでECS Agentをサービス化する
initctl start $AGENT_NAME
initctl reload-configuration

この状態を独自のAMIを焼いて、インスタンスを作ってます。Management Consoleで見ると・・・

ちゃんとDocker1.8.1になってますね。ちなみにuserdataはTerraformでも制御できるので、このAMIとTerraformを駆使してあっという間にDocker1.8化とUbuntu化に対応しました。