はじめに
スケジュールタスクの管理・運用に便利な「ecschedule」について、別の記事で基本操作をご紹介しました。前回の記事では、ローカル環境で操作しタスクスケジュールを更新する方法を説明しました。
しかし、ecscheduleにはタスク定義を更新する機能がないため、実運用では別の方法でタスク定義を更新する必要があります。
そこで、ecspressoのタスク定義更新機能と組み合わせることで、タスクスケジュールの更新を自動化できるのではないかと考えました。
今回は、ecscheduleに加え、ecspressoとGitHub Actionsを組み合わせて、タスクスケジュールを自動更新する方法について書いていきます。
書くこと
- ecspresso + ecschedule + Actionsでスケジュールタスクを自動更新する方法
前提
- AWS Fargate上でApache httpdイメージからコンテナを起動する環境を用意
- ecspressoで使用する設定ファイルの用意
- AWSのnetwork周りをTerraformで管理
ディレクトリ構成
.
├── .github
│ └── workflows
│ └── deploy.yml
├── .gitignore
├── deploy
│ ├── ecs-task-def.json
│ ├── ecschedule.yaml
│ └── ecspresso.yml
└── terraform
└── env
└── prod
├── .terraform-version
├── .terraform.lock.hcl
├── main.tf
├── network.tf
└── variable.tf
Actionsの作成
Github Actionsを使ってスケジュールタスクの自動更新ワークフローを作成していきます。
大まかな処理の流れは以下の通りです。
- ecspressoを使ってタスク定義の更新
- 最新のタスク定義のリビジョンを取得
- ecscheduleでスケジュールタスクを更新
name: 'deploy'
on:
push:
branches:
- master
jobs:
register-task-definition:
runs-on: ubuntu-latest
steps:
- name: "checkoutする"
uses: actions/checkout@v4
- name: "ecspressoのインストール"
uses: kayac/ecspresso@v2
with:
version: latest
- name: "タスク定義の登録"
run: |
ecspresso register --config ecspresso.yml
shell:
bash
working-directory: ./deploy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
AWS_DEFAULT_REGION: ap-northeast-1
update-ecs-schedule:
needs: ["register-task-definition"]
runs-on: ubuntu-latest
steps:
- name: "checkoutする"
uses: actions/checkout@v4
- name: "ecscheduleのインストール"
uses: Songmu/ecschedule@main
with:
version: latest
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
aws-region: ap-northeast-1
- name: "ECSのスケジュールを更新する"
run: |
ecschedule -conf ecschedule.yaml apply -all
shell: bash
working-directory: ./deploy
env:
S3_TFSTATE_URL: ${{ secrets.S3_TFSTATE_URL_PROD }}
タスク定義の更新
はじめにregister-task-definition
ジョブでタスク定義を更新しています。
まずはタスク定義の更新に必要なecspressoをインストールし、その後register
コマンドでタスク定義を更新しています。
deployディレクトリ以下にあるecspresso関連の設定ファイルの内容は以下のようになっています。
region: "ap-northeast-1"
cluster: ecshedule-test
service: ecschedule-test
task_definition: ecs-task-def.json
timeout: "10m0s"
{
"containerDefinitions": [
{
"command": [
"sh",
"-c",
"echo 'Hello World.' \u003e index.html \u0026\u0026 httpd-foreground"
],
"cpu": 0,
"essential": true,
"image": "httpd:latest",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/ecschedule-test",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
},
"name": "apache",
"portMappings": [
{
"appProtocol": "http",
"containerPort": 80,
"hostPort": 80,
"name": "apache-80-tcp",
"protocol": "tcp"
}
],
"workingDirectory": "/usr/local/apache2/htdocs/"
}
],
"cpu": "256",
"executionRoleArn": "arn:aws:iam::XXXXXXXXXXX:role/ecsTaskExecutionRole",
"family": "ecschedule-test",
"memory": "512",
"networkMode": "awsvpc",
"requiresCompatibilities": [
"FARGATE"
],
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
},
"taskRoleArn": "arn:aws:iam::XXXXXXXXXXX:role/ecsTaskExecutionRole"
}
スケジュールタスクの更新
update-ecs-schedule
ジョブでは、最新のタスク定義リビジョンの取得とスケジュールタスクの更新を行います。ここで、register-task-definition
ジョブで登録されたタスク定義のリビジョンを取得するために、needs
キーワードを使って依存関係を作成しています。
最新のリビジョン番号を取得するには、AWS CLIのaws ecs list-task-definitions
コマンドとシェルスクリプトを組み合わせています。取得したリビジョン番号はGitHub Actionsの環境変数TASK_DEFINITION_REVISION
に追加され、後続のステップで利用可能になります。
今回は--family-prefix ecschedule-test
で対象のタスク定義を指定していますが、皆さんの環境に合わせて適宜書き換えてください。
taskDefinitionにリビジョン番号を指定しなければ、自動的に最新のリビジョンを指定してくれるので上記の手順は必要ありませんでした。
ecschedule.yaml
の設定は以下のようになっています。
region: ap-northeast-1
cluster: ecshedule-test
rules:
- name: ecschedule-example
scheduleExpression: rate(10 minutes)
disabled: true
targetId: test
taskDefinition: ecschedule-test
launch_type: FARGATE
platform_version: LATEST
network_configuration:
aws_vpc_configuration:
subnets:
- {{ tfstate `aws_subnet.private_subnet_a.id` }}
- {{ tfstate `aws_subnet.private_subnet_c.id` }}
- {{ tfstate `aws_subnet.private_subnet_d.id` }}
security_groups:
- {{ tfstate `aws_security_group.default_sg.id` }}
assign_public_ip: DISABLE
plugins:
- name: tfstate
config:
url: {{ must_env `S3_TFSTATE_URL` }}
説明
タスク定義リビジョンの置き換え
- taskDefinitionのリビジョン番号部分を、最新のリビジョン番号である
TASK_DEFINITION_REVISION
に置き換えます
ネットワーク設定
- subnetsおよびsecurity_groupsの値は、tfstateから取得するように設定しています。これにより、TerraformのstateファイルからサブネットIDとセキュリティグループIDを動的に取得します
プラグイン設定
- tfstateプラグインを追加し、Terraformの状態ファイルが保管されているURLもしくはパスを指定する必要があります
- 今回はstateファイルをS3で管理しているのでs3のURLを入れています
この設定により、最新のタスク定義リビジョンを確実に取得し、それを使用してスケジュールタスクを更新することができます。サブネットとセキュリティグループの設定は、Terraformのstateファイルから動的に取得されるため、インフラストラクチャの変更や複数環境への反映に柔軟に対応できます。
デプロイに必要な権限
上記Actionsを実行するために必要な権限は以下になります。
各用途毎にpolicyを分けています。
ecschedule-policy
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"events:TagResource",
"events:PutTargets",
"events:PutRule",
"events:ListTargetsByRule",
"events:ListRules"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
get-tfstate
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::hoge/terraform.tfstate"
]
},
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::hoge" #tfstateを保管しているバケットを指定
]
}
]
}
passrole
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "IAM",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::XXXXXXXXXXXX:role/ecsTaskExecutionRole",
"arn:aws:iam::XXXXXXXXXXXX:role/ecsEventsRole"
]
}
]
}
register-ecs-task-def
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ecs:RegisterTaskDefinition",
"ecs:ListTaskDefinitions",
"ecs:DescribeTaskDefinition"
],
"Effect": "Allow",
"Resource": "*",
"Sid": "ECSRegisterTaskDefinition"
}
]
}
実行結果
実際に動くか検証していきます。
タスク定義のcomanndを書き換えてapacheのバージョンを出力するように書き換えます。
command": [
- "sh",
- "-c",
- "echo 'Hello World.' \u003e index.html \u0026\u0026 httpd-foreground"
+ "httpd",
+ "-v"
]
変更をコミットしてリポジトリにpush
ワークフローが実行完了したことを確認
Cloudwatch logsにApacheのバージョンが記録されているので、更新したスケジュールタスクの処理が完了している
まとめ
今回は、ecschedule、ecspresso、そしてGitHub Actionsを使ってスケジュールタスクを自動更新する方法を紹介しました。
自動化することで、タスク定義を更新した際にスケジュールタスクの設定を変更し忘れるといったミスを防ぐことが期待できます。
皆さんの環境に合わせて設定を調整し、より効率的なスケジュールタスクの運用を目指していきましょう!!