iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
Cloud Native

AWS AI交易室實戰系列 第 4

Day 4 - 基礎設施虛擬化 - CloudFormation

  • 分享至 

  • xImage
  •  

~ 運籌帷幄之中,決勝於千里之外 ~
Infrastructure as Code

相關程式碼:https://github.com/slindevel/modern-aws-marathon

虛擬化讓我們能在文件腳本中定義資源,即基礎設施及代碼(Infrastructure as Code,IaC)
CloudFormation 能幫助您模型化與設定 AWS 資源的服務。我們建立一個描述所有所需之 AWS 資源的範本 (如 Amazon EC2 執行個體或 Amazon RDS 資料庫執行個體),而 CloudFormation 負責為您佈建與設定這些資源。

這個服務中有兩大重要名詞:

  1. template:是一個格式為json或是yaml的檔案,定義了AWS資源的藍圖
    json:https://zh.wikipedia.org/zh-tw/JSON
    yaml:https://zh.wikipedia.org/zh-tw/YAML
  2. stack:一個template定義的一組AWS資源組統稱為一個stack

我們先來看一段官方的 workshop 裡的定義:
An AWS CloudFormation template is a declaration of the AWS resources that make up a stack.

template 他是一種資源的**「宣告」,雖然說是用代碼寫資源配置,感覺上是比較偏向「靜態」定義資源**。
接著我們來解析一下 template 的文件,yaml & json 格式最大的差別在於yaml可以加上註釋,所以之後的說明我們都以 yaml 格式為主,比較好解說,另外 yaml 的文件看的時候要注意 「縮排」 & 「階層」,json ↔ yaml 是可以互轉的喔!

我們先從 yaml 文件的 Top-Level objects 開始:

AWSTemplateFormatVersion: 'version date' (optional) # version of the CloudFormation template. Only accepted value is '2010-09-09'

Description: 'String' (optional) # a text description of the Cloudformation template

Metadata: 'template metadata' (optional) # objects that provide additional information about the template

Parameters: 'set of parameters' (optional) # a set of inputs used to customize the template

Rules: 'set of rules' (optional) # a set of rules to validate the parameters provided at deployment/update

Mappings: 'set of mappings' (optional) # a mapping of keys and associated values

Conditions: 'set of conditions' (optional) # conditions that control whether certain resources are created

Transform: 'set of transforms' (optional) # for serverless applications

Resources: 'set of resources' (required) # a components of your infrastructure

Hooks: 'set of hooks' (optional) # Used for ECS Blue/Green Deployments

Outputs: 'set of outputs' (optional) # values that are returned whenever you view your stack's properties

讓我們一個個來看看:

  • AWSTemplateFormatVersion - 讓大家知道這是一個 cloudformation template
  • Description - 可以加入一些描述
AWSTemplateFormatVersion: '2010-09-09'
Description: A simple queue for the demo purpose
  • Parameters:我們可以藉由參數(Parameters)從外部輸入到template中
  • Resources:
# Day4/cfn-s3-demo.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Create S3 Bucket named 'slin-cfn-s3-demo'

Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: slin-cfn-s3-demo
      VersioningConfiguration:
        Status: Enabled
  • 我們來執行看看,註:AWS CLI指令裡面,"file://xxx”代表”當前”路徑下的 xxx 文字檔,如果是 fileb,則是指二進位(binary)檔案
# cloudformation stack name: cf-s3-demo
$ aws cloudformation create-stack \
		--stack-name cf-s3-demo \
		--template-body file://Day4/cf-s3-demo.yaml \
		--capabilities CAPABILITY_IAM
$ aws cloudformation delete-stack --stack-name cf-s3-demo.   #記得清除資源
  • 接著我們試著加入參數,注意 Default 的部分被我們mark掉了,接著我們再執行它
# Day4/cf-s3-parameters-demo.yaml
# aws cloudformation create-stack \
#	  --stack-name cf-s3-demo \
#		--template-body file://Day4/cf-s3-parameters-demo.yaml \
#		--capabilities CAPABILITY_IAM

AWSTemplateFormatVersion: 2010-09-09
Description: Create S3 Bucket named 'slin-cf-s3-demo'

Parameters:
  BucketName:
    # Default: slin-cf-s3-demo
    Type: String
    Description: 'A bucket name to set.'

Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !Ref BucketName
      VersioningConfiguration:
        Status: Enabled

# output: 
# An error occurred (ValidationError) when calling the CreateStack operation: 
# Parameters: [BucketName] must have values
  • 然後我們試著在CLI中帶入參數
