Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
691 lines (639 sloc) 23 KB
---
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Deploy external workers pool for Cycloid.io CI Platform.
Version of Concourse worker is automatically generated by a curl on scheduler_api_address/api/v1/info'
Parameters:
SchedulerApiAddress:
Description: Cycloid CI scheduler http api address
Type: String
Default: https://scheduler.cycloid.io
SchedulerHost:
Description: Cycloid CI scheduler address
Type: String
Default: scheduler.cycloid.io
SchedulerPort:
Description: Cycloid CI scheduler port
Type: String
Default: 32223
AutoScalingGroupName:
Description: The name of the Auto Scaling group. This name must be unique per Region per account.
Type: String
Default: asg-cycloid-ci-workers
NumberOfWorkers:
Description: Number of Cycloid CI workers. If the InstanceSpotPriceEnabled variable is true, the value will be always 0 but will be used for Desired Capacity.
Type: Number
Default: 1
ConstraintDescription: If the InstanceSpotPriceEnabled variable is true, the value will be always 0.
VolumeSize:
Description: Size of the EBS volume for Cycloid CI worker
Type: Number
Default: 150
TeamId:
Description: Cycloid CI team ID
Type: String
TsaPublicKey:
Description: Cycloid CI tsa public key
Type: String
Default: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+To6R1hDAO00Xrt8q5Md38J9dh+aMIbV2GTqQkFcKwVAB6czbPPcitPWZ7y3Bw1dKMC8R7DGRAt01yWlkYo/voRp5prqKMc/uzkObhHNy42eJgZlStKU1IMw/fx0Rx+6Y3NClCCOecx415dkAH+PFudKosq4pFB9KjfOp3tMHqirMSF7dsbM3910gcPBL2NFHkOZ4cNfeSztXEg9wy4SExX3CHiUyLiShpwXa+C2f6IPdOJt+9ueXQIL0hcMmd12PRL5UU6/e5U5kldM4EWiJoohVbfoA1CRFF9QwJt6H3IiZPmd3sWqIVVy6Vssn5okjYLRwCwEd8+wd8tI6OnNb"
WorkerKey:
Description: Cycloid CI worker private key. Base64 encoded
Type: String
InstanceType:
Description: Worker EC2 instance type
Type: String
Default: c5d.xlarge
AllowedValues:
- t1.micro
- t2.nano
- t2.micro
- t2.small
- t2.medium
- t2.large
- t3.nano
- t3.micro
- t3.small
- t3.medium
- t3.large
- t3.xlarge
- t3.2xlarge
- m1.small
- m1.medium
- m1.large
- m1.xlarge
- m2.xlarge
- m2.2xlarge
- m2.4xlarge
- m3.medium
- m3.large
- m3.xlarge
- m3.2xlarge
- m4.large
- m4.xlarge
- m4.2xlarge
- m4.4xlarge
- m4.10xlarge
- m5.large
- m5.xlarge
- m5.2xlarge
- m5.4xlarge
- m5d.large
- m5d.xlarge
- m5d.2xlarge
- m5d.4xlarge
- m5d.8xlarge
- c1.medium
- c1.xlarge
- c3.large
- c3.xlarge
- c3.2xlarge
- c3.4xlarge
- c3.8xlarge
- c4.large
- c4.xlarge
- c4.2xlarge
- c4.4xlarge
- c4.8xlarge
- c5d.large
- c5d.xlarge
- c5d.2xlarge
- c5d.4xlarge
- g2.2xlarge
- g2.8xlarge
- r3.large
- r3.xlarge
- r3.2xlarge
- r3.4xlarge
- r3.8xlarge
- i2.xlarge
- i2.2xlarge
- i2.4xlarge
- i2.8xlarge
- d2.xlarge
- d2.2xlarge
- d2.4xlarge
- d2.8xlarge
- hi1.4xlarge
- hs1.8xlarge
- cr1.8xlarge
- cc2.8xlarge
- cg1.4xlarge
ConstraintDescription: must be a valid EC2 instance type.
InstanceSpotPriceEnabled:
Type: String
Description: Activate or deactivate spot instances.
AllowedValues:
- 'true'
- 'false'
Default: 'false'
ConstraintDescription: must specify true or false.
InstanceSpotPrice:
Description: |
The maximum hourly price to be paid for any Spot Instance launched to fulfill the request. Spot Instances are launched when the price you specify exceeds the current Spot market price.
You can find more information about the pricing here: https://aws.amazon.com/ec2/spot/pricing/.
Type: String
Default: "0.5"
ConstraintDescription: If the InstanceSpotPriceEnabled variable is true, you must specify the maximum hourly price to be paid.
KeyName:
Description: The EC2 Key Pair to allow SSH access to the instances
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair.
SSHSecurityGroup:
Description: Instances from this security group will be allowed to connect using SSH on Cycloid CI workers
Type: AWS::EC2::SecurityGroup::Id
MetricsSecGroup:
Description: Instances from this security group will be allowed to read metrics endpoint on Cycloid workers
Type: AWS::EC2::SecurityGroup::Id
# SSHLocation:
# Description: The IP address range that can be used to SSH to the EC2 instances
# Type: String
# MinLength: '9'
# MaxLength: '18'
# Default: 0.0.0.0/0
# AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
# ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
VpcId:
Type: AWS::EC2::VPC::Id
Description: VpcId of your existing Virtual Private Cloud (VPC)
ConstraintDescription: must be the VPC Id of an existing Virtual Private Cloud.
Subnets:
Type: List<AWS::EC2::Subnet::Id>
Description: The list of SubnetIds in your Virtual Private Cloud (VPC)
ConstraintDescription: They should be residing in the
selected Virtual Private Cloud.
ScheduledWorkersEnabled:
Type: String
Description: Activate or deactivate scheduling.
AllowedValues:
- 'true'
- 'false'
Default: 'false'
ConstraintDescription: must specify true or false.
ScheduledWorkersStartRecurrence:
Type: String
Description: Specifying the recurring StartTime (UTC) for this action, in Unix cron syntax format. For more information about cron syntax, see http://crontab.org/.
Default: "0 20 * * *"
ScheduledWorkersStopRecurrence:
Type: String
Description: Specifying the recurring EndTime (UTC) for this action, in Unix cron syntax format. For more information about cron syntax, see http://crontab.org/.
Default: "0 7 * * *"
CustomerTag:
Description: Name of the Cycloid Organization, used as customer variable name
Type: String
ProjectTag:
Description: Name of the project
Type: String
Default: cycloid-ci-workers
EnvironmentTag:
Description: Name of the project's environment
Type: String
Default: prod
Mappings:
# Generate :
# export regions="us-east-1 us-west-2 us-west-1 eu-west-1 eu-west-2 eu-west-3 eu-central-1 ap-northeast-1 ap-northeast-2 ap-northeast-3 ap-southeast-1 ap-southeast-2 ap-south-1 us-east-2 ca-central-1 sa-east-1 cn-north-1 cn-northwest-1"
# for region in $regions; do image=$(aws --region $region ec2 describe-images --owners 379101102735 --filters "Name=name,Values=debian-stretch-*" "Name=architecture,Values=x86_64" "Name=virtualization-type,Values=hvm" | jq -r '.Images[] | "\(.CreationDate) \(.ImageId)"' | sort | awk 'END{print $2}'); echo -e " $region:\n image: $image"; done
AWSRegionArch2AMI:
us-east-1:
image: ami-0f9e7e8867f55fd8e
us-west-2:
image: ami-01d07e14f082b3ba1
us-west-1:
image: ami-0afda78f1d0272d99
eu-west-1:
image: ami-035c67e6a9ef8f024
eu-west-2:
image: ami-0ef10a4062f24d89d
eu-west-3:
image: ami-0cb185e7696ffe300
eu-central-1:
image: ami-05449f21272b4ee56
ap-northeast-1:
image: ami-0c4290d7ce45d7bbe
ap-northeast-2:
image: ami-0fa1392d5d545f9e8
ap-southeast-1:
image: ami-04c9740a9ed018dba
ap-southeast-2:
image: ami-0b91189c4f9f5cd9e
ap-south-1:
image: ami-0b6490868957ce747
us-east-2:
image: ami-00c5940f2b52c5d98
ca-central-1:
image: ami-0857efbad274a1a89
sa-east-1:
image: ami-0bc0ce4ab8b82305c
Conditions:
EnabledScheduling: !Equals [!Ref ScheduledWorkersEnabled, 'true']
EnabledSpotInstances: !Equals [!Ref InstanceSpotPriceEnabled, 'true']
DisabledSpotInstances: !Equals [!Ref InstanceSpotPriceEnabled, 'false']
Resources:
WorkersRole:
Type: "AWS::IAM::Role"
Properties:
#RoleName: "cycloid-ci-workers"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
Policies:
-
PolicyName: "cycloid-ci-workers"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action: "ec2:DescribeTags"
Resource: "*"
-
PolicyName: "cycloid-ci-workers-cf-signals"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action: "cloudformation:SignalResource"
Resource:
Ref: AWS::StackId
-
PolicyName: "cycloid-ci-workers-cw-logs-push"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "logs:UntagLogGroup"
- "logs:TagLogGroup"
- "logs:PutRetentionPolicy"
- "logs:PutLogEvents"
- "logs:DeleteRetentionPolicy"
- "logs:CreateLogStream"
Resource: "arn:aws:logs:*:*:log-group:cycloid-ci-workers_prod:*"
-
PolicyName: "cycloid-ci-workers-cw-logs"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "logs:ListTagsLogGroup"
- "logs:DescribeSubscriptionFilters"
- "logs:DescribeMetricFilters"
- "logs:DescribeLogStreams"
- "logs:DescribeLogGroups"
- "logs:TestMetricFilter"
- "logs:DescribeResourcePolicies"
- "logs:DescribeExportTasks"
- "logs:DescribeDestinations"
- "logs:CreateLogGroup"
Resource: "*"
WorkersInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
- Ref: "WorkersRole"
WorkersGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier:
Ref: Subnets
LaunchConfigurationName:
Fn::If:
- EnabledSpotInstances
- Ref: LaunchConfigSpotPrice
- Ref: LaunchConfig
DesiredCapacity:
Ref: NumberOfWorkers
MinSize:
Fn::If:
- EnabledSpotInstances
- 0
- Ref: NumberOfWorkers
MaxSize:
Ref: NumberOfWorkers
Tags:
- Key: "Name"
Value: "cycloid-ci-workers"
PropagateAtLaunch: true
- Key: "cycloid.io"
Value: "true"
PropagateAtLaunch: true
- Key: "project"
Value:
Ref: ProjectTag
PropagateAtLaunch: true
- Key: "customer"
Value:
Ref: CustomerTag
PropagateAtLaunch: true
- Key: "role"
Value: "worker"
PropagateAtLaunch: true
- Key: "env"
Value:
Ref: EnvironmentTag
PropagateAtLaunch: true
CreationPolicy:
ResourceSignal:
Timeout: PT15M
Count: '1'
UpdatePolicy:
AutoScalingRollingUpdate:
MinInstancesInService: '1'
MaxBatchSize: '1'
PauseTime: PT15M
WaitOnResourceSignals: 'true'
LaunchConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Condition: DisabledSpotInstances
Properties:
KeyName:
Ref: KeyName
ImageId:
Fn::FindInMap:
- AWSRegionArch2AMI
- Ref: AWS::Region
- image
SecurityGroups:
- Ref: InstanceSecurityGroup
- Ref: MetricsSecurityGroup
InstanceType:
Ref: InstanceType
IamInstanceProfile:
Ref: "WorkersInstanceProfile"
BlockDeviceMappings:
- DeviceName: "/dev/xvdf"
Ebs:
VolumeSize:
Ref: VolumeSize
VolumeType: "gp2"
DeleteOnTermination: "true"
UserData:
Fn::Base64:
Fn::Join:
- ''
- - "#!/bin/bash -xe\n"
- "export STACK_NAME="
- Ref: AWS::StackId
- "\n"
- "export SCHEDULER_API_ADDRESS='"
- Ref: SchedulerApiAddress
- "'\n"
- "export SCHEDULER_HOST="
- Ref: SchedulerHost
- "\n"
- "export SCHEDULER_PORT="
- Ref: SchedulerPort
- "\n"
- "export TSA_PUBLIC_KEY='"
- Ref: TsaPublicKey
- "'\n"
- "export WORKER_KEY='"
- Ref: WorkerKey
- "'\n"
- "export TEAM_ID="
- Ref: TeamId
- "\n"
- |
export LOG_FILE="/var/log/user-data.log"
exec &> >(tee -a ${LOG_FILE})
function finish {
if [ $? -eq 0 ]; then
echo "cloudformation signal-resource SUCCESS"
aws cloudformation signal-resource --stack-name ${STACK_NAME} --logical-resource-id WorkersGroup --unique-id ${AWS_UNIQUE_ID} --region ${AWS_DEFAULT_REGION} --status SUCCESS
else
set +e
echo "cloudformation signal-resource FAILURE"
if ! [ -f "/tmp/keeprunning" ]; then
aws cloudformation signal-resource --stack-name ${STACK_NAME} --logical-resource-id WorkersGroup --unique-id ${AWS_UNIQUE_ID} --region ${AWS_DEFAULT_REGION} --status FAILURE
sleep 60
halt -p
fi
fi
}
trap finish EXIT
echo "### starting setup of cycloid worker"
apt-get update
apt-get install -y git python-setuptools curl jq
easy_install pip
pip install -U cryptography
pip install ansible==2.6
pip install awscli
# Be able to use paris region (https://github.com/boto/boto/issues/3783)
pip install --upgrade boto
echo '[Boto]
use_endpoint_heuristics = True' > /etc/boto.cfg
cd /opt/
git clone https://github.com/cycloid-community-catalog/stack-external-worker
cd stack-external-worker/ansible
export HOME=/root
export AWS_DEFAULT_REGION=$(curl -sL http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region)
export AWS_UNIQUE_ID=$(curl -L http://169.254.169.254/latest/meta-data/instance-id)
export VERSION=$(curl -sL "${SCHEDULER_API_ADDRESS}/api/v1/info" | jq -r '.version')
cat >> prod-worker.yml <<EOF
concourse_version: "${VERSION}"
concourse_tsa_port: "$SCHEDULER_PORT"
concourse_tsa_host: "$SCHEDULER_HOST"
concourse_tsa_public_key: "$TSA_PUBLIC_KEY"
concourse_tsa_worker_key_base64: "$WORKER_KEY"
concourse_tsa_worker_key: "{{ concourse_tsa_worker_key_base64 | b64decode}}"
concourse_worker_team: "$TEAM_ID"
nvme_mapping_run: true
EOF
ansible-galaxy install -r requirements.yml --force --roles-path=/etc/ansible/roles
echo "Run packer.yml"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local packer.yml
echo "Run external-worker.yml build steps"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local external-worker.yml --diff --skip-tags deploy,notforbuild,telegraf
echo "Run /home/admin/first-boot.yml"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local /home/admin/first-boot.yml --diff
echo "Run external-worker.yml boot steps"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local external-worker.yml --diff --tags runatboot,notforbuild --skip-tags telegraf
sleep 60 && systemctl status concourse-worker
LaunchConfigSpotPrice:
Type: AWS::AutoScaling::LaunchConfiguration
Condition: EnabledSpotInstances
Properties:
KeyName:
Ref: KeyName
ImageId:
Fn::FindInMap:
- AWSRegionArch2AMI
- Ref: AWS::Region
- image
SecurityGroups:
- Ref: InstanceSecurityGroup
- Ref: MetricsSecurityGroup
InstanceType:
Ref: InstanceType
SpotPrice:
Ref: InstanceSpotPrice
IamInstanceProfile:
Ref: "WorkersInstanceProfile"
BlockDeviceMappings:
- DeviceName: "/dev/xvdf"
Ebs:
VolumeSize:
Ref: VolumeSize
VolumeType: "gp2"
DeleteOnTermination: "true"
UserData:
Fn::Base64:
Fn::Join:
- ''
- - "#!/bin/bash -xe\n"
- "export STACK_NAME="
- Ref: AWS::StackId
- "\n"
- "export SCHEDULER_API_ADDRESS='"
- Ref: SchedulerApiAddress
- "'\n"
- "export SCHEDULER_HOST="
- Ref: SchedulerHost
- "\n"
- "export SCHEDULER_PORT="
- Ref: SchedulerPort
- "\n"
- "export TSA_PUBLIC_KEY='"
- Ref: TsaPublicKey
- "'\n"
- "export WORKER_KEY='"
- Ref: WorkerKey
- "'\n"
- "export TEAM_ID="
- Ref: TeamId
- "\n"
- |
export LOG_FILE="/var/log/user-data.log"
exec &> >(tee -a ${LOG_FILE})
function finish {
if [ $? -eq 0 ]; then
echo "cloudformation signal-resource SUCCESS"
aws cloudformation signal-resource --stack-name ${STACK_NAME} --logical-resource-id WorkersGroup --unique-id ${AWS_UNIQUE_ID} --region ${AWS_DEFAULT_REGION} --status SUCCESS
else
set +e
echo "cloudformation signal-resource FAILURE"
if ! [ -f "/tmp/keeprunning" ]; then
aws cloudformation signal-resource --stack-name ${STACK_NAME} --logical-resource-id WorkersGroup --unique-id ${AWS_UNIQUE_ID} --region ${AWS_DEFAULT_REGION} --status FAILURE
sleep 60
halt -p
fi
fi
}
trap finish EXIT
echo "### starting setup of cycloid worker"
apt-get update
apt-get install -y git python-setuptools curl jq
easy_install pip
pip install -U cryptography
pip install ansible==2.4.6
pip install awscli
# Be able to use paris region (https://github.com/boto/boto/issues/3783)
pip install --upgrade boto
echo '[Boto]
use_endpoint_heuristics = True' > /etc/boto.cfg
cd /opt/
git clone https://github.com/cycloid-community-catalog/stack-external-worker
cd stack-external-worker/ansible
export HOME=/root
export AWS_DEFAULT_REGION=$(curl -sL http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region)
export AWS_UNIQUE_ID=$(curl -L http://169.254.169.254/latest/meta-data/instance-id)
export VERSION=$(curl -sL "${SCHEDULER_API_ADDRESS}/api/v1/info" | jq -r '.version')
cat >> prod-worker.yml <<EOF
concourse_version: "${VERSION}"
concourse_tsa_port: "$SCHEDULER_PORT"
concourse_tsa_host: "$SCHEDULER_HOST"
concourse_tsa_public_key: "$TSA_PUBLIC_KEY"
concourse_tsa_worker_key_base64: "$WORKER_KEY"
concourse_tsa_worker_key: "{{ concourse_tsa_worker_key_base64 | b64decode}}"
concourse_worker_team: "$TEAM_ID"
nvme_mapping_run: true
EOF
ansible-galaxy install -r requirements.yml --force --roles-path=/etc/ansible/roles
echo "Run packer.yml"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local packer.yml
echo "Run external-worker.yml build steps"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local external-worker.yml --diff --skip-tags deploy,notforbuild,telegraf
echo "Run /home/admin/first-boot.yml"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local /home/admin/first-boot.yml --diff
echo "Run external-worker.yml boot steps"
ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook -e role=workers -e env=prod -e project=cycloid-ci-workers --connection local external-worker.yml --diff --tags runatboot,notforbuild,telegraf
sleep 60 && systemctl status concourse-worker
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable SSH access and HTTP from the load balancer only
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
SourceSecurityGroupId:
Ref: SSHSecurityGroup
VpcId:
Ref: VpcId
Tags:
-
Key: "Name"
Value: "cycloid-ci-workers"
-
Key: "cycloid.io"
Value: "true"
-
Key: "project"
Value: "cycloid-ci-workers"
MetricsSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow metrics server to collect metrics
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '9100'
ToPort: '9100'
SourceSecurityGroupId:
Ref: MetricsSecGroup
VpcId:
Ref: VpcId
Tags:
-
Key: "Name"
Value: "cycloid-ci-workers"
-
Key: "cycloid.io"
Value: "true"
-
Key: "project"
Value: "cycloid-ci-workers"
ScheduledWorkersStop:
Type: AWS::AutoScaling::ScheduledAction
Condition: EnabledScheduling
Properties:
AutoScalingGroupName:
Ref: WorkersGroup
MaxSize:
Ref: NumberOfWorkers
DesiredCapacity:
Ref: NumberOfWorkers
MinSize:
- 0
Recurrence:
Ref: ScheduledWorkersStopRecurrence
ScheduledWorkersStart:
Type: AWS::AutoScaling::ScheduledAction
Condition: EnabledScheduling
Properties:
AutoScalingGroupName:
Ref: WorkersGroup
MaxSize: 0
MinSize: 0
Recurrence:
Ref: ScheduledWorkersStartRecurrence
You can’t perform that action at this time.