Move dev-machine Cloudformation template to the same repo
gyuho opened this issue · 3 comments
gyuho commented
Currently it's in my private repo...
gyuho commented
This is the current template
---
# ref. https://github.com/gyuho/dev-machine/blob/main/aws-dev-machine/src/cfn-templates/asg_ubuntu.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: "Development machine"
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
Parameters:
Id:
Type: String
Description: Unique identifier, prefix for all resources created below.
KmsKeyArn:
Type: String
Description: KMS CMK ARN that de/encrypts resources.
AadTag:
Type: String
Description: AAD tag for envelope encryption with KMS.
S3BucketName:
Type: String
Description: S3 bucket name.
Ec2KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Description: EC2 SSH key name
InstanceProfileArn:
Type: String
Description: Instance profile ARN
PublicSubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: The public subnet IDs where node instances are to be created.
SecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: EC2 security group ID
ArchType:
Type: String
Default: "amd64"
Description: The name of the CPU/GPU architecture. Used for names only.
OsType:
Type: String
AllowedValues: ["ubuntu20.04", "ubuntu22.04"]
Default: "ubuntu20.04"
Description: The name of the OS distribution and kind. Used for Rust binary download links.
ImageId:
Type: String
Default: ""
Description: (Optional) Custom image ID. This value overrides any AWS Systems Manager Parameter Store value specified above.
# Make sure to use the same OS version as binary builder host
# otherwise, it can fail with:
# error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory
# https://ubuntu.com/server/docs/cloud-images/amazon-ec2
# https://aws.amazon.com/blogs/compute/query-for-the-latest-amazon-linux-ami-ids-using-aws-systems-manager-parameter-store/
ImageIdSsmParameter:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/canonical/ubuntu/server/20.04/stable/current/amd64/hvm/ebs-gp2/ami-id
Description: AWS Systems Manager Parameter Store parameter of the AMI ID.
SshKeyEmail:
Type: String
Default: "none"
Description: The email to link to an SSH key. If empty, SSH key is not created.
# use https://github.com/gyuho/aws-manager/blob/main/src/ec2/mod.rs for better defaults
InstanceTypes:
Type: CommaDelimitedList
Default: c6a.4xlarge,m6a.4xlarge,m5.4xlarge,c5.4xlarge
# Default: c6g.4xlarge,m6g.4xlarge,r6g.4xlarge,t4g.2xlarge
Description: EC2 instance types
InstanceTypesCount:
Type: Number
Default: 4
MinValue: 1
MaxValue: 10
Description: The number of instance types
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping-ebs.html#cfn-ec2-launchtemplate-blockdevicemapping-ebs-volumetype
VolumeType:
Type: String
Default: gp3
Description: Volume type.
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping-ebs.html#cfn-ec2-launchtemplate-blockdevicemapping-ebs-volumesize
VolumeSize:
Type: Number
Default: 1024
MinValue: 40
MaxValue: 1024
Description: Size of the root disk for the EC2 instances, in GiB.
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping-ebs.html#cfn-ec2-launchtemplate-blockdevicemapping-ebs-iops
VolumeIops:
Type: Number
Default: 3000
Description: The number of I/O operations per second (IOPS).
# only for gp3
# https://aws.amazon.com/ebs/volume-types/
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping-ebs.html#cfn-ec2-launchtemplate-blockdevicemapping-ebs-throughput
# "1000" does not work -- "InvalidParameterValue - Throughput (MiBps) to iops ratio of 0.333333 is too high; maximum is 0.250000 MiBps per iops."
VolumeThroughput:
Type: Number
Default: 500
Description: The throughput to provision for a gp3 volume, with a maximum of 1,000 MiB/s.
# wait longer by default, because EC2 tag population takes awhile...
ProvisionerInitialWaitRandomSeconds:
Type: Number
Default: 30
MinValue: 0
MaxValue: 500
Description: Only set non-zero if multiple instances may compete for the same EBS volume in the same zone.
IpMode:
Type: String
AllowedValues: ["ephemeral", "elastic"]
Default: "elastic"
Description: Set "elastic" to allocate Elastic IP.
InstanceMode:
Type: String
AllowedValues: ["spot", "on-demand"]
Default: "spot"
Description: Set to "spot" to run spot instance.
AsgLaunchTemplateId:
Type: String
Default: ""
Description: (Optional) Non-empty to reuse.
AsgLaunchTemplateVersion:
Type: String
Default: ""
Description: (Optional) Non-empty to reuse.
AsgName:
Type: String
Description: Unique identifier for this Asg.
AsgMinInstancesInService:
Type: Number
Description: Minimum instances in service for update.
Default: 1
MinValue: 1
MaxValue: 1000
AsgMinSize:
Type: Number
Description: Minimum size auto scaling group
Default: 0
MinValue: 0
MaxValue: 3
AsgMaxSize:
Type: Number
Description: Maximum size auto scaling group
Default: 2
MinValue: 1
MaxValue: 3
AsgDesiredCapacity:
Type: Number
Description: Desired size auto scaling group
Default: 1
MinValue: 0
MaxValue: 3
OnDemandPercentageAboveBaseCapacity:
Type: Number
Default: 100
MinValue: 0
MaxValue: 100
Description: 0 for Spot only. 100 for On-Demand only.
Conditions:
HasImageId:
Fn::Not:
- Fn::Equals:
- Ref: ImageId
- ""
Has2InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 2
- Fn::Equals:
- Ref: InstanceTypesCount
- 3
- Fn::Equals:
- Ref: InstanceTypesCount
- 4
- Fn::Equals:
- Ref: InstanceTypesCount
- 5
- Fn::Equals:
- Ref: InstanceTypesCount
- 6
- Fn::Equals:
- Ref: InstanceTypesCount
- 7
- Fn::Equals:
- Ref: InstanceTypesCount
- 8
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has3InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 3
- Fn::Equals:
- Ref: InstanceTypesCount
- 4
- Fn::Equals:
- Ref: InstanceTypesCount
- 5
- Fn::Equals:
- Ref: InstanceTypesCount
- 6
- Fn::Equals:
- Ref: InstanceTypesCount
- 7
- Fn::Equals:
- Ref: InstanceTypesCount
- 8
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has4InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 4
- Fn::Equals:
- Ref: InstanceTypesCount
- 5
- Fn::Equals:
- Ref: InstanceTypesCount
- 6
- Fn::Equals:
- Ref: InstanceTypesCount
- 7
- Fn::Equals:
- Ref: InstanceTypesCount
- 8
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has5InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 5
- Fn::Equals:
- Ref: InstanceTypesCount
- 6
- Fn::Equals:
- Ref: InstanceTypesCount
- 7
- Fn::Equals:
- Ref: InstanceTypesCount
- 8
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has6InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 6
- Fn::Equals:
- Ref: InstanceTypesCount
- 7
- Fn::Equals:
- Ref: InstanceTypesCount
- 8
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has7InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 7
- Fn::Equals:
- Ref: InstanceTypesCount
- 8
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has8InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 8
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has9InstanceTypes:
Fn::Or:
- Fn::Equals:
- Ref: InstanceTypesCount
- 9
- Fn::Equals:
- Ref: InstanceTypesCount
- 10
Has10InstanceTypes:
Fn::Equals:
- Ref: InstanceTypesCount
- 10
Resources:
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata.html
AsgLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Join ["-", [!Ref Id, !Ref ArchType]]
LaunchTemplateData:
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata-iaminstanceprofile.html
IamInstanceProfile:
Arn: !Ref InstanceProfileArn
ImageId:
Fn::If:
- HasImageId
- !Ref ImageId
- !Ref ImageIdSsmParameter
KeyName: !Ref Ec2KeyPairName
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping.html
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping-ebs.html#cfn-ec2-launchtemplate-blockdevicemapping-ebs-volumesize
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-blockdevicemapping-ebs.html
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/RootDeviceStorage.html
BlockDeviceMappings:
# mounted to "/dev/root"
- DeviceName: "/dev/sda1"
Ebs:
VolumeType: gp3
VolumeSize: 200
Monitoring:
Enabled: true
# need this for public DNS + SSH access
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
Groups:
- !Ref SecurityGroupId
TagSpecifications:
- ResourceType: instance
Tags:
- { Key: Name, Value: !Sub "${Id}-${ArchType}" }
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata.html#cfn-ec2-launchtemplate-launchtemplatedata-userdata
# https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html
# /var/log/cloud-init-output.log
# takes about 3-minute
UserData:
Fn::Base64:
Fn::Sub: |
#!/bin/bash
set -xeu
export DEBIAN_FRONTEND=noninteractive
# install aws cli
while [ 1 ]; do
sudo rm -f /tmp/awscli-exe-linux-$(uname -m).zip || true;
sudo apt-get install -yq wget unzip && wget --quiet --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 --tries=70 --directory-prefix=/tmp/ --continue https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
unzip /tmp/awscli-exe-linux-$(uname -m).zip
sudo ./aws/install
/usr/local/bin/aws --version
# TODO: move these to bash script
pwd
# running as "root"
whoami
sudo lscpu
while [ 1 ]; do
sudo apt-get update -y && sudo apt-get upgrade -y \
&& sudo apt-get install -yq \
build-essential tmux zsh git \
jq curl wget \
unzip zip gzip tar \
libssl-dev \
python3-pip \
pkg-config \
protobuf-compiler \
linux-headers-$(uname -r)
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
gcc --version
cat<<EOF >> /home/ubuntu/.profile
export GOPATH=/home/ubuntu/go
export PATH=/usr/local/go/bin:/home/ubuntu/go/bin:/home/ubuntu/.cargo/bin:$PATH
. /opt/rust/env
EOF
cat<<EOF >> /home/ubuntu/.bashrc
export GOPATH=/home/ubuntu/go
export PATH=/usr/local/go/bin:/home/ubuntu/go/bin:/home/ubuntu/.cargo/bin:$PATH
. /opt/rust/env
EOF
# install go
sudo rm -rf /usr/local/go
GO_VERSION=1.20.4
sudo curl -s https://storage.googleapis.com/golang/go$GO_VERSION.linux-$(dpkg --print-architecture).tar.gz | sudo tar -v -C /usr/local/ -xz
/usr/local/go/bin/go version
# install rust
export RUSTUP_HOME=/opt/rust
export CARGO_HOME=/opt/rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y --no-modify-path --default-toolchain stable --profile default
sudo -H -u ubuntu bash -c 'source /opt/rust/env && rustup default stable'
# install docker
while [ 1 ]; do
sudo apt-get install -yq \
ca-certificates gnupg lsb-release
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
while [ 1 ]; do
sudo rm -f /usr/share/keyrings/docker-archive-keyring.gpg && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
while [ 1 ]; do
sudo apt-get update -y && sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
sudo systemctl enable docker
sudo usermod -aG docker ubuntu
sudo newgrp docker
sudo systemctl start docker.service
sudo systemctl enable --now docker
sudo docker ps
sudo docker version
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html
# "x86_64" (mac, linux x86), "arm64" (M1), "aarch64" (graviton)
# https://aws.amazon.com/blogs/developer/aws-cli-v2-now-available-for-linux-arm/
export LINUX_ARCH_TYPE=$(uname -m)
echo LINUX_ARCH_TYPE: ${!LINUX_ARCH_TYPE}
# install ssm agent
# https://docs.aws.amazon.com/systems-manager/latest/userguide/agent-install-ubuntu.html
sudo snap install amazon-ssm-agent --classic
sudo systemctl enable snap.amazon-ssm-agent.amazon-ssm-agent.service
sudo systemctl restart snap.amazon-ssm-agent.amazon-ssm-agent.service
mkdir -p /etc/systemd/system/snap.amazon-ssm-agent.amazon-ssm-agent.service.d
cat > /tmp/amazon-ssm-agent-10-restart-always.conf <<EOF
[Service]
Restart=always
RestartSec=60s
EOF
sudo mv /tmp/amazon-ssm-agent-10-restart-always.conf /etc/systemd/system/snap.amazon-ssm-agent.amazon-ssm-agent.service.d/10-restart-always.conf
sudo systemctl start --no-block snap.amazon-ssm-agent.amazon-ssm-agent.service
# install cw agent
# https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html
while [ 1 ]; do
sudo rm -f /tmp/amazon-cloudwatch-agent.deb || true;
wget --quiet --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 --tries=70 --directory-prefix=/tmp/ --continue https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/$(dpkg --print-architecture)/latest/amazon-cloudwatch-agent.deb
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
while [ 1 ]; do
echo "installing amazon-cloudwatch-agent"
sudo dpkg -i -E /tmp/amazon-cloudwatch-agent.deb
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
# install aws-volume-manager
# https://github.com/ava-labs/volume-manager/releases
while [ 1 ]; do
sudo rm -f /tmp/aws-volume-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu || true;
wget --quiet --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 --tries=70 --directory-prefix=/tmp/ --continue https://github.com/ava-labs/volume-manager/releases/download/latest/aws-volume-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
chmod +x /tmp/aws-volume-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu
/tmp/aws-volume-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu --version
/tmp/aws-volume-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu \
--log-level=info \
--region ${AWS::Region} \
--initial-wait-random-seconds=${ProvisionerInitialWaitRandomSeconds} \
--id-tag-key=Id \
--id-tag-value=${Id} \
--kind-tag-key=Kind \
--kind-tag-value=aws-volume-provisioner \
--ec2-tag-asg-name-key=ASG_NAME \
--asg-tag-key=autoscaling:groupName \
--volume-type=${VolumeType} \
--volume-size=${VolumeSize} \
--volume-iops=${VolumeIops} \
--volume-throughput=${VolumeThroughput} \
--ebs-device-name=/dev/xvdb \
--block-device-name=/dev/nvme1n1 \
--filesystem-name=ext4 \
--mount-directory-path=/data
# set permissions
sudo chown -R $(whoami) /data || true
sudo chown -R ubuntu /data || true
# install aws-ip-manager
# https://github.com/ava-labs/ip-manager/releases
if [[ ${IpMode} == "elastic" ]]; then
sudo rm -f /tmp/aws-ip-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu
while [ 1 ]; do
sudo rm -f /tmp/aws-ip-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu || true;
wget --quiet --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 --tries=70 --directory-prefix=/tmp/ --continue https://github.com/ava-labs/ip-manager/releases/download/latest/aws-ip-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
chmod +x /tmp/aws-ip-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu
/tmp/aws-ip-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu --version
/tmp/aws-ip-provisioner.${!LINUX_ARCH_TYPE}-${OsType}-linux-gnu \
--log-level=info \
--region ${AWS::Region} \
--id-tag-key=Id \
--id-tag-value=${Id} \
--kind-tag-key=Kind \
--kind-tag-value=aws-ip-provisioner \
--ec2-tag-asg-name-key=ASG_NAME \
--asg-tag-key=autoscaling:groupName \
--initial-wait-random-seconds=${ProvisionerInitialWaitRandomSeconds} \
--mounted-eip-file-path=/data/eip.yaml
else
echo "skipping allocating elastic IP address..."
fi;
# install saml2aws
# https://api.github.com/repos/Versent/saml2aws/releases/latest
while [ 1 ]; do
export SAML2AWS_CURRENT_VERSION=$(curl -Ls https://api.github.com/repos/Versent/saml2aws/releases/latest | grep 'tag_name' | cut -d'v' -f2 | cut -d'"' -f1)
echo SAML2AWS_CURRENT_VERSION: ${!SAML2AWS_CURRENT_VERSION}
sudo rm -f /tmp/saml2aws_${!SAML2AWS_CURRENT_VERSION}_linux_$(dpkg --print-architecture).tar.gz || true;
wget --quiet --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 --tries=70 --directory-prefix=/tmp/ --continue https://github.com/Versent/saml2aws/releases/download/v${!SAML2AWS_CURRENT_VERSION}/saml2aws_${!SAML2AWS_CURRENT_VERSION}_linux_$(dpkg --print-architecture).tar.gz -O - | tar -xzv -C /tmp
if [ $? = 0 ]; then break; fi; # check return value, break if successful (0)
sleep 2s;
done;
chmod u+x /tmp/saml2aws
sudo cp /tmp/saml2aws /usr/local/bin/saml2aws
saml2aws --version
# create an SSH key
if [[ "${SshKeyEmail}" != "none" ]]; then
echo "generating an SSH key with ${SshKeyEmail}"
ssh-keygen -q -t rsa -b 4096 -C "${SshKeyEmail}" -N '' -f /home/ubuntu/.ssh/id_rsa <<<y >/dev/null 2>&1
eval "$(ssh-agent -s)"
ssh-add /home/ubuntu/.ssh/id_rsa
echo "generated the following SSH public key"
cat /home/ubuntu/.ssh/id_rsa.pub
# set permissions
sudo chown -R $(whoami) /home/ubuntu/.ssh || true
sudo chown -R ubuntu /home/ubuntu/.ssh || true
else
echo "skipping generating an SSH key..."
fi;
# sync time
sudo timedatectl set-ntp on
# e.g.,
# "Accept error: accept tcp [::]:9650: accept4: too many open files; retrying in 1s"
sudo echo "* hard nofile 1000000" >> /etc/security/limits.conf
sudo echo "* soft nofile 1000000" >> /etc/security/limits.conf
sudo sysctl -w fs.file-max=1000000
sudo sysctl -p
# TODO: more with bash script file from S3
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html
ASG:
Type: AWS::AutoScaling::AutoScalingGroup
UpdatePolicy:
AutoScalingRollingUpdate:
MinInstancesInService: !Ref AsgMinInstancesInService
MaxBatchSize: 1
SuspendProcesses:
- HealthCheck
- ReplaceUnhealthy
- AZRebalance
- AlarmNotification
- ScheduledActions
Properties:
AutoScalingGroupName: !Ref AsgName
MinSize: !Ref AsgMinSize
MaxSize: !Ref AsgMaxSize
DesiredCapacity: !Ref AsgDesiredCapacity
VPCZoneIdentifier: !Ref PublicSubnetIds
HealthCheckType: EC2
HealthCheckGracePeriod: 120
MetricsCollection:
- Granularity: "1Minute"
Tags:
- Key: Name
Value: !Ref AsgName
PropagateAtLaunch: true
- Key: ASG_NAME
Value: !Ref AsgName
PropagateAtLaunch: true
- Key: ID
Value: !Ref Id
PropagateAtLaunch: true
- Key: ARCH_TYPE
Value: !Ref ArchType
PropagateAtLaunch: true
- Key: OS_TYPE
Value: !Ref OsType
PropagateAtLaunch: true
- Key: INSTANCE_MODE
Value: !Ref InstanceMode
PropagateAtLaunch: true
- Key: KMS_KEY_ARN
Value: !Ref KmsKeyArn
PropagateAtLaunch: true
- Key: AAD_TAG
Value: !Ref AadTag
PropagateAtLaunch: true
- Key: S3_BUCKET_NAME
Value: !Ref S3BucketName
PropagateAtLaunch: true
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-mixedinstancespolicy.html
# https://aws.amazon.com/getting-started/hands-on/ec2-auto-scaling-spot-instances/
MixedInstancesPolicy:
# define balance between spot vs. on-demand
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-instancesdistribution.html
# https://ec2spotworkshops.com/launching_ec2_spot_instances/asg.html
InstancesDistribution:
OnDemandAllocationStrategy: "lowest-price"
# minimum amount of the Auto Scaling group's capacity that must be fulfilled by On-Demand Instances
OnDemandBaseCapacity: 0
# percentages of On-Demand Instances and Spot Instances for your additional capacity beyond OnDemandBaseCapacity
# 20 specifies 20% On-Demand Instances, 80% Spot Instances
# If set to 0, only Spot Instances are used.
# If set to 100, only On-Demand Instances are used.
OnDemandPercentageAboveBaseCapacity: !Ref OnDemandPercentageAboveBaseCapacity
SpotAllocationStrategy: "lowest-price"
# number of Spot Instance pools across which to allocate your Spot Instances
SpotInstancePools: 3
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-launchtemplate.html
LaunchTemplate:
LaunchTemplateSpecification:
LaunchTemplateId: !Ref AsgLaunchTemplate
Version: !GetAtt AsgLaunchTemplate.LatestVersionNumber
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-launchtemplateoverrides.html
Overrides:
- InstanceType: !Select [0, !Ref InstanceTypes]
- Fn::If:
- Has2InstanceTypes
- InstanceType: !Select [1, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has3InstanceTypes
- InstanceType: !Select [2, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has4InstanceTypes
- InstanceType: !Select [3, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has5InstanceTypes
- InstanceType: !Select [4, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has6InstanceTypes
- InstanceType: !Select [5, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has7InstanceTypes
- InstanceType: !Select [6, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has8InstanceTypes
- InstanceType: !Select [7, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has9InstanceTypes
- InstanceType: !Select [8, !Ref InstanceTypes]
- !Ref AWS::NoValue
- Fn::If:
- Has10InstanceTypes
- InstanceType: !Select [9, !Ref InstanceTypes]
- !Ref AWS::NoValue
Outputs:
# same as "AutoScalingGroupName"
AsgLogicalId:
Value: !Ref ASG
Exported by these functions
use std::io::{self, Error, ErrorKind};
use rust_embed::RustEmbed;
pub fn asg_ubuntu_yaml() -> io::Result<String> {
#[derive(RustEmbed)]
#[folder = "src/cfn-templates/"]
#[prefix = "src/cfn-templates/"]
struct Asset;
let f = Asset::get("src/cfn-templates/asg_ubuntu.yaml").unwrap();
let s = std::str::from_utf8(f.data.as_ref()).map_err(|e| {
Error::new(
ErrorKind::InvalidInput,
format!("failed to convert embed file to str {}", e),
)
})?;
Ok(s.to_string())
}
pub fn ec2_instance_role_yaml() -> io::Result<String> {
#[derive(RustEmbed)]
#[folder = "src/cfn-templates/"]
#[prefix = "src/cfn-templates/"]
struct Asset;
let f = Asset::get("src/cfn-templates/ec2_instance_role.yaml").unwrap();
let s = std::str::from_utf8(f.data.as_ref()).map_err(|e| {
Error::new(
ErrorKind::InvalidInput,
format!("failed to convert embed file to str {}", e),
)
})?;
Ok(s.to_string())
}
pub fn vpc_yaml() -> io::Result<String> {
#[derive(RustEmbed)]
#[folder = "src/cfn-templates/"]
#[prefix = "src/cfn-templates/"]
struct Asset;
let f = Asset::get("src/cfn-templates/vpc.yaml").unwrap();
let s = std::str::from_utf8(f.data.as_ref()).map_err(|e| {
Error::new(
ErrorKind::InvalidInput,
format!("failed to convert embed file to str {}", e),
)
})?;
Ok(s.to_string())
}