こんにちは、SREチームの平田です。
私が担当しているチームではTerraformを使用してAWSのリソースを管理しておりますが、Amazon ECSはecspressoで管理するようにしました。
本ブログではecspressoへの置き換え手順とコードに変更を加えてデプロイするまでの手順を共有します。
ecspressoとは
escpressoとはECS用のデプロイツールで、Go言語で書かれたOSSです。
ECSサービスとタスクのコード管理に特化しており、それ以外のリソース(VPCやELB等)は管理できませんが、Terraformのstateファイルを使用しECSに関連するリソースと連携できます。
https://github.com/kayac/ecspresso
なぜecspressoに移行したのか
VPCやELB等のインフラレイヤーのリソースは1度デプロイすると頻繁に構成変更を行わないのが一般的です。ただしECSはアプリケーションレイヤーのリソースのため頻繁に構成変更する必要があります。そのためTerraformでECSを管理し頻繁に構成変更すると、意図しないECS関連リソースの変更が発生してしまう恐れがあります。
そのためECSの管理をTerraformからecspressoに移行し操作範囲を限定することで、ECSのデプロイを安全に実施する必要がありました。
ecspressoへの移行手順
移行手順と実際にコードを変更してデプロイするまでの手順を共有します。
インストール
バイナリやHomebrewでインストールができますが、ここではGitHub Actionsを使用してインストールを実施します。他のやり方については公開されているGitHubのページを参照してください。
jobs:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: kayac/ecspresso@v2
with:
version: v2.2.4 # or latest
既存のECSリソースから設定ファイルを生成
ecspressoを使用するためにはECSサービスとタスクを定義した設定ファイルが必要です。ただ一から作成するのは手間がかかるため、ecspresso init
を使用して既存リソースから設定ファイルを作成していきます。
AWSクレデンシャル設定
ecspressoからAWSにアクセスするためにはAWSクレデンシャルの設定が必要になります。ここではactionsのaws-actions/configure-aws-credentials
を使用します。
https://github.com/aws-actions/configure-aws-credentials
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role # 事前にAWSでOIDC設定とIAMロール設定が必要になります
aws-region: ap-northeast-1
ecspresso initコマンドを実行する
現在ECSタスクのPublic IPにアクセスするとHello Worldの文字列が返却されるECSサービスをデプロイしております。この既存リソースからecspressoの設定ファイルを作成していきます。
ecspresso init
コマンドに--cluster
と--service
オプションを追加し対象のクラスター名とECSサービス名を設定します。
実行後は3つのファイルが生成されます。
- name: ecspresso init
run: |
escpresso init --cluster demo-ecspresso --service demo-ecspresso
2023/11/29 14:25:46 demo-ecspresso/demo-ecspresso save service definition to ecs-service-def.json
2023/11/29 14:25:46 demo-ecspresso/demo-ecspresso save task definition to ecs-task-def.json
2023/11/29 14:25:46 demo-ecspresso/demo-ecspresso save config to ecspresso.yml
ecspresso.yml
YAML形式のecspressoの基本設定用ファイルです。クラスター名やECSサービス名等の設定ができます。
region: "ap-northeast-1"
cluster: demo-ecspresso
service: demo-ecspresso
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: "10m0s"
ecs-service-def.json
JSON形式のECSサービスの定義用ファイルです。タスク数やどのサブネットにデプロイするか等の設定ができます(一部コメントアウトしております)。
{
"deploymentConfiguration": {
"deploymentCircuitBreaker": {
"enable": true,
"rollback": true
},
"maximumPercent": 200,
"minimumHealthyPercent": 100
},
"deploymentController": {
"type": "ECS"
},
"desiredCount": 1,
"enableECSManagedTags": true,
"enableExecuteCommand": false,
"launchType": "FARGATE",
"networkConfiguration": {
"awsvpcConfiguration": {
"assignPublicIp": "ENABLED",
"securityGroups": [
"***"
],
"subnets": [
"***",
"***"
]
}
},
"platformFamily": "Linux",
"platformVersion": "LATEST",
"propagateTags": "NONE",
"schedulingStrategy": "REPLICA"
}
ecs-task-def.json
JSON形式のECSタスクの定義用ファイルです。コンテナイメージやCPU等の設定ができます(一部コメントアウトしております)。
{
"containerDefinitions": [
{
"cpu": 0,
"essential": true,
"image": "***.dkr.ecr.ap-northeast-1.amazonaws.com/demo-ecspresso:latest",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/demo-ecspresso",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
},
"name": "nginx",
"portMappings": [
{
"appProtocol": "http",
"containerPort": 80,
"hostPort": 80,
"name": "nginx-80-tcp",
"protocol": "tcp"
}
]
}
],
"cpu": "512",
"executionRoleArn": "arn:aws:iam::***:role/ecsTaskExecutionRole",
"family": "demo-ecspresso",
"ipcMode": "",
"memory": "1024",
"networkMode": "awsvpc",
"pidMode": "",
"requiresCompatibilities": [
"FARGATE"
],
"runtimePlatform": {
"cpuArchitecture": "ARM64",
"operatingSystemFamily": "LINUX"
},
"taskRoleArn": "arn:aws:iam::***:role/ecsTaskExecutionRole"
}
ecspressoの設定ファイルを使用してデプロイする
設定ファイルの準備が完了したのでecspresso deploy
コマンドを使用してデプロイしていきます。
まずはHelloWorld以外の文字列が返却されるようにDockerイメージを更新しECRにプッシュします(ECRへのプッシュの手順は省略します)。
プッシュが完了したら、ecspresso init
とは別のGithub Actionsを用意し設定ファイルがあるディレクトリでecspresso deploy
を実行します。(同様にecspressoのインストールとAWSクレデンシャルの設定が必要になります)
- name: ecspresso deploy
run: |
escpresso deploy
処理の流れとしては新しいタスク定義が登録されると、ECSサービスに設定されているタスク定義が新しいものに置き換わり、ECSサービスがstableの状態になるまで待ちます。 実行すると次のようなログが表示されます。
2023/11/29 14:34:35 demo-ecspresso/demo-ecspresso Starting deploy
Service: demo-ecspresso
Cluster: demo-ecspresso
TaskDefinition: demo-ecspresso:2
Deployments:
PRIMARY demo-ecspresso:2 desired:1 pending:0 running:1 COMPLETED(ECS deployment ecs-svc/6450379161618437361 completed.)
Events:
2023/11/29 14:34:35 demo-ecspresso/demo-ecspresso Registering a new task definition...
2023/11/29 14:34:35 demo-ecspresso/demo-ecspresso Task definition is registered demo-ecspresso:3
2023/11/29 14:34:35 demo-ecspresso/demo-ecspresso service attributes will not change
2023/11/29 14:34:35 demo-ecspresso/demo-ecspresso desired count: 1
2023/11/29 14:34:35 demo-ecspresso/demo-ecspresso Updating service tasks...
2023/11/29 14:34:39 demo-ecspresso/demo-ecspresso Waiting for service stable...(it will take a few minutes)
2023/11/29 14:34:49 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:0 pending:0 running:0 IN_PROGRESS(ECS deployment ecs-svc/2871655535974756192 in progress.)
2023/11/29 14:34:49 demo-ecspresso/demo-ecspresso ACTIVE demo-ecspresso:2 desired:1 pending:0 running:1 COMPLETED(ECS deployment ecs-svc/6450379161618437361 completed.)
2023/11/29 14:34:53 (service demo-ecspresso) has started 1 tasks: (task 1d3228c06169488c86b28c3d94409942).
2023/11/29 14:34:59 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:1 pending:1 running:0 IN_PROGRESS(ECS deployment ecs-svc/2871655535974756192 in progress.)
2023/11/29 14:34:59 demo-ecspresso/demo-ecspresso ACTIVE demo-ecspresso:2 desired:1 pending:0 running:1 COMPLETED(ECS deployment ecs-svc/6450379161618437361 completed.)
2023/11/29 14:35:19 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:1 pending:0 running:1 IN_PROGRESS(ECS deployment ecs-svc/2871655535974756192 in progress.)
2023/11/29 14:35:19 demo-ecspresso/demo-ecspresso ACTIVE demo-ecspresso:2 desired:1 pending:0 running:1 COMPLETED(ECS deployment ecs-svc/6450379161618437361 completed.)
2023/11/29 14:35:29 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:1 pending:0 running:1 IN_PROGRESS(ECS deployment ecs-svc/2871655535974756192 in progress.)
2023/11/29 14:35:29 demo-ecspresso/demo-ecspresso ACTIVE demo-ecspresso:2 desired:0 pending:0 running:1 COMPLETED(ECS deployment ecs-svc/6450379161618437361 completed.)
2023/11/29 14:36:25 (service demo-ecspresso) has stopped 1 running tasks: (task 31c9660ce56d45deb944f03620e9b398).
2023/11/29 14:36:29 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:1 pending:0 running:1 IN_PROGRESS(ECS deployment ecs-svc/2871655535974756192 in progress.)
2023/11/29 14:36:29 demo-ecspresso/demo-ecspresso ACTIVE demo-ecspresso:2 desired:0 pending:0 running:0 COMPLETED(ECS deployment ecs-svc/6450379161618437361 completed.)
2023/11/29 14:38:09 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:1 pending:0 running:1 IN_PROGRESS(ECS deployment ecs-svc/2871655535974756192 in progress.)
2023/11/29 14:38:09 demo-ecspresso/demo-ecspresso DRAINING demo-ecspresso:2 desired:0 pending:0 running:0 COMPLETED(ECS deployment ecs-svc/6450379161618437361 completed.)
2023/11/29 14:38:19 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:1 pending:0 running:1 IN_PROGRESS(ECS deployment ecs-svc/2871655535974756192 in progress.)
2023/11/29 14:38:48 (service demo-ecspresso) (deployment ecs-svc/2871655535974756192) deployment completed.
2023/11/29 14:38:48 (service demo-ecspresso) has reached a steady state.
2023/11/29 14:38:49 demo-ecspresso/demo-ecspresso PRIMARY demo-ecspresso:3 desired:1 pending:0 running:1 COMPLETED(ECS deployment ecs-svc/2871655535974756192 completed.)
2023/11/29 14:38:59 demo-ecspresso/demo-ecspresso Service is stable now. Completed!
デプロイが完了したのでECSタスクのPublic IPにアクセスすると、新しい文字列が表示されていることが確認できます。
stateファイルからECSリソースの設定を削除する
デプロイ完了後はterraform state rm
コマンドを使用して、ECSリソースの管理をTerraformから外すことで移行が完了です。
まとめ
ECSのリソース管理をTerraformからecspressoに移行する手順を共有しました。ecspresso init
で既存リソースから設定ファイルを作成できるため、比較的スムーズに移行ができたと実感しております。
ただし定義ファイル内でAWSリソースのidやarnを直接参照しているため、それらをTerraformのstateファイルから参照する必要があります。別の記事でリファクタリング方法について共有する予定です。