以前、CloudFormationでLBなしのECS(EC2)最小構成を構築したが、今回はALBのTargetGroupまでをCDKで作成し、Serviceのデプロイをecs-cliで行う。
EC2をECSクラスタに登録する際の echo ECS_CLUSTER=<cluster_name> >> /etc/ecs/ecs.config
といった処理は
クラスタのAsgCapacityProvider
にASGを指定すると追加される。
ECS(EC2)のCloudFormation最小構成 - sambaiz-net
import * as cdk from '@aws-cdk/core'
import * as ecr from '@aws-cdk/aws-ecr'
import * as ecs from '@aws-cdk/aws-ecs'
import * as ec2 from '@aws-cdk/aws-ec2'
import * as iam from '@aws-cdk/aws-iam'
import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'
import * as autoscaling from '@aws-cdk/aws-autoscaling'
import { Cluster } from '@aws-cdk/aws-ecs'
export class ECSEC2Stack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props)
this.createECRRepository('test')
this.createLogGroup("test")
const ecsCluster = this.createECSCluster('test')
this.createASGForCluster(ecsCluster)
this.createALB('test', ecsCluster.vpc)
}
createECRRepository(name: string) {
const repository = new ecr.Repository(this, 'ECRRepository', {
repositoryName: name
})
return repository
}
createLogGroup(name: string) {
return new logs.LogGroup(this, 'LogGroup', {
logGroupName: name,
retention: RetentionDays.TWO_WEEKS
})
}
createECSCluster(name: string) {
const cluster = new ecs.Cluster(this, 'ECSCluster', {
clusterName: name,
})
return cluster
}
createASGForCluster(ecsCluster: Cluster) {
const securityGroup = new ec2.SecurityGroup(this, 'EC2SecurityGroup', {
vpc: ecsCluster.vpc,
})
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.allTcp())
const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', {
vpc: ecsCluster.vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
machineImage: ecs.EcsOptimizedImage.amazonLinux2(),
minCapacity: 1,
maxCapacity: 1,
securityGroup
})
ecsCluster.addAsgCapacityProvider(new ecs.AsgCapacityProvider(this, 'ASGCapacityProvider', {
autoScalingGroup
}))
autoScalingGroup.role.addManagedPolicy(
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSTaskExecutionRolePolicy'))
return autoScalingGroup
}
createALB(name: string, vpc: ec2.IVpc) {
const securityGroup = new ec2.SecurityGroup(this, 'EC2SecurityGroup', {
vpc: ecsCluster.vpc,
})
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(80))
const alb = new elbv2.ApplicationLoadBalancer(this, `ALB`, {
vpc: vpc,
internetFacing: true,
securityGroup
})
const target = new elbv2.ApplicationTargetGroup(this, 'TargetGroup', {
targetGroupName: name,
targetType: elbv2.TargetType.INSTANCE,
vpc: vpc,
protocol: elbv2.ApplicationProtocol.HTTP,
port: 80,
healthCheck: {
path: "/ping"
},
deregistrationDelay: cdk.Duration.seconds(5)
})
new elbv2.ApplicationListener(this, 'Listener', {
loadBalancer: alb,
defaultTargetGroups: [target],
protocol: elbv2.ApplicationProtocol.HTTP,
port: 80,
})
return alb
}
}
CloudWatchにログを送るためのawslogs log driverの設定を行う。 ECSコンソールのLogsにログを表示するにはprefixを指定する必要がある。
services:
app:
...
logging:
driver: awslogs
options:
awslogs-group: test
awslogs-region: ap-northeast-1
awslogs-stream-prefix: app
docker-compose.yml
がサポートしていないパラメータはecs-params.ymlに記述する。
version: 1
task_definition:
docker_volumes:
- name: log
scope: shared
autoprovision: true
ecs-cli compose service upでdocker-compose.ymlからサービスを作成する。
$ ecs-cli compose service up --target-groups "targetGroupArn=${TARGET_GROUP_ARN},containerName=app,containerPort=8080" --launch-type EC2 --cluster ${CLUSTER_NAME}
もしLBが503か504を返す場合、ECSのTaskがエラーで落ちていないか、TargetGroupのTargetにEC2インスタンスが紐づいているか、HealthCheckが通っているかといったことを確認する。