Skip to content

Instantly share code, notes, and snippets.

@hierynomus
Created March 26, 2019 18:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hierynomus/7293e4c0d233bf50df1f50627566bfb4 to your computer and use it in GitHub Desktop.
Save hierynomus/7293e4c0d233bf50df1f50627566bfb4 to your computer and use it in GitHub Desktop.
Description: >
Sub template to setup an ECS cluster for running XebiaLabs JetPack
Parameters:
EnvironmentName:
AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$
Description: An environment name that will be prefixed to resource names.
Type: String
InstanceType:
Description: Which instance type should we use to build the ECS cluster?
Type: String
Default: c4.large
MinimumClusterSize:
Description: How many ECS hosts need to be deployed minimally?
Type: Number
Default: 2
DesiredClusterSize:
Description: How many ECS hosts do you want to initially deploy?
Type: Number
Default: 2
MaximumClusterSize:
Description: How many ECS hosts need to be deployed maximally?
Type: Number
Default: 2
VPC:
Description: Choose which VPC this ECS cluster should be deployed to
Type: AWS::EC2::VPC::Id
Subnets:
Description: Choose which subnets this ECS cluster should be deployed to
Type: List<AWS::EC2::Subnet::Id>
ECSSecurityGroup:
Description: The security group to attach to the ECS cluster instances
Type: AWS::EC2::SecurityGroup::Id
ECSAMI:
Description: ECS-Optimized AMI ID
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ecs/optimized-ami/amazon-linux/recommended/image_id
KeyPairName:
Description: The name of an existing public/private key pair, which allows you to securely connect to your instance after it launches
Type: AWS::EC2::KeyPair::KeyName
MountPoint:
Description: The Linux mount point for the EFS volume
Type: String
MinLength: '1'
Default: /mnt/efs
Filesystem:
Description: EFS FileSystem to be used on ECS for persistent sotrage
Type: String
Resources:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref EnvironmentName
ECSAutoScalingGroup:
DependsOn: ECSCluster
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier: !Ref Subnets
LaunchConfigurationName: !Ref ECSLaunchConfiguration
MinSize: !Ref MinimumClusterSize
MaxSize: !Ref MaximumClusterSize
DesiredCapacity: !Ref DesiredClusterSize
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} ECS host
PropagateAtLaunch: true
CreationPolicy:
ResourceSignal:
Timeout: PT15M
UpdatePolicy:
AutoScalingRollingUpdate:
MinInstancesInService: 1
MaxBatchSize: 1
PauseTime: PT15M
SuspendProcesses:
- HealthCheck
- ReplaceUnhealthy
- AZRebalance
- AlarmNotification
- ScheduledActions
WaitOnResourceSignals: true
ECSLaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !Ref ECSAMI
InstanceType: !Ref InstanceType
SecurityGroups:
- !Ref ECSSecurityGroup
IamInstanceProfile: !Ref ECSInstanceProfile
UserData:
"Fn::Base64": !Sub |
#!/bin/bash
yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
yum install -y https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
yum install -y aws-cfn-bootstrap hibagent
/opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSLaunchConfiguration
/opt/aws/bin/cfn-signal -e $? --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSAutoScalingGroup
/usr/bin/enable-ec2-spot-hibernation
Metadata:
AWS::CloudFormation::Init:
config:
packages:
yum:
collectd: []
nfs-utils: []
commands:
01_add_instance_to_cluster:
command: !Sub echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config
02_enable_cloudwatch_agent:
command: !Sub /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c ssm:${ECSCloudWatchParameter} -s
03_createdir:
command: !Sub "mkdir -p /${MountPoint}"
04_mount:
command: !Sub >
mount -t nfs4 -o nfsvers=4.1 ${Filesystem}.efs.${AWS::Region}.amazonaws.com:/ /${MountPoint}
05_fstab:
command: !Sub >
echo ${Filesystem}.efs.${AWS::Region}.amazonaws.com:/ /${MountPoint} nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0 >> /etc/fstab
# 03_permissions:
# command: !Sub "chown -R ec2-user:ec2-user /${MountPoint}"
06_permissions_ecs_xld:
command: !Sub "mkdir -p /${MountPoint}/xl-deploy/repository && mkdir -p /${MountPoint}/xl-deploy/work && chmod g+w -R /${MountPoint}"
07_permissions_ecs_xlr:
command: !Sub "mkdir -p /${MountPoint}/xl-release/repository && mkdir -p /${MountPoint}/xl-release/work && chmod g+w -R /${MountPoint}"
# 08_restart_docker_and_ecs:
# command: "service docker restart && start ecs"
files:
/etc/cfn/cfn-hup.conf:
mode: 000400
owner: root
group: root
content: !Sub |
[main]
stack=${AWS::StackId}
region=${AWS::Region}
/etc/cfn/hooks.d/cfn-auto-reloader.conf:
content: !Sub |
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.ECSLaunchConfiguration.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSLaunchConfiguration
services:
sysvinit:
cfn-hup:
enabled: true
ensureRunning: true
files:
- /etc/cfn/cfn-hup.conf
- /etc/cfn/hooks.d/cfn-auto-reloader.conf
# This IAM Role is attached to all of the ECS hosts. It is based on the default role
# published here:
# http://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html
#
# You can add other IAM policy statements here to allow access from your ECS hosts
# to other AWS services. Please note that this role will be used by ALL containers
# running on the ECS host.
ECSInstanceRole:
Type: AWS::IAM::Role
Properties:
Path: /
RoleName: !Sub ${EnvironmentName}-ECSRole-${AWS::Region}
AssumeRolePolicyDocument: |
{
"Statement": [{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}]
}
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
Policies:
- PolicyName: ecs-service
PolicyDocument: |
{
"Statement": [{
"Effect": "Allow",
"Action": [
"ecs:CreateCluster",
"ecs:DeregisterContainerInstance",
"ecs:DiscoverPollEndpoint",
"ecs:Poll",
"ecs:RegisterContainerInstance",
"ecs:StartTelemetrySession",
"ecs:Submit*",
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
"ecr:GetAuthorizationToken"
],
"Resource": "*"
}]
}
ECSInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref ECSInstanceRole
ECSServiceAutoScalingRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
Action:
- "sts:AssumeRole"
Effect: Allow
Principal:
Service:
- application-autoscaling.amazonaws.com
Path: /
Policies:
- PolicyName: ecs-service-autoscaling
PolicyDocument:
Statement:
Effect: Allow
Action:
- application-autoscaling:*
- cloudwatch:DescribeAlarms
- cloudwatch:PutMetricAlarm
- ecs:DescribeServices
- ecs:UpdateService
Resource: "*"
ECSServiceRole:
Type: AWS::IAM::Role
Properties:
Path: /
RoleName: !Sub ${EnvironmentName}-ECSServiceRole-${AWS::Region}
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ecs.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: !Sub ecs-service-${AWS::StackName}
PolicyDocument:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:Describe*",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:Describe*",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:RegisterTargets"
],
"Resource": "*"
}]
}
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
Path: /
RoleName: !Sub ${EnvironmentName}-ECSTaskExecutionRole-${AWS::Region}
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
ECSCloudWatchParameter:
Type: AWS::SSM::Parameter
Properties:
Description: ECS
Name: !Sub "AmazonCloudWatch-${ECSCluster}-ECS"
Type: String
Value: !Sub |
{
"logs": {
"force_flush_interval": 5,
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/messages",
"log_group_name": "${ECSCluster}-/var/log/messages",
"log_stream_name": "{instance_id}",
"timestamp_format": "%b %d %H:%M:%S"
},
{
"file_path": "/var/log/dmesg",
"log_group_name": "${ECSCluster}-/var/log/dmesg",
"log_stream_name": "{instance_id}"
},
{
"file_path": "/var/log/docker",
"log_group_name": "${ECSCluster}-/var/log/docker",
"log_stream_name": "{instance_id}",
"timestamp_format": "%Y-%m-%dT%H:%M:%S.%f"
},
{
"file_path": "/var/log/ecs/ecs-init.log",
"log_group_name": "${ECSCluster}-/var/log/ecs/ecs-init.log",
"log_stream_name": "{instance_id}",
"timestamp_format": "%Y-%m-%dT%H:%M:%SZ"
},
{
"file_path": "/var/log/ecs/ecs-agent.log.*",
"log_group_name": "${ECSCluster}-/var/log/ecs/ecs-agent.log",
"log_stream_name": "{instance_id}",
"timestamp_format": "%Y-%m-%dT%H:%M:%SZ"
},
{
"file_path": "/var/log/ecs/audit.log",
"log_group_name": "${ECSCluster}-/var/log/ecs/audit.log",
"log_stream_name": "{instance_id}",
"timestamp_format": "%Y-%m-%dT%H:%M:%SZ"
}
]
}
}
},
"metrics": {
"append_dimensions": {
"AutoScalingGroupName": "${!aws:AutoScalingGroupName}",
"InstanceId": "${!aws:InstanceId}",
"InstanceType": "${!aws:InstanceType}"
},
"metrics_collected": {
"collectd": {
"metrics_aggregation_interval": 60
},
"disk": {
"measurement": [
"used_percent"
],
"metrics_collection_interval": 60,
"resources": [
"/"
]
},
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 60
},
"statsd": {
"metrics_aggregation_interval": 60,
"metrics_collection_interval": 10,
"service_address": ":8125"
}
}
}
}
Outputs:
Cluster:
Description: A reference to the ECS cluster
Value: !Ref ECSCluster
ECSServiceAutoScalingRole:
Description: A reference to ECS service auto scaling role
Value: !GetAtt ECSServiceAutoScalingRole.Arn
ECSServiceRole:
Description: A reference to ECS service role
Value: !GetAtt ECSServiceRole.Arn
ECSRole:
Description: A reference to the ECS Role
Value: !GetAtt ECSInstanceRole.Arn
ECSTaskExecutionRole:
Description: A reference to the ECS Task Execution Role
Value: !GetAtt ECSTaskExecutionRole.Arn
ECSAutoScalingGroupName:
Description: A reference to ECS AutoScaling Group Name
Value: !Ref ECSAutoScalingGroup
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment