我們將首先安裝對流層庫:
$ pip install troposphere
安裝完成后,您可以創(chuàng)建一個名為 helloworld-cf-template.py 的新文件。
我們將通過從對流層模塊導入一些定義來開始我們的文件:
"""Generating CloudFormation template."""
from troposphere import (
Base64,
ec2,
GetAtt,
Join,
Output,
Parameter,
Ref,
Template,
)
從代碼的角度來看,我們要做的第一件事是初始化一個模板變量。在我們的腳本結束時,模板將包含我們基礎設施的完整描述,我們將能夠簡單地打印其輸出以獲取我們的 CloudFromation 模板:
t = Template()
在本書中,我們將同時創(chuàng)建和運行多個 CloudFormation 模板。為了幫助我們識別給定堆棧中的內(nèi)容,我們可以提供描述。創(chuàng)建模板后,添加如下描述:
t.add_description("Effective DevOps in AWS: HelloWorld web application")
當我們使用 Web 命令行界面啟動 EC2 實例時,我們選擇了使用哪個密鑰對以獲得對主機的 SSH 訪問。為了不失去這種能力,我們的模板首先要有一個參數(shù),它為 CloudFormation 用戶提供在啟動 EC2 實例時選擇要使用的密鑰對的能力。
為此,我們將創(chuàng)建一個 Parameter 對象,并通過提供標識符、描述、參數(shù)類型、描述和約束描述來初始化它,以幫助做出正確的決定
當我們啟動堆棧時。為了讓這個參數(shù)存在于我們的最終模板中,我們還將使用模板類中定義的 add_paramter() 函數(shù):
t.add_parameter(Parameter(
"KeyPair",
Description="Name of an existing EC2 KeyPair to SSH",
Type="AWS::EC2::KeyPair::KeyName",
ConstraintDescription="must be the name of an existing EC2 KeyPair.",
))
接下來我們要看的是安全組。我們將完全按照我們對 KeyPair 參數(shù)所做的那樣進行。
ApplicationPort = 3000
t.add_resource(ec2.SecurityGroup(
"SecurityGroup",
GroupDescription="Allow SSH and TCP/{} access".format(ApplicationPort),
SecurityGroupIngress=[
ec2.SecurityGroupRule(
IpProtocol="tcp",
FromPort="22",
ToPort="22",
CidrIp="0.0.0.0/0",
),
ec2.SecurityGroupRule(
IpProtocol="tcp",
FromPort=ApplicationPort,
ToPort=ApplicationPort,
CidrIp="0.0.0.0/0",
),
],
))
在下一節(jié)中,我們將不再需要登錄到我們的 EC2 實例并手動安裝 helloworld.js 文件及其初始化腳本。為此,我們將利用 EC2 提供的 UserData 功能。
創(chuàng)建 EC2 實例時,您可以通過 UserData 可選參數(shù)提供一組命令,以便在虛擬機啟動后運行。
user_data = Base64(Join('\n', [
"#!/bin/bash",
"sudo yum install --enablerepo=epel -y nodejs",
"wget http://bit.ly/2vESNuc -O /home/ec2-user/helloworld.js",
"wget http://bit.ly/2vVvT18 -O /etc/init/helloworld.conf",
"start helloworld"
]))
我們現(xiàn)在將專注于我們模板的主要資源,我們的 EC2 實例。創(chuàng)建實例需要提供用于標識資源的名稱、映像 ID、實例類型、安全組、用于 SSH 訪問的密鑰對以及用戶數(shù)據(jù)。
為了簡單起見,我們將對 AMI ID ( ami-a4c7edb2 ) 和實例類型 ( t2.micro ) 進行硬編碼。
創(chuàng)建我們的 EC2 實例所需的其余信息是安全組信息和密鑰對名稱,我們之前通過定義參數(shù)和資源收集了這些信息。在 CloudFormation 中,您可以使用關鍵字 Ref 來引用模板的預先存在的小節(jié)。
在對流層中,這是通過調(diào)用 Ref() 函數(shù)來完成的。和以前一樣,我們將在 add_resource 函數(shù)的幫助下將結果輸出添加到我們的模板中:
t.add_resource(ec2.Instance(
"instance",
ImageId="ami-a4c7edb2",
InstanceType="t2.micro",
SecurityGroups=[Ref("SecurityGroup")],
KeyName=Ref("KeyPair"),
UserData=user_data,
))
在我們腳本的最后一部分,我們將專注于生成模板的輸出部分,當 CloudFormation 創(chuàng)建堆棧時,該部分會被填充。
此選擇允許您打印出在堆棧啟動期間計算的有用信息。在我們的例子中,有兩個有用的信息,訪問我們的 Web 應用程序的 URL 和實例的公共 IP 地址,以便我們可以根據(jù)需要通過 SSH 訪問它。
為了檢索此類信息,CloudFormation 使用函數(shù) Fn::GetAtt 。在對流層,這被轉(zhuǎn)換為使用 GetAttr() 函數(shù):
t.add_output(Output(
"InstancePublicIp",
Description="Public IP of our instance.",
Value=GetAtt(instance, "PublicIp"),
))
t.add_output(Output(
"WebUrl",
Description="Application endpoint",
Value=Join("", [
"http://", GetAtt(instance, "PublicDnsName"), ":", ApplicationPort
]),
))
此時,我們可以讓我們的腳本輸出我們生成的模板的最終結果:
print t.to_json()