Section 4 Main Menu
- EC2 User Data Overview
- EC2 User Data & Fn::Base64 in CloudFormation
- CloudFormation Init Overview
- Packages
- Groups and Users
- Sources
- Files
- Fn::Sub (substitute function)
- Commands
- Services
- CFN Init and Signal
- CFN Hands On
- Summary
EC2 User Data Overview
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139272?start=0
What is CFN-Init and EC2-user data
- Many of the CF templates will be about provisioning computing resources in your AWS Cloud
- These resources can be either:
- EC2 Instances
- AutoScaling Groups
- Usually, you want the instances to be self configured so that they can perform the job they are supposed to perform.
- You can fully automate your EC2 fleet state with CloudFormation Init.
EC2 User data
- This is the area of the AWS Console under EC2 Provisioning where you upload/enter your boot scripts
Example:
#!/bin/bash
yum update -y
yum install -y httpd24 php56 mysql55-server php56-mysqlnd
service httpd start
chkconfig httpd on
groupadd www
usermod -a -G www ec2-user
chown -R root:www /var/www
chmod 2775 /var/www
find /var/www -type d -exec chmod 2775 {} +
find /var/www -type f -exec chmod 0664 {} +
echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php
EC2 User Data & Fn::Base64 in CloudFormation
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8162182?start=0
Same Script as above, using CloudFormation and Fn::Base64
General Outline
Resources:
ResourceID:
Properties:
UserData:
Fn::Base64: |
#! /bin/bash
...
Example:
Resources:
WebServer:
Type: AWS::EC2::Instance
Properties:
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd24 php56 mysql55-server php56-mysqlnd
service httpd start
chkconfig httpd on
groupadd www
usermod -a -G www ec2-user
chown -R root:www /var/www
chmod 2775 /var/www
find /var/www -type d -exec chmod 2775 {} +
find /var/www -type f -exec chmod 0664 {} +
echo "" > /var/www/html/phpinfo.php
CloudFormation Init Overview
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139294?start=0
Syntax
cfn-init --stack|-s stack.name.or.id \
--resource|-r logical.resource.id \
--region region
--access-key access.key \
--secret-key secret.key \
--role rolename\
--credential-file|-f credential.file \
--configsets|-c config.sets \
--url|-u service.url \
--http-proxy HTTP.proxy \
--https-proxy HTTPS.proxy \
--verbose|-v
The Problems with EC2 User Data
- What if you have a very large instance configuration
- UserData only allows a certain number of characters
- What if you want to evolve the state of the EC2 instance without terminating it and creating a new one?
- How do we make our EC2 user data more readable?
- How do we know or signal that our CE2 user-data script actually completed successfully?
CloudFormation Helper Scripts
- There are 4 Python scrips that come directly on Amazon Linux AMI, or can be installed using yum on non-Amazon Linux
- cfn-init
- Used to retrieve and interpret the resource metadata, installing packages, creating files and starting services
- cfn-signal
- A simple wrapper to signal an AWS CF CreationPolicy or WaitCondition, enabling you to synchronize other resources in the stack with the application being ready.
- chn-get-metadata
- A wrapper scrip making it easy to retrieve either all metadata defined for a resource or path to a specific key or subtree of the resource metadata.
- cfn-hup
- A daemon to check for updates to metadata and execute custom hooks when the changes are detected.
- #This seems very similar to a cron job.
- cfn-init
- Usual flow:
- cfn-init
- cfn-signal
- Optionally cfn-hup
AWS::CloudFormation::Init pt.1
- A config contains the following and is executed in that order:
- Packages: Install a list of packages on the Linux OS (mysql, wordpress, etc.)
- Groups: defines user groups
- Users: define users and which group they belong to
- Sources: download an archive file and place it on the ec2 instance (tar, zip, bz2)
- Files: create files on the ec2 instance using inline or can be pulled from a URL
- Commands: run a series of commands
- Services: launch a list of sysvinit
General Outline
Resources:
ResourceID:
Metadata:
AWS::CloudFormation::Init:
config: #! /bin/bash
packages:
...
Example:
Resources:
MyInstance:
Type: "AWS::EC2::Instance"
Metadata:
AWS::CloudFormation::Init:
config:
packages:
:
groups:
:
users:
:
sources:
:
files:
:
commands:
:
services:
:
Properties:
:
AWS::CloudFormation::Init pt.2
- You can have multiple configs in your CloudFormation::Init
- You create configsets with multiple configs
- You invoke config sets from your ec2-user data
Packages
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139306?start=0
- You can install packages from the following repositories:
- apt
- msi
- python
- rpm
- rubygems
- yum
- Packages are processed in the following order:
- rpm
- yum/apt
- rubygems
- python
- You can specify a version, or no version (empty array) to get the latest version
rpm:
epel: "http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm"
yum:
httpd: []
php: []
wordpress: []
rubygems:
chef:
- "0.10.2"
Example from script:
WebServerHost:
Type: AWS::EC2::Instance
Metadata:
Comment: Install a simple PHP application
AWS::CloudFormation::Init:
config:
packages:
yum:
httpd: []
php: []
groups:
...
Groups and Users
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139308?start=0
- If you want to have multiple users and groups (with an optional gid) in your ec2 instance, you and do the following.
- Let’s add groups and users to our CloudFormation Init Metadata
groups:
groupOne: {}
groupTwo:
gid: "45"
users:
myUser:
groups:
- "groupOne"
- "groupTwo"
uid: "50"
homeDir: "/tmp"
Example from script:
WebServerHost:
Type: AWS::EC2::Instance
Metadata:
Comment: Install a simple PHP application
AWS::CloudFormation::Init:
config:
packages:
...
groups:
apache: {}
users:
"apache":
groups:
- "apache"
sources:
...
Sources
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139310?start=0
In short, these are used to download and extract archived (.zip, .tar, .tgz, etc.)
- We can download whole compressed archives from the web and unpack them on the instance directly
- It is very handy if you:
- Have a set of standardized scripts for your instances that you store in S3 for example
- Want to download a whole github project directly on your instance.
- Each source is set in a key: value comfiguration
- The key is the location of the unpacked source (Where you download to)
- The value is the url of the file
sources: /etc/puppet: "https://github.com/user1/cfn-demo/tarball/master" /etc/myapp: "https://s3.amazonaws.com/mybucket/myapp.tar.gz"
Example from script:
WebServerHost:
Type: AWS::EC2::Instance
Metadata:
Comment: Install a simple PHP application
AWS::CloudFormation::Init:
config:
...
sources:
"/home/ec2-user/aws-cli": "https://github.com/aws/aws-cli/tarball/master"
...
Files
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139312?start=0
This is pretty cool… pay close attention!
- Files are very powerful as you have full control over any content you want.
- They can come from a specific URL, or be written inline
files:
/tmp/setup.mysql:
content: !Sub |
CREATE DATABASE ${DBName};
CREATE USER '${dbuSERNAME}'@'localhost' IDENTIFIED BY '${DBPassword}';
GRANT ALL ON ${DBName}.* TO '${DBUswername}'.@'localhost';
FLUSH PRIVILEGES;
mode" "000644"
owner: "root"
group: "root"
Example from script:
WebServerHost:
Type: AWS::EC2::Instance
Metadata:
Comment: Install a simple PHP application
AWS::CloudFormation::Init:
config:
...
files:
"/tmp/cwlogs/apacheaccess.conf":
content: !Sub |
[general]
state_file= /var/awslogs/agent-state
[/var/log/httpd/access_log]
file = /var/log/httpd/access_log
log_group_name = ${AWS::StackName}
log_stream_name = {instance_id}/apache.log
datetime_format = %d/%b/%Y:%H:%M:%S
mode: '000400'
owner: apache
group: apache
"/var/www/html/index.php":
content: !Sub |
mode: '000644'
owner: apache
group: apache
"/etc/cfn/cfn-hup.conf":
content: !Sub |
[main]
stack=${AWS::StackId}
region=${AWS::Region}
mode: "000400"
owner: "root"
group: "root"
"/etc/cfn/hooks.d/cfn-auto-reloader.conf":
content: !Sub |
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.WebServerHost.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerHost --region ${AWS::Region}
mode: "000400"
owner: "root"
group: "root"
commands:
...
Fn::Sub (substitute function)
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139314?start=0
- Fn::Sub or !Sub as a shorthand, is used to substitute variables from a text allowing you to fully customize your templates.
- For example, you can combine Fn::Sub with References or AWS Pseudo varables
- String must contain ${VariableName} and will substitute them.
Syntax Example 1 (less common):
!Sub - String - { Var1Name: Var1Value, Var2Name: Var2Value }
Syntax Example 2 (more common):
!Sub String
Commands
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139318?start=0
- You can run commands one at a time in alphabetical order
- You can set a directory from which that command is run as well as environmental variables
- You can provide a test to control whether the command is executied or not
- Example: test:if a file does not exist, command: the download command)
Example: Call the echo command only if the file does not exist
commands:
test:
command: "echo \"$MAGIC\" > test.txt
env:
MAGIC: "I come from the environment!"
cwd: "~"
test: "test ! -e ~/test.txt"
ignoreErrors: "false"
- It is recommended to:
- use command as a last resort since most of this can be performed in the above sections
- Use the Files section to write your scripts, then use command to execute those scripts.
Services
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139320?start=0
- Launch several services at the instance launch
- Ensure services are restarted when files change, or packages are updated by cfn-init.
Example from script:
WebServerHost:
Type: AWS::EC2::Instance
Metadata:
Comment: Install a simple PHP application
AWS::CloudFormation::Init:
config:
...
services:
sysvinit:
httpd:
enabled: 'true'
ensureRunning: 'true'
sendmail:
enabled: 'false'
ensureRunning: 'false'
CFN Init and Signal
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8162188?start=0
Calling cfn-signal
- Use cfn-init first to launch the configuration
- Next use cfn-signal when the configuration has completed to let CF know that the resoiurce creation has been successful
-
- This has to be used in conjunction with a CreationPolicy.
CreationPolicy: ResourceSignal: Timeout: PT5M- This example means we are waiting a maximum of 5 minutes for the instance to come online and be self configured. If we don’t hear from cfn-signal by then, the CF will fail and roll back.
-
Properties:
…
UserData:
“Fn::Base64”:
!Sub |
#!/bin/bash -xe
# Get the latest CloudFormation package
yum update -y aws-cfn-bootstrap
# Start cfn-init
/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerHost –region ${AWS::Region} || error_exit ‘Failed to run cfn-init’
# Start up the cfn-hup daemon to listen for changes to the EC2 instance metadata
/opt/aws/bin/cfn-hup || error_exit ‘Failed to start cfn-hup’
# All done so signal success
/opt/aws/bin/cfn-signal -e $? –stack ${AWS::StackId} –resource WebServerHost –region ${AWS::Region}
* -s == --stack (StackId) * -r == --resource
Cfn-hup (cfn Helper Update?)
-
- Cfn-hup can be used to tell your EC2 instnaces to look for Metadata changes every 15 minutes and apply the metadata configuration again.
-
- Very powerful, but strongly recommended to tro try it to fully understand how it works.
-
- Relies on a cfn-hup configuration, reference:
-
- /etc/cfn/cfn-hup.conf
-
- /etc/cfn/hooks.d/cfn-auto-reloader.conf
-
- Relies on a cfn-hup configuration, reference:
Example from script
files:
...
"/etc/cfn/cfn-hup.conf":
content: !Sub |
[main]
stack=${AWS::StackId}
region=${AWS::Region}
mode: "000400"
owner: "root"
group: "root"
"/etc/cfn/hooks.d/cfn-auto-reloader.conf":
content: !Sub |
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.WebServerHost.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerHost --region ${AWS::Region}
mode: "000400"
owner: "root"
group: "root"
CFN Hands On
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139328?start=0
Upload the script and run it.
- View the updates on the CF Events tab
- View the outputs on the CD Outputs tab
Summary
https://www.udemy.com/aws-cloudformation-master-class/learn/v4/t/lecture/8139330?start=0
- Use the template as a basis for future CloudFormation scripts.
- For practice, create a CF script with Init for an AutoScaling group.
- Log locations
- EC2-user data: /var/log/cloud-init-output.log
- cfn-init: /var/log/cfn-init.log
- Use the logs to see which commands did not complete as expected and why.