ちょっと話題の記事

【コンテナのデプロイを簡単にしませんか?】ECSのデプロイツールである「ecspresso」を触ってみた

2019.10.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちわ、札幌のヨシエです。
先日のAWS DevDay Tokyo 2019は自分も参加出来て本当に勉強になりました。
今回は発表された複数セッションで度々登場した「ecspresso」が気になったので使用感を知りたく触ってみました。

ecspressoとは?

面白法人カヤック様から提供されているGo製のECSデプロイツールです。
kayac/ecspresso

読み方は「エスプレッソ」というようです。

インストール方法(macOSのみ)

brew install kayac/tap/ecspresso

確認バージョン

% ecspresso version
ecspresso v0.11.1

ECSサービスのコードエクスポート

最初にやることとしてecspressoで管理出来る設定ファイルをエクスポートします。
ecspressoではクラスター名とサービス名を指定するすることで実行中のECSサービス情報をコード出力してくれます。

ecspresso init --region ap-northeast-1 --cluster test-fargate --service test-fargate-service --config test-fargate.yaml

成果物として以下のファイルがカレントディレクトリへ出力されました。

  • test-fargate.yaml
  • ecs-service-def.json
  • ecs-task-def.json

test-fargate.yaml

ECSで定義されているクラスターやクラスターに設定されているサービスとタスク定義のファイル名が記載されてます。

% cat test-fargate.yaml
region: ap-northeast-1
cluster: test-fargate
service: test-fargate-service
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: 5m0s

ecs-service-def.json

サービス定義情報が記述されております。 イメージとしてはaws ecs describe-services --cluster test-fargate --services test-fargate-serviceを実行した結果と同じように見えますが、AWSCLIではサービス自体のイベントが出力される点から「定義情報のみ」を求める際は非常に重宝する情報です。

% cat ecs-service-def.json
{
  "deploymentConfiguration": {
    "maximumPercent": 200,
    "minimumHealthyPercent": 100
  },
  "desiredCount": 5,
  "enableECSManagedTags": false,
  "healthCheckGracePeriodSeconds": 0,
  "launchType": "FARGATE",
  "loadBalancers": [
    {
      "containerName": "http",
      "containerPort": 80,
      "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:xxx:targetgroup/ecs-test-fargate-tg/cbbc19d1ce3e8f4a"
    }
  ],
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "assignPublicIp": "DISABLED",
      "securityGroups": [
        "sg-xxx"
      ],
      "subnets": [
        "subnet-xxx",
        "subnet-xxx"
      ]
    }
  },
  "placementConstraints": [],
  "placementStrategy": [],
  "schedulingStrategy": "REPLICA",
  "serviceRegistries": []
}

ecs-task-def.json

設定されているタスク定義が出力されます。 service情報と同じようにECS上でJSONファイルを表示すると普段はあまり必要としていない項目が表示されてしまいますが
主にユーザーが必須として入力する部分を網羅して表示してくれます。

% cat ecs-task-def.json
{
  "compatibilities": [
    "EC2",
    "FARGATE"
  ],
  "containerDefinitions": [
    {
      "cpu": 0,
      "environment": [],
      "essential": true,
      "image": "httpd:latest",
      "memory": 128,
      "mountPoints": [],
      "name": "http",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        }
      ],
      "volumesFrom": []
    }
  ],
  "cpu": "256",
  "family": "monitor-http",
  "memory": "512",
  "networkMode": "awsvpc",
  "placementConstraints": [],
  "requiresCompatibilities": [
    "EC2",
    "FARGATE"
  ],
  "volumes": []
}

確認:タスクのスケールアウト/スケールイン

コンテナ環境の運用で特に対応を行うスケールアウト/スケールインをやってみました。 まずは、statusサブコマンドを指定して現在のコンテナ数を確認します。

% ecspresso status --config test-fargate.yaml
Service: test-fargate-service
Cluster: test-fargate
TaskDefinition: monitor-http:9
Deployments:
   PRIMARY monitor-http:9 desired:1 pending:0 running:1

現時点ではmonitor-http:9というコンテナが1台のみ起動していることが見えました。 このコンテナを10個にスケールアウトします。

% ecspresso deploy --config test-fargate.yaml --tasks 10 --skip-task-definition
2019/10/12 15:53:42 test-fargate-service/test-fargate Starting deploy
Service: test-fargate-service
Cluster: test-fargate
TaskDefinition: monitor-http:9
Deployments:
   PRIMARY monitor-http:9 desired:1 pending:0 running:1
Events:
2019/10/12 15:53:44 test-fargate-service/test-fargate Creating a new task definition by ecs-task-def.json
2019/10/12 15:53:44 test-fargate-service/test-fargate Registering a new task definition...
2019/10/12 15:53:44 test-fargate-service/test-fargate Task definition is registered monitor-http:9
2019/10/12 15:53:44 test-fargate-service/test-fargate desired count: 10
2019/10/12 15:53:44 test-fargate-service/test-fargate Updating service...
2019/10/12 15:53:48 test-fargate-service/test-fargate Waiting for service stable...(it will take a few minutes)
2019/10/12 15:55:48 test-fargate-service/test-fargate  PRIMARY monitor-http:9 desired:10 pending:0 running:10
2019/10/12 15:55:31 (service test-fargate-service) has stopped 1 running tasks: (task 032e
db94-74fa-4109-ab2a-24d2c5415b5d).
2019/10/12 15:55:21 (service test-fargate-service) has begun draining connections on 1 tas
ks.
2019/10/12 15:55:21 (service test-fargate-service) deregistered 1 targets in (target-group
 arn:aws:elasticloadbalancing:ap-northeast-1:xxx:targetgroup/ecs-test-fargate-tg/
cbbc19d1ce3e8f4a)

〜

2019/10/12 15:55:52 test-fargate-service/test-fargate Service is stable now. Completed!

無事にmonitor-http:9のコンテナが10台にスケールアウトが出来ました。
ここでポイントなのが--skip-task-definitionというオプションです。
このオプションをせずに実行した場合でもコンテナのスケールアウトが実現できますが、リビジョンが一つ上がります。
使い方としては新しいコンテナを追加起動したい時に使うのが良いかと思いますが、テストが未完や急なアクセスが予想される目的のスケールアウトでは--skip-task-definitonを指定してスケールアウトする形になると思います。

同じようにスケールインを実施してみます。 やり方は--tasksで指定している数値を変更するのみです。

% ecspresso deploy --config test-fargate.yaml --tasks 3 --skip-task-definition
2019/10/12 16:02:55 test-fargate-service/test-fargate Starting deploy
Service: test-fargate-service
Cluster: test-fargate
TaskDefinition: monitor-http:9
Deployments:
   PRIMARY monitor-http:9 desired:10 pending:0 running:10
Events:
2019/10/12 16:02:56 test-fargate-service/test-fargate desired count: 3
2019/10/12 16:02:56 test-fargate-service/test-fargate Updating service...
2019/10/12 16:03:00 test-fargate-service/test-fargate Waiting for service stable...(it will take a few minutes)
2019/10/12 16:03:30 test-fargate-service/test-fargate  PRIMARY monitor-http:9 desired:3 pending:0 running:3
2019/10/12 16:03:29 (service test-fargate-service) has reached a steady state.
2019/10/12 16:03:20 (service test-fargate-service) has stopped 2 running tasks: (task c879
a5b9-2aae-4496-85b3-62e193ca777c) (task e13d5d7d-fe74-4deb-9a53-40b087cbf105).
2019/10/12 16:03:10 (service test-fargate-service) has stopped 5 running tasks: (task 7d91
5eb4-ee3d-41ac-a362-0922f4f41055) (task 7a360d1f-0228-4a36-9d74-f445e7217214) (task d32e2f
13-64ca-4eb3-a2dd-38ce4df1ce45) (task 94a391dc-86ce-44a1-aa63-78a77aa2fa5c) (task bef77b1d
-bb8a-4462-a397-66eb6ebb7fa5).
2019/10/12 16:03:30 test-fargate-service/test-fargate Service is stable now. Completed!
% ecspresso status --config test-fargate.yaml
Service: test-fargate-service
Cluster: test-fargate
TaskDefinition: monitor-http:9
Deployments:
   PRIMARY monitor-http:9 desired:3 pending:0 running:3

※今回の検証環境はALBとコンテナを接続しており、ECSとしてスケールインの処理は素早く入りました。
ですが、ALBの接続維持時間の設定を忘れていたのでdraining状態が続いたことでスケールインの完了までに時間がかかりました。

確認:タスクのロールバック

コンテナの良いところであるロールバック機能も対応しております。
このコマンドを実行すると、一つ前のコンテナリビジョンに戻ってくれます。

% ecspresso rollback --config test-fargate.yaml
2019/10/12 16:07:28 test-fargate-service/test-fargate Starting rollback
Service: test-fargate-service
Cluster: test-fargate
TaskDefinition: monitor-http:9
Deployments:
   PRIMARY monitor-http:9 desired:3 pending:0 running:3
