CloudFormation 作為 AWS 基礎設施即程式碼 (IaC) 的核心服務,能以宣告式方式管理雲端資源。本文將探討如何利用 CloudFormation 的進階功能,例如 Fn::Cidr
函式、條件元素和刪除政策,建構更具彈性且可重複使用的範本。透過 Fn::Cidr
,我們可以根據 VPC 的 CIDR 範圍自動生成子網路的 CIDR 範圍,簡化網路設定流程並減少錯誤。條件元素則允許我們根據不同的環境(例如測試或生產環境)調整資源組態,提升範本的通用性。刪除政策則提供更精細的資源生命週期管理,確保關鍵資料在堆積疊刪除時得到妥善保護。此外,文章也將探討安全性考量、效能最佳化以及 CloudFormation 的未來發展趨勢,協助讀者掌握 IaC 最佳實務。
進階範本開發
在網路架構方面,我們的堆積疊將包含以下資源:
- 1個VPC
- 3個公有子網路
- 3個WebTier子網路
- 3個中介軟體子網路
- 3個資料函式庫子網路
- 1個網際網路閘道
- 1個NAT閘道
- 1個公有路由表
- 1個私有路由表
- 2個IAM角色(供管理員和開發人員使用)
這些資源將具有諸如名稱(Name)和環境(Env)等標籤。
在這種情況下,我們希望引數化資源的屬性,例如CIDR範圍和標籤。因此,我們將具備以下引數:
- VPC CIDR範圍
- 公有子網路1 CIDR範圍
- 公有子網路2 CIDR範圍
- 公有子網路3 CIDR範圍
- WebTier子網路1 CIDR範圍
- WebTier子網路2 CIDR範圍
- WebTier子網路3 CIDR範圍
- 中介軟體子網路1 CIDR範圍
- 中介軟體子網路2 CIDR範圍
- 中介軟體子網路3 CIDR範圍
- 資料函式庫子網路1 CIDR範圍
- 資料函式庫子網路2 CIDR範圍
- 資料函式庫子網路3 CIDR範圍
- 環境(Environment)
建立可重複使用的範本
所有這些引數都將具有字串(String)型別。讓我們來撰寫引數(Parameters)部分:
Parameters:
VpcCidr:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
PublicSubnetCidr1:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
PublicSubnetCidr2:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
PublicSubnetCidr3:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
# 依此類別推...
DatabaseSubnetCidr1:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
DatabaseSubnetCidr2:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
DatabaseSubnetCidr3:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
Environment:
Type: String
AllowedValues: ["prod", "test"]
內容解密:
此段落定義了範本的引數部分,用於接收使用者輸入的各種網路組態資訊。Type
欄位指定了引數的資料型別,而AllowedPattern
欄位則確保輸入的CIDR範圍符合特定的正規表示式格式。AllowedValues
欄位限制了Environment
引數的可能值。
在我們的資源中,我們將使用Fn::Ref
函式將引數值注入資源屬性。同時,我們也會使用另一個內建函式Fn::Sub
來連線一個良好的字串名稱給我們的VPC:
Resources:
Vpc:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsHostnames: True
EnableDnsSupport: True
InstanceTenancy: Default
Tags:
- Key: 'Name'
Value: !Sub '${Environment}-vpc'
- Key: 'Env'
Value: !Ref Environment
內容解密:
此部分定義了VPC資源的建立。!Ref
用於參照引數值或資源的屬性。!Sub
函式用於替換字串中的變數,從而動態生成VPC的名稱標籤。
對於其餘的資源,我們將採用類別似的模式。
重點注意事項
Fn::Ref
函式也可以用於在堆積疊中的一個資源中參照某些屬性。在這種情況下,我們向Fn::Ref
提供資源的邏輯名稱,而不是引數。
在以下範例中,我們使用Fn::Ref
來參照VPC ID,並用於建立子網路:
PublicSubnet1:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock: !Ref PublicSubnetCidr1
VpcId: !Ref Vpc
內容解密:
此段程式碼建立了一個公有子網路,並將其CIDR區塊和VPC ID分別設定為PublicSubnetCidr1
引數的值和先前建立的VPC的ID。
請注意,我們沒有在範本檔案中指定引數的預設值。在這種情況下,我們需要在create-stack
命令中提供它們,否則驗證將不會透過。
有兩種方法可以向CloudFormation提供引數:作為JSON檔案或作為位置引數。
對於具有大量引數的大型範本,建議使用JSON檔案:
[
{
"ParameterKey": "Environment",
"ParameterValue": "Testing"
},
{
"ParameterKey": "VpcCidr",
"ParameterValue": "10.0.0.0/16"
},
{
"ParameterKey": "PublicSubnetCidr1",
"ParameterValue": "10.0.1.0/24"
},
{
"ParameterKey": "PublicSubnetCidr2",
"ParameterValue": "10.0.2.0/24"
},
# 依此類別推...
]
在建立範本時,我們在引數中指定引數檔案:
$ aws cloudformation create-stack \
--stack-name core \
--template-body file://core.yaml \
--parameters file://testing.json
如果我們有預設值並希望進行一些更改,我們可以逐一指定引數作為位置引數:
$ aws cloudformation create-stack \
--stack-name core \
--template-body file://core.yaml \
--parameters \
ParameterKey="Environment",ParameterValue="Testing" \
ParameterKey="VpcCidr",ParameterValue="10.0.0.0/16"
這適用於引數較少的情況,但對於大量的引數集來說太過複雜。
重點注意事項
引數以列表形式提供,元素之間以空格分隔。請注意列表型別的引數,您將需要使用雙反斜線:
ParameterKey=List,ParameterValue=Element1\\,Element2
讓我們對引數進行一些更改。由於我們有多個CIDR範圍對應每個層級的子網路,讓我們使用列表引數而不是字串:
Parameters:
VpcCidr:
Type: String
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
PublicSubnetCidrs:
Type: List<String>
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
# 依此類別推...
MiddlewareSubnetCidrs:
Type: List<String>
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
DatabaseSubnetCidrs:
Type: List<String>
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'
Environment:
Type: String
AllowedValues: ["prod", "test"]
內容解密:
此變更將多個子網路的CIDR範圍合併成一個列表引數,使得管理更加方便。
由於我們使用的是列表,我們不能再使用Fn::Ref
(雖然技術上可以,但會傳遞整個列表)。相反,我們將使用Fn::Select
:
PublicSubnet1:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock: !Select [0, PublicSubnetCidrs]
VpcId: !Ref Vpc
PublicSubnet2:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock: !Select [1, PublicSubnetCidrs]
VpcId: !Ref Vpc
PublicSubnet3:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock: !Select [2, PublicSubnetCidrs]
VpcId: !Ref Vpc
內容解密:
Fn::Select
函式用於從列表中選擇特定的元素。在此例中,我們用它來選擇PublicSubnetCidrs
列表中的特定CIDR範圍,並將其分配給不同的子網路。
現在,我們需要稍微更改引數檔案:
{
"ParameterKey": "PublicSubnetCidrs",
"ParameterValue": [
"10.0.1.0/24",
"10.0.2.0/24",
"10.0.3.0/24"
]
}
內容解密:
此JSON範例展示瞭如何為列表引數PublicSubnetCidrs
提供多個CIDR範圍值。
這樣看起來好多了,對吧?
隨著雲端運算技術的不斷進步,範本開發的最佳實踐也在不斷演變。未來,我們可以期待看到更多關於範本模組化、自動化和安全性的創新。持續關注AWS CloudFormation和其他IaC工具的新功能和最佳實踐,將有助於保持您的基礎設施管理技能與時俱進。
進階範本開發
在建立可重複使用的 CloudFormation 範本時,我們經常需要處理網路設定的細節。特別是在設定多個子網路(Subnet)時,手動指定 CIDR 範圍可能既繁瑣又容易出錯。幸運的是,AWS CloudFormation 提供了內建函式 Fn::Cidr
,讓我們能夠更輕鬆地管理子網路的 CIDR 範圍。
使用 Fn::Cidr 自動生成 CIDR 範圍
Fn::Cidr
函式的主要功能是將一個較大的 CIDR 範圍分割成多個較小的 CIDR 範圍。這在設計網路架構時非常有用,特別是當你需要建立多個子網路,而這些子網路都來自同一個大的 IP 範圍。
假設我們的 VPC CIDR 範圍定義在引數檔案中,如下所示:
[
{
"ParameterKey": "VpcCidr",
"ParameterValue": "10.0.0.0/16"
}
]
我們需要將這個大的 CIDR 範圍(/16
)分割成多個較小的 /24
範圍。為此,我們可以使用 Fn::Cidr
函式,並提供以下引數:
ipBlock
: 我們的 VPC CIDR 範圍。count
: 需要生成的 CIDR 範圍數量。cidrBits
: 指定生成的 CIDR 範圍的遮罩大小。對於/24
範圍,我們需要指定8
。
程式碼範例:使用 Fn::Cidr 生成 CIDR 範圍
PublicSubnet1:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 9, 8]]
VpcId: !Ref Vpc
PublicSubnet2:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock: !Select [1, !Cidr [!Ref VpcCidr, 9, 8]]
VpcId: !Ref Vpc
PublicSubnet3:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock: !Select [2, !Cidr [!Ref VpcCidr, 9, 8]]
VpcId: !Ref Vpc
內容解密:
在上述程式碼中,我們使用了 Fn::Cidr
函式來生成多個 /24
CIDR 範圍。!Cidr [!Ref VpcCidr, 9, 8]
表示根據 VpcCidr
引數生成 9 個 /24
的 CIDR 範圍。然後,我們使用 !Select
函式從生成的列表中選擇特定的 CIDR 範圍,並將其分配給不同的子網路。
使用條件元素
在某些情況下,我們希望根據不同的環境(例如測試環境和生產環境)建立不同的資源組態。CloudFormation 的條件元素(Conditions)允許我們根據引數值來決定是否建立某個資源,或是為資源指定不同的屬性。
程式碼範例:使用條件元素
Parameters:
Env:
Type: String
Default: test
AllowedValues: ["test", "prod"]
ImageId:
Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
Conditions:
IsProd: !Equals [!Ref Env, "prod"]
Resources:
WebLt:
Type: 'AWS::EC2::LaunchTemplate'
Properties:
LaunchTemplateName: "web"
LaunchTemplateData:
ImageId: !Ref ImageId
InstanceType: !If [IsProd, "m5.large", "t3.micro"]
內容解密:
在這個範例中,我們定義了一個名為 Env
的引數,用於區分測試環境和生產環境。根據 Env
的值,IsProd
條件會被評估為 true
或 false
。然後,在 WebLt
資源中,我們使用 !If
函式根據 IsProd
條件的值來選擇 EC2 例項的型別。如果 Env
是 prod
,則使用 m5.large
;否則,使用 t3.micro
。
刪除政策
在管理 CloudFormation 堆積疊時,我們經常需要確保關鍵資源不會被意外刪除。刪除政策(Deletion Policies)提供了一種機制,讓我們能夠控制資源在堆積疊刪除時的行為。
程式碼範例:使用刪除政策
Resources:
VeryImportantDb:
Type: 'AWS::RDS::DBInstance'
DeletionPolicy: Snapshot
Properties:
# RDS 例項的屬性設定
內容解密:
在這個範例中,我們為 VeryImportantDb
資源指定了 DeletionPolicy: Snapshot
。這意味著當我們刪除包含這個資源的 CloudFormation 堆積疊時,CloudFormation 會先為 RDS 例項建立一個快照,然後再刪除該例項。這樣可以確保資料的安全。
隨著雲端運算技術的不斷進步,CloudFormation 也在不斷演進。未來,我們可以期待更多的功能和改進,以進一步簡化基礎設施的管理和佈署。作為基礎設施即程式碼(IaC)的重要工具,CloudFormation 將繼續在雲端運算領域發揮關鍵作用。
安全性考量
在使用 CloudFormation 時,安全性是一個非常重要的考量。我們需要確保範本的安全性,避免敏感資訊洩露。此外,合理使用刪除政策和條件元素,也可以提高資源的安全性。
效能最佳化
在設計 CloudFormation 範本時,效能最佳化是一個重要的方面。合理使用內建函式,如 Fn::Cidr
,可以提高範本的靈活性。同時,精簡範本結構,避免不必要的資源定義,也可以提高佈署效率。