- AWS
CloudFormation Product Details
- User
guide
- 19
Best
Practices for Creating Amazon CloudFormation Templates
- Designer
- Preserve resources after stack destruction
- Info
- Tags
- CLI
Cloudformation
- EC2
- Instance
- Volume
- VPC
- single EC2
instance
- single_ec2.json
{
"Description": "Single EC2
instance",
"AWSTemplateFormatVersion":
"2010-09-09",
"Metadata": {},
"Resources": {
"singleEC2": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId":"ami-xxxxxxxx",
"KeyName":"my_key_pair",
"InstanceType":"t2.micro"
}
}
}
}
- single ec2
instance with an extra volume
- single_ec2_volume.json
"Resources": {
...
"EC2Instance": {
"Type":
"AWS::EC2::Instance",
"Properties": {
"ImageId":{"Ref" : "ImageId"},
"SecurityGroups" : [ { "Ref" :
"InstanceSecurityGroup" } ],
"KeyName":"my_server_key",
"InstanceType":{"Ref" : "InstanceType"},
"UserData":
{
"Fn::Base64": {
"Fn::Join" : [ "", [
"#!/bin/bash
-xe\n",
"sudo mkfs
-t xfs /dev/xvdh \n ",
"sudo mkdir
/mnt/vol \n ",
"sudo chmod
777 /mnt/vol \n ",
"sudo mount
/dev/xvdh /mnt/vol \n ",
] ]
}
},
"Tags":[{"Key":"Name","Value":{"Ref":"BaseName"}}]
}
},
...
"NewVolume" : {
"Type" :
"AWS::EC2::Volume",
"Properties"
: {
"Size" : "100",
"AvailabilityZone"
: { "Fn::GetAtt" : [ "EC2Instance",
"AvailabilityZone" ]}
}
},
"MountPoint" : {
"Type" :
"AWS::EC2::VolumeAttachment",
"Properties"
: {
"InstanceId" : { "Ref" :
"EC2Instance" },
"VolumeId" : { "Ref" :
"NewVolume" },
"Device" : "/dev/xvdh"
}
},
- single EC2 with
UserData
and extra volume
- Notes:
- When using direct bash commands:
- add "\n" at the end of each command
- no need to call sudo
- single_ec2_userdata_volume.json
{
"Description": "Single EC2
instance with extra volume",
"AWSTemplateFormatVersion":
"2010-09-09",
"Metadata": {},
"Parameters" : {
"InstanceType" : {
"Description" : "EC2 instance type",
"Type" :
"String",
"Default" :
"t2.micro",
"AllowedValues" : [ "t1.micro", "t2.micro",
"t2.small", "t2.medium", "m1.small", "m1.medium",
"m1.large", "m1.xlarge", "m2.xlarge",
"m2.2xlarge", "m2.4xlarge", "m3.medium",
"m3.large", "m3.xlarge", "m3.2xlarge",
"c1.medium", "c1.xlarge", "c3.large", "c3.xlarge",
"c3.2xlarge", "c3.4xlarge", "c3.8xlarge",
"c4.large", "c4.xlarge", "c4.2xlarge",
"c4.4xlarge", "c4.8xlarge", "g2.2xlarge",
"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."
},
"HostedZone" : {
"Type" :
"String",
"Description" : "The DNS name of an existing
Amazon Route 53 hosted zone",
"AllowedPattern" :
"(?!-)[a-zA-Z0-9-.]{1,63}(?<!-)",
"ConstraintDescription" : "must be a valid DNS
zone name.",
"Default" :
"example.net"
},
"ImageId" : {
"Type" :
"String",
"Description" : "The image_id for the ec2
instance"
},
"NewVolumeSize" : {
"Type" :
"String",
"Description" : "The size of the new volume (GB)",
"Default":
"5"
}
},
"Resources": {
"EC2Instance": {
"Type":
"AWS::EC2::Instance",
"Properties": {
"ImageId":{"Ref" : "ImageId"},
"SecurityGroups" : [ { "Ref" :
"InstanceSecurityGroup" } ],
"KeyName":"wct_streaming_server",
"InstanceType":{"Ref" : "InstanceType"},
"UserData":
{
"Fn::Base64": {
"Fn::Join" : [ "", [
"#!/bin/bash
-xe \n",
"while [ !
-e /dev/xvdh ]; do echo waiting for /dev/xvdh to
attach; sleep 10; done \n",
"mkfs -t xfs
/dev/xvdh \n",
"mkdir -p
/mnt/vol1 \n",
"mount
/dev/xvdh /mnt/vol1 \n",
"chmod 777
/mnt/vol1 \n"
] ]
}
},
"Tags":[{"Key":"Name","Value":{"Ref":"BaseName"}}]
}
},
"NewVolume" : {
"Type" :
"AWS::EC2::Volume",
"Properties"
: {
"Size" :
{"Ref" : "NewVolumeSize"},
"AvailabilityZone" : { "Fn::GetAtt" : [
"EC2Instance", "AvailabilityZone" ]}
}
},
"MountPoint" : {
"Type" :
"AWS::EC2::VolumeAttachment",
"Properties"
: {
"InstanceId"
: { "Ref" : "EC2Instance" },
"VolumeId" : { "Ref" : "NewVolume" },
"Device" :
"/dev/xvdh"
}
},
}
- single EC2 entry with
Route53
- single_ec2_r53.json
{
"Description":
"Single EC2 instance",
"AWSTemplateFormatVersion":
"2010-09-09",
"Metadata": {},
"Parameters" : {
"InstanceType" : {
"Description" : "EC2 instance type",
"Type" :
"String",
"Default" :
"m1.small",
"AllowedValues" : [ "t1.micro", "t2.micro",
"t2.small", "t2.medium", "m1.small", "m1.medium",
"m1.large", "m1.xlarge", "m2.xlarge",
"m2.2xlarge", "m2.4xlarge", "m3.medium",
"m3.large", "m3.xlarge", "m3.2xlarge",
"c1.medium", "c1.xlarge", "c3.large", "c3.xlarge",
"c3.2xlarge", "c3.4xlarge", "c3.8xlarge",
"c4.large", "c4.xlarge", "c4.2xlarge",
"c4.4xlarge", "c4.8xlarge", "g2.2xlarge",
"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."
},
"HostedZone" : {
"Type" :
"String",
"Description" : "The DNS name of an existing
Amazon Route 53 hosted zone",
"AllowedPattern" :
"(?!-)[a-zA-Z0-9-.]{1,63}(?<!-)",
"ConstraintDescription" : "must be a valid DNS
zone name."
}
},
"Resources": {
"EC2Instance": {
"Type":
"AWS::EC2::Instance",
"Properties": {
"ImageId":"ami-437da730",
"SecurityGroups" : [ { "Ref" :
"InstanceSecurityGroup" } ],
"KeyName":"my_key_pair",
"InstanceType":"t2.micro"
}
},
"InstanceSecurityGroup" : {
"Type" :
"AWS::EC2::SecurityGroup",
"Properties"
: {
"GroupDescription" : "Enable SSH, HTTP, RTMP",
"SecurityGroupIngress" : [
{
"IpProtocol" : "tcp",
"FromPort" : "22",
"ToPort" : "22",
"CidrIp" : "0.0.0.0/0"
},
{
"IpProtocol" : "tcp",
"FromPort" : "80",
"ToPort" : "80",
"CidrIp" : "0.0.0.0/0"
},
{
"IpProtocol" : "tcp",
"FromPort" : "1935",
"ToPort" : "1935",
"CidrIp" : "0.0.0.0/0"
}
]
}
},
"MyDNSRecord" : {
"Type" :
"AWS::Route53::RecordSet",
"Properties"
: {
"HostedZoneName" : { "Fn::Join" : [ "", [{"Ref" :
"HostedZone"}, "." ]]},
"Comment" :
"DNS name for my instance.",
"Name" : {
"Fn::Join" : [ "", [{"Ref" : "EC2Instance"}, ".",
{"Ref" : "AWS::Region"}, ".", {"Ref" :
"HostedZone"} ,"."]]},
"Type" :
"A",
"TTL" :
"900",
"ResourceRecords" : [ { "Fn::GetAtt" : [
"EC2Instance", "PublicIp" ] } ]
}
}
},
"Outputs" : {
"InstanceId" : {
"Description" : "InstanceId of the newly created
EC2 instance",
"Value" : {
"Ref" : "EC2Instance" }
},
"AZ" : {
"Description" : "Availability Zone of the newly
created EC2 instance",
"Value" : {
"Fn::GetAtt" : [ "EC2Instance", "AvailabilityZone"
] }
},
"PublicDNS" : {
"Description" : "Public DNSName of the newly
created EC2 instance",
"Value" : {
"Fn::GetAtt" : [ "EC2Instance", "PublicDnsName" ]
}
},
"PublicIP" : {
"Description" : "Public IP address of the newly
created EC2 instance",
"Value" : {
"Fn::GetAtt" : [ "EC2Instance", "PublicIp" ] }
},
"DomainName" : {
"Description" : "Fully qualified domain name",
"Value" : {
"Ref" : "MyDNSRecord" }
}
}
}
- EFS
- AWS::EFS::FileSystem
- AWS::EFS::MountTarget
- exemple
...
"Resources" : {
"MyFileSystem" : {
"Type":
"AWS::EFS::FileSystem",
"Properties": {
"PerformanceMode": "generalPurpose",
"FileSystemTags": [
{
"Key": "Name",
"Value": "my-fs"
}
]
}
},
"MyMountTargetSecurityGroup" : {
"Type" :
"AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable ports 2049 (nfs)",
"VpcId" : {"Ref"
: "VPCId"},
"SecurityGroupIngress" : [
{
"IpProtocol" : "tcp",
"FromPort" : "2049",
"ToPort" : "2049",
"CidrIp" : {"Ref": "CidrSubnet"}
}
]
}
},
"MyMountTarget" : {
"Type":
"AWS::EFS::MountTarget",
"Properties": {
"FileSystemId":
{ "Ref": "MyFileSystem" },
"SubnetId": {
"Ref": "MySubnet" },
"SecurityGroups": [ { "Ref":
"MyMountTargetSecurityGroup" }
]
}
},
...
"# mount efs
from instance \n",
"# mount -t nfs4 -o
nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport
", {"Ref": "ProcessFileSystem"},".efs.",{"Ref" :
"AWS::Region"},".amazonaws.com:/ /mnt/efs \n",
" mkdir -p /mnt/efs \n",
"echo ", {"Ref":
"ProcessFileSystem"},".efs.",{"Ref" :
"AWS::Region"},".amazonaws.com:/ /mnt/efs nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport
0 0 >>/etc/fstab \n",
" mount /mnt/efs \n",
...
}
- Route53
- Alarm
- Autoscaling group
- Recover
- CloudFront
- AWS::CloudFront::Distribution
"PriceClass"
:
"PriceClass_100" -> Use Only U.S.,
Canada and Europe
"PriceClass_200" -> Use U.S.,
Canada, Europe, Asia and Africa
"PriceClass_All" -> Use All Edge
Locations (Best Performance)
- No cache for 404
"MyCloudFront" : {
"Type" :
"AWS::CloudFront::Distribution",
"Properties" : {
"DistributionConfig"
: {
"CustomErrorResponses" : [ {
"ErrorCode"
: "404",
"ErrorCachingMinTTL" : "2"
} ]
...
}
}
}
- Cache
behaviour
/ Forward headers: Whitelist
- Configuring
CloudFront
to Cache Objects Based on Request Headers
- To avoid problems with CORS and 403 response from CloudFront
"DefaultCacheBehavior"
: {
"TargetOriginId"
: { "Fn::Join" : [ "", ["S3-", {"Ref":"BucketName"},
"-my_dir" ] ]},
"ForwardedValues"
: {
"Headers" :
["Origin","Access-Control-Request-Headers"," Access-Control-Request-Method "],
"QueryString"
: "false",
"Cookies"
: { "Forward" : "none" }
},
"AllowedMethods" :
["GET", "HEAD", "OPTIONS"],
"CachedMethods"
: ["GET", "HEAD", "OPTIONS"],
"ViewerProtocolPolicy"
: "allow-all"
},
- Full examples:
- Origin is S3, with whitelist for forwarded headers
("Origin"):
"Resources": {
"MyCloudFront" : {
"Type"
: "AWS::CloudFront::Distribution",
"Properties"
: {
"DistributionConfig"
: {
"Origins"
: [ {
"DomainName":
{ "Fn::Join" : [ "", [{"Ref":"BucketName"},
".s3.amazonaws.com"]]},
"OriginPath":
"my_dir",
"Id"
: { "Fn::Join" : [ "", ["S3-",
{"Ref":"BucketName"}, "-my_dir" ] ]},
"S3OriginConfig":
{}
}],
"Enabled"
: "true",
"Comment"
: "My comments",
"DefaultCacheBehavior"
: {
"TargetOriginId"
: { "Fn::Join" : [ "", ["S3-",
{"Ref":"BucketName"}, "-my_dir" ] ]},
"ForwardedValues"
: {
"Headers"
: ["Origin"],
"QueryString"
: "false",
"Cookies"
: { "Forward" : "none" }
},
"ViewerProtocolPolicy"
: "allow-all"
},
"PriceClass"
: "PriceClass_100"
}
}
}
},
- Origin is own http server, with no cache for 404
responses:
"Resources": {
"MyCloudFront" : {
"Type"
: "AWS::CloudFront::Distribution",
"Properties"
: {
"DistributionConfig"
: {
"Origins"
: [ {
"DomainName":
"myserver.toto.org",
"OriginPath":
"/root_dir",
"Id"
: "oid-root_dir",
"CustomOriginConfig":
{
"HTTPPort":
"80",
"HTTPSPort":
"443",
"OriginProtocolPolicy":
"http-only"
}
}],
"Enabled"
: "true",
"Comment"
: "My comments",
"DefaultCacheBehavior"
: {
"TargetOriginId"
: "oid-root_dir" ,
"ForwardedValues"
: {
"QueryString"
: "false",
"Cookies"
: { "Forward" : "none" }
},
"ViewerProtocolPolicy"
: "allow-all"
},
"CustomErrorResponses"
: [ {
"ErrorCode"
: "404",
"ErrorCachingMinTTL"
: "2"
}
],
"PriceClass"
: "PriceClass_100"
}
}
}
},
- Amazon
CloudFront
Template Snippets
- Amazon
CloudFront
- Introduction
- LoadBalancer
-
- Classic Load Balancer
- listener with redirect ports http/80, http/8088,
https/8089, tcp/1935 and LBCookieStickinessPolicy:
"MyLoadBalancer": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer ",
"Properties": {
"LoadBalancerName": "MyLoadbalancerName",
"SecurityGroups" : [ ... ],
"AvailabilityZones": {
"Fn::GetAZs":
""
},
"CrossZone": "true",
"ConnectionSettings":
{
"IdleTimeout"
: 60
}
"Listeners":
[
{
"LoadBalancerPort":
"80",
"InstancePort":
"80",
"Protocol":
"HTTP",
"PolicyNames":
["MyFirstLBCookieStickinessPolicy"]
},
{
"LoadBalancerPort":
"8088",
"InstancePort":
"8088",
"Protocol":
"HTTP",
"PolicyNames":
["MySecondLBCookieStickinessPolicy"]
},
{
"LoadBalancerPort":
"8089",
"Protocol":
"HTTPS",
"InstancePort":
"8089",
"InstanceProtocol":
"HTTPS",
"SSLCertificateId":
"arn:aws:acm:eu-west-1:...",
"PolicyNames":
["MySecondLBCookieStickinessPolicy"]
},
{
"LoadBalancerPort":
"1935",
"InstancePort":
"1935",
"Protocol":
"TCP"
}
],
"LBCookieStickinessPolicy" : [
{
"CookieExpirationPeriod"
: "500",
"PolicyName"
: "MyFirstLBCookieStickinessPolicy"
},
{
"CookieExpirationPeriod"
: "1000",
"PolicyName"
: "MySecondLBCookieStickinessPolicy"
}
],
"HealthCheck": {
"Target":
"HTTP:80/",
"HealthyThreshold":
"3",
"UnhealthyThreshold":
"5",
"Interval":
"30",
"Timeout":
"5"
}
}
}
- listener with a certificate from ACM
- SecurityGroup
- UDP
- AutoScalingGroup
- Prerequisites:
- cfn-signal
- Download from: Bootstrapping
Applications
using AWS CloudFormation
- kixorz/ubuntu-cloudformation.json
- Install
mkdir aws-cfn-bootstrap-latest
curl
https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz
| tar xz -C aws-cfn-bootstrap-latest
--strip-components 1
easy_install aws-cfn-bootstrap-latest
- Problemes / Problems
Traceback (most recent call last):
File "/bin/easy_install", line 9, in
<module>
load_entry_point('setuptools==0.9.8',
'console_scripts', 'easy_install')()
[...]
File
"/usr/lib/python2.7/site-packages/setuptools/command/easy_install.py",
line 701, in process_distribution
distreq.project_name,
distreq.specs, requirement.extras
TypeError: __init__() takes exactly 2
arguments (4 given)
- Diagnose
- python
>>> from
pkg_resources import
load_entry_point
>>>
load_entry_point('setuptools==0.9.8',
'console_scripts',
'easy_install')()
...
pkg_resources.VersionConflict:
(setuptools 25.1.4
(/usr/lib/python2.7/site-packages/setuptools-25.1.4-py2.7.egg),
Requirement.parse('setuptools==0.9.8'))
- Solució / Solution
sudo rm -rf
/usr/lib/python2.7/site-packages/setuptools-25.1.4-py2.7.egg
- You must install a UserData
on your instance (AMI) that generates a cfn-signal received by CreationPolicy
"LaunchConfig" : {
"Type" :
"AWS::AutoScaling::LaunchConfiguration",
"Properties"
: {
"ImageId":{"Ref" : "MyImageId"},
"SecurityGroups" : [ { "Ref" : "MySecurityGroup" }
],
"KeyName":"my_key",
"InstanceType":{"Ref" : "MyInstanceType"},
"IamInstanceProfile":
"role_my_server",
"UserData":
{
"Fn::Base64": {
"Fn::Join" : [ "", [
"#!/bin/bash
-xe\n",
"/usr/bin/cfn-signal -e
0 --stack ", { "Ref": "AWS::StackName" },
" --resource
MyAutoscalingGroup ",
" --region
", { "Ref" : "AWS::Region" }, "\n"
] ]
}
}
}
},
- Auto
Scaling
Template Snippets
- AutoScalingGroup
- AWS::AutoScaling::AutoScalingGroup
- example.json
"MyAutoScalingGroup" : {
"Type" :
"AWS::AutoScaling::AutoScalingGroup",
"Properties"
: {
"LaunchConfigurationName" : { "Ref" :
"MyLaunchConfig" },
"MinSize" :
"1",
"MaxSize" :
"3",
"LoadBalancerNames" : [ { "Ref" : "MyLoadBalancer"
} ],
"Tags":[
{
"Key":"Name",
"Value":{ "Fn::Join" : [ "",
["myinstance-", {"Ref" : "MyName"}]]},
"PropagateAtLaunch" : "true"
}
]
},
"CreationPolicy" : {
"ResourceSignal" : {
"Timeout" : "PT15M",
"Count" : "1"
}
},
"UpdatePolicy": {
"AutoScalingRollingUpdate": {
"MinInstancesInService": "1",
"MaxBatchSize": "1",
"PauseTime" : "PT15M",
"WaitOnResourceSignals": "true"
}
}
},
- ScalingPolicy
- Alarm
- AWS::...
- example.json
"MyUpScalingPolicy" : {
"Type" :
"AWS::AutoScaling::ScalingPolicy",
"Properties"
: {
"AdjustmentType" : "ChangeInCapacity",
"AutoScalingGroupName" : { "Ref" :
"MyAutoScalingGroup" },
"Cooldown" :
"60",
"ScalingAdjustment" : "1"
}
},
"MyCPUHighAlarm": {
"Type":
"AWS::CloudWatch::Alarm",
"Properties": {
"EvaluationPeriods": "1",
"Statistic":
"Average",
"Threshold":
"80",
"AlarmDescription": "Alarm if CPU too high or
metric disappears indicating instance is down",
"Period":
"60",
"AlarmActions": [ { "Ref": "MyUpScalingPolicy" }
],
"Namespace":
"AWS/EC2",
"Dimensions": [ {
"Name": "AutoScalingGroupName",
"Value": { "Ref":
"MyAutoScalingGroup" }
} ],
"ComparisonOperator": "GreaterThanThreshold",
"MetricName": "CPUUtilization"
}
},
- LaunchConfiguration
- Example:
- ElastiCache
- ...
|
- AWS Command Line
Interface
- Instal·lació / Installation (python)
- Ús / Usage
- Problemes / Problems
ImportError: No module named history
- the problem is that a pair of awscli (1.14.28) and
botocore (1.6.0), installed from yum (
awscli.noarch ),
does not work
- Solucions / Solutions
- Swap s3transfer packages (awscli-1.14.28-5):
yum swap python2-s3transfer
python-s3transfer
- Use pip
sudo pip install awscli
- a pair of working packages is, e.g.:
awscli==1.14.28,
botocore==1.8.32
- queries
- templates
--generate-cli-skeleton > skeleton.json
--cli-input-json file://skeleton.json
- stdin/stdout
aws s3 cp s3://bucket/key - | bzip2 -best | aws s3
cp - s3://bucket/key.bz2
- CLI
reference
- general
options
--region eu-west-1
--profile myprofile
--output json
...
aws autoscaling
- launch configuration
- autoscaling
group
aws autoscaling create-auto-scaling-group
--auto-scaling-group-name grup_stateless
--launch-configuration-name lc_stateless_ yyyymmdd_hhmm
--min-size 1 --max-size 2 --load-balancer-names
lb-stateless
aws autoscaling update-auto-scaling-group
--auto-scaling-group-name grup_stateless
--launch-configuration-name lc_stateless_ yyyymmdd_hhmm
- number of instances inside an autoscaling group,
given its name
result=$(aws --output json autoscaling
describe-auto-scaling-groups
--auto-scaling-group-names $asg_name )
number_instances=$(echo $result | jq
'.AutoScalingGroups[0].Instances | length')
- get autoscaling group, given its tag Name=myname:
asg_info= $(aws --output
json autoscaling describe-auto-scaling-groups)
asg_name_tag_value="myname"
asg=$(echo "$asg_info" | jq
".AutoScalingGroups[] | select( .Tags[] | .
and .Key==\"Name\" and
.Value==\"${asg_name_tag_value}\")")
aws autoscaling set-desired-capacity
--auto-scaling-group-name $asg_name
--desired-capacity 2
- Instance protection
aws autoscaling set-instance-protection
--instance-ids i-93633f9b
--auto-scaling-group-name
my-auto-scaling-group
--protected-from-scale-in
- given an instance id, get the autoscaling group
name it belongs to:
aws ec2 describe-tags --filters
"Name=resource-id,Values=$instance_id"
"Name=key,Values=aws:autoscaling:groupName" |
jq '.Tags[] | .Value'
- get all autoscaling groups (with pagination)
aws_options="--profile
my_profile --output json --region eu-west-1"
next_token=""
max_items=50
page_size=100
total_number=0
total_elements=$(jq -n '[]')
while [[ $next_token != "null" ]]
do
if [[ "$next_token" ]]
then
lc_info=$(aws ${aws_options} autoscaling
describe-launch-configurations --max-items
$max_items --page-size $page_size --starting-token
$next_token)
else
lc_info=$(aws ${aws_options} autoscaling
describe-launch-configurations --max-items
$max_items --page-size $page_size)
fi
#echo $lc_info | jq '.'
returned_number=$(echo $lc_info
| jq '.LaunchConfigurations | length' )
returned_elements=$(echo
$lc_info | jq '.LaunchConfigurations')
echo $returned_elements | jq
'.'
total_elements=$( echo
$total_elements | jq ". += $returned_elements")
echo "returned_number:
$returned_number"
total_number=$(( total +
returned_number ))
echo "total_number:
$total_number"
echo $lc_info | jq
'.LaunchConfigurations[] |
([.LaunchConfigurationName] | join (" "))'
next_token=$(echo $lc_info | jq
'.NextToken')
echo "next_token: $next_token"
done
echo "---------------------------"
echo $total_elements | jq
'.[].LaunchConfigurationName'
aws cloudformation
aws cloudfront
aws configure set preview.cloudfront true
- list all distributions
aws cloudfront list-distributions --output
json
- get a specific distribution:
- aws cloudfront get-distribution --id
E1KBXTVP599T0A
- get the config for a specific distribution
- aws cloudfront get-distribution-config --id
E1KBXTVP599T0A
- update distribution
aws cloudfront
get-distribution-config --id ${cloudfront_id}
--output json > /tmp/${cloudfront_id}.json
# get etag
etag=$(jq -r '.ETag' /tmp/${cloudfront_id}.json)
# modify /tmp/${cloudfront_id}.json
...
aws cloudfront update-distribution --id
${cloudfront_id} --if-match $etag
--distribution-config $(jq -c
'.DistributionConfig'
/tmp/${cloudfront_id}.json)
aws configure
- boto3 credentials
- generated files
~/.aws/credentials (for all SDKs)
~/.aws/config (only for CLI)
- crearà / will create: ~/.aws/config
[default]
output = json
region = eu-west-1 aws_access_key_id
= xxx
aws_secret_access_key = yyy
[preview]
cloudfront = true
- i/and
~/.aws/credentials (? now included in
~/.aws/config)
[default]
aws_access_key_id = xxx
aws_secret_access_key = yyy
- per a fer servir un altre perfil / to use another
profile
aws --profile myprofile configure
- will create ~/.aws/config
[profile myprofile]
output = json
region = eu-west-1
- and ~/.aws/credentials
[myprofile]
aws_access_key_id = xxx
aws_secret_access_key = yyy
aws --profile myprofile
...
- per a fer servir un altre fitxer de configuració / to
use an alternate config file (e.g.
/etc/aws/config ):
- aws efs
- file system
name="fs-toto"
creation_token=$( openssl
rand -hex 10 )
response=$(aws efs create-file-system
--creation-token ${creation_token} --tags
Key=Name,Value=${name})
file_system_id=$(echo ${response} | jq -r
'.FileSystemId')
echo ${file_system_id}
- mount targets
- create a security group for NFS (port 2049)
group_name="sgroup-nfs-toto"
vpc_id="vpc-..."
description="Enable port 2049 (nfs)"
response=$(aws ec2 create-security-group
--group-name ${group_name} --vpc-id ${vpc_id}
--description "${description}")
group_id=$(echo ${response} | jq -r '.GroupId')
echo ${group_id}
protocol=tcp
port=2049
cidr="" # cidr of the subnet inside the vpc
aws ec2 authorize-security-group-ingress
--group-id ${group_id} --protocol ${protocol}
--port ${port} --cidr "${cidr}"
- create a mount target
subnet_id="subnet-..."
response=$(aws efs create-mount-target
--file-system-id ${file_system_id} --subnet-id
${subnet_id} --security-groups ${group_id})
mount_target_id=$(echo ${response} | jq -r
'.MountTargetId') echo
${mount_target_id}
- get info about a mount target
response=$(aws efs
describe-mount-targets --mount-target-id
${mount_target_id})
- mount efs from an
instance
aws ec2
- instances
aws ec2 start-instances
--instance-ids i-9b789ed8
aws ec2 describe-instances
--filter Name=tag:Name,Values=ubuntu_1310
- ...
TAGS Name
ubuntu_1310
- get PublicIpAddress
aws --output json ec2 describe-instances
--instance-ids i-9b789ed8 | jq
-r
'.Reservations[0].Instances[0].PublicIpAddress'
aws ec2 describe-instance-attribute
--instance-id i-896b92c9 --attribute instanceType
aws ec2 stop-instances
--instance-ids i-9b789ed8
aws ec2 terminate-instances
--instance-ids i-9b789ed8
- waiters
aws ec2 wait
instance-running --instance-id
i-896b92c9
aws ec2 wait
instance-status-ok --instance-id
i-896b92c9
aws ec2 wait
instance-stopped --instance-id
i-896b92c9
- images
- create an image:
instance_id=i-xxxxxxx
image_prefix=image_u1404
data=$(date '+%Y%m%d_%H%M')
imatge_id=$(aws ec2 create-image
--instance-id ${instance_id} --name
"${image_prefix}_${data}" --description "My
description")
echo "${imatge_id} ${image_prefix}_${data}
(from ${instance_id})"
- create an image but root volume (
/dev/sda1 )
will be destroyed on termination (useful when this
image will be used in a launch configuration of an
autoscaling group)
instance_id=i-xxxxxxx
image_prefix=image_u1404
data=$(date '+%Y%m%d_%H%M')
imatge_id=$(aws ec2 create-image
--instance-id ${instance_id} --name
"${image_prefix}_${data}" --description "My
description" --block-device-mappings
"[{\"DeviceName\":
\"/dev/sda1\",\"Ebs\":{\"VolumeType\":\"gp2\",\"DeleteOnTermination\":true}}]")
echo "${imatge_id} ${image_prefix}_${data}
(from ${instance_id})"
- describe images:
- get all own images
aws ec2 describe-images
--owners self
aws_options="--profile my_profile
--output json --region eu-west-1"
ami_info=$(aws ${aws_options} ec2
describe-images --owners self)
echo $ami_info | jq
'.Images | sort_by(.Name) | .[] |
[.ImageId, .OwnerId, .Name] | join("
")'
- describe an image given its id
- get an image by name:
aws ec2 describe-images
--owners self --filters
"Name=name,Values=my_image_name" --output
json
- using wildcards:
aws ec2 describe-images
--owners self --filters
"Name=name,Values=my_image_basename*" --output
json
- get image_id of an image with given its name:
aws ec2 describe-images
--owners self --filters
"Name=name,Values=my_image_name" --output
json | awk
'/ImageId/ {print $2}' | tr -d '",'
aws ec2 describe-images
--owners self --filters
"Name=name,Values=my_image_name" --output
json | jq -r '.Images[].ImageId'
- get a list of amis, sorted by creation date
aws ec2 describe-images
--owners self --filters
"Name=name,Values=my_image_basename*"
--output json | jq -r '(.Images |
sort_by(.CreationDate) | .[] |
[.CreationDate, .ImageId] | join(" ") )'
- get image_id of the most recent image:
aws ec2 describe-images
--owners self --filters
"Name=name,Values=my_image_basename*"
--output json | jq -r
'(.Images | sort_by(.CreationDate) | .[-1]
| .ImageId )'
aws ec2 describe-image-attribute
--image-id ami-6be62b1c --attribute
description
- waiters
- snapshots
- add tags to an:
- instance:
aws ec2 create-tags
--resources
i-9b789ed8
--tags Key=Name,Value=ubuntu_1404
- image:
aws ec2 create-tags
--resources ami-6be62b1c --tags
Key=Name,Value=image_ubuntu_1404
value="..."
# escape commas and remove single quotes
escaped_value=$(echo ${value//,/\\,} | tr -d
"'")
aws ec2 create-tags
--resources ami-6be62b1c --tags
Key=Name,Value="${escaped_value}"
- get tags from an:
- instance
aws ec2 describe-tags
--filters
"Name=resource-id,Values=i-1234567890abcdef8"
- create an instance from an image:
aws ec2 run-instances
--image-id ami-6be62b1c
--security-groups launch-wizard-2 --count
1 --key-name my_keyname --placement
AvailabilityZone='eu-west-1a',Tenancy='default' --instance-type
t2.micro
- get the instance_id:
- reponse in json (parse with jq)
instance_description=$(aws --output
json ec2 run-instances --image-id
$image_id --security-groups
$security_group_name
--iam-instance-profile
Name="role-nfs_server" --count 1
--key-name $key_name --placement
AvailabilityZone=${availability_zone},Tenancy='default'
--instance-type $instance_type
--block-device-mappings
'DeviceName=/dev/sda1,Ebs={DeleteOnTermination=true,VolumeType=gp2}'
)
instance_id=$(echo
$instance_description | jq -r
'.Instances[0].InstanceId')
- response in text (parse with awk)
instance_id=$(aws --output text ec2
run-instances
--image-id ami-6be62b1c
--security-groups launch-wizard-2
--count 1 --key-name my_keyname
--placement
AvailabilityZone='eu-west-1a',Tenancy='default'
--instance-type
t2.micro | awk '/INSTANCES/
{print $8}')
aws ec2 describe-instances
--instance-ids $ instance_id
- overwrite the delete on termination behaviour:
aws ec2 run-instances
--image-id ami-6be62b1c ...
--block-device-mappings
'DeviceName=/dev/sda1,Ebs={DeleteOnTermination=true,VolumeType=gp2} '
- ...
- dades d'usuari
/user data:
- when creating instance:
- des de la instància / from ec2 instance:
curl
http://169.254.169.254/latest/user-data/
- ec2-run-user-data
(ec2ubuntu)
(already installed in EC2 Ubuntu ami)
- assign a role to the instance
- Launching
an
Instance with an IAM Role Using the AWS CLI
- Passos / Steps
- If role has not been created using the
console:
- create a role
- create an instance
profile
- add the existing role (
s3access )
to the instance profile
- launch an instance with the instance
profile (if role was created using console,
an instance profile with the same name of
the role was automatically created)
aws ec2 run-instances
... --iam-instance-profile
Name="s3access-profile" ...
- Problems:
- Client.InvalidParameterCombination: Could not
create volume with size 10GiB and iops 30 from
snapshot 'snap-xxxxx'
- AutoScaling -
Client.InvalidParameterCombination
- Re: Stabilization
Error (Again)
- "Iops" should
not be there (?)
- Workaround:
create image from web interface instead
- Solution: add
--block-device-mappings
option (following example is for 10GiB
volume)
aws ec2 create-image
--instance-id i-xxxxxxxx --name
AMIName --block-device-mappings
'[{"DeviceName":"/dev/sda1","Ebs":{"VolumeType":"gp2","DeleteOnTermination":"true","VolumeSize":10}}]'
- volumes
- create a volume
volume_description=$(aws ec2
create-volume --availability-zone
$availability_zone --volume-type $volume_type
--size $small_volume_size_gibytes)
volume_id=$(echo $volume_description |
jq '.VolumeId')
- wait for volume to be created
- tag a volume with a name
aws ec2 create-tags
--resources $volume_id --tags
Key=Name,Value=$volume_name
- describe a volume with specified name:
- get availability zone of a volume
aws_cli_options="--profile my_profile
--output json"
volume_name= my-volume-name
volume_description=$(aws $aws_cli_options
ec2 describe-volumes --filters
"Name=tag:Name,Values=$volume_name")
availability_zone=$(echo $volume_description |
jq -r '.Volumes[0].AvailabilityZone')
- attach a volume to an instance
aws ec2 attach-volume
--volume-id $volume_id --instance-id
$instance_id --device /dev/sd${volume_letter}
- detach volume
- list all volumes
response=$(aws
--output json ec2 describe-volumes)
while IFS= read -r; do
volume=$REPLY
volume_id=$(echo $volume |
jq -r '.VolumeId')
echo "--- VolumeId:
$volume_id"
#tags=$(echo $volume | jq
-c -r '(.Tags | values | .[] | select(.Key ==
"Name") )')
tags=$(echo $volume | jq -c
-r '(.Tags | values | .[] )')
for tag in $tags
do
tag_key=$(echo $tag | jq '.Key')
tag_value=$(echo $tag | jq '.Value')
echo " $tag_key: $tag_value"
done
done < <(echo "$response" | jq -c -r
'.[] | .[]')
aws elb
- create a load balancer and associate to an instance:
aws elb create-load-balancer
--load-balancer-name lb-stateful --listeners
Protocol=HTTP,LoadBalancerPort=80,InstanceProtocol=HTTP,InstancePort=80
--availability-zones eu-west-1a eu-west-1b
eu-west-1c --security-groups sg-ba33c2df
aws elb configure-health-check
--load-balancer-name lb-stateful --health-check
Target=TCP:80,Interval=30,Timeout=10,UnhealthyThreshold=2,HealthyThreshold=2
aws elb register-instances-with-load-balancer
--load-balancer-name lb-stateful --instances
i-9b789ed8
create a load balancer to be associated
to an autoscaling group:
aws elb create-load-balancer
--load-balancer-name lb-stateless --listeners
Protocol=TCP,LoadBalancerPort=1935,InstanceProtocol=TCP,InstancePort=1935
Protocol=HTTP,LoadBalancerPort=8080,InstanceProtocol=HTTP,InstancePort=8080
--availability-zones
eu-west-1a eu-west-1b eu-west-1c --security-groups
sg-ba33c2df
aws elb configure-health-check
--load-balancer-name lb-stateless --health-check
Target=TCP:8080,Interval=30,Timeout=10,UnhealthyThreshold=2,HealthyThreshold=2
- add an HTTPS listener
with ARN
of an uploaded IAM certificate
aws --region eu-west-1 elb create-load-balancer-listeners
--load-balancer-name $load_balancer_name
--listeners
Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=HTTPS,InstancePort=443,SSLCertificateId=$ARN
- modify the certificate of an existing listener for a
given port:
- aws iam
- certificats
de servidor / server certificates
- upload a certificate
- obtained e.g. from Letsencrypt
letsencrypt_dirname=/etc/letsencrypt
aws iam upload-server-certificate
--server-certificate-name cert-${domain} \
--certificate-body
file://${letsencrypt_dirname}/live/${domain}/cert.pem
\
--private-key
file://${letsencrypt_dirname}/live/${domain}/privkey.pem
\
--certificate-chain
file://${letsencrypt_dirname}/live/${domain}/chain.pem
- self-signed, to be used in cloudfront:
openssl req -new -nodes -keyout
www.toto.org.key -sha256 -x509 -days 365
-out www.toto.org.crt
- Common Name:
www.toto.org
aws iam upload-server-certificate
\
--server-certificate-name
cert-www.toto.org \
--certificate-body
file://.../ www.toto.org.crt \
--private-key
file://.../ www.toto.org.key \
--certificate-chain
file://.../ www.toto.org.crt
\
--path /cloudfront/
- get a list of server certificates
- get ARN of a
certificate (will be specified when adding a listener to a
ELB)
ARN=$(aws --output json iam get-server-certificate
--server-certificate-name ${domain}.cert | jq
'.ServerCertificate.ServerCertificateMetadata.Arn')
- check if a certificate is available
aws route53
- Adding
EC2
instances to Route53 (bash+boto)
aws route53 list-resource-record-sets
--hosted-zone-id xxxxxx
aws route53 change-resource-record-sets
--hosted-zone-id xxxxxx --change-batch file:///absolute_path_to/change_entry.json
change_entry.json (to modify record
www.toto.org; e.g. TTL value)
{
"Comment": "Modifying TTL to 55",
"Changes": [
{
"Action":
"UPSERT",
"ResourceRecordSet": {
"Name": "www.toto.org.",
"Type": "A",
"TTL": 55,
"ResourceRecords": [
{
"Value":
"xx.xx.xx.xx"
}
]
}
}
]
}
- Auto configuration of Route53 from EC2 at boot (Ubuntu
Upstart)
- previously, from any computer:
- option 1 (preferred): create a role and assign
it to the instance when launching it
- option 2: create a user
- create a user and group that can only
modify Route53 entries:
- from web interface:
- Grup
- Group name
- Policy
{
"Version":
"2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:*"
],
"Resource": [
"*"
]
}
]
}
- alternatively, from aws cli:
- once logged into EC2 instance:
- only if used option 2 (not using a role):
- /usr/local/bin/route53.sh
#!/bin/bash
# zone_id for mydomain.org
ZONE_ID=$(cat zone_id.txt)
ip_address=$(curl
http://169.254.169.254/latest/meta-data/public-ipv4)
name=www.mydomain.org
tmp_file=/tmp/modify_record_set.json
rm -f $tmp_file
#aws route53 list-resource-record-sets
--hosted-zone-id $ZONE_ID
cat > $tmp_file <<EOF
{
"Comment": "Modifying ip address",
"Changes": [
{
"Action":
"UPSERT",
"ResourceRecordSet": {
"Name": "${name}.",
"Type": "A",
"TTL": 60,
"ResourceRecords": [
{
"Value":
"$ip_address"
}
]
}
}
]
}
EOF
#source /opt/p27/bin/activate
aws route53 change-resource-record-sets
--hosted-zone-id $ZONE_ID --change-batch
file://$tmp_file
#deactivate
exit 0
- init script
- CentOS
- /etc/systemd/system/route53.service
[Unit]
Description=Description of my
script
After=syslog.target network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/route53.sh
[Install]
WantedBy=multi-user.target
sudo systemctl enable
route53.service
sudo systemctl start
route53.service
- Ubuntu
- /etc/init/route53.conf
description
"route53 daemon"
start on (filesystem and
net-device-up IFACE=lo)
stop on runlevel [!2345]
env
DAEMON=/usr/local/bin/route53.sh
env PID=/var/run/route53.pid
env
AWS_CONFIG_FILE=/home/ubuntu/.aws/credentials
exec $DAEMON
aws s3
- Note: no need to create dirs: they do not exist
- list all buckets
- list all files in a "directory":
aws s3 ls --recursive
s3://my_bucket/my_dir1/
- copy a single file to S3:
aws s3 cp
toto.txt s3://my_bucket/
- recursively copy to S3:
aws s3
cp
--recursive . s3://my_bucket/
- recursively copy from S3:
aws s3 cp
--recursive s3://my_bucket/ .
- sync
aws s3 sync ... --exclude '*.png' --exclude
'log' ...
- Problemes / Problems
- sinctronització lenta quan hi ha molts fitxers
/ slow sync when a lot of files exist
|