Events:
2019/10/12 16:07:29 test-fargate-service/test-fargate Rollbacking to monitor-http:8
2019/10/12 16:07:29 test-fargate-service/test-fargate Updating service...
2019/10/12 16:07:33 test-fargate-service/test-fargate Waiting for service stable...(it will take a few minutes)
2019/10/12 16:09:33 test-fargate-service/test-fargate  PRIMARY monitor-http:8 desired:3 pending:0 running:3
2019/10/12 16:09:10 (service test-fargate-service) has stopped 3 running tasks: (task e691
3def-908e-4d04-b2eb-0d280d6ec033) (task 6f2f95a5-6a83-4829-9193-385d2631772a) (task 4bb208
de-af09-4a1d-bba8-5832245c6702).
2019/10/12 16:09:00 (service test-fargate-service) has begun draining connections on 3 tas
ks.

〜

2019/10/12 16:09:36 test-fargate-service/test-fargate Service is stable now. Completed!

コマンド一行でロールバックが出来ました。
動作自体はロールバック先のリビジョンを起動した後に残っているロールバック元のコンテナを終了していたので気になったのが今回はFargateを利用していたので問題はありませんでした。
ですが、EC2をコンテナホストとして使っているとENIの数制限が引っかかる可能性があるのでAWSVPC Trunking設定を入れるとより安全にロールバックが出来るかと思います。(というよりも必須で入れたほうが良い設定です)

ECSにおけるインスタンスのENI制限が大幅に改善されネットワーク設計が簡単になりました!

確認:タスクのデプロイ

今度は使っているApacheコンテナを監視したくなる時があると思いまして、mackerel-container-agentをサイドカーで起動してみます。
タスク定義はecs-task-def.jsonに記載されており、今回は「>」で指定している部分をmackerel-container-agentのコンテナ定義を部分ととして、containerDefinitionsに追加の記述を行います。

{
  "compatibilities": [
    "EC2",
    "FARGATE"
  ],
  "containerDefinitions": [
    {
      "cpu": 0,
      "environment": [],
      "essential": true,
      "image": "httpd:latest",
      "memory": 128,
      "mountPoints": [],
      "name": "http",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        }
      ],
      "volumesFrom": []
    },
>    {
>      "cpu": 0,
>      "environment": [
>        {
>          "name": "MACKEREL_APIKEY",
>          "value": "xxx"
>        },
>        {
>          "name": "MACKEREL_CONTAINER_PLATFORM",
>          "value": "ecs"
>        }
>      ],
>      "essential": true,
>      "image": "mackerel/mackerel-container-agent:latest",
>      "mountPoints": [],
>      "name": "mackerel-container-agent",
>      "portMappings": [],
>      "volumesFrom": []
>    }
  ],
  "cpu": "256",
  "family": "monitor-http",
  "memory": "512",
  "networkMode": "awsvpc",
  "placementConstraints": [],
  "requiresCompatibilities": [
    "EC2",
    "FARGATE"
  ],
  "volumes": []
}

同じようにデプロイを行ってみます。 

% ecspresso deploy --config test-fargate.yaml --tasks 5
2019/10/12 16:43:56 test-fargate-service/test-fargate Starting deploy
Service: test-fargate-service
Cluster: test-fargate
TaskDefinition: monitor-http:13
Deployments:
   PRIMARY monitor-http:13 desired:5 pending:0 running:5
Events:
2019/10/12 16:43:57 test-fargate-service/test-fargate Creating a new task definition by ecs-task-def.json
2019/10/12 16:43:57 test-fargate-service/test-fargate Registering a new task definition...
2019/10/12 16:43:57 test-fargate-service/test-fargate Task definition is registered monitor-http:14
2019/10/12 16:43:57 test-fargate-service/test-fargate desired count: 5
2019/10/12 16:43:57 test-fargate-service/test-fargate Updating service...
2019/10/12 16:44:01 test-fargate-service/test-fargate Waiting for service stable...(it will take a few minutes)
2019/10/12 16:45:41 test-fargate-service/test-fargate  PRIMARY monitor-http:14 desired:5 pending:0 running:5
2019/10/12 16:45:41 test-fargate-service/test-fargate   ACTIVE monitor-http:13 desired:5 pending:0 running:0
2019/10/12 16:45:49 test-fargate-service/test-fargate Service is stable now. Completed!

このように無事mackerel-container-agentがサイドカーとして起動して、監視が出来るようになりました。

最後に

コンテナを運用する上で担当者がかゆいと思う部分を網羅されたツールでした。
スケール対応はもちろんですが、ロールバックやデプロイ周りが一つに集約されてイメージしやすいコマンドを実行することで
環境を維持しやすくなることやCD向けのオプションを処理に組み込むことで容易にコンテナ環境のCD環境を作ることが可能です。
今回書ききれませんでしたが、--dry-runsuspend-autoscalingといった様々な環境に対して導入しやすいツールだと考えております。

既にコンテナ環境を運用している皆様も試して頂けると幸いです。