RunTask APIでタスクが起動できるようにするまでの手順があやふやだったので。
VPC, サブネットのみがある状態から好きな処理をRunTaskできるようにするまでの手順。
Dockerイメージ作成まで
Amazon Linux 2インスタンス起動。ECSへのアクションはIAMロールで許可しておく。
sudo yum install -y docker
sudo service docker start
node用のDockerfile
の作り方はnode公式が詳しい。
FROM node:14
WORKDIR /usr/src/app
COPY . .
CMD [ "node", "index.js" ]
index.js
をDockerfile
と同じディレクトリに作る。1秒sleepするだけ。
const main = async () => {
console.log("start");
await sleep(1000);
console.log("end");
}
const sleep = (waitSec) => {
return new Promise( (resolve) => {
setTimeout(() => { resolve() }, waitSec);
});
}
main();
ビルドしてrunすると実行される。
sudo docker build . -t sleep-batch
sudo docker run sleep-batch
ECRコンソールからレポジトリを作成しておき、表示されるコマンドを順次打つだけでECRへ上記のイメージがpushできる。
ECSタスク定義をCloudFormationで作成するまで
前提条件
- VPC は事前作成されていること
- サブネットも事前作成されていること、多分インターネットアクセスが必要?(特に確かめておらず)
テンプレート
この記事をすごく参考にした。
作成されるリソース
- アウトバウンドのみ全許可のSG
- タスクのログ出力用のCloudWatchロググループ
- ECSクラスター
- ECSタスク定義
※ 先ほど作ったdockerイメージを使ってサービスもデプロイすると、ひたすらタスクが起動と停止を繰り返して気持ち悪いのでコメントアウト。書く段階であまりサービスの意味がわかっていなかった...
Parameters:
ECSClusterName:
Type: String
Default: "ECS-cluster"
ECSTaskName:
Type: String
Default: "ECS-task"
ECSContainerName:
Type: String
Default: "ECS-container"
ECSServiceName:
Type: String
Default: "service"
ECSTaskCPUUnit:
AllowedValues: [ 256, 512, 1024, 2048, 4096 ]
Type: String
Default: "256"
ECSTaskMemory:
AllowedValues: [ 512, 1024, 2048, 4096 ]
Type: String
Default: "512"
ECSImage:
Type: String
Description: "Image URL or name"
TargetVpc:
Type: AWS::EC2::VPC::Id
# TargetSubnets:
# Type: List<AWS::EC2::Subnet::Id>
Resources:
# SGはアウトバウンドのみ
ECSSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
VpcId: !Ref TargetVpc
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
GroupDescription: "ECS SG created by CloudFormation"
# ContainerDefinitions.Options で awslogs-create-group: true にするためにはタスク実行ロールに reateLogGroup 権限をつける必要があるという噂があるので、ロググループを作る
ECSLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: !Sub "/ecs/${ECSTaskName}"
RetentionInDays: 30
# クラスター
ECSCluster:
Type: 'AWS::ECS::Cluster'
Properties:
ClusterName: !Ref ECSClusterName
# タスク
ECSTaskDefinition:
Type: "AWS::ECS::TaskDefinition"
Properties:
Cpu: !Ref ECSTaskCPUUnit
ExecutionRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole"
Memory: !Ref ECSTaskMemory
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
# コンテナ
ContainerDefinitions:
- Name: !Ref ECSContainerName
Image: !Ref ECSImage
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ECSLogGroup
awslogs-region: !Ref "AWS::Region"
awslogs-stream-prefix: "ECS"
# # サービス
# ECSService:
# Type: AWS::ECS::Service
# Properties:
# Cluster: !Ref ECSCluster
# LaunchType: FARGATE
# NetworkConfiguration:
# AwsvpcConfiguration:
# AssignPublicIp: ENABLED
# SecurityGroups:
# - !Ref ECSSecurityGroup
# Subnets: !Ref TargetSubnets
# ServiceName: !Ref ECSServiceName
# TaskDefinition: !Ref ECSTaskDefinition
その後
力尽きたのでコンソールからタスク実行した。AssignPublicIpを明示的にtrueにしないと以下の理由でタスクの起動に失敗していたので、やっぱりインターネット接続が必要なのではなかろうか...?
ResourceInitializationError: unable to pull secrets or registry auth: pull command failed: : signal: killed
あとはStep Functionsなりで定期実行するなりするつもり。