介紹
全名為 Elastic Container Service, 是由 AWS 提供的容器服務,可以讓我們使用它來運行容器。
ECS 三大核心概念
- Capacity: 執行 ECS 的基礎設施,可以使用 EC2, Fargate 以及 VM
- Controller: 管理以及部署 Container 的應用程式
- 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。
- 啟動一個 EC2 Instance 擁有上方建立的 ecsInstanceRole
- 進入 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 藍綠部署:
- 創建 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
參考資源: