Link Search Menu Expand Document

AWS CloudFormation

Nội dung

  1. Cài đặt VPC
  2. Bổ sung VPC Subnets trong Stack
  3. Cấu hình Public Subnet trong VPC
  4. Cài đặt EC2 Instance trong Public Subnet
  5. Cài đặt PostgreSQL Instance trong Private Subnets
  6. Kết nối DB PostgreSQL từ EC2 Instance

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:

  • Khai báo VPC và Subnets
  • Tạo Internet Gateway và liên kết với VPC
  • Tạo và cấu hình Route Table, Public Subnet
  • Cài đặt EC2 Instance trong Public Subnet
  • Cài đặt DB Instance trong Private Subnet
  • Kết nối DB Instance từ EC2 Instance

Cách làm này có một số điểm hạn chế:

  • Câu lệnh CLI phức tạp, không có tính tái sử dụng
  • Sử dụng nhiều các giá trị tham số, dễ gặp sai sót
  • Không cung cấp cơ chế quản lý thay đổi, rollback

Để 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.

AWS Resource Provision Engines AWS Resource Provision Engines

Để 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

  • Tạo template file 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}"
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
  • Theo cấu trúc của một file CloudFormation Template, nội dung rds.yaml bao gồm các phần:
    • AWSTemplateFormatVersion: khai báo định dạng Template
    • Description: mô tả mục đích sử dụng của Template
    • Parameters: tham số khi tạo Stack với giá trị mặc định
      • VpcCIDR - CIDR của VPC
    • Resources: tài nguyên cần tạo ra trong Stack, bao gồm:
      • VPC với giá trị thuộc tính CIdrBlock tham chiếu bởi Ref function
    • Outputs: kết quả hiển thị khi Stack hoàn thành
      • Trả về VPC ID tạo ra qua build-in function Ref
  • Triển khai CloudFormation Stack

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"
}
  • Sử dụng câu lệnh describe-stack kiểm tra kết quả từ Stack:
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"
            }
        }
    ]
}
  • Sử dụng AWS Console, CloudFormation -> Stack để hiển thị kết quả Stacks:

CloudFormation Stack Overview CloudFormation Stack Overview

  • Click tab Outputs để kiểm tra kết quả trả về khi việc tạo Stack hoàn thành:

CloudFormation Stack Output with VPC ID CloudFormation Stack Output with VPC ID


Bổ sung VPC Subnets trong Stack

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
  • Thay đổi này bao gồm các bổ sung:
    • Parameters: khai báo CIRD cho Subnets A, B, C cùng giá trị CIDR mặc định
    • Resources: yêu cầu tạo các Subnets bên trong VPC
      • Sử dụng Ref function để tham chiếu đến VPC và giá trị CIDR
      • Kết hợp Select & GetAZs để cài đặt Subnet trong những AZs khác nhau

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:

  • Áp dụng trực tiếp lệnh ` aws cloudformation update-stack`
  • Tạo và thực thi Change Set

Process of Update by Change Set Process of Update by Change Set

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"
}

Stack Change Set in AWS Console Stack Change Set in AWS Console

  • Dựa trên Change Set Id, thực thi thay đổi với lệnh:
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
  • Sử dụng AWS Console, xác nhận việc thực thi Change Set

Stack Change Set Execution Stack Change Set Execution

Stack Change Set Events Stack Change Set Events

  • Trong hiển thị của rds-stack trên AWS Console, click tab Template để hiển thị nội dung Template hiện tại của Stack. Trên màn hình này, click button View in Designer cho phép chúng ta có được hiển thị trực quan các thành phần trong Stack hiện tại:

Stack in View Designer Stack in View Designer


Cấu hình Public Subnet trong VPC

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).

  • Nội dung cập nhật của CloudFormation Template 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}"      
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
  • Tóm tắt những nội dung thay đổi:
    • Khai báo và liên kết Internet Gateway với VPC
    • Tạo Custom Route Table và khai báo Route kết nối Internet Gateway
    • Liên kết SubnetA và Custom Route Table
  • Tạo Change Set với lệnh:
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"
}

Change Set for Public VPC Change Set for Public VPC

  • Thực thi Change Set:
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

VPC with Public Subnet in Designer VPC with Public Subnet in Designer


Cài đặt EC2 Instance trong Public Subnet

Để 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
  • Các nội dung thay đổi chú ý:
    • Parameters: bổ sung Instance Type tương ứng cấu hình phần cứng của EC2 Instance.
    • Mappings: khai báo mapping - AWSRegionArch2AMI. Mỗi giá trị key trong Map tương ứng với một tập hợp Mapping khác.
      • Key us-east-1: tương ứng Map giữa HVM64 và AMI ID
      • Key ap-southeast-2: tương ứng Map giữa HVM64 với AMI ID
    • Resources:
      • Security Group Ec2SecurityGroup cho phép truy cập SSH qua Port 22
      • EC2 Instance EC2Instance:
        • ImageId: sử dụng look-up function FindInMap trả về AMI ID tương ứng region
        • InstanceType: dựa trên tham số đưa vào, giá trị mặc định t2.micro
        • Liên kết với Security Group Ec2SecurityGroup dựa trên Ref function
        • Sử dụng UserData để thực hiện các cài đặt psql client trong quá trình khởi tạo

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 đó.

  • Ngoài ra, để có được giá trị AMI ID cập nhật từ AWS theo từng region, chúng ta có thể sử dụng câu lệnh sau:

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).

  • Tạo và thực thi Change Set
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

VPC with Public Subnet / EC2 in Designer VPC with Public Subnet / EC2 in Designer

  • Kiểm tra giá trị Public IP và kết nối đến EC2 Instance qua lệnh SSH
ssh -i "FriendReminders.pem" ec2-user@3.25.117.212
  • Trên Terminal của EC2 Instance, xác nhận version cài đặt của psql
psql --version

Cài đặt PostgreSQL Instance trong Private Subnets

  • Để bổ sung DB 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
  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
  • Các nội dung thay đổi chú ý:
    • Parameters: bổ sung các tham số liên quan đến DB Instance (Identifier, Storage, etc…)
    • Resources:
      • Security Group Rule - VpcDefaultSecurityGroupIngress áp dụng cho VPC Security Group
      • DB Subnets Group - DBSubnetGroup sử dụng bởi PostgreSQL DB Instance
      • PostgreSQL DB Instance DBInstance:
        • VPCSecurityGroups: sử dụng VPC Security Group thông qua GetAtt function
        • DBSubnetGroupName: tham chiếu đến DB Subnets Group qua Ref function
  • Tạo và thực thi Change Set với nội dung thay đổi của rds.yaml file.

VPC with EC2 and DB Instances VPC with EC2 and DB Instances


Kết nối DB PostgreSQL từ EC2 Instance

  • Kết nối EC2 Instance qua SSH
ssh -i "FriendReminders.pem" ec2-user@3.25.117.212
  • Kiểm tra kết quả DB Endpoint trên AWS Console

DB Endpoint URL DB Endpoint URL

  • Sử dụng lệnh psql kiểm tra kết nối giữa EC2 Instance và PostgreSQL
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.