Cloudformation là gì
Nội dung Show Trong bài thực hành Virtual Private Cloud, chúng ta sử dụng AWS CLI để cài đặt EC2 Instance và PostgreSQL Server trong Subnets của một VPC theo các bước sau:
Cách làm này có một số điểm hạn chế:
Để khắc phục điều này, AWS cung cấp dịch vụ CloudFormation cho phép chúng ta mô hình hoá và triển khai (provisioning) các tài nguyên AWS theo hướng tiếp cận Declarative. Với cách tiếp cận này, người sử dụng chỉ cần khai báo tài nguyên cùng các thuộc tính yêu cầu, cũng như mối quan hệ giữa các tài nguyên trong một file Template dưới định dạng dạng YAML hoặc JSON. Dựa trên thông tin khai báo, dịch vụ CloudFormation sẽ thực hiện việc gọi các AWS API để cấp phát và cấu hình tài nguyên theo mong muốn. Bên cạnh đó, tập hợp các tài nguyên này được quản lý bởi cùng một đối tượng Stack, cho phép người sử dụng dễ dàng nâng cấp, bổ sung những cấu hình mong muốn cũng như quản lý được mọi thay đổi trong quá trình cập nhật hay triển khai. Để thực hành CloudFormation, chúng ta sẽ bắt đầu với một cấu trúc template file đơn giản, từ đó bổ sung các thành phần cần thiết để xây dựng EC2 và DB Instances trong một VPC tương tự kết quả như kết quả thực hành từ bài viết Virtual Private Cloud. Cài đặt VPC
AWSTemplateFormatVersion: "2010-09-09" Description: Deploys a VPC with Subnets in differents Availability Zones. It deploys an EC2 Instance on Public Subnet and RDS PostgreSQL Instance on Private Subnets Parameters: VpcCIDR: Description: IP range (CIDR notation) for this VPC Type: String Default: "10.0.0.0/16" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: VPC Sample Outputs: StackVPC: Description: The ID of the VPC Value: !Ref VPC
Trong cùng folder chứa rds.yaml, thực hiện lệnh tạo Stack - rds-stack: aws cloudformation create-stack --stack-name rds-stack --template-body file://rds.yaml Output: { "StackId": "arn:aws:cloudformation:ap-southeast-2:729365137003:stack/rds-stack/4156e520-101a-11eb-ab18-0218c804214a" }
aws cloudformation describe-stacks --stack-name rds-stack Output { "Stacks": [ { "StackId": "arn:aws:cloudformation:ap-southeast-2:729365137003:stack/rds-stack/4156e520-101a-11eb-ab18-0218c804214a", "StackName": "rds-stack", "Description": "Deploys a VPC with Subnets in differents Availability Zones. It deploys an EC2 Instance on Public Subnet and RDS PostgreSQL Instance on Private Subnets", "Parameters": [ { "ParameterKey": "VpcCIDR", "ParameterValue": "10.0.0.0/16" } ], "CreationTime": "2020-10-17T01:44:11.681000+00:00", "RollbackConfiguration": {}, "StackStatus": "CREATE_COMPLETE", "DisableRollback": false, "NotificationARNs": [], "Outputs": [ { "OutputKey": "StackVPC", "OutputValue": "vpc-0dcabb2e4dc217670", "Description": "The ID of the VPC" } ], "Tags": [], "EnableTerminationProtection": false, "DriftInformation": { "StackDriftStatus": "NOT_CHECKED" } } ] }
Dựa trên VPC đã tạo ra, trong phần này chúng ta sẽ bổ sung khai báo Subnets trong VPC. Các bước thực hiện bao gồm: Bước 1: Cập nhật nội dung rds.yaml để bổ sung Subnets: AWSTemplateFormatVersion: "2010-09-09" Description: Deploys a VPC with Subnets in differents Availability Zones. It deploys an EC2 Instance on Public Subnet and RDS PostgreSQL Instance on Private Subnets Parameters: VpcCIDR: Description: IP range (CIDR notation) for this VPC Type: String Default: "10.0.0.0/16" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetACidr: Description: Public Subnet of VPC Type: String Default: "10.0.0.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetBCidr: Description: Private Subnet of VPC Type: String Default: "10.0.1.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetCCidr: Description: Private Subnet of VPC Type: String Default: "10.0.2.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: VPC Sample SubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref SubnetACidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet A (AZ1) SubnetB: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref SubnetBCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet B (AZ2) SubnetC: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [2, !GetAZs ""] CidrBlock: !Ref SubnetCCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet C (AZ3) Outputs: StackVPC: Description: The ID of the VPC Value: !Ref VPC
Bước 2: Thực thi việc cập nhật thay đổi Bằng cách sử dụng AWS CLI, CloudFormation cung cấp hai cách thức để thực thi quá trình thay đổi CloudFormation Stack:
Chú ý Việc sử dụng Change Set giúp người dùng có thể xem xét trước nội dung thay đổi cũng như ảnh hưởng đến resources hiện tại khi thực thi những thay đổi này. Ví dụ: khi Stack đang quản lý một database, việc thay đổi giá trị một thuộc tính có khả năng dẫn đến việc xoá bỏ và tạo database mới, mất đi những dữ liệu hiện có. Bằng cách sử dụng change set, người dùng có thể đánh giá ảnh hưởng trước khi quyết định việc thực thi thay đổi. Thực hiện tạo Change Set dựa trên cập nhật từ file rds.yaml: aws cloudformation create-change-set \ --stack-name rds-stack \ --change-set-name rds-subnets-change-set \ --template-body file://rds.yml Output { "Id": "arn:aws:cloudformation:ap-southeast-2:729365137003:changeSet/rds-subnets-change-set/80984f68-adca-4f0d-b70f-2a45f27d8ecc", "StackId": "arn:aws:cloudformation:ap-southeast-2:729365137003:stack/rds-stack/4156e520-101a-11eb-ab18-0218c804214a" }
aws cloudformation execute-change-set --change-set-name arn:aws:cloudformation:ap-southeast-2:729365137003:changeSet/rds-subnets-change-set/80984f68-adca-4f0d-b70f-2a45f27d8ecc
Trong phần này, chúng ta tiếp tục bổ sung các thành phần Internet Gateway và Route Table cho phép các thành phần trong Subnet A có khả năng giao tiếp môi trường Internet (Public Subnet).
AWSTemplateFormatVersion: "2010-09-09" Description: Deploys a VPC with Subnets in differents Availability Zones. It deploys an EC2 Instance on Public Subnet and RDS PostgreSQL Instance on Private Subnets Parameters: VpcCIDR: Description: IP range (CIDR notation) for this VPC Type: String Default: "10.0.0.0/16" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetACidr: Description: Public Subnet of VPC Type: String Default: "10.0.0.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetBCidr: Description: Private Subnet of VPC Type: String Default: "10.0.1.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetCCidr: Description: Private Subnet of VPC Type: String Default: "10.0.2.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: VPC Sample SubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref SubnetACidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet A (AZ1) SubnetB: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref SubnetBCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet B (AZ2) SubnetC: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [2, !GetAZs ""] CidrBlock: !Ref SubnetCCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet C (AZ3) InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: Internet Gateway InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Public Route Table DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetARouteTableAssoc: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref SubnetA Outputs: StackVPC: Description: The ID of the VPC Value: !Ref VPC
aws cloudformation create-change-set \ --stack-name rds-stack \ --change-set-name public-subnets-change-set \ --template-body file://rds.yml Output { "Id": "arn:aws:cloudformation:ap-southeast-2:729365137003:changeSet/public-subnets-change-set/401a95e9-4dbd-4049-8609-1a654f27121c", "StackId": "arn:aws:cloudformation:ap-southeast-2:729365137003:stack/rds-stack/4156e520-101a-11eb-ab18-0218c804214a" } aws cloudformation execute-change-set --change-set-name arn:aws:cloudformation:ap-southeast-2:729365137003:changeSet/public-subnets-change-set/401a95e9-4dbd-4049-8609-1a654f27121c Để bổ sung EC2 Instance trong Public Subnet của VPC, thực hiện thay đổi sau trên rds.yaml: AWSTemplateFormatVersion: "2010-09-09" Description: Deploys a VPC with Subnets in differents Availability Zones. It deploys an EC2 Instance on Public Subnet and RDS PostgreSQL Instance on Private Subnets Parameters: VpcCIDR: Description: IP range (CIDR notation) for this VPC Type: String Default: "10.0.0.0/16" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetACidr: Description: Public Subnet of VPC Type: String Default: "10.0.0.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetBCidr: Description: Private Subnet of VPC Type: String Default: "10.0.1.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetCCidr: Description: Private Subnet of VPC Type: String Default: "10.0.2.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" InstanceType: Description : WebServer EC2 instance type Type : String Default : t2.micro AllowedValues: - t2.micro - m1.small - m1.large Description: Enter t2.micro, m1.small, or m1.large. Default is t2.micro. Mappings: AWSRegionArch2AMI: us-east-1: HVM64: ami-0e7067c52e5fac7aa ap-southeast-2: HVM64: ami-0b007620b3c6fd7ff Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: VPC Sample SubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref SubnetACidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet A (AZ1) SubnetB: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref SubnetBCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet B (AZ2) SubnetC: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [2, !GetAZs ""] CidrBlock: !Ref SubnetCCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet C (AZ3) InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: Internet Gateway InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Public Route Table DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetARouteTableAssoc: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref SubnetA EC2Instance: Type: AWS::EC2::Instance Properties: ImageId: !FindInMap [AWSRegionArch2AMI, !Ref "AWS::Region", HVM64] InstanceType: !Ref InstanceType SecurityGroupIds: - !Ref Ec2SecurityGroup SubnetId: !Ref SubnetA KeyName: FriendReminders UserData: Fn::Base64: !Sub | #!/bin/bash -xe sudo yum install -y amazon-linux-extras sudo amazon-linux-extras install postgresql11 Ec2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VPC GroupDescription: Enable SSH access via port 22 SecurityGroupIngress: - CidrIp: 0.0.0.0/0 FromPort: 22 IpProtocol: tcp ToPort: 22 Outputs: StackVPC: Description: The ID of the VPC Value: !Ref VPC
Hướng dẫn Tập hợp các Name - Value trong Mapping thường được kết hợp với một Look-up function FindInMap trả về giá trị Value dựa trên tham số truyền vào. Trong ví dụ của EC2 Instance, tương ứng với mỗi AWS Region, function FindInMap sẽ trả về giá trị AMI tương ứng với Amazon Linux 2 AMI ID được tạo ra bởi Amazon trên Region đó.
Hiển thị danh sách AMI ID của Amazon Linux theo region ap-southeast-2 aws ssm get-parameters-by-path --path /aws/service/ami-amazon-linux-latest --region ap-southeast-2 Trong ví dụ trên, chúng ta chỉ sử dụng tập hợp các giá trị AMI ID tương ứng với amzn-ami-hvm-x86_64-ebs. Đây là hệ điều hành Amazon Linux 2 sử dụng cơ chế ảo hoá phần cứng - Hardware Virtual Machine (HVM). So với cơ chế ảo hoá song song - Paravirtual (PV), HVM đem lại hiệu năng cao hơn do khả năng tận dụng những khả năng mở rộng của phần cứng (CPU, Network, Storage).
aws cloudformation create-change-set \ --stack-name rds-stack \ --change-set-name public-subnets-change-set \ --template-body file://rds.yml Output { "Id": "arn:aws:cloudformation:ap-southeast-2:729365137003:changeSet/ec2-change-set/cc5fd8d3-06be-4520-877a-4134e1fdc287", "StackId": "arn:aws:cloudformation:ap-southeast-2:729365137003:stack/rds-stack/4156e520-101a-11eb-ab18-0218c804214a" } aws cloudformation execute-change-set --change-set-name arn:aws:cloudformation:ap-southeast-2:729365137003:changeSet/ec2-change-set/cc5fd8d3-06be-4520-877a-4134e1fdc287
ssh -i "FriendReminders.pem"
Cài đặt PostgreSQL Instance trong Private Subnets
AWSTemplateFormatVersion: "2010-09-09" Description: Deploys a VPC with Subnets in differents Availability Zones. It deploys an EC2 Instance on Public Subnet and RDS PostgreSQL Instance on Private Subnets Parameters: VpcCIDR: Description: IP range (CIDR notation) for this VPC Type: String Default: "10.0.0.0/16" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetACidr: Description: Public Subnet of VPC Type: String Default: "10.0.0.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetBCidr: Description: Private Subnet of VPC Type: String Default: "10.0.1.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" SubnetCCidr: Description: Private Subnet of VPC Type: String Default: "10.0.2.0/24" AllowedPattern: "((\\d{1,3})\\.){3}\\d{1,3}/\\d{1,2}" InstanceType: Description : WebServer EC2 instance type Type : String Default : t2.micro AllowedValues: - t2.micro - m1.small - m1.large DBInstanceIdentifier: Type: String Default: "dbpostgresql" DBEngine: Type: String Default: "postgres" DBEngineVersion: Type: String Default: "12.3" DBSourceRegion: Type: String Default: "ap-southeast-2" DBInstanceClass: Type: String Default: "db.t2.micro" DBStorageType: Type: String Default: "gp2" DBAllocatedStorage: Type: Number Default: 20 DBName: Type: String Default: "postgres" DBUser: Type: String Default: "postgres" DBPassword: Type: String Default: "password" NoEcho: True Mappings: AWSRegionArch2AMI: us-east-1: HVM64: ami-0e7067c52e5fac7aa ap-southeast-2: HVM64: ami-0b007620b3c6fd7ff Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: VPC Sample SubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref SubnetACidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet A (AZ1) SubnetB: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref SubnetBCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet B (AZ2) SubnetC: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [2, !GetAZs ""] CidrBlock: !Ref SubnetCCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: Subnet C (AZ3) DBSubnetGroup: Properties: DBSubnetGroupDescription: DBSubnetsGroup for RDS instances SubnetIds: - Ref: SubnetB - Ref: SubnetC Type: AWS::RDS::DBSubnetGroup InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: Internet Gateway InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Public Route Table DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetARouteTableAssoc: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref SubnetA Ec2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VPC GroupDescription: Enable SSH access via port 22 SecurityGroupIngress: - CidrIp: 0.0.0.0/0 FromPort: 22 IpProtocol: tcp ToPort: 22 EC2Instance: Type: AWS::EC2::Instance Properties: ImageId: !FindInMap [AWSRegionArch2AMI, !Ref "AWS::Region", HVM64] InstanceType: !Ref InstanceType SecurityGroupIds: - !Ref Ec2SecurityGroup SubnetId: !Ref SubnetA KeyName: FriendReminders UserData: Fn::Base64: !Sub | #!/bin/bash -xe sudo yum install -y amazon-linux-extras sudo amazon-linux-extras install postgresql11 VpcDefaultSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !GetAtt VPC.DefaultSecurityGroup SourceSecurityGroupId: !GetAtt Ec2SecurityGroup.GroupId IpProtocol: tcp FromPort: 5432 ToPort: 5432 DBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: Ref: DBInstanceIdentifier DBName: Ref: DBName AllocatedStorage: Ref: DBAllocatedStorage DBInstanceClass: Ref: DBInstanceClass StorageType: Ref: DBStorageType Engine: Ref: DBEngine EngineVersion: Ref: DBEngineVersion MasterUsername: Ref: DBUser MasterUserPassword: Ref: DBPassword PubliclyAccessible: False Tags: - Key: Project Value: "Demo of RDS PostgreSQL" VPCSecurityGroups: - !GetAtt VPC.DefaultSecurityGroup DBSubnetGroupName: Ref: DBSubnetGroup Outputs: StackVPC: Description: The ID of the VPC Value: !Ref VPC
Kết nối DB PostgreSQL từ EC2 Instance
ssh -i "FriendReminders.pem"
psql -h dbpostgresql2.ctcnoszp8xta.ap-southeast-2.rds.amazonaws.com -U postgres Kết luận CloudFormation giúp việc cấu hình và triển khai AWS Resource hiệu quả hơn so với AWS CLI hoặc AWS Console. Bằng việc sử dụng Parameters và Output, CloudFormation Templates có tính tái sử dụng cao hơn, đồng thời người sử dụng có thể kết hợp nhiều templates khi muốn triển khai các cơ sở hạ tầng phức tạp. Tài liệu tham khảo
Copyright © 2019-2022 Tuan Anh Le. |