Ubuntu 16.04 LTS を Amazon ECS で使う

# 先人の知恵

- [UbuntuでAmazon ECS用のインスタンスを作る - Qiita](http://qiita.com/masuidrive/items/1e9ca51930810f826c24)

ほとんどは上の記事の通りでいけます。神。

ただ、 Ubuntu, Docker, ecs-agent のバージョンがそれぞれ上がっていることにより、何点か変更が必要なので、そこをフォローしてみます。

- [Installing the Amazon ECS Container Agent - Amazon EC2 Container Service](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-install.html)
- [Docker - Installation on Ubuntu](https://docs.docker.com/engine/installation/linux/ubuntulinux/)

これらの公式ドキュメントは既にそれぞれの最新に対応してます。

# Role for tasks への対応

- [ECSタスクのためのIAMロールによってコンテナ利用アプリケーションをより安全にする | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/help-secure-container-enabled-applications-with-iam-roles-for-ecs-tasks/)
- [IAM Roles for Tasks - Amazon EC2 Container Service](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html)

この ECS の新機能により、コンテナーインスタンスの Role とは別に**タスク用の Role**（Trust Relationship の Principal は `ecs-tasks.amazonaws.com`）を割り当てられるようになりました。

これを使うにあたり、 Amazon Linux 以外では `iptables` を使ってネットワークを曲げる必要があります。

```shell-session
$ sudo sysctl -w net.ipv4.conf.all.route_localnet=1
$ sudo iptables -t nat -A PREROUTING -p tcp -d 169.254.170.2 --dport 80 -j DNAT --to-destination 127.0.0.1:51679
$ sudo iptables -t nat -A OUTPUT -d 169.254.170.2 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 51679
```

`net.ipv4.conf.all.route_localnet=1` は適当にファイルを作って永続化しておきます。

```:/etc/sysctl.d/95-enable-nat.conf
net.ipv4.conf.all.route_localnet = 1
```

# `execdriver` マウントパスの変更

ecs-agent の長い長い起動コマンドのうちの以下の行です。

```
--volume=/var/run/docker/execdriver/native:/var/lib/docker/execdriver/native:ro \
```

Docker が 1.11 以降である場合、ホスト側のパスを変更する必要があります。

Ubuntu 16.04 に Docker 1.12 をインストールした場合、ここに指定するべきは

```
--volume=/var/run/docker/libcontainerd:/var/lib/docker/execdriver/native:ro \
```

です。

# `systemd` への対応

Ubuntu は 15 以降 `upstart` ではなく `systemd` が標準になったのでこれに対応します。

と言っても大した事はないです。適当な位置に起動用スクリプトを置いておき、それを叩くような `.service` ファイルを作るだけです。

```bash:/opt/misc/bin/ecs-agent
#!/bin/bash

start() {
  docker ps -a | grep ecs-agent

  if [ $? = 0 ]; then
    docker restart ecs-agent
  else
    export AWS_DEFAULT_REGION=$(ec2metadata --availability-zone | sed -e 's/.$//')
    export ECS_CLUSTER=$(aws ec2 describe-tags --filter "Name=resource-id,Values=$(ec2metadata --instance-id)" "Name=key,Values=EcsCluster" --query "Tags[*].[Value]" --output text)

    docker run --name ecs-agent \
    --detach=true \
    --restart=on-failure:10 \
    --volume=/var/run/docker.sock:/var/run/docker.sock \
    --volume=/var/log/ecs/:/log \
    --volume=/var/lib/ecs/data:/data \
    --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \
    --volume=/var/run/docker/libcontainerd:/var/lib/docker/execdriver/native:ro \
    --net=host \
    --env=ECS_LOGFILE=/log/ecs-agent.log \
    --env=ECS_LOGLEVEL=info \
    --env=ECS_DATADIR=/data \
    --env=ECS_CLUSTER=$ECS_CLUSTER \
    --env=ECS_ENABLE_TASK_IAM_ROLE=true \
    --env=ECS_AVAILABLE_LOGGING_DRIVERS=["json-file","awslogs"] \
    amazon/amazon-ecs-agent:latest
  fi
}

stop() {
  docker stop ecs-agent
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  *)
    echo "Usage: ecs-agent (start|stop)"
    exit 1
    ;;
esac
exit $?
```

```:/etc/systemd/system/ecs-agent.service
[Unit]
Description=ecs-agent

[Service]
Type=oneshot
WorkingDirectory=/opt/misc/bin/
ExecStart=/opt/misc/bin/ecs-agent start
ExecStop=/opt/misc/bin/ecs-agent stop
RemainAfterExit=yes

[Install]
WantedBy=network-online.target
```

```shell-session
$ sudo chmod +x /opt/misc/bin/ecs-agent
$ sudo systemctl daemon-reload
$ sudo systemctl enable ecs-agent
```

リブートして確認してみましょう。

```shell-session
ubuntu@ip-172-31-26-135:~$ sudo docker ps
CONTAINER ID        IMAGE                            COMMAND             CREATED             STATUS              PORTS               NAMES
d892a247688d        amazon/amazon-ecs-agent:latest   "/agent"            36 minutes ago      Up 36 minutes                           ecs-agent
```

```shell-session
ubuntu@ip-172-31-26-135:~$ sudo systemctl status ecs-agent
● ecs-agent.service - ecs-agent
   Loaded: loaded (/etc/systemd/system/ecs-agent.service; enabled; vendor preset: enabled)
   Active: active (exited) since Fri 2016-08-26 19:46:46 JST; 35min ago
  Process: 1743 ExecStart=/opt/misc/bin/ecs-agent start (code=exited, status=0/SUCCESS)
 Main PID: 1743 (code=exited, status=0/SUCCESS)
    Tasks: 0
   Memory: 0B
      CPU: 0
   CGroup: /system.slice/ecs-agent.service

Aug 26 19:46:44 ip-172-31-26-135 ecs-agent[1743]: 953909e9e1a5: Pull complete
Aug 26 19:46:44 ip-172-31-26-135 ecs-agent[1743]: b8482e34df6d: Verifying Checksum
Aug 26 19:46:44 ip-172-31-26-135 ecs-agent[1743]: b8482e34df6d: Download complete
Aug 26 19:46:45 ip-172-31-26-135 ecs-agent[1743]: 465ca331a4fe: Pull complete
Aug 26 19:46:45 ip-172-31-26-135 ecs-agent[1743]: a3a270f9aa99: Pull complete
Aug 26 19:46:45 ip-172-31-26-135 ecs-agent[1743]: b8482e34df6d: Pull complete
Aug 26 19:46:45 ip-172-31-26-135 ecs-agent[1743]: Digest: sha256:ad59bd654c6f9a889264fdf21dcb538b4ca8c7f10b86f141ef7203d19f46f443
Aug 26 19:46:45 ip-172-31-26-135 ecs-agent[1743]: Status: Downloaded newer image for amazon/amazon-ecs-agent:latest
Aug 26 19:46:45 ip-172-31-26-135 ecs-agent[1743]: d892a247688dbc13304d21b1a054a34e841db0803f8e7e6a812660f003bb4d3d
Aug 26 19:46:46 ip-172-31-26-135 systemd[1]: Started ecs-agent.
```

やったね。

ついでに Roles for task が使えるのか確認。

```shell-session
ubuntu@ip-172-31-26-135:~$ sudo docker ps
CONTAINER ID        IMAGE                            COMMAND             CREATED              STATUS              PORTS               NAMES
37269ca69a41        ubuntu:latest                    "sleep 300"         About a minute ago   Up About a minute                       ecs-mytask-3-ubuntu-aae8f5eea0bab9c7f601
d892a247688d        amazon/amazon-ecs-agent:latest   "/agent"            About an hour ago    Up About an hour                        ecs-agent
ubuntu@ip-172-31-26-135:~$ sudo docker exec -it 37269ca69a41 /bin/bash
root@8bc619ee3a75:/# curl 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
{"RoleArn":"arn:aws:iam::12345678xxxx:role/orenotask","AccessKeyId":"ASxxxxxxxxxxxxxxxxx","SecretAccessKey":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","Token":"xxxxxxxxxxxx//////////xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","Expiration":"2016-08-26T17:47:38Z"}
```

ほほー。

# 雑感

Docker と ECS の進化が早すぎてハゲそう。