拆解五步驟: 使用 Amazon ECS Exec 穿越直達 Fargate/ECS 上的容器

(圖說:貓穿越!圖片來源:by Tomas Tuma on Unsplash)

今天原本在追 AWS Pi Week 慶祝 AWS 15 週年為 S3 慶生的資訊,很開心看到 Amazon ECS 也迎來了敲碗許久的新功能 Amazon ECS Exec。

本文記錄參考了

接著就來試試看透過 AWS CLI 介面,來嘗試看看 Amazon ECS Exec 穿越直達一個 Amazon ECS (EC2) 上的容器。



重點摘要

Massimo 的文章和 Amazon ECS 官方文件都有詳細步驟,但使用前建議先看一下官方文件開頭所提的限制條件(也可能隨時時間演進而有所改變)。以下幾個重點摘要:

  • 架構
    • Amazon ECS Exec 使用 AWS Systems Manager (SSM) Session Manager 建立與容器間的連線,並使用 AWS IAM policies 控管執行指令的權限。
    • Amazon ECS agent 或 AWS Fargate agent 會種一隻 SSM agent 在指定的容器中,來個裡應外合。
  • 考量
    • 目前 Amazon ECS Exec 僅支援 Linux 容器。
    • 目前還未支援 AWS Management Console 使用介面。
    • 目前還未支援 Asia Pacific (Osaka) Region。(覺得好奇,少了什麼相依底層?
    • 現存 tasks 不能直接啟用 ECS Exec,要執行新的 tasks 來啟用 ECS Exec。(例如更新 ECS service)
    • 就算有在容器指定 user ID,SSM agent 會用 root 權限執行指令。
    • Amazon ECS Exec 會使用一些 CPU/Memory 資源。可在 task definition 預留資源。
  • 準備

有個心理準備後,那我們開始動手做看看 :)

以下的操作情境是假設已經有現存的專案運行在 Amazon ECS,調整成可以執行 ECS Exec 穿越的環境,並成功執行 ECS Exec 進到容器內。

0.1 預備工作: 更新 Amazon ECS optimized AMI

對現有既存 ECS cluster (EC2 launch type) 記得做這個更新 Amazon ECS optimized AMI 步驟,才能滿足 ECS Exec 的運作條件。

這個大家就用自己熟悉的方法做更新,我是將久久但時不時會用到的 AWS CLI 指令包在 Makefile 裡頭。(隨著年紀增長,指令都記不太住了… 有次 AWSUG Taiwan 聚會聽到一場 gslin 分享 AWS CodeBuild 還是 CodeDeploy,過程中大量使用 Makefile 進行,覺得實用就跟進了 :)

1
2
3
4
5
6
7
❯ make get-ami-id
Getting latest Amazon ECS optimized AMI ID (Amazon Linux 2) of assigned region (region-codename)...
AMI_ID = ami-0abcdefghijklmnop

❯ make create-asg-lc

❯ make update-asg

0.2 預備工作: 確認安裝 Session Manager plugin

安裝 Session Manager plugin

1
2
3
❯ session-manager-plugin

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.

1. 授權 ECS task IAM role

授權 ECS task IAM role 讓 SSM agent 可以與 SSM service 通訊。

ECS task definition 裡面有個 Task role 可以指定一組 Amazon ECS task IAM role,這個 IAM role 需要包含有以下這個權限,也可以定義成一組 IAM policy,給多組 IAM roles 引用。(我是習慣一個 ECS service 對應一個 task role,區分乾淨。)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
   "Version": "2012-10-17",
   "Statement": [
       {
       "Effect": "Allow",
       "Action": [
            "ssmmessages:CreateControlChannel",
            "ssmmessages:CreateDataChannel",
            "ssmmessages:OpenControlChannel",
            "ssmmessages:OpenDataChannel"
       ],
      "Resource": "*"
      }
   ]
}

AWS CLI 操作範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
❯ aws iam create-policy --policy-name ecsExecPolicy --policy-document file://ecs-exec-policy.json
{
    "Policy": {
        "PolicyName": "ecsExecPolicy",
        "PolicyId": "ANxxxxxxxxxxxxxxxxxxx",
        "Arn": "arn:aws:iam::123456789012:policy/ecsExecPolicy",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 0,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "CreateDate": "2021-03-17T09:03:45+00:00",
        "UpdateDate": "2021-03-17T09:03:45+00:00"
    }
}

❯ aws iam attach-role-policy --policy-arn arn:aws:iam:123456789012:policy/ecsExecPolicy --role-name YourEcsTaskRoleNameHere

2. 修改 task definition

修改 task definition 參數,使 initProcessEnabled = true,將在容器中跑 init process,這個程序會清掉可能成為殭屍的 SSM agent 子程序。

文件寫選配,可改可不改,看你想不想養殭屍(咦?!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "containerDefinitions": [
        {
            "linuxParameters": {
                "initProcessEnabled": true
            }
        }
    ],
    "family": "ecs-exec-task"
}

3. 啟用 Amazon ECS Exec

依照條件限制,得要重新跑新的 ECS task 起來,才會有 SSM agent 在裡頭,有四種動作都可以完成這件事情:

因為本文的情境是已經有既存工作任務運行在 Amazon ECS,所以在此先試試 AWS CLI 指令的 update-service 搭配參數 --enable-execute-command。(本文撰寫 (March 18, 2021) 當時 AWS CLI v2 還未支援此參數。)

1
2
3
4
5
6
7
8
9
❯ aws --version
aws-cli/1.19.32 Python/3.8.5 Linux/4.19.121-linuxkit botocore/1.20.32

❯ aws ecs update-service \
  --cluster your-cluster-name \
  --service your-service-name \
  --task-definition your-td-family-name:N \
  --force-new-deployment \
  --enable-execute-command

對一個 task 啟用 ECS Exec 之後,可以用 describe-tasks 指令檢查 ExecuteCommandAgentlastStatus 狀態應該要是 RUNNING,以及 enableExecuteCommand 屬性有被設定成 true。這樣這個 task 就設定完成。

1
2
3
❯ aws ecs describe-tasks \
    --cluster your-cluster-name \
    --tasks your-task-id

擷取輸出結果的重點檢查:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
    "tasks": [
        {
            ...
            "containers": [
                {
                    ...
                    "managedAgents": [
                        {
                            "lastStartedAt": "2021-03-01T14:49:44.574000-06:00",
                            "name": "ExecuteCommandAgent",
                            "lastStatus": "RUNNING"
                        }
                    ]
                }
            ],
            ...
            "enableExecuteCommand": true,
            ...
        }
    ]
}

4. 穿越吧!Amazon ECS Exec!

使用指令 execute-command 開始穿越!Go!

--command 參數可以換成任何你想在你的容器中執行的指令。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
❯ aws ecs execute-command --cluster your-cluster-name \
    --task your-task-id \
    --container your-container-name \
    --interactive \
    --command "/bin/bash"

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.


Starting session with SessionId: ecs-execute-command-0936520b5bac0473e
root@46baf93bef74:/var/www/html#

穿越成功!

總結

Amazon ECS Exec 功能滿好上手的,跟大部分的 AWS 服務相同,搞定 IAM 給予對應的權限,然後將服務更新到對應的版本以上,就可以運作了。

雖然本文從步驟 0 到步驟 4 總共列了 5 個步驟,但前置環境設定完成後,往後就只要撈到想穿越進去的 ECS task id,直接衝第 4 個步驟即可。

因為 Amazon ECS Exec 功能釋出時就有 CloudFormation 支援,就等 AWS CDK L2 支援,但已經可以用 CDK 的方式實作了 :) 大家可以參考 Pahud 使用 CDK 來實作 Amazon ECS Exec 所需要的環境設定,比 AWS CLI 更方便,大家可以選擇自己擅長的工具來使用,都很棒。

穿越成功的話,歡迎到 AWS User Group Taiwan (AWSUG TW) 社團分享喔 :)

延伸閱讀

Loading comments…