$ aws cloudformation create-stack \
	  --stack-name cf-s3-demo \ 
		--template-body file://Day4/cf-s3-parameters-demo.yaml \
		--capabilities CAPABILITY_IAM \
		--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo
$ aws s3 ls    #檢查s3 bucket slin-cf-s3-demo 是否建立
$ aws cloudformation delete-stack --stack-name cf-s3-demo.   #記得清除資源
  • Outputs:可以定義template的輸出,這些輸出可以被其他的AWS資源所使用
# Day4/cf-s3-outputs-demo.yaml
...
Outputs:   #add to the tail
  MyStacksRegion:
    Value: !Ref 'AWS::Region'
  • 這次我們執行此template,然後使用 describe-stack指令查看 stack 資訊,
    最後加上”--query "Stacks[].Outputs",一樣最後記得清除這個 stack,注意建立stack成功後才能查得到值喔
$ aws cloudformation create-stack \
	  --stack-name cf-s3-demo \ 
		--template-body file://Day4/cf-s3-parameters-demo.yaml \
		--capabilities CAPABILITY_IAM \
		--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo
$ aws cloudformation describe-stacks --stack-name cf-s3-demo --query "Stacks[].Outputs"
[
    [
        {
            "OutputKey": "BucketARN",
            "OutputValue": "arn:aws:s3:::slin-cf-s3-demo",
            "Description": "The ARN of the bucket."
        },
        {
            "OutputKey": "MyStacksRegion",
            "OutputValue": "ap-northeast-1"
        }
    ]
]
$ aws cloudformation delete-stack --stack-name cf-s3-demo   #記得清除資源
  • Mappings:與一般我們熟知map不太相同,他是個三層式架構,注意SecondLevelKeyXX重用了
Mappings:
	Mapping01:
		TopLevelKey01:
			SecondLevelKey01: Value01
			SecondLevelKey02: Value02
		TopLevelKey02:
			SecondLevelKey01: Value03
			SecondLevelKey02: Value04
...
  • Mappings 主要目的是以簡馭繁,常用來使用它切換不同區域的”識別碼“,比如說EC2 ImageId…等等,我們看以下例子,另外我們在這個例子中加入 parameter 的 AllowedValues:
# Day4/cf-s3-mappings-demo.yaml
Parameters:
...
	Environment:
	    Type: String
	    AllowedValues:
	      - Dev
	      - Test
	      - Prod
	    Description: 'Select an environment.'

Mappings:
  EnvironmentToBucketSuffix:
    Dev:
      Suffix: 'this-is-dev'
    Test:
      Suffix: 'use-only-for-testing'
    Prod:
      Suffix: 'be-careful-it-is-production'
...
  • 然後我們執行看看
$ aws cloudformation create-stack \
          --stack-name cf-s3-demo \
          --template-body file://Day4/cf-s3-mappings-demo.yaml \
          --capabilities CAPABILITY_IAM \
          --parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
                       ParameterKey=Environment,ParameterValue=foobar
An error occurred (ValidationError) when calling the CreateStack operation: Parameter 'Environment' must be one of AllowedValues
$ aws cloudformation create-stack \
          --stack-name cf-s3-demo \
                --template-body file://Day4/cf-s3-mappings-demo.yaml \
                --capabilities CAPABILITY_IAM \
                --parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
                             ParameterKey=Environment,ParameterValue=Dev
$ aws s3 ls
...
2023-08-13 00:07:33 slin-cf-s3-demo-this-is-dev
...
  • Conditions:可以定義在哪些情況下建立或設定實體。
# Day4/cf-s3-conditions-demo.yaml
...
Conditions:
  isProduction: !Equals [ !Ref Environment, Prod]

Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !If [ isProduction, slin-cf-s3-prod, slin-cf-s3-demo ]
      VersioningConfiguration:
        Status: Enabled
...
  • 接著執行看看
$ aws cloudformation create-stack \
          --stack-name cf-s3-demo \
          --template-body file://Day4/cf-s3-conditions-demo.yaml \
          --capabilities CAPABILITY_IAM \
          --parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
                       ParameterKey=Environment,ParameterValue=Prod
$ aws s3 ls
...
2023-08-13 00:29:16 slin-cf-s3-prod
...

$ aws cloudformation delete-stack --stack-name cf-s3-demo    #delete stack again

$ aws cloudformation create-stack \
          --stack-name cf-s3-demo \
          --template-body file://Day4/cf-s3-conditions-demo.yaml \
          --capabilities CAPABILITY_IAM \
          --parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
                       ParameterKey=Environment,ParameterValue=Dev
$ aws s3 ls
...
2023-08-13 00:38:26 slin-cf-s3-demo
...
  • Cloudformation 一個很大的優勢在因為是定義檔有 cloudformation designer 可以用,不過因為在執行偵錯方面比較不容易學習語法,以最傳統方式 try/result/error 方式學習可能是比較容易上手的方式
    Cloudformation Designer
    cloudformation designer

CloudFormation **內部函數(**Intrinsic function)

AWS CloudFormation 提供多個內建函數,可協助您管理您的堆疊。在範本中使用內部函數,將值指派給要到執行時間才能使用的屬性。 ~ by AWS ~

我們直接從一個簡單的範例來看看這些內部函數如何使用,這個範例會建立一個 EC2 Instance,使用到了兩個內置函數:

  • !Ref AmiId 參考到了 Parameters 中的外部輸入 AmiID
  • !Ref InstanceType 參考到了 Parameters 中的 InstanceType,因為沒有輸入,所以就帶入預設值 t2.micro
  • !Join 組合了 (!Ref InstanceType) & webserver 以 ‘-’ 作為組合字符

最後會在 EC2 看到 name:t2.micro-webserver 的 Instance

# Day4/cf-intrinsic-functions.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: AWS CloudFormation Intrinsic functions Sample

Parameters:
  InstanceType:
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - t2.small
    Description: 'Enter t2.micro or t2.small. Default is t2.micro.'
  AmiID:
    Type: AWS::EC2::Image::Id
    Description: 'The ID of the AMI.'

  # Add AmiId parameter here

Resources:
  WebServerInstance:
    Type: AWS::EC2::Instance
    Properties:
      # Use !Ref function in ImageId property
      ImageId: !Ref AmiID
      InstanceType: !Ref InstanceType
      Tags:
        - Key: Name
          Value: !Join [ '-', [ !Ref InstanceType, webserver ] ]

執行看看,其中 AmiID 需要用指令查詢,這個 AmiID是會變動的唷
ParameterValue 要帶入查詢到的 AmiID
AmiID 指的是 Amazon Machine Image,AWS 虛擬機器映像檔

$ aws cloudformation create-stack \
--stack-name cf-day4-intrinsic-functions 
--template-body file://Day4/cf-intrinsic-functions.yaml 
--parameters ParameterKey="AmiID",ParameterValue=<AmiId>

{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:<AccountId>:stack/cf-day4-intrinsic-functions/d5fa02b0-4e61-11ee-91ec-067eb25769dd"
}

# query statck status
$ aws cloudformation describe-stacks --stack-name cf-day4-intrinsic-functions

# clean up resource
$ aws cloudformation delete-stack --stack-name cf-day4-intrinsic-functions

如何查詢 AMI ID ?

$ aws ec2 describe-images --owners self amazon
{
    "Images": [
        {
            "Architecture": "x86_64",
            "CreationDate": "2022-11-14T23:19:27.000Z",
            "ImageId": "ami-07b14acc0c4d11fcc",
            "ImageLocation": "amazon/amzn2-ami-minimal-hvm-2.0.20221103.3-x86_64-ebs",
            "ImageType": "machine",
            "Public": true,
            "OwnerId": "137112412989",
            "PlatformDetails": "Linux/UNIX",
            "UsageOperation": "RunInstances",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/xvda",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-016aca1439d9dc407",
:

到這裡為止,是否對 cloudformation 上手了呢,AWS 官方有提供一個 github 裡面有各式各樣的可以參考的 template ,網址是:https://github.com/awslabs/aws-cloudformation-templates.git

筆者認為現在比較流行的 IaC 是使用 terraform 或是 AWS CDK,CDK 不用說 DevOps 專門

CloudFormation 與 Terreform 各有優缺點,兩者通常會交互使用,尤其是 Terreform 可以跨雲部署道路是更寬廣了

參考資料:
https://blog.awsfundamentals.com/infrastructure-as-code-on-aws-an-introduction
https://blog.awsfundamentals.com/infrastructure-as-code-on-aws-an-introduction
https://docs.aws.amazon.com/zh_tw/AWSCloudFormation/latest/UserGuide/Welcome.html
https://catalog.workshops.aws/cfn101/en-US/basics/templates/template-anatomy
https://keshavbist.com.np/anatomy-of-aws-cloudformation-templates
https://rickhw.github.io/2017/03/31/AWS/Study-Notes-CloudFormation-Template-Anatomy/
https://godleon.github.io/blog/AWS/AWS-SOA-CloudFormation/


上一篇
Day 3 - AWS Region/AZ & IAM & S3 概念介紹
下一篇
Day 5 - 建立 VPC
系列文
AWS AI交易室實戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言