0

Triển Khai Hệ Thống AWS ECS Với AWS CLI (Phần 2)

Tạo Relational Database Service

Tổng quan

Dịch vụ cơ sở dữ liệu quan hệ của Amazon (Amazon RDS) là một tập hợp các dịch vụ được quản lý giúp bạn dễ dàng thiết lập, vận hành và điều chỉnh quy mô cơ sở dữ liệu trên đám mây.

Trong phần này, chúng ta sẽ thiết lập Dịch vụ Cơ sở dữ liệu Quan hệ (RDS) trên AWS

Quy trình

  1. Tạo RDS Subnet Group

    Trong phần này, chúng ta tạo một RDS Subnet Group

    rds_subnet_group_name=$project-subnet-group
    rds_subnet_group_descript="Subnet Group for Postgres RDS"
    rds_subnet1_id=$subnet_private_1
    rds_subnet2_id=$subnet_private_2 
    # Create Subnet group
    aws rds create-db-subnet-group \
        --db-subnet-group-name $rds_subnet_group_name \
        --db-subnet-group-description "$rds_subnet_group_descript" \
        --subnet-ids $rds_subnet1_id $rds_subnet2_id \
        --tags "$tags"
    

    Trong mã trên:

    • rds_subnet_group_name: Đây là tên của Nhóm Subnet RDS, dựa trên biến $project.
    • aws rds create-db-subnet-group: Dòng này tạo một Nhóm Subnet RDS với tên và mô tả được chỉ định, và liên kết nó với các subnet riêng tư.
  2. Deploy RDS

    Trong phần này, chúng ta triển khai Dịch vụ Cơ sở dữ liệu Quan hệ (RDS) bằng cách sử dụng Nhóm Subnet RDS đã tạo trước đó.

    rds_name=$project-rds
    rds_db_name="workshop"
    rds_db_username="postgres"
    rds_db_password="postgres"
    # Create RDS
    aws rds create-db-instance \
        --db-instance-identifier $rds_name \
        --engine postgres \
        --db-name $rds_db_name \
        --db-instance-class db.t3.micro \
        --allocated-storage 20 \
        --master-username $rds_db_username \
        --master-user-password $rds_db_password \
        --storage-type gp2 \
        --no-enable-performance-insights \
        --availability-zone $az_01 \
        --db-subnet-group-name $rds_subnet_group_name \
        --vpc-security-group-ids $rds_sgr_id \
        --backup-retention-period 0 \
        --tags "$tags"
    
    aws rds wait db-instance-available \
        --db-instance-identifier $rds_name
    
    # Get RDS information
    rds_address=$(aws rds describe-db-instances \
        --db-instance-identifier $rds_name \
        --query 'DBInstances[0].Endpoint.Address' \
        --output text)
    echo rds_address=$rds_address
    

    Trong đoạn code trên:

    • rds_instance_name: Đây là tên của phiên bản RDS, dựa trên biến $project.
    • aws rds create-db-instance: Dòng này triển khai một phiên bản RDS với cấu hình cụ thể, bao gồm lớp phiên bản, loại engine, kích thước lưu trữ, nhóm subnet, nhóm bảo mật, tên người dùng chính, và mật khẩu.
    • aws rds describe-db-instances để lấy thông tin chi tiết về một phiên bản RDS dựa trên định danh của nó (db-instance-identifier) và sử dụng --query 'DBInstances[0].Endpoint.Address': để tìm ra địa chỉ của DB instance từ json mà lệnh trả về

Tạo SecretsManager

Tổng quan

AWS Secrets Manager giúp bạn mã hóa, lưu trữ và lấy thông tin đăng nhập một cách an toàn cho các cơ sở dữ liệu và dịch vụ khác của bạn. Thay vì cứ mã hóa trực tiếp thông tin đăng nhập trong ứng dụng của bạn, bạn có thể gọi tới Secrets Manager để lấy thông tin đăng nhập mỗi khi cần. Secrets Manager giúp bảo vệ quyền truy cập vào tài nguyên và dữ liệu IT của bạn bằng cách cho phép bạn xoay vòng và quản lý quyền truy cập vào các bí mật của mình.

Quy trình

Tạo Secret Manager

Để Tạo Secret Manager, chúng ta sử dụng lệnh aws secretsmanager create-secret

secret_name=$project-sm
secret_string=$(echo "{\"POSTGRES_HOST\":\"$rds_address\",\"POSTGRES_PORT\":\"5432\",\"POSTGRES_DB\":\"$rds_db_name\",\"POSTGRES_USERNAME\":\"$rds_db_username\",\"POSTGRES_PASSWORD\":\"$rds_db_password\"}")
# Create SecretManager
aws secretsmanager create-secret \
    --name $secret_name \
    --description "To save database information" \
    --tags "$tags" \
    --secret-string $secret_string

Tạo Application Load Balancing

Tổng quan

Application Load Balancer hoạt động ở tầng ứng dụng, là tầng thứ bảy của mô hình Open Systems Interconnection (OSI).
Sau khi ALB nhận yêu cầu, nó đánh giá các quy tắc trình nghe (listener rule) theo thứ tự ưu tiên để xác định quy tắc nào được áp dụng, sau đó chọn một mục tiêu từ Target Group để tiếp tục thực hiện.

image.png

Quy trình

  1. Cấu hình biến

    alb_name=$project-alb
    alb_tgr_name=$project-tgr
    alb_vpc_id=$vpc_id
    alb_subnet1_id=$subnet_public_1
    alb_subnet2_id=$subnet_public_2
    
  2. Tạo ALB

    # Create ALB
    alb_arn=$(aws elbv2 create-load-balancer \
        --name $alb_name  \
        --subnets $alb_subnet1_id $alb_subnet2_id \
        --security-groups $alb_sgr_id \
        --tags "$tags" \
        --query 'LoadBalancers[0].LoadBalancerArn' \
        --output text)
    
    echo alb_arn=$alb_arn
    
  3. Tạo Target Group

    alb_tgr_arn=$(aws elbv2 create-target-group \
        --name $alb_tgr_name \
        --protocol HTTP \
        --target-type ip \
        --health-check-path "/api/product" \
        --port 8080 \
        --vpc-id $alb_vpc_id \
        --tags "$tags" \
        --query 'TargetGroups[0].TargetGroupArn' \
        --output text)
    
    echo alb_tgr_arn=$alb_tgr_arn
    
  4. Tạo Listener

    alb_listener_arn=$(aws elbv2 create-listener \
    --load-balancer-arn $alb_arn \
    --protocol HTTP \
    --port 80 \
    --default-actions Type=forward,TargetGroupArn=$alb_tgr_arn \
    --query 'Listeners[0].ListenerArn' \
    --output text)
    
    echo alb_listener_arn$alb_listener_arn
    

Tạo Elastic Container Service (ECS)

Tạo ECS Cluster

Tổng quan

ECS cluster là một nhóm về mặt logic của các ECS tasks hay services.

Ngoài các tasks and services, a cluster bao gồm các tài nguyên sau:

  • Hạ tầng:
    • Amazon EC2 instances trên AWS
    • Serverless (AWS Fargate (Fargate)) trên AWS
    • On-premises virtual machines (VM) hoặc servers
  • Mạng (VPC and subnet).
  • A namespace: được sử dụng cho giao tiếp từ dịch vụ này sang dịch vụ khác với Service Connect.
  • A monitoring option: CloudWatch Container Insights tự động thu thập, tổng hợp và tóm tắt các số liệu và nhật ký của Amazon ECS.

Quy trình

Sử dụng lệnh sau để tạo một Cluster ECS.

ecs_cluster_name=$project-cluster
# Create ECS Cluster
aws ecs create-cluster \
    --cluster-name $ecs_cluster_name \
    --region $region \
    --tags "$tags2"

# Check ECS Cluster created correctly
aws ecs list-clusters

Tạo ECS Capacity

Tổng quan

Amazon ECS capacity là cơ sở hạ tầng nơi mà các container của bạn chạy.

ECS capacity có 3 loại sau:

  • Các instance Amazon EC2: Bạn chọn loại instance, số lượng instance và quản lý capacity.
  • Serverless (AWS Fargate): Với Fargate, bạn không cần quản lý máy chủ, xử lý kế hoạch capacity, hoặc cách ly các công việc container để bảo mật.
  • On-premise Máy ảo (VM) hoặc server: Amazon ECS Anywhere cung cấp hỗ trợ để đăng ký một instance bên ngoài như on-premises server hoặc virtual machine (VM), vào Amazon ECS cluster của bạn.

ECS cluster capacity providers với ECS capacity không phải là một.
ECS capacity đề cập đến khả năng cơ sở hạ tầng mà có sẵn để chạy các nhiệm vụ và dịch vụ trong một cluster ECS. Capacity này có thể được cung cấp bằng cách sử dụng các nhà cung cấp capacity.
Capacity provider strategy xác định cách các nhiệm vụ được phân phối đến các nguồn cơ sở hạ tầng khác nhau trong cluster. Điều này giúp tối ưu hóa việc sử dụng tài nguyên và chi phí dựa trên yêu cầu của task. Mỗi cluster có một hoặc nhiều nhà capacity provider và một cấu hình capacity provider strategy mặc định tùy chọn. Capacity provider stratergy xác định cách các task được phân phối qua các capacity provider. Khi chạy một task hoặc tạo một service, bạn có thể sử dụng capacity provider stragtegy mặc định của cluster hoặc chỉ định một capacity provider stragtegy thay thế.

Quy trình

  1. Truy xuất ECS-optimized AMI

    # Get ECS AMI ID
    ecs_instance_ami_id=$(aws ssm get-parameters \
        --names /aws/service/ecs/optimized-ami/amazon-linux-2/recommended \
        --region $region | jq -r '.Parameters[0].Value | fromjson.image_id')
    

    Ở đây chúng ta sử dụng Amazon Linux 2 làm hệ điều hành cơ sở, đối với các hệ điều hành cơ sở khác, tìm hiểu thông tin tại Retrieving Amazon ECS-Optimized AMI metadata

  2. Tạo Launch Template với Amazon ECS-optimized AMI

    ECS agent là một công cụ containerization mà ECS sử dụng để quản lý instance. Để ECS agent biết rằng Instance này thuộc về ECS Cluster nào, bạn phải cấu hình như sau trong tệp /etc/ecs/ecs.config

    ECS_CLUSTER=ecs_cluster_name
    
    ecs_instance_type=t3.medium
    ecs_instance_subnet_id=$subnet_public_1
    ecs_launch_template_name=$project-ecs-launch-template
    # Tạo Launch template file
    cat <<EOF | tee ecs-launch-template.json
    {
        "ImageId": "$ecs_instance_ami_id",
        "InstanceType": "$ecs_instance_type",
        "IamInstanceProfile": {
            "Arn": "$ecs_instance_profile_arn"
        },
        "NetworkInterfaces": [{
            "DeviceIndex": 0,
            "AssociatePublicIpAddress": true,
            "Groups": ["$ecs_instance_sgr_id"],
            "SubnetId": "$ecs_instance_subnet_id"
        }],
        "KeyName": "$ecs_instance_key_name",
        "TagSpecifications": [{
            "ResourceType": "instance",
            "Tags": `echo '['$tagspec | sed 's/{/{"/g; s/}/"}/g; s/,/","/g; s/}","{/},{/g; s/=/":"/g'`
        }],
        "UserData": "`cat <<EOF | openssl base64 -A
    #!/bin/bash
    echo ECS_CLUSTER=$ecs_cluster_name >> /etc/ecs/ecs.config
    EOF`"
    }
    EOF
    # Tạo launch template sử dụng file launch template vừa tạo
    aws ec2 create-launch-template \
        --launch-template-name $ecs_launch_template_name \
        --launch-template-data file://ecs-launch-template.json
    
  3. Tạo Auto Scaling Group sử dụng template vừa tạo

    ecs_instance_name=$project-ecs-instance
    ecs_autoscaling_group_name=$project-ecs-autoscaling-group
    # create Autoscaling group
    aws autoscaling create-auto-scaling-group \
        --auto-scaling-group-name $ecs_autoscaling_group_name \
        --launch-template "$(echo "{\"LaunchTemplateName\":\"$ecs_launch_template_name\"}")" \
        --min-size 1 \
        --max-size 3 \
        --desired-capacity 1 \
        --tags "$(echo $tags | jq -c '. + [{"Key":"Name","Value":"'"$ecs_instance_name"'"}]')"
    
    
    ecs_autoscaling_group_arn=$(aws autoscaling describe-auto-scaling-groups \
        --auto-scaling-group-names $ecs_autoscaling_group_name \
        | jq .AutoScalingGroups[0].AutoScalingGroupARN)
    
  4. List Container Instance

    Kiểm tra các instance trong autoscaling group đã thuộc ECS quản lý chưa

    aws ecs list-container-instances --cluster $ecs_cluster_name
    
  5. Tạo Capacity Provider và sử dụng cho ECS Cluster

    Thật ra trong bài lab này tạo ECS Capacity Provider không ý nghĩa lắm. Chủ yếu để biết và hiểu cách tạo ECS Capacity Provider. (Bỏ phần này Lab vẫn hoạt động 🥲)

    ecs_capacity_provider=$project-capacity-provider
    # Tạo Capacity provider
    aws ecs create-capacity-provider \
        --name $ecs_capacity_provider \
        --auto-scaling-group-provider `echo "autoScalingGroupArn=$ecs_ec2_autoscaling_arn,managedScaling={status=ENABLED,targetCapacity=100},managedTerminationProtection=DISABLED"` \
        --tags $tags2
    
        aws ecs put-cluster-capacity-providers \
            --cluster $ecs_cluster_name \
            --capacity-providers $ecs_capacity_provider \
            --default-capacity-provider-strategy capacityProvider=$ecs_capacity_provider,weight=1
    

Tạo ECS Task Definition

Tổng quan

Task Definition là một bản thiết kế cho ứng dụng của bạn. Đó là một tệp văn bản có định dạng JSON mô tả các tham số và một hoặc nhiều container tạo nên ứng dụng của bạn.

Quy trình

  1. Tạo IAM Role cho Task Definition

    1. Tạo IAM Role cho Task Definition với quyền được sử dụng bởi ecs-tasks.amazonaws.com

      # Lấy ARN của AWS secret manager
      secret_arn=$(aws secretsmanager describe-secret --secret-id $secret_name --query 'ARN' --output text)
      # Tạo IAM Role cho Task Definition
      ecs_task_role_name=$project-ecs-task-role
      ecs_task_policy_name=${project}_ecs_task_policy
      ecs_task_name=$project-task
      ecs_task_uri=$ecr_image_uri
      # Tạo IAM Role
      ecs_task_role_arn=$(aws iam create-role \
          --role-name $ecs_task_role_name \
          --assume-role-policy-document '{
              "Version": "2012-10-17",
              "Statement": [{
                  "Effect": "Allow",
                  "Principal": {
                      "Service": "ecs-tasks.amazonaws.com"
                  },
                  "Action": ["sts:AssumeRole"]
              }]
          }' \
          --tags "$tags" \
          --output text \
          --query 'Role.Arn')
      
      echo ecs_task_role_arn=$ecs_task_role_arn
      
    2. Gắn các chính sách vào IAM Role này

      cat <<EOF | tee ecs-task-role.json
      {
      "Version": "2012-10-17",
      "Statement": [
          {
          "Effect": "Allow",
          "Action": [
              "ssm:GetParameters",
              "secretsmanager:GetSecretValue"
          ],
          "Resource": [
              "`echo $secret_arn`",
              "`echo $secret_arn`*"
          ]
          }
      ]
      }
      EOF
      
      aws iam put-role-policy \
          --role-name $ecs_task_role_name \
          --policy-name $ecs_task_policy_name \
          --policy-document file://ecs-task-role.json
      
      aws iam attach-role-policy \
          --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \
          --role-name $ecs_task_role_name
      
  2. Tạo Task Definition

    1. Tạo tệp định nghĩa Task definition

      Nội dung của SecretsManager tạo từ trước có dạng Json như sau

      {
          "POSTGRES_HOST":"test.rds.amazonaws.com",
          "POSTGRES_PORT":"5432",
          "POSTGRES_DB":"workshop",
          "POSTGRES_USERNAME":"postgres",
          "POSTGRES_PASSWORD":"postgres"
      }
      
      # Nội dung của task-definition
      cat <<EOF | tee task-definition.json
      {
          "name": "$ecs_task_name",
          "image": "$ecs_task_uri",
          "portMappings": [
              {
                  "containerPort": 8080,
                  "hostPort": 8080
              }
          ],
          "secrets" : [
              {
                  "valueFrom" : "$secret_arn:POSTGRES_HOST::",
                  "name" : "POSTGRES_HOST"
              },
              {
                  "valueFrom" : "$secret_arn:POSTGRES_DB::",
                  "name" : "POSTGRES_DB"
              },
              {
                  "valueFrom" : "$secret_arn:POSTGRES_PASSWORD::",
                  "name" : "POSTGRES_PASSWORD"
              }
          ]
      }
      EOF
      
    2. Sử dụng file này để tạo Task Definition

      # Tạo task-definition
      ecs_task_definition=$(aws ecs register-task-definition \
          --family $ecs_task_name \
          --network-mode awsvpc \
          --requires-compatibilities EC2 \
          --cpu "512" \
          --memory "1024" \
          --execution-role-arn "$ecs_task_role_arn" \
          --tags "$tags2" \
          --container-definitions "`jq -c . task-definition.json`" )
      
      # Kiểm tra việc tạo ECS task definition
      aws ecs list-task-definitions
      
      ecs_task_arn=$(aws ecs describe-task-definition \
          --task-definition $ecs_task_name \
          --query "taskDefinition.taskDefinitionArn" \
          --output text)
      

Tạo ECS Service

Tổng quan

Amazon ECS (Elastic Container Service) Service là một dịch vụ chạy và quản lý một số lượng xác định các phiên bản của một task definition đồng thời trong một cluster Amazon ECS.

Tạo ECS Service

Tạo ECS service dựa trên 1 task definition có sẵn bằng lệnh

ecs_service_name=$project-service
# Tạo Service
aws ecs create-service \
   --cluster $ecs_cluster_name \
   --service-name $ecs_service_name \
   --task-definition $ecs_task_arn \
   --desired-count 1 \
   --network-configuration "awsvpcConfiguration={subnets=[$ecs_instance_subnet_id],securityGroups=[$ecs_instance_sgr_id]}" 

aws ecs update-service --cluster $ecs_cluster_name \
    --service $ecs_service_name \
    --desired-count 1 \
    --load-balancers targetGroupArn=$alb_tgr_arn,containerName=`echo $ecs_task_definition | jq -r '.taskDefinition.containerDefinitions[0].name'`,containerPort=8080

Kiểm tra kết quả

  1. Kiểm tra Target Group (Check Healthy)

    aws elbv2 describe-target-health --target-group-arn $alb_tgr_arn
    
  2. Lấy giá trị ALB public DNS

    aws elbv2 describe-load-balancers \
        --load-balancer-arns $alb_arn \
        --query 'LoadBalancers[0].DNSName' \
        --output text
    
  3. Kiểm tra ứng dụng bằng api

image.png

Dọn dẹp

Xóa ALB và các thành phần liên quan

aws elbv2 delete-listener --listener-arn $alb_listener_arn

aws elbv2 delete-target-group --target-group-arn $alb_tgr_arn

aws elbv2 delete-load-balancer --load-balancer-arn $alb_arn

Xóa ECS Service

aws ecs delete-service --cluster $ecs_cluster_name \
    --service $ecs_service_name --force

Xóa ECS Task Definition

task_definition_arns=$(aws ecs list-task-definitions \
    --status ACTIVE \
    --query 'taskDefinitionArns[]' --output text)

for arn in $task_definition_arns; do
    aws ecs deregister-task-definition --task-definition $arn
done

task_definition_inactive_arns=$(aws ecs list-task-definitions \
    --status INACTIVE \
    --query 'taskDefinitionArns[]' --output text)

aws ecs delete-task-definitions \
    --task-definitions $task_definition_inactive_arns

Xóa Task Role

aws iam delete-role-policy \
    --role-name $ecs_task_role_name \
    --policy-name $ecs_task_policy_name

aws iam detach-role-policy \
    --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \
    --role-name $ecs_task_role_name

aws iam delete-role --role-name $ecs_task_role_name

Xóa ECS instance và các thành phần liên quan

instance_ids=$(aws autoscaling describe-auto-scaling-groups \
    --auto-scaling-group-names $ecs_autoscaling_group_name \
    --query "AutoScalingGroups[].Instances[].InstanceId" \
    --output text)

aws autoscaling delete-auto-scaling-group \
    --auto-scaling-group-name $ecs_autoscaling_group_name \
    --force-delete

aws ec2 terminate-instances --instance-ids $instance_ids
aws ec2 wait instance-terminated --instance-ids $instance_ids

aws ec2 delete-launch-template \
    --launch-template-name $ecs_launch_template_name

Xóa ECS Cluster

aws ecs delete-cluster --cluster $ecs_cluster_name

Xóa ECS Capacity Provider

# aws ecs put-cluster-capacity-providers \
#     --cluster $ecs_cluster_name \
#     --capacity-providers $ecs_capacity_provider \
#     --default-capacity-provider-strategy capacityProvider=$ecs_capacity_provider,weight=0,base=0

aws ecs delete-capacity-provider --capacity-provider $ecs_capacity_provider

Xóa Secrets Manager

aws secretsmanager delete-secret \
    --secret-id $secret_name \
    --force-delete-without-recovery

Xóa RDS

aws rds delete-db-instance \
    --db-instance-identifier $rds_name \
    --skip-final-snapshot

aws rds wait db-instance-deleted --db-instance-identifier $rds_name

aws rds delete-db-subnet-group --db-subnet-group-name $rds_subnet_group_name

Xóa Security Group

aws ec2 delete-security-group --group-id $alb_sgr_id

aws ec2 delete-security-group --group-id $rds_sgr_id

aws ec2 delete-security-group --group-id $ecs_instance_sgr_id

Xóa Network

aws ec2 delete-subnet --subnet-id $subnet_public_1
aws ec2 delete-subnet --subnet-id $subnet_public_2
aws ec2 delete-subnet --subnet-id $subnet_public_3

aws ec2 delete-subnet --subnet-id $subnet_private_1
aws ec2 delete-subnet --subnet-id $subnet_private_2
aws ec2 delete-subnet --subnet-id $subnet_private_3

aws ec2 delete-route-table --route-table-id $rtb_public_id
aws ec2 delete-route-table --route-table-id $rtb_private_id

aws ec2 detach-internet-gateway \
    --internet-gateway-id $gateway_id \
    --vpc-id $vpc_id
aws ec2 delete-internet-gateway --internet-gateway-id $gateway_id

aws ec2 delete-vpc --vpc-id $vpc_id

Xóa ECR

aws ecr batch-delete-image \
    --repository-name $ecr_name \
    --image-ids imageTag=latest \
    --region $region

aws ecr delete-repository \
    --repository-name $ecr_name \
    --force \
    --region $region

docker rmi $ecr_image_uri

docker rmi $ecr_name

# docker rmi $(docker image ls -aq)

Xóa Keypair

aws ec2 delete-key-pair --key-name $ecs_instance_key_name

rm -f $ecs_instance_key_name.pem

Xóa IAM Role

aws iam remove-role-from-instance-profile \
    --instance-profile-name $ecs_instance_role_name \
    --role-name $ecs_instance_role_name

aws iam delete-instance-profile \
    --instance-profile-name $ecs_instance_role_name

aws iam detach-role-policy \
    --policy-arn arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role \
    --role-name $ecs_instance_role_name

aws iam detach-role-policy \
    --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore \
    --role-name $ecs_instance_role_name

aws iam delete-role --role-name $ecs_instance_role_name

Kết thúc

Vậy là bạn đã hoàn thành việc cài đặt ECS với công cụ AWS CLI. Hy vọng hướng dẫn này đã giúp bạn dễ dàng hơn trong việc thiết lập môi trường ECS. Nếu bạn có bất kỳ câu hỏi hay góp ý nào, hãy để lại bình luận bên dưới. Chúc bạn thành công!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí