- AWS
CloudFormation Product Details
- User
guide
- 19
Best Practices for Creating Amazon CloudFormation Templates
- Designer
- Preserve resources after stack destruction
- Info
- 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"
}
}
}
}
- 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:
- ...
|
- 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
- Solució / Solution
sudo pip install awscli
- a pair of working packages is, e.g.:
awscli==1.14.28, botocore==1.8.32
- queries
--query <query-expression>
- uses JMESPath
- 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
- 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 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:
- sync
aws s3 sync ... --exclude '*.png' --exclude
'log' ...
- recursively copy from S3:
aws s3 cp s3://my_bucket/ . --recursive
|