AWS學習筆記(六)--利用CloudFormation管理AWS資源
利用CloudFormation不必再單獨的創建和配置AWS資源,解除了繁瑣的手工安裝配置工作,又可以將代碼進行版本管理,利於以後的更新維護,也不用編寫安裝手冊了。
Template
CloudFormation Template支持兩種格式:JSON和YAML,可以將模板文件保存為任何擴展名,比如:.json, .yaml, .template, .txt。YAML語法更簡捷易讀,並且支持註釋,但CloudFormation Designer目前只支持JSON。
{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "A sample template", "Resources" : { "MyEC2Instance" : { "Type" : "AWS::EC2::Instance", "Properties" : { "ImageId" : "ami-2f726546", "InstanceType" : "t1.micro", "KeyName" : "testkey", "BlockDeviceMappings" : [ { "DeviceName" : "/dev/sdm", "Ebs" : { "VolumeType" : "io1", "Iops" : "200", "DeleteOnTermination" : "false", "VolumeSize" : "20" } } ] } } } }
YAML示例
AWSTemplateFormatVersion: "2010-09-09" Description: A sample template Resources: MyEC2Instance: Type: "AWS::EC2::Instance" Properties: ImageId: "ami-2f726546" InstanceType: t1.micro KeyName: testkey BlockDeviceMappings: - DeviceName: /dev/sdm Ebs: VolumeType: io1 Iops: 200 DeleteOnTermination: false VolumeSize: 20
模板基本知識請參考:
Template Anatomy
Learn Template Basics
Parameters
參數類型除String、Number、List<Number>、CommaDelimitedList外,還支持特定的類型,比如AWS::EC2::KeyPair::KeyName、AWS::EC2::AvailabilityZone::Name、AWS::EC2::SecurityGroup::GroupName等,用戶必須指定其賬戶中現有的 AWS 值。
在通過CloudFormation Console創建Stack時,參數默認是按字母排序的,如果參數多看起來會很亂,不易查找,這就需要借助Metadata了,AWS::CloudFormation::Interface用於定義參數在CloudFormation控制臺中的分組和排序方式:
"Metadata" : {
"AWS::CloudFormation::Interface" : {
"ParameterGroups" : [
{
"Label" : { "default" : "Network Configuration" },
"Parameters" : [ "VPCID", "SubnetId", "SecurityGroupID" ]
},
{
"Label" : { "default":"Amazon EC2 Configuration" },
"Parameters" : [ "InstanceType", "KeyName" ]
}
]
}
}
下面的代碼演示了CloudFormation中cfn-init和shell的使用。AMI使用了RHEL 7,其中包括安裝cfn-init、awscli、awslogs,配置DNS、awscli、awslog等。
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"InstanceTest": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"configSets": {
"Install": [
"Install"
]
},
"Install": {
"packages": {
"yum": {
"ntp": [],
"nfs-utils": [],
"rpcbind": []
}
},
"files": {
"/etc/sysconfig/network-scripts/ifcfg-eth0": {
"content": { "Fn::Join": ["", [
"DEVICE=\"eth0\"\n",
"BOOTPROTO=\"dhcp\"\n",
"ONBOOT=\"yes\"\n",
"TYPE=\"Ethernet\"\n",
"USERCTL=\"yes\"\n",
"PEERDNS=\"no\"\n",
"IPV6INIT=\"no\"\n",
"DNS1=\"10.184.13.14\""
]]},
"owner": "root",
"group": "root"
},
"/root/.aws/config": {
"content": { "Fn::Join": ["", [
"[default]\n",
"output = json\n",
"region = cn-north-1"
]]},
"mode": "000600",
"owner": "root",
"group": "root"
},
"/root/.aws/credentials": {
"content": { "Fn::Join": ["", [
"[default]\n",
"aws_access_key_id = AKIAPM6UDU6DGZPYXXXX\n",
"aws_secret_access_key = CrYrR/LeiDXJWbAX3KQwFnaScDU0zGE+XXXXXXXX"
]]},
"mode": "000600",
"owner": "root",
"group": "root"
},
"/root/.aws/awslogs.conf": {
"content": { "Fn::Join": ["", [
"[general]\n",
"state_file = /var/awslogs/state/agent-state\n",
"[/var/log/messages]\n",
"datetime_format = %Y-%m-%d %H:%M:%S\n",
"file = /var/log/messages\n",
"buffer_duration = 5000\n",
"log_stream_name = server-log\n",
"initial_position = start_of_file\n",
"log_group_name = /var/log/messages"
]]},
"mode": "000600",
"owner": "root",
"group": "root"
}
},
"commands": {
"1-timezone": {
"command": "timedatectl set-timezone UTC",
"ignoreErrors": "true"
},
"2-groups": {
"command": "groupadd -g 1001 monet",
"ignoreErrors": "true"
},
"3-users": {
"command": "useradd -d /monet -g monet -u 1001 monetmanager\nchmod 755 /monet ",
"ignoreErrors": "true"
}
},
"services": {
"sysvinit": {
"ntpd": { "enabled" : "true", "ensureRunning" : "true" },
"rpcbind": { "enabled" : "true", "ensureRunning" : "true" },
"nfslock": { "enabled" : "true", "ensureRunning" : "true" }
}
}
}
}
},
"Properties": {
"AvailabilityZone": "cn-north-1a",
"DisableApiTermination": "false",
"EbsOptimized": "false",
"ImageId": "ami-3ce23651",
"InstanceInitiatedShutdownBehavior": "stop",
"InstanceType": "t2.small",
"KeyName": "Prod Key Pair",
"Monitoring": "false",
"PrivateIpAddress": "10.184.12.247",
"SecurityGroupIds": [
{
"Fn::ImportValue": "prod-network-sg-private-id"
}
],
"SubnetId": {
"Fn::ImportValue": "prod-network-subnet-private-id"
},
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"VolumeSize": "30"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": "test-ec2"
}
],
"UserData": {
"Fn::Base64": {
"Fn::Join" : ["", [
"#!/bin/bash\n",
"# Install cfn-init\n",
"curl -O https://bootstrap.pypa.io/ez_setup.py\n",
"python ez_setup.py\n",
"easy_install --script-dir /opt/aws/bin https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
"# Install the files and packages from the metadata\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ", { "Ref" : "AWS::StackName" },
" --resource InstanceTest ",
" --configsets Install ",
" --region ", { "Ref" : "AWS::Region" }, "\n",
"# Install awscli\n",
"curl -O https://bootstrap.pypa.io/get-pip.py\n",
"python get-pip.py\n",
"pip install awscli\n",
"# Install awslogs\n",
"curl -O https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py\n",
"python ./awslogs-agent-setup.py --region cn-north-1 --non-interactive --configfile=/root/.aws/awslogs.conf\n",
"# Delete installation files\n",
"rm -f get-pip.py ez_setup.py setuptools*.zip awslogs-agent-setup.py\n"
]
]
}
}
}
}
}
}
下面演示了在Windows 2016上通過powershell安裝DNS:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"InstanceDNS": {
"Type": "AWS::EC2::Instance",
"Properties": {
"AvailabilityZone": "cn-north-1a",
"DisableApiTermination": "false",
"EbsOptimized": "false",
"ImageId": "ami-2797404a",
"InstanceInitiatedShutdownBehavior": "stop",
"InstanceType": "t2.small",
"KeyName": "Prod Key Pair",
"Monitoring": "false",
"PrivateIpAddress": "10.184.13.15",
"SecurityGroupIds": [
"sg-b0525cd5"
],
"SubnetId": "subnet-a65208c3",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"VolumeSize": "30"
}
}
],
"UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
"<powershell>\n",
"Install-WindowsFeature -Name DNS -IncludeManagementTools\n",
"Add-DnsServerPrimaryZone -Name \"iata.org\" -ZoneFile \"iata.org.dns\"\n",
"Add-DnsServerResourceRecordA -Name \"test\" -ZoneName \"iata.org\" -AllowUpdateAny -IPv4Address \"10.184.12.111\"\n",
"</powershell>"
]]}},
"Tags": [
{
"Key": "Name",
"Value": "test-dns"
}
]
}
}
}
}
CloudFormation Designer
AWS CloudFormation Console提供圖形化的Template設計器,支持拖拽操作,集成JSON編輯器,支持自動完成功能。
使用CloudFormation Designer的拖拽功能,或用其打開已有的Template會增加組件位置信息,這些信息在實際應用中是沒有必要的,也增加了Template的復雜度,故本人只利用它的自動完成功能,要編輯已有的Template時,使用Copy/Paste的方式。
快捷鍵
【Ctrl+Shift+Space】 顯示提示列表
【Ctrl+F】 搜索
【Ctrl+\】 格式化Template(會刪除所有空行)
【Ctrl+Shift+\】 刪除所有空格
Sample Templates
CloudFormation提供了大量的示例模板Sample Templates可供學習,其中China Region的示例較少,推薦US West (Northern California) Region。比如Services中下面的示例,全面演示了從創建VPC到EC2。
Creates a VPC and adds an Amazon EC2 instance with an Elastic IP address and a security group
CloudFormer
CloudFormer是模板創建工具,可從現有AWS資源創建CloudFormation Template,用來作為初始Template,是學習Template語法結構的好工具。
CloudFormer使用很簡單,它是一個CloudFormation Stack,可從CloudFormation Console創建,創建後在一個EC2實例上運行,不需其他資源。
創建CloudFormer
登錄CloudFormation Console > Create New Stack > Select a sample template > CloudFormer > Next > 輸入Stack name、Username、Password > 根據提示信息完成後續步驟
啟動CloudFormer
點擊CloudFormer Stack選項卡Outputs中的鏈接,輸入用戶名,密碼即可啟動CloudFormer。然後Select the AWS Region > Create Template > 一步步的選擇要創建模板的資源。
註:如出現錯誤NoMethodError in TemplatesController,可能是資源配置有問題,試著減少一些資源。
Best Practices
- 按生命周期和所有權組織堆棧,而不是將所有資源放在一個Stack內,避免資源變化時互相影響。另外,可以根據層次結構和面向的服務(SOA)劃分資源。
- 使用跨堆棧引用來導出共享資源,其他堆棧使用 Fn::ImportValue函數調用導出的資源。引用另一個 AWS CloudFormation 堆棧中的資源輸出
- 重復使用模板以在多個環境中復制堆棧,要使模板可重用,可使用參數、映射和條件部分,以便能在創建堆棧時對其進行自定義。
- 使用嵌套堆棧來重復使用常見模板,要創建嵌套堆棧,可使用模板中的AWS::CloudFormation::Stack資源來引用其他模板。
AWS CloudFormation CLI
Creating a Stack
You must provide the stack name, the location of a valid template, and any input parameters. If you specify a local template file, AWS CloudFormation uploads it to an Amazon S3 bucket in your AWS account.
$ aws cloudformation create-stack --stack-name myteststack --template-body file:///home/testuser/mytemplate.json --parameters ParameterKey=Parm1,ParameterValue=test1 ParameterKey=Parm2,ParameterValue=test2
Listing Your Stacks
Note The aws cloudformation list-stacks command returns information on deleted stacks for 90 days after they have been deleted.
$ aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE
Describing Your Stacks
$ aws cloudformation describe-stacks --stack-name myteststack
By default, aws cloudformation describe-stacks returns parameter values. To prevent sensitive parameter values such as passwords from being returned, include a NoEcho property set to TRUE in your AWS CloudFormation template.
Viewing Stack Event History
You can track the status of the resources AWS CloudFormation is creating and deleting with the aws cloudformation describe-stack-events command. The amount of time to create or delete a stack depends on the complexity of your stack.
$ aws cloudformation describe-stack-events --stack-name myteststack
Listing Stack Resources
$ aws cloudformation list-stack-resources --stack-name myteststack
Retrieving a Template
AWS CloudFormation stores the template you use to create your stack as part of the stack.
$ aws cloudformation get-template --stack-name myteststack
Validating a Template
You can validate templates locally by using the --template-body parameter, or remotely with the --template-url parameter.
$ aws cloudformation validate-template --template-url https://s3.amazonaws.com/cloudformation-templates-us-east-1/S3_Bucket.template
$ aws cloudformation validate-template --template-body file:///home/local/test/sampletemplate.json
Deleting a Stack
$ aws cloudformation delete-stack --stack-name myteststack
Getting Started with AWS CloudFormation
Template Anatomy
Learn Template Basics
AWS CloudFormation Templates
AWS Resource Types Reference
Using CloudFormer to Create AWS CloudFormation Templates from Existing AWS Resources
Using the AWS Command Line Interface
AWS CloudFormation Best Practices
Install roles, role services, and features by using Windows PowerShell cmdlets
Domain Name System (DNS) Server Cmdlets
AWS學習筆記(六)--利用CloudFormation管理AWS資源