AWS ECS 教學

Gary Ng
22 min readAug 12, 2024

--

介紹

全名為 Elastic Container Service, 是由 AWS 提供的容器服務,可以讓我們使用它來運行容器。

ECS 三大核心概念

  1. Capacity: 執行 ECS 的基礎設施,可以使用 EC2, Fargate 以及 VM
  2. Controller: 管理以及部署 Container 的應用程式
  3. Provisioning: 部署以及管理 Container 的工具,例如: web console, terraform 等

以下主要會使用 EC2 搭配 ECS, 而 Fargate 的部分則是會稍微提到,但是底下不會進行實作。

首先要使用 ECS 前,我們要先新增 EC2 所需的 instance role , 新增完後才能開始著手新增 ECS Cluster 並且將 EC2 註冊為 Container Instance

開始建立基本的 ECS

創建 EC2 Instance Role, 使 EC2 可以存取 ECS

將此 Policy Assign 給 IAM Role

IAM Role 名稱命名為 ecsInstanceRole

首先新增 ECS Cluster

輸入可識別的 Cluster 名稱

選擇使用 EC2 並且設定 ASG(Auto Scaling Group)

這邊為了測試所以 ASG 的 Desired Capacity min 以及 max 都設定為 1, 且 instance 的規格設定為 t2.micro

網路的部分倘若使用 Use subnet setting 的話請確認 subnet 是否有打開 auto assign public ip address (進入到 VPC Service 查看)

為了監控 Container 的資源因此需打開 Container Insights

備註: 現在創建 ECS Cluster, AWS 預設會使用 CloudFormation 去創建相對應的資源,例如: EC2、ASG。

注意: 假如創建失敗的話記得去 CloudFormation 進行 RollBack。

創建 Task Execution Role

Task Execution Role 是 Task 在執行的時候會使用到的 Role, 例如: 從 ecr pull image。

IAM Role Use Case 選擇 Elastic Container Service Task

Policy 選擇 AmazonECSTaskExecutionRolePolicy

名稱命名為 ecsTaskExecutionRole

倘若會從 s3 抓取設定檔的話還需要設定以下 s3 GetObject, GetBucketLocation Policy, 範例如下:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::<bucket name>/<config path>"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation"
],
"Resource": [
"arn:aws:s3:::<bucket name>"
]
}
]
}

創建 Task Definition

輸入自定義的 task family 名稱

launch type選擇 ec2, 並且 network mode 選擇 awsvpc

Task Exection Role 選擇前面步驟建立的 ecsTaskExecutionRole

測試用,所以image uri 輸入 httpd:2.4

其餘的都使用預設值,之後再做解釋。

創建 Service

使用已建立的 Cluster, 並且選擇已建立的 auto scaling group

因為服務會一直運行所以 Application Type 選擇 Service

都設定好之後點選創建。

之後便會在 EC2 看到多開了一台機器。

進入機器檢查 Docker 是否有運行 httpd container

docker ps

使用 ECR 部署基本的 PHP 服務

此類型需要搭配 ECR 使用, 可以觀看我的 K8S 教學文章 裏面有教 ECR 建置

network mode

awsvpc:

沒有對外的 public ip, 只有 private ip 倘若需要對外需要設定 ALB 或者 NLB, 且 target group 需為 IP 不能為 instance, 因為 awsvpc mode 是被綁定在 ENI 上。

host:

直接佔用主機的 80 port, 因此不能在一台機器內執行多個 task。

倘若上方 Task 使用 awsvpc network mode 的話需要建置 LoadBalancer, 依照下方步驟建立。

選擇使用的 vpc

輸入 ENI 的 private ip address, 倘若不知道 ENI private ip address 在哪看,可以去 ECS 所創建的 Task 查看,點選 Tasks (Task ID) > Networking , 即可看到 private ipv4 address

Task Role VS Task Execution Role

Task Role : Container 運行在呼叫 AWS Service 所會使用到的 IAM Role, 例如: SQS, S3 等 AWS Service

Task Execution Role: ECS agent 所使用的 IAM Role, 例如: 從 ECR 拉 docker image、使用 awslog driver 等

Log 推送到 CloudWatch

在創建 Task Definition 的時候倘若有開啟 Log Collection 的話則會將 Docker log 推送至 CloudWatch

客制 AMI

倘若不想要自己手動安裝 ECS agent 的話可以直接使用 ECS optimize AMI, 但是倘若不想使用 aws 提供的 AMI 的話就需要手動安裝 ecs agent。

  1. 啟動一個 EC2 Instance 擁有上方建立的 ecsInstanceRole
  2. 進入 EC2 Instance 安裝 Docker

倘若是 ubuntu18.04 的使用者可以參考以下教學進行安裝

設定 docker command 不用 sudo 也可以執行

https://stackoverflow.com/questions/48957195/how-to-fix-docker-got-permission-denied-issue

3.檢查 docker version 是否符合最小版本要求

docker --version

4. 倘若是 aws region 東京的話可以直接使用以下語法下載 ecs container agent

curl -O https://s3.ap-northeast-1.amazonaws.com/amazon-ecs-agent-ap-northeast-1/amazon-ecs-init-latest.amd64.deb
sudo dpkg -i amazon-ecs-init-latest.amd64.deb

5. 編輯此檔案 /lib/systemd/system/ecs.service

vim /lib/systemd/system/ecs.service

6. 在 Unit 區塊的最下方增加

After=cloud-final.service

7. 編輯 /etc/ecs/ecs.config 設定 ecs cluster 的名稱

ECS_CLUSTER=<ECS ClusterName>

8. 建立所需的資料夾

mkdir -p /var/log/ecs /etc/ecs /var/lib/ecs/data

9. 使用 awsvpc network mode 啟動 container agent

/usr/bin/docker run --name ecs-agent \
--init \
--restart=on-failure:10 \
--volume=/var/run:/var/run \
--volume=/var/log/ecs/:/log:Z \
--volume=/var/lib/ecs/data:/data:Z \
--volume=/etc/ecs:/etc/ecs \
--volume=/sbin:/host/sbin \
--volume=/lib:/lib \
--volume=/lib64:/lib64 \
--volume=/usr/lib:/usr/lib \
--volume=/usr/lib64:/usr/lib64 \
--volume=/proc:/host/proc \
--volume=/sys/fs/cgroup:/sys/fs/cgroup \
--net=host \
--env-file=/etc/ecs/ecs.config \
--cap-add=sys_admin \
--cap-add=net_admin \
--env ECS_ENABLE_TASK_ENI=true \
--env ECS_UPDATES_ENABLED=true \
--env ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=1h \
--env ECS_DATADIR=/data \
--env ECS_ENABLE_TASK_IAM_ROLE=true \
--env ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true \
--env ECS_LOGFILE=/log/ecs-agent.log \
--env ECS_AVAILABLE_LOGGING_DRIVERS='["json-file","awslogs","syslog","none"]' \
--env ECS_LOGLEVEL=info \
--detach \
amazon/amazon-ecs-agent:latest

10. docker ps -a 檢查 container agent 是否有運行起來

11. 將系統的 ecs 運行起來

sudo systemctl start ecs

12. 檢查是否運行起來

sudo systemctl status ecs

11.此時在 ECS Dashboard 會看到已註冊的 Container Instance 數量變為 1

倘若有需要設定 EC2 Launch Template 的話範本如下

注意!! 產生的 EC2 Launch Template 記得先把 ecs.service 改為 disable 以免產生 deadlock

#!/bin/bash

# 暫停 ecs-agent container
docker stop ecs-agent

# 移除 ecs-agent container
docker rm ecs-agent

# prevent user data deadlock
systemctl enable --now --no-block ecs.service

# 重新執行 ecs container
docker run --name ecs-agent \
--init \
--restart=on-failure:10 \
--volume=/var/run:/var/run \
--volume=/var/log/ecs/:/log:Z \
--volume=/var/lib/ecs/data:/data:Z \
--volume=/etc/ecs:/etc/ecs \
--volume=/sbin:/host/sbin \
--volume=/lib:/lib \
--volume=/lib64:/lib64 \
--volume=/usr/lib:/usr/lib \
--volume=/usr/lib64:/usr/lib64 \
--volume=/proc:/host/proc \
--volume=/sys/fs/cgroup:/sys/fs/cgroup \
--net=host \
--env-file=/etc/ecs/ecs.config \
--cap-add=sys_admin \
--cap-add=net_admin \
--env ECS_ENABLE_TASK_ENI=true \
--env ECS_UPDATES_ENABLED=true \
--env ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=1h \
--env ECS_DATADIR=/data \
--env ECS_ENABLE_TASK_IAM_ROLE=true \
--env ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true \
--env ECS_LOGFILE=/log/ecs-agent.log \
--env ECS_AVAILABLE_LOGGING_DRIVERS='["json-file","awslogs","syslog","none"]' \
--env ECS_LOGLEVEL=info \
--detach \
amazon/amazon-ecs-agent:latest

ECS Rolling Update vs Blue-Green Deployment

Rolling update 滾動式更新:

慢慢的替換成新的容器,需搭配 ALB draining 使用,而在替換前舊容器的 request 需要先消化完。因為是慢慢地替換成新容器,所以有一段時間新舊會並存。此方式也是 ECS 預設提供的。

Blue-Green Deployment 藍綠部署:

  1. 創建 CodeDeploy IAM Role 允許可以對 ECS 進行操作

點選 Create Role

選擇 AWS Service

選擇 CodeDeploy ECS

使用 AWSCodeDeployRoleForECS Policy

Role 命名為 ecsCodeDeployRole

複製以下權限到 ecsCodeDeployRole

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": ["arn:aws:iam::<aws_account_id>:role/<ecsCodeDeployRole>"]
}
]
}

2. 創建 CodeDeploy 所會用到的 ALB

CodeDeploy ECS 藍綠部署主要會用到 2 個 listener port,一個是 Production 使用,另一個則是測試用。這邊的範例 Product Port 使用 80, 測試的則是使用 8080 port。

注意! 2 個不同的 listener port 要對應到不同的 target group, 否則再新增 ECS Service 的時候會因為 target group 重複有不能新增

分別建立 ALB 80 以及 8080 listen port

3. 創建 Service 的時候記得勾選 add a test listener, 然後選擇 8080 port

4. 手動觸發 Deployment

Create Deployment 的時候設定 appspec.yml

version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: "arn:aws:ecs:region:aws_account_id:task-definition/tutorial-task-def:2"
LoadBalancerInfo:
ContainerName: "<container name>"
ContainerPort: 80

實作 Load Balancer

請查看上方 awvpc mode 區塊,倘若是 awsvpc Load Balancer target group 需使用 IP 且需搭配 ENI。

實作 Auto Scale

在創建 ECS launch Type 為 EC2 的時候 AWS 會使用 CloudFormation 幫我們創建一個 Auto Scaling Group。

除了使用上方所創建的 Auto Scaling Group ,倘若真的需要自動擴展的功能也需要設定 Service Auto Scale, 甚至搭配 ALB。

啟用 service auto scaling, 這邊 min, max 先設定為 1, 後續測試的時候會做調整。

注意事項

有些東西再創完之後便不可以透過 AWS Console 去修改資訊,只能透過 aws-cli 、SDK 去做更新。

例如: Load balancer listener rule 等。

壓測工具:

倘若使用 aws 自己的 ami image 需使用下面指令安裝 stress

sudo amazon-linux-extras install epel -y
sudo yum install stress stress-ng -y

執行壓測試得指令

參數說明:

  • c: 針個 n 個 cpu
  • -l: 使其 cpu 達到 80%
stress-ng -c 4 -l 80

倘若是需要壓測 docker container 服務則需安裝 pumba

curl -SL https://github.com/alexei-led/pumba/releases/download/0.7.2/pumba_linux_amd64 -O
sudo mv pumba_linux_amd64 /usr/bin/pumba
sudo chmod +x /usr/bin/pumba
pumba --version

參考資源:

--

--

Gary Ng
Gary Ng

Written by Gary Ng

軟體工程師、後端工程師

No responses yet