在 AWS 雲端環境中,自動化組態管理對於維護系統一致性和可靠性至關重要。CloudFormation 的 cfn-init
工具提供了一個有效的方法,讓開發者能夠以程式化的方式定義和管理 EC2 例項的組態。透過 cfn-init
,我們可以自動安裝軟體套件、設定檔案、啟動服務,並確保所有組態步驟都按照預期執行。此外,cfn-signal
的整合讓 CloudFormation 能夠準確掌握資源的佈署狀態,避免因資源尚未完全初始化而導致的錯誤。這對於需要長時間初始化的應用程式,例如 Web 服務或資料函式庫,尤其重要。結合 cfn-init
和 cfn-signal
,可以建立更穩固、可重複且易於管理的雲端基礎架構。
使用 cfn-init 進行 EC2 例項的組態管理
在現代化的雲端基礎架構中,自動化組態管理是確保系統一致性和可靠性的關鍵。本文將探討如何利用 AWS CloudFormation 的 cfn-init
工具來自動化組態和管理 EC2 例項。我們將透過具體範例,展示如何佈署一個簡單的 Flask Web 應用程式,以及如何建立一個完整的 LNMP(Linux, NGINX, MySQL, PHP)堆積疊。
佈署 Flask Web 應用程式
首先,我們將建立一個簡單的 Flask Web 應用程式,並使用 cfn-init
自動佈署到 EC2 例項上。
步驟 1:建立 CloudFormation 範本
Resources:
MyEC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !Ref ImageId
InstanceType: t2.micro
KeyName: !Ref KeyName
UserData:
'Fn::Base64': !Sub |
#!/bin/bash -xe
/opt/aws/bin/cfn-init -v \
--stack ${AWS::StackName} \
--resource MyEC2Instance \
--configsets InstallAndRun \
--region ${AWS::Region}
Metadata:
'AWS::CloudFormation::Init':
configSets:
InstallAndRun:
- "InstallFlask"
- "ConfigureService"
InstallFlask:
packages:
yum:
python3: []
python3-pip: []
commands:
install_flask:
command: "pip3 install flask"
ConfigureService:
files:
/opt/helloworld.py:
content: !Sub |
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World, from AWS!"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
mode: '755'
owner: root
group: root
/etc/systemd/system/helloworld.service:
content: !Sub |
[Unit]
Description=HelloWorld service
After=network.target
[Service]
Type=simple
User=root
ExecStart=/opt/helloworld.py
Restart=on-abort
[Install]
WantedBy=multi-user.target
mode: '755'
owner: root
group: root
commands:
reload_systemd:
command: "systemctl daemon-reload"
services:
sysvinit:
helloworld:
enabled: 'true'
ensureRunning: 'true'
步驟 2:上傳應用程式原始碼到 S3
aws s3 cp hello-world-flask.py s3://hello-world-prep-sourcebucket-16l5b2vvpr5js
步驟 3:佈署 CloudFormation 堆積疊
aws cloudformation deploy \
--stack-name helloworld \
--template-file hello-world-app.yaml \
--capabilities CAPABILITY_IAM
#### 內容解密:
- CloudFormation 範本解析:範本定義了一個 EC2 例項,並使用
cfn-init
在例項啟動時執行組態。 cfn-init
組態集:定義了兩個組態步驟:InstallFlask
和ConfigureService
。第一步安裝必要的軟體包,第二步組態並啟動 Flask 應用程式服務。- 服務組態:使用 systemd 管理服務,確保 Flask 應用程式在例項啟動時自動執行。
建立 LNMP 堆積疊
接下來,我們將建立一個更複雜的 LNMP 堆積疊,展示如何使用 cfn-init
組態多個服務。
步驟 1:定義 EC2 例項和 cfn-init
組態
Resources:
Lnmp:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !Ref ImageId
InstanceType: t2.micro
KeyName: !Ref KeyName
UserData:
'Fn::Base64': !Sub |
#!/bin/bash -xe
/opt/aws/bin/cfn-init -v \
--stack ${AWS::StackName} \
--resource Lnmp \
--configsets Configure \
--region ${AWS::Region}
Metadata:
'AWS::CloudFormation::Init':
configSets:
Configure:
- "Mysql"
- "DbSetup"
- "Php"
- "Nginx"
# ... 其他組態省略
#### 內容解密:
cfn-init
組態集:定義了一個名為Configure
的組態集,包含四個組態步驟:MySQL 安裝、資料函式庫設定、PHP 組態和 NGINX 組態。- 命令執行順序:在
commands
部分,使用數字字首確保命令按特定順序執行,因為cfn-init
預設按字母順序執行命令。 - 服務管理:使用
services
部分確保必要的服務(如 MySQL 和 NGINX)在組態完成後啟動並執行。
LNMP 堆積疊架構圖
graph LR A[Client] -->|HTTP Request| B[NGINX] B -->|Forward Request| C[PHP-FPM] C -->|Query| D[MySQL] D -->|Return Data| C C -->|Return Response| B B -->|HTTP Response| A
圖表翻譯: 此圖示展示了 LNMP 堆積疊的架構。客戶端傳送 HTTP 請求到 NGINX,NGINX 將請求轉發給 PHP-FPM 處理。PHP-FPM 可能需要查詢 MySQL 資料函式庫,將結果傳回給客戶端。整個流程展示了各元件之間的互動關係。
#### 內容解密:
- 架構概述:LNMP 堆積疊由 NGINX、PHP-FPM 和 MySQL 組成,共同處理客戶端請求。
- 請求處理流程:客戶端請求首先到達 NGINX,然後轉發給 PHP-FPM。PHP-FPM 可能需要與 MySQL 互動以取得資料,最終將處理結果傳回給客戶端。
使用cfn-signal通知CloudFormation資源就緒狀態
在前面的章節中,我們已經學習瞭如何使用cfn-init
進行EC2例項的初始組態。現在,我們將進一步瞭解如何使用cfn-signal
通知CloudFormation有關資源的就緒狀態。
為什麼需要cfn-signal?
CloudFormation通常會在資源建立後立即報告資源就緒狀態。然而,這種方法對於根據EC2例項的服務可能不適用。因為CloudFormation只會檢查EC2例項是否處於執行狀態,而不會等待例項上的應用程式完全啟動。
問題示例
假設我們有一個使用AutoScaling群組的Web應用程式。在這種情況下,如果例項需要時間來安裝軟體包和啟動服務,AutoScaling可能會因為例項未透過健康檢查而終止它。這樣會導致一個惡性迴圈:新的例項啟動,然後被終止,迴圈重複。
解決方案:使用cfn-signal
為瞭解決這個問題,AWS提供了一個名為cfn-signal
的輔助指令碼。這個指令碼可以向CloudFormation傳送訊號,報告資源是否成功建立。
如何使用cfn-signal?
步驟1:新增CreationPolicy
首先,我們需要在EC2例項資源上新增CreationPolicy
。這個策略定義了CloudFormation等待訊號的數量和超時時間。
// lnmp-signal.yaml
Lnmp:
Type: AWS::EC2::Instance
CreationPolicy:
ResourceSignal:
Count: 1
Timeout: PT5M
Properties:
# ...
Metadata:
# ...
在這個例子中,Timeout
被設定為5分鐘(PT5M),這意味著CloudFormation將等待最多5分鐘來接收訊號。
步驟2:在UserData中使用cfn-signal
接下來,我們需要在UserData
中呼叫cfn-signal
指令碼,以傳送訊號給CloudFormation。
// lnmp-signal.yaml
Lnmp:
Type: AWS::EC2::Instance
CreationPolicy:
# ...
Properties:
ImageId: !Ref ImageId
InstanceType: t2.micro
KeyName: !Ref KeyName
UserData:
Fn::Base64:
Fn::Sub: |
#!/bin/bash -xe
/opt/aws/bin/cfn-init -v \
--stack ${AWS::StackName} \
--resource Lnmp \
--configsets Configure \
--region ${AWS::Region}
# 傳送訊號
/opt/aws/bin/cfn-signal -e $? \
--stack ${AWS::StackName} \
--resource Lnmp \
--region ${AWS::Region}
在這個指令碼中,cfn-signal
會根據cfn-init
的離開碼(exit code)傳送相應的訊號。如果cfn-init
成功執行(離開碼為0),cfn-signal
會傳送成功訊號;否則,它會傳送失敗訊號。
cfn-signal與AutoScaling群組的結合使用
cfn-signal
和CreationPolicy
也可以與AutoScaling群組結合使用,以實作滾動更新。
MyAsg:
Type: AWS::AutoScaling::AutoScalingGroup
CreationPolicy:
AutoScalingCreationPolicy:
MinSuccessfulInstancesPercent: 50
在這個例子中,AutoScaling群組將等待至少一半的例項傳送成功訊號後,才會報告群組建立成功。
重點回顧
- cfn-signal的作用:向CloudFormation傳送訊號,報告資源是否成功建立。
- CreationPolicy的組態:定義CloudFormation等待訊號的數量和超時時間。
- 在UserData中使用cfn-signal:呼叫
cfn-signal
指令碼,以傳送訊號給CloudFormation。 - 與AutoScaling群組結合使用:實作滾動更新和提高佈署的可靠性。
思考題
- 如果組態集有多個組態項,它們的執行順序是什麼?
- 是否可以有多個組態集?
cfn-init
是否需要IAM策略來存取資源後設資料?- 是否可以使用
cfn-init
建立目錄? - 什麼是
WaitCondition
?
進一步閱讀
內容解密:
本章節詳細介紹了cfn-signal
的使用方法和重要性。透過結合cfn-init
和cfn-signal
,我們可以實作更可靠的資源佈署和管理。同時,本章節也提供了與AutoScaling群組結合使用的示例,以實作滾動更新和提高佈署的可靠性。
圖表說明
graph LR F[F] A[啟動EC2例項] --> B[執行cfn-init] B --> C[組態應用程式] C --> D[傳送cfn-signal] D --> E[CloudFormation接收訊號] E --> F{訊號是否成功?} F -->|是| G[報告資源建立成功] F -->|否| H[報告資源建立失敗]
圖表翻譯:
此圖示展示了使用cfn-signal
通知CloudFormation資源就緒狀態的流程。首先,啟動EC2例項並執行cfn-init
進行初始組態。然後,傳送cfn-signal
給CloudFormation。CloudFormation接收訊號後,根據訊號的內容(成功或失敗)報告資源的建立狀態。
程式碼範例
Resources:
MyInstance:
Type: 'AWS::EC2::Instance'
CreationPolicy:
ResourceSignal:
Count: 1
Timeout: PT5M
Properties:
ImageId: !Ref ImageId
InstanceType: t2.micro
KeyName: !Ref KeyName
UserData:
Fn::Base64:
Fn::Sub: |
#!/bin/bash -xe
/opt/aws/bin/cfn-init -v \
--stack ${AWS::StackName} \
--resource MyInstance \
--configsets InstallAndConfigure \
--region ${AWS::Region}
/opt/aws/bin/cfn-signal -e $? \
--stack ${AWS::StackName} \
--resource MyInstance \
--region ${AWS::Region}
內容解密:
此程式碼範例展示瞭如何在CloudFormation範本中使用CreationPolicy
和cfn-signal
。首先,定義了一個EC2例項資源,並設定了CreationPolicy
以等待訊號。然後,在UserData
中使用cfn-init
進行初始組態,並使用cfn-signal
傳送訊號給CloudFormation。這個範例確保了CloudFormation在資源完全就緒後才會報告資源建立成功。