Study Notes - CloudFormation Debugging


整理開發 CloudFormation Template 和 Debug Stack 遇到的問題。。。


問題整理

底下整理一些開發 Template 過程遇到的問題。

如何有效的學習 CloudFormation?

CloudFormation 其實滿複雜的,而且要了解每一個 Resource 本身的 Attributes。建立 Template 的過程,還不了解 Resource 之前,先一個一個慢慢增加,重複確認是否符合預期的再繼續往下走。

以下是我自己練習的例子:

  • 建立一個 S3 Bucket
  • 建立 VPC, Internet Gateway, NAT Gateway, Subnets, RouteTable, Security Groups
  • 建立 EC2, 設定多個 EBS, 指定 IOPS
  • 建立 EC2, 並且執行 UserData
  • 建立 EC2, 設計 AWS::CloudFormation::Init 流程
  • 建立 CloudWatch Alarm
  • 建立 Auto Scaling, Launch Configuration, ELB ..

簡單說,就是:

一個一個 Resource 慢慢增加,然後去了解每個 Resource 的屬性、與其他服務的關聯性

開發 Template 需要注意些什麼?

通常開發 Template 過程當中,開發者需要這些條件:

  • 基本功
    • 對 AWS 服務有一定程度認識
    • 了解 Resource Types 與 Attributes
    • 了解 Stack 的生命週期、工作流程
  • 權限與帳號:開發 Template 會需要較大的權限,所以實務上建議給予完整的 Admin 權限,甚至是獨立的 AWS Account,不然開發過程會很卡。

使用 YAML 取代 JSON

JSON 真的不是很好閱讀,而且無法註解,所以盡可能用 YAML 取代 JSON.

確認 cfn-hup, hooks config 內容正確

如果 VM Level 的配置想要透過 CloudFormation,那麼要注意控制的生命週期。EC2 or LaunchConfiguration 會透過 Metadata -> AWS::CloudFormation::Init 的 configSets 產生 cfn-hup 的設定檔,其中包含 cfn-hup.conf 和多個 hooks ,要確認這些檔案的內容是否正確。

/etc/cfn/cfn-hup.conf

1
2
3
4
# /etc/cfn/cfn-hup.conf
[main]
stack=arn:aws:cloudformation:ap-northeast-1:123456778890:stack/App-Dev-20170514-2310/8826e330-38b7-11e7-92d6-50d5ca9ff4c6
region=ap-northeast-1

/etc/cfn/hooks.d/cfn-auto-reloader.conf

1
2
3
4
5
6
# /etc/cfn/hooks.d/cfn-auto-reloader.conf
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.AppLaunchConfiguration.Metadata.AWS::CloudFormation::Init
action=/usr/local/bin/cfn-init -v --stack App_Dev-20170514-2310 --resource AppLaunchConfiguration --configsets app_init --region ap-northeast-1
runas=root

Debug cfn-init, cfn-signal

以下是我在 LaunchConfiguration 裡的 UserData,我會在每個步驟前後 touch xxxx.txt 作為程序的確認。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
AppLaunchConfiguration:
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html
Type: AWS::Auto Scaling::LaunchConfiguration

Properties:
UserData:
"Fn::Base64":
!Sub |
#!/bin/bash -xe
# --------------------------------------------------
touch /tmp/start_cfn-init_${AWS::StackName}.txt
# --------------------------------------------------
# run the configSets in AWS::CloudFormation::Init
/usr/local/bin/cfn-init \
--stack ${AWS::StackName} \
--resource AppLaunchConfiguration \
--configsets App_init \
--region ${AWS::Region}
EXIT_CODE=$?
echo $EXIT_CODE >> /tmp/cfn_exit-code.txt
# --------------------------------------------------
touch /tmp/done_cfn-init_${AWS::StackName}.txt
# Signal the status from cfn-init
touch /tmp/start_cfn-signal_${AWS::StackName}.txt
/usr/local/bin/cfn-signal \
--exit-code $EXIT_CODE \
--stack ${AWS::StackName} \
--resource AppAuto ScalingGroup \
--region ${AWS::Region}
touch /tmp/done_cfn-signal_${AWS::StackName}.txt

除了 上述方法,一定要查看 cfn 自身的 log:

  • /var/log/cfn-hup.log
  • /var/log/cfn-init.log
  • /var/log/cfn-init-cmd.log
  • /var/log/cfn-wire.log

確認 Helper Scripts (aws-cfn-bootstrap-latest) 安裝正確

是 EC2 Instance 起來時用來控制安裝程序的小程式。

Ubuntu and Amazon Linux AMI (CentOS) 的安裝方式不一樣,確認也不一樣。官方文件並沒有很清楚的描述他們的差異。

Amazon Linux AMI 預設就會安裝,如果要手動安裝如下:

1
yum install -y aws-cfn-bootstrap

但是 Ubuntu 就沒那麼簡單了,底下是 Ubuntu 14.04 的安裝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# see: https://gist.github.com/kixorz/10194688
cd /opt
mkdir aws-cfn-bootstrap-latest
apt-get update
apt-get -y install python-setuptools
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

# 要自行把 init 程序做 link, AWS AMI (CentOS) 似乎不用
# see: http://stackoverflow.com/questions/39760158/ubuntu-could-not-enable-service-cfn-hup
ln /usr/local/bin/cfn-hup /etc/init.d/
initctl reload-configuration
chmod 700 /etc/init.d/cfn-hup
chown root:root /etc/init.d/cfn-hup
update-rc.d cfn-hup defaults
update-rc.d cfn-hup enable

在 Stack Name 上加入時間

開發 Template 過程,會反覆建立 Stack,這時候要確認很多東西,會來來回回跑。我習慣會在 Stack Name 上加入底下資訊,協助開發:

1
2
3
4
5
6
7
8
9
10
ROLE_NAME=api
VERSION=$1
ENV=$2
TS=$(date +%m%d-%H%M)

aws cloudformation create-stack \
--stack-name ${ROLE_NAME}-${VERSION}-${ENV}-${TS} \
--template-body file://template-${ROLE_NAME}.yml \
--parameters ParameterKey=VERSION,ParameterValue=${VERSION} ParameterKey=ENV,ParameterValue=${ENV} ParameterKey=TS,ParameterValue=${TS} \
--output text

版本、環境、時間,這三個當作參數傳給 Stack,確保每次的開發與除錯,不需要相互干擾。如果開發出來的 Stack 無法同時存在多個,也就表示無法重複利用此 Template。


結論與結語

實務上,依照狀況,不見得全部的資源都要透過 CloudFormation 建置,通常已經服務化的資源,像是 CloudFront、ELB、ALB、CloudWatch 適合用 CloudFormation 建置,但是如果是自行安裝配置在 EC2 上的 Middleware 就不太適合,反而要利用其他工具,像是 EC2 Template、Hashicorp Packer、AWS Machine Image、Ansible 等方式來配置與管理。


延伸閱讀

系列文章

延伸閱讀 (站內)

參考資料

更新紀錄

  • 2017/03/31: 初版
  • 2018/12/22: 調整排版

Comments