Amazon ECSのデプロイにecspressoを使うとビルド・デプロイの境界やアプリ・インフラのIaC境界が明確になる ~ fujiwara-ware OSS ~
クラスメソッドは2024年に5つのOSSに対して支援を実施しました
当方が推薦した @fujiwara さん作による Amazon ECSのデプロイツールである ecspressoが選定されたので、簡単に紹介します。
継続的デリバリーの責任範囲を明確にするecspresso
ecspresso(「エスプレッソ」と発音します)はAWSのコンテナサービスAmazon ECSのデプロイツールです。
ECSでのデリバリーを思い出してみましょう。
- ECSのデリバリーは、新しいコンテナイメージのビルドと、新しいコンテナイメージのデプロイの2つのフェーズに分かれている
- ECSのデプロイは、タスク定義を更新し、サービスの参照するタスク定義を更新すること
- 頻繁に更新されるアプリケーションに対して、VPCやALBといったインフラストラクチャの更新頻度は低く、この2つの更新のライフサイクルは大きく異なる
以上を踏まえ、 ecspressoはECSのデプロイにフォーカスするように設計されたツール であり、コンテナが実行されるインフラストラクチャのVPC系リソースは参照するだけです。特に、TerraformでAWSインフラをIaC化されている場合、後述のようにシームレスに連携できます。
ecspressoを導入してデプロイするまでの流れ
既存のECSサービスを ecspresso
でデプロイするまでの流れを紹介します。
TerraformでAWSリソースがIaC管理されているものとします。
ecspressoをダウンロード
まずはecspresso
をダウンロードします
macOSならbrew
からインストールできます
$ brew install kayac/tap/ecspresso
様々なアーキテクチャー向けにバイナリが用意されています。
既存のサービスを取り込む
ecspresso init
コマンドを利用すると、既存サービスを取り込めます。
- クラスター
- サービス
を指定し、取り込みましょう。
$ ecspresso init --region ap-northeast-1 --cluster your-cluster --service your-service --config ecspresso.yml
$ ls -1
ecs-service-def.json
ecs-task-def.json
ecspresso.yml
$ cat ecspresso.yml
region: ap-northeast-1
cluster: your-cluster
service: your-service
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: "10m0s"
ecspresso.yml
はecspresso
固有の定義ファイルであり、 ecs-service-def.json
と ecs-task-def.json
にはECSのサービスとタスクが定義されています。
特に、ecs-service-def.json
にはセキュリティグループやサブネットなどインフラ系リソースを確認できます。
...
"networkConfiguration": {
"awsvpcConfiguration": {
"assignPublicIp": "ENABLED",
"securityGroups": [
"sg-123"
],
"subnets": [
"subnet-123",
"subnet-456"
]
}
},
...
ecspresso
からタスク一覧が見えていることを確認しましょう。
$ ecspresso tasks
2024/08/12 03:22:29 [INFO] ecspresso version: v2.4.0
| ID | TASKDEFINITION | INSTANCE | LASTSTATUS | DESIREDSTATUS | CREATEDAT | GROUP | TYPE |
+----------------------------------+------------------+----------+------------+---------------+----------------------+-------------------+---------+
| a6f7a3a95be64eb2a4e00383dd5b9a11 | demo-lb-httpd:3 | | PENDING | RUNNING | 2024-08-12T03:22:07Z | service:alb-httpd | FARGATE |
Terraformと連携する
ecspresso
の嬉しい機能の一つは、Terafformとシームレスに連携できることです。
具体的には、Terraformのリソース状態をStateファイル(tfstate
)で管理していると、AWSリソースIDをTerraformの論理名に置き換えられます。
まず、ecspresso.yml
の冒頭で tfstate
プラグインを有効化します
plugins:
- name: tfstate
config:
url: s3://YOUR-BUCKET/terraform.tfstate
続いて、サービス定義ファイル(ecs-service-def.json
)内のTerraform管理されているリソースを Terraformの論理名で置き換えます。
...
"networkConfiguration": {
"awsvpcConfiguration": {
"assignPublicIp": "ENABLED",
"securityGroups": [
"{{ tfstate tfstate `data.aws_security_group.app.id` }}"
],
"subnets": [
"{{ tfstate `aws_subnet.private_a.id` }}",
"{{ tfstate `aws_subnet.private_c.id` }}"
]
}
},
...
Terraformのリソース一覧は $ terraform state list
で確認できます。
デプロイ
新しいコンテナイメージをビルドした前提で、このイメージをデプロイしてみましょう。
デプロイ前に便利なdry-runを2つ紹介します。
$ ecspresso diff
で設定の差分を確認できます。
$ ecspresso diff
2024/08/12 03:27:41 [INFO] ecspresso version: v2.4.0
--- arn:aws:ecs:ap-northeast-1:123456789012:task-definition/test-httpd:4
+++ ecs-task-def.json
@@ -10,7 +10,7 @@
"-c"
],
"essential": true,
- "image": "public.ecr.aws/docker/library/httpd:2.4.61",
+ "image": "public.ecr.aws/docker/library/httpd:2.4.62",
"name": "httpd-app",
"portMappings": [
{
$ ecspresso verify
でコンテナが依存するリソースのチェック、例えば、イメージの存在や権限の整合性をチェックできます。
タスク定義で宣言したイメージが存在しない場合のエラー出力例です。
$ ecspresso verify
2024/08/12 03:47:44 [INFO] ecspresso version: v2.4.0
2024/08/12 03:47:44 httpd-alb/your-cluster Starting verify
TaskDefinition
ExecutionRole[arn:aws:iam::123456789012:role/ecsTaskExecutionRole]
--> [OK]
TaskRole[arn:aws:iam::123456789012:role/ecsTaskRole]
--> [OK]
ContainerDefinition[httpd-app]
Image[123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/not-exist/web-service:2]
--> [NG] 404 Not Found
--> [NG] verify Image[123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/not-exist/web-service:2] failed: 404 Not Found
--> [NG] verify ContainerDefinition[httpd-app] failed: verify Image[123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/not-exist/web-service:2] failed: 404 Not Found
2024/08/12 03:47:45 [ERROR] FAILED. verify TaskDefinition failed: verify ContainerDefinition[httpd-app] failed: verify Image[123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/not-exist/web-service:2] failed: 404 Not Found
最後に $ ecspresso deploy
を実行し、タスク定義とサービスを更新し、コンテナが更新されればデプロイ完了です。
$ ecspresso deploy
2024/08/12 03:40:35 [INFO] ecspresso version: v2.4.0
2024/08/12 03:40:35 httpd-alb/your-cluster Starting deploy
Service: httpd-alb
Cluster: your-cluster
TaskDefinition: test-httpd:5
Deployments:
PRIMARY test-httpd:5 desired:1 pending:0 running:1 COMPLETED(ECS deployment ecs-svc/5601475856890297997 completed.)
Events:
2024/08/12 03:40:36 httpd-alb/DevCluster Registering a new task definition...
...
2024/08/12 03:43:43 httpd-alb/your-cluster Service is stable now. Completed!
最後に
Amazon ECSのデプロイツールである @fujiwara さん作の ecspresso を紹介しました。シンプルで狙いが明確なツールのため、導入や評価は容易ではないかと思います。
ecspresso
の設計思想は作者本人による次のZennの記事が参考になります
網羅的なリファレンスがZennで公開されています。
既存プロダクトに ecspresso
を組み込む場合、現実と向き合った泥臭い対応が求められます。他社の導入事例を参考にしましょう。
- 7年続いたサービスをEC2構成からECS構成へ乗り換えた話 - KAYAC Engineers' Blog
- GitHub Actions & ecspressoによるデプロイフロー構築 - コネヒト開発者ブログ
- モンスターストライク スタジアムをAmazon EC2からAmazon ECS Fargateに移行しました
- ecspressoを活用したECSデプロイの改善 - LayerX エンジニアブログ
なお、 @fujiwara さんは、 ECSデプロイツールの ecspresso 以外にも、AWS Lambdaをデプロイする lambroll、Go版AWS CLI(=静的リンクされたシングルバイナリ版)の awslim、Amazon ECRの溜まったゴミをお掃除する ecrm など、今回紹介しきれなかったたくさんの便利な OSS を開発されています。