この記事はAWS Containers Advent Calendar 2021の7日目です。
業務でAWS Fargateを使ってシステムを構築しているんですが、手元から直接DBにアクセスしたい作業などがあるのでポートフォワーディングをなんとかできないかと考えていました。
ECS ExecがマネージドなSSMエージェントで動いているようだったので、なんとなくポートフォワーディングできそうな雰囲気を感じていたのですが、マネージドなSSMエージェントを使う具体的なやり方は不明。
- New – Amazon ECS Exec による AWS Fargate, Amazon EC2 上のコンテナへのアクセス | Amazon Web Services ブログ
-
デバッグ用にAmazon ECS Exec を使用 - Amazon ECS
− AWS Fargateで動いているコンテナにログインしたくて Systems Manager の Session Manager を使ってみた話 - SMARTCAMP Engineer Blog - 踏み台EC2を廃止してSession Manager接続に置き換えました | by Daichi Harada | Eureka Engineering | Medium
多分、aws ssm start-session
の--target
に何かを渡せば良さそうですが、何を渡せばいいのかわからず。aws ecs execute-command
実行時にsession-manager-pluginを実行しているようだったので、とりあえずpsコマンドを打ってみたところ
sugawara 80091 0.1 0.1 5441620 17444 s002 S+ 4:39PM 0:00.11 session-manager-plugin {"sessionId": "ecs-execute-command-0acebb01a1ed41142", "streamUrl": "wss://ssmmessages.ap-northeast-1.amazonaws.com/v1/data-channel/ecs-execute-command-0acebb01a1ed41142?role=publish_subscribe", "tokenValue": "(省略)"} ap-northeast-1 StartSession {"Target": "ecs:hello_7412261320c54ef9a1ae606175e9bec1_7412261320c54ef9a1ae606175e9bec1-3811061257"} https://ecs.ap-northeast-1.amazonaws.com
"Target": "ecs:hello_7412261320c54ef9a1ae606175e9bec1_7412261320c54ef9a1ae606175e9bec1-3811061257"
という謎の文字列。
ドキュメントを探しても見当たらなかったので、AWS CLIのソースコードを読みました。
def build_ssm_request_paramaters(response, client):
cluster_name = response['clusterArn'].split('/')[-1]
task_id = response['taskArn'].split('/')[-1]
container_name = response['containerName']
# in order to get container run-time id
# we need to make a call to describe-tasks
container_runtime_id = \
get_container_runtime_id(client, container_name,
task_id, cluster_name)
target = "ecs:{}_{}_{}".format(cluster_name, task_id,
container_runtime_id)
ssm_request_params = {"Target": target}
return ssm_request_params
クラスタ名・タスクID・コンテナIDでTergetの文字列を構築している模様。クラスタ名・タスクID・コンテナ名がわかっているなら、以下のように直接aws ssm start-session
を実行できます。
CLUSTER=hello
TASK_ID=7412261320c54ef9a1ae606175e9bec1
CONTAINER_NAME=busybox
CONTAINER_ID=$(aws ecs describe-tasks \
--cluster $CLUSTER \
--task $TASK_ID \
| jq -r --arg N=$CONTAINER_NAME \
'.tasks[0].containers[] | select(.name == $N).runtimeId')
$ aws ssm start-session --target ecs:${CLUSTER}_${TASK_ID}_${CONTAINER_ID}
Starting session with SessionId: root-06ad4aa7ce3831373
#
SSMドキュメントを指定すればポートフォワーディングも可能です。
$ aws ssm start-session \
--target ecs:${CLUSTER}_${TASK_ID}_${CONTAINER_ID} \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["8080"],"localPortNumber":["18080"]}'
Starting session with SessionId: root-08212759680ea948b
Port 18080 opened for sessionId root-08212759680ea948b.
Waiting for connections...
Connection accepted for session [root-08212759680ea948b]
$ curl localhost:18080
Hello World!
これでコンテナにstoneでも入れておけば、Fargateのタスクを踏み台にしてDBにアクセスできるようになりました。
※ちなみに一連のTarget文字列生成とaws ssm start-session
をまとめて行うecs-exec-pfというコマンドも作成しました。