Skip to content

Instantly share code, notes, and snippets.

@irvingpop
Last active September 6, 2017 21:01
Show Gist options
  • Save irvingpop/a8bb9e3fa4563e82bf4a3d8ee701136d to your computer and use it in GitHub Desktop.
Save irvingpop/a8bb9e3fa4563e82bf4a3d8ee701136d to your computer and use it in GitHub Desktop.
Automate on Habitat on ECS, phase 1
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Description: Name of an existing EC2 KeyPair to enable SSH access to the ECS instances.
VPC:
Type: AWS::EC2::VPC::Id
Description: Select a VPC that allows instances access to the Internet.
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: Select at least two subnets in your selected VPC.
DesiredCapacity:
Type: Number
Default: '1'
Description: Number of instances to launch in your ECS cluster.
MaxSize:
Type: Number
Default: '2'
Description: Maximum number of instances that can be launched in your ECS cluster.
InstanceType:
Description: EC2 instance type
Type: String
Default: m4.xlarge
AllowedValues: [t2.micro, t2.small, t2.medium, t2.large, m3.medium, m3.large,
m3.xlarge, m3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge,
c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge, c3.large, c3.xlarge,
c3.2xlarge, c3.4xlarge, c3.8xlarge, r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge,
r3.8xlarge, i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge]
ConstraintDescription: Please choose a valid instance type.
ContactDept:
Description: Contact department for billing purposes
Type: String
ContactEmail:
Description: Contact email for Cloudwatch notifications and instance tagging
Type: String
Mappings:
AWSRegionToAMI:
us-east-1:
AMIID: ami-04351e12
us-east-2:
AMIID: ami-207b5a45
us-west-1:
AMIID: ami-7d664a1d
us-west-2:
AMIID: ami-57d9cd2e
Resources:
################################################################################
# Combo Service - runs all of the containers in a single task definition (1 host), so linking can work
################################################################################
AutomateService:
Type: AWS::ECS::Service
DependsOn: ALBListener
Properties:
Cluster: !Ref ECSCluster
DesiredCount: 1
LoadBalancers:
- ContainerName: automate-nginx
ContainerPort: 80
TargetGroupArn: !Ref ECSTG
Role: !Ref ECSServiceRole
TaskDefinition: !Ref AutomateTask
AutomateTask:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${AWS::StackName}-automate
ContainerDefinitions:
- Name: postgresql-data
Cpu: '10'
Essential: 'false'
Image: chefdemo/postgresql-data:stable
Memory: 300
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
MountPoints:
- ContainerPath: /hab/svc/postgresql/data
SourceVolume: postgresql-data
- Name: postgresql
Hostname: postgresql
Cpu: 10
Essential: 'true'
Image: chefdemo/postgresql:stable
Memory: 300
Environment:
- Name: HAB_POSTGRESQL
Value: |
[superuser]
name = 'hab'
password = 'chefrocks'
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
MountPoints:
- ContainerPath: /hab/svc/postgresql/data
SourceVolume: postgresql-data
VolumesFrom:
- SourceContainer: postgresql-data
ReadOnly: false
- Name: rabbitmq
Hostname: rabbitmq
Cpu: 10
Essential: 'true'
Image: chefdemo/rabbitmq:stable
Memory: 512
Links:
- postgresql
Command:
- --peer
- postgresql
Environment:
- Name: HAB_RABBITMQ
Value: |
[rabbitmq]
default_vhost = '/insights'
default_user = 'insights'
default_pass = 'chefrocks'
[rabbitmq.management]
enabled = true
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
- Name: elasticsearch
Hostname: elasticsearch
Cpu: 10
Essential: 'true'
Image: chefdemo/elasticsearch:stable
Memory: 2048
Links:
- postgresql
Command:
- --peer
- postgresql
Ulimits:
- Name: nofile
HardLimit: 262144
SoftLimit: 262144
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
- Name: logstash
Cpu: 10
Essential: 'true'
Image: chefdemo/logstash:stable
Memory: 2048
Links:
- rabbitmq
- elasticsearch
Command:
- --peer
- rabbitmq
- --bind
- elasticsearch:elasticsearch.default
- --bind
- rabbitmq:rabbitmq.default
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
- Name: workflow
Hostname: workflow
Cpu: 10
Essential: 'true'
Image: chefdemo/workflow-server:stable
Memory: 768
Links:
- postgresql
- rabbitmq
- elasticsearch
Command:
- --peer
- postgresql
- --bind
- database:postgresql.default
- --bind
- elasticsearch:elasticsearch.default
- --bind
- rabbitmq:rabbitmq.default
MountPoints:
- ContainerPath: /var/opt/delivery/delivery/etc
SourceVolume: maintenance
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
- Name: notifications
Hostname: notifications
Cpu: 10
Essential: 'true'
Image: chefdemo/notifications:stable
Memory: 768
Links:
- postgresql
- rabbitmq
- elasticsearch
Command:
- --peer
- postgresql
- --bind
- database:postgresql.default
- --bind
- elasticsearch:elasticsearch.default
- --bind
- rabbitmq:rabbitmq.default
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
- Name: compliance
Hostname: compliance
Cpu: 10
Essential: 'true'
Image: chefdemo/compliance:stable
Memory: 768
Links:
- postgresql
Command:
- --peer
- postgresql
- --bind
- elasticsearch:elasticsearch.default
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
- Name: automate-nginx
Hostname: automate-nginx
Cpu: 10
Essential: 'true'
Image: chefdemo/automate-nginx:stable
Memory: 300
PortMappings:
- ContainerPort: 80
- ContainerPort: 443
Links:
- postgresql
- rabbitmq
- elasticsearch
- compliance
Command:
- --peer
- postgresql
- --bind
- elasticsearch:elasticsearch.default
- --bind
- workflow:workflow-server.default
- --bind
- compliance:compliance.default
- --bind
- notifications:notifications.default
MountPoints:
- ContainerPath: /var/opt/delivery/delivery/etc
SourceVolume: maintenance
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref 'CloudwatchLogsGroup'
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Sub ${AWS::StackName}
Volumes:
- Name: postgresql-data
- Name: maintenance
ECSALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: ECSALB
Scheme: internet-facing
LoadBalancerAttributes:
- Key: idle_timeout.timeout_seconds
Value: '30'
Subnets: !Ref SubnetIds
SecurityGroups: [!Ref 'EcsSecurityGroup']
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn: ECSServiceRole
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref 'ECSTG'
LoadBalancerArn: !Ref 'ECSALB'
Port: '80'
Protocol: HTTP
ECSALBListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
DependsOn: ALBListener
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref 'ECSTG'
Conditions:
- Field: path-pattern
Values: [/]
ListenerArn: !Ref 'ALBListener'
Priority: 1
ECSTG:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
DependsOn: ECSALB
Properties:
HealthCheckIntervalSeconds: 10
HealthCheckPath: /viz/
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Name: ECSTG
Port: 80
Protocol: HTTP
UnhealthyThresholdCount: 2
VpcId: !Ref VPC
ECSServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action: ['elasticloadbalancing:DeregisterInstancesFromLoadBalancer', 'elasticloadbalancing:DeregisterTargets',
'elasticloadbalancing:Describe*', 'elasticloadbalancing:RegisterInstancesWithLoadBalancer',
'elasticloadbalancing:RegisterTargets', 'ec2:Describe*', 'ec2:AuthorizeSecurityGroupIngress']
Resource: '*'
################################################################################
# ECS Cluster - the EC2 instances (docker hosts) in an Autoscale group that make up the cluster
################################################################################
ECSCluster:
Type: AWS::ECS::Cluster
ECSAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier: !Ref SubnetIds
LaunchConfigurationName: !Ref 'DockerHosts'
MinSize: '1'
MaxSize: !Ref 'MaxSize'
DesiredCapacity: !Ref 'DesiredCapacity'
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-dockerhost
PropagateAtLaunch: true
- Key: X-Dept
Value: !Ref ContactDept
PropagateAtLaunch: true
- Key: X-Contact
Value: !Ref ContactEmail
PropagateAtLaunch: true
CreationPolicy:
ResourceSignal:
Timeout: PT15M
UpdatePolicy:
AutoScalingReplacingUpdate:
WillReplace: 'true'
DockerHosts:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !FindInMap [AWSRegionToAMI, !Ref 'AWS::Region', AMIID]
SecurityGroups: [!Ref 'EcsSecurityGroup']
InstanceType: !Ref 'InstanceType'
IamInstanceProfile: !Ref 'EC2InstanceProfile'
KeyName: !Ref 'KeyName'
EbsOptimized: true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 200
VolumeType: gp2
DeleteOnTermination: true
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config
yum install -y aws-cfn-bootstrap
# up the vm.max_map_count for elasticsearch
sysctl -w vm.max_map_count=262144
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region}
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action: ['ecs:CreateCluster', 'ecs:DeregisterContainerInstance', 'ecs:DiscoverPollEndpoint',
'ecs:Poll', 'ecs:RegisterContainerInstance', 'ecs:StartTelemetrySession',
'ecs:Submit*', 'logs:CreateLogStream', 'logs:PutLogEvents']
Resource: '*'
AutoscalingRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [application-autoscaling.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: service-autoscaling
PolicyDocument:
Statement:
- Effect: Allow
Action: ['application-autoscaling:*', 'cloudwatch:DescribeAlarms', 'cloudwatch:PutMetricAlarm',
'ecs:DescribeServices', 'ecs:UpdateService']
Resource: '*'
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles: [!Ref 'EC2Role']
EcsSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ECS Security Group
VpcId: !Ref VPC
EcsSecurityGroupHTTPinbound:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref 'EcsSecurityGroup'
IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 0.0.0.0/0
EcsSecurityGroupSSHinbound:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref 'EcsSecurityGroup'
IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: 0.0.0.0/0
EcsSecurityGroupALBports:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref 'EcsSecurityGroup'
IpProtocol: tcp
FromPort: '31000'
ToPort: '61000'
SourceSecurityGroupId: !Ref 'EcsSecurityGroup'
CloudwatchLogsGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Join ['-', [ECSLogGroup, !Ref 'AWS::StackName']]
RetentionInDays: 14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment