こんにちは。AWS CLI が好きな福島です。
はじめに
プライベート環境の EC2 には、SSM の Session Manager(以降、Session Manager) を使うことで踏み台サーバーなしで接続できますが、RDS への接続には通常、踏み台サーバーが必要になります。
多くの場合、踏み台には EC2 を利用しますが、先日 ECS on Fargate を踏み台として RDS に接続する検証を行いました。
この方法については既に多くの方がブログで紹介されていますが、備忘録として私もまとめておきます。
参考
- ECS Exec に関するドキュメント
- Session Manager で ECS on Fargate に接続する際のターゲット ID
- 一次ソースを参考にすることを心がけているのですが、私が調べた限り、Session Manager のターゲットに指定する ID については、AWS のドキュメントには記載されていなかったため、以下の方のブログを参考にさせていただきました。
- 上記ブログを手かがりに調べたところ、ターゲットに指定するID(
ecs:クラスタ名_タスクID_コンテナID
) は、AWS CLI(aws ecs execute-command) のソースコードが1番公式に近い情報になりそうです- aws-cli/awscli/customizations/ecs/executecommand.py at c0edee0a7427b6e7b654df0696015e96105497a3 · aws/aws-cli · GitHub
- 私は以下の方のブログから AWS CLI のソースコードに
ecs:クラスタ名_タスクID_コンテナID
が記載されていることを知りました
イメージ図
図の通り、Fargate から RDS へ接続する方法は、2パターンの接続方法があります。
- ECS Exec を利用する方法
- ECS Exec の裏側で利用されている Session Manager(AWS-StartPortForwardingSessionToRemoteHost)を利用する
ポイント
踏み台にECS on Fargate を使う際のポイント
- ECS on Fargate を踏み台として利用するため、ECS Exec を有効化する
- ECS Exec は、裏側で Session Manager が利用されている
ECS Exec は、AWS Systems Manager (SSM) セッションマネージャーを使用して実行中のコンテナとの接続を確立
- ECS Exec を使用して Amazon ECS コンテナをモニタリングする - Amazon Elastic Container Service
- ECS Exec を利用する場合、RDS へは CLI による接続のみ可能
- Session Manager を利用する場合、CLI およびツールの利用が可能
- ECS Exec の裏側で利用されている SSM の機能は利用可能だが、セッションログ保存ができない点は注意
ECS Exec の外部コンテナで SSM セッションを開始することは可能ですが、セッションがログに記録されない可能性があります。ECS Exec 以外で開始されたセッションも、セッションクォータに対してカウントされません。IAM ポリシーを使用して Amazon ECS タスクに対する ssm:start-session アクションを直接拒否することで、このアクセスを制限することをお勧めします。
- ECS Exec を使用して Amazon ECS コンテナをモニタリングする - Amazon Elastic Container Service
- Fargate は、ECS Exec(Session Manager)を有効化しても、フリートマネージャーの画面から確認できないが、セッションマネージャーの画面から接続しているセッションを確認可能
- Fargate に Session Manager で接続する際のターゲットは、
ecs:クラスタ名_タスクID_コンテナID
となる
サンプル CFn のポイント
- 踏み台は常時起動が不要なケースが多いため、サービスではなく、タスクとして都度起動する
- コンテナ起動時に
sleep
コマンドを実行しているため、指定した時間が経過後、自動で停止できるsleep
する時間はタスク定義の環境変数で定義しており、CFn デプロイ時のパラメーターで調整可能- デフォルトは1時間
- Amazon ECR Public Gallery にある ubuntu のイメージを利用する
- ECS Exec のログ保存に必要な
script
が導入されているかつコンテナイメージが軽量だったため - 当初はAmazon Linux を使って検証していたのですが、
script
が導入されていなかったため、ubuntu に変更
- ECS Exec のログ保存に必要な
前提
- VPC, Subnet, SG などネットワークリソースが構築できていること
- Subnet から Systems Manager Session Manager (ssmmessages) のエンドポイントにアクセスできること
- (インターネットに接続できる環境もしくは ssmmessages の VPC エンドポイントにアクセスできればOK)
試してみる
環境構築
- ソースコードのダウンロード
git clone git@github.com:kazuya9831/blog-sample.git
- ディレクトリの移動
cd fargate-bastion
ディレクトリの構成は以下の通りです
$ tree fargate-bastion fargate-bastion ├── fargate-bastion.yml ## CloudFormation のテンプレート ├── parameter.json ## CloudFormation のパラメーターファイル └── tools ├── config-sample.ini ## スクリプト用の定義ファイルのサンプル └── ecs-task-run-and-connect.py ## 接続を簡素化するスクリプト 2 directories, 5 files $
- スタックの作成
aws cloudformation create-stack \ --stack-name fargate-bastion \ --template-body file://fargate-bastion.yml \ --parameters file://parameter.json \ --capabilities CAPABILITY_NAMED_IAM
- デプロイされるリソースは赤枠の箇所になります
タスクの起動
- タスク(コンテナ)を起動するために必要な変数を定義
CLUSTER_NAME="sample-ecs-cluster" TASK_DEFINITION="sample-task-definition" SUBNET_ID="subnet-xxxxxx" SECURITY_GROUP_ID="sg-xxxx"
- タスク(コンテナ)の起動
aws ecs run-task \ --cluster ${CLUSTER_NAME} \ --task-definition ${TASK_DEFINITION} \ --launch-type FARGATE \ --network-configuration "awsvpcConfiguration={ subnets=[${SUBNET_ID}], securityGroups=[${SECURITY_GROUP_ID}] }" \ --enable-execute-command
以下赤枠の箇所が起動されるイメージです。
動作確認
ECS Exec で接続
- クラスタ名の定義
CLUSTER_NAME="sample-ecs-cluster"
- タスクIDの取得
task_id=$(aws ecs list-tasks \ --cluster ${CLUSTER_NAME} \ --query "taskArns[]" --output text \ | cut -d/ -f 3 )
- コンテナ名の取得
container_name=$(aws ecs describe-tasks \ --cluster ${CLUSTER_NAME} \ --tasks ${task_id} \ --query "tasks[].containers[].name" \ --output text )
- ECS Exec を利用しコンテナへ接続
aws ecs execute-command \ --cluster ${CLUSTER_NAME} \ --task ${task_id} \ --container ${container_name} \ --interactive \ --command "/bin/sh"
実行結果例)
$ aws ecs execute-command \ --cluster ${CLUSTER_NAME} \ --task ${task_id} \ --container ${container_name} \ --interactive \ --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-aknprngnvx5jkqivi43tby2n2u #
- 必要に応じて、RDS へ接続
今回検証のため、maridb-client をインストールしていますが、 このような使い方をする場合は、必要なツールを導入したコンテナイメージをあらかじめ作成しておく方が良いかと思います。
# apt update : 省略 # # apt-get install mariadb-client : 省略 # # mysql -u admin -p -h fk-test-aurora.cluster-xxxx.ap-northeast-1.rds.amazonaws.com Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 39 Server version: 8.0.39 37a93b09 Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]>
Session Manager で接続
- クラスタ名の定義
CLUSTER_NAME="sample-ecs-cluster"
- タスクIDの取得
task_id=$(aws ecs list-tasks \ --cluster ${CLUSTER_NAME} \ --query "taskArns[]" --output text \ | cut -d/ -f 3 )
- ランタイムIDの取得
ECS Exec を実行する際はコンテナ名が必要になりますが、Session Manager の接続にはランタム ID が必要となります。
runtime_id=$(aws ecs describe-tasks \ --cluster "${CLUSTER_NAME}" \ --task "${task_id}" \ --query 'tasks[].containers[].runtimeId' \ --output text )
- Session Manager によるリモートポートフォワード
aws ssm start-session \ --target "ecs:${CLUSTER_NAME}_${task_id}_${runtime_id}" \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters '{ "portNumber":["3306"], "localPortNumber":["13306"], "host":["fk-test-aurora.cluster-xxxx.ap-northeast-1.rds.amazonaws.com"] }'
- 実行結果例)
## ターミナルA $ aws ssm start-session \ --target "ecs:${CLUSTER_NAME}_${task_id}_${runtime_id}" \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters '{ "portNumber":["3306"], "localPortNumber":["13306"], "host":["fk-test-aurora.cluster-xxxxxxx.ap-northeast-1.rds.amazonaws.com"] }' Starting session with SessionId: administrator-yhlrebbg9svtpbpz9663nz3vei Port 13306 opened for sessionId administrator-yhlrebbg9svtpbpz9663nz3vei. Waiting for connections...
別のターミナルを起動し、DB に接続するコマンドを実行します
## ターミナルB $ mysql -u admin -p -P 13306 -h 127.0.0.1 Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 223 Server version: 8.0.39 37a93b09 Copyright (c) 2000, 2025, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
参考) 踏み台 Fargate を楽に利用する
一部は値を固定化できるものの、タスクを都度起動するため、動的に変わる値もあり、 以下の工程を都度実施するのは正直めんどくさいです。
- ①タスクの起動
- ②クラスタ名の定義
- ③タスクIDの取得
- ④コンテナ名もしくはランタイムIDの取得
- ⑤ECS Exec もしくは Session Manager の接続
- ⑥RDS へ接続
そのため、ChatGPT を活用し、①−⑤を簡素化するスクリプトを書いてみました。 一応①の処理は無駄にタスクを起動しないよう、タスクが起動していた場合、処理をスキップするようにしています。
- CFn テンプレートが存在するディレクトリに移動
cd blog-sample/fargate-bastion
- config.ini を作成
cp -ip config-sample.ini config.ini vi config.ini
; [base] ; cluster = ECSクラスタ名 ; task_definition = タスク定義名 ; subnet = コンテナをデプロイするサブネットID ; security_group = コンテナに適用するセキュリティグループID ; [base.db-name1] ; db_host = リモートポートフォワードするDBホスト名 ; local_port = ローカルポート ; remote_port = リモートポート
- ECS Exec による接続
$ python tools/ecs-task-run-and-connect.py
実行結果例)
$ python tools/ecs-task-run-and-connect.py No existing task found. Running new task... Task started: arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxx:task/sample-ecs-cluster/0a0b8ec85b41405e84d0dfa1aa55b11f The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-q4tysfh8xrls8drhhodqxohy9y # exit
- Session Manager によるリモートポートフォワード
$ python tools/ecs-task-run-and-connect.py -d db-name1
実行結果例)
$ python tools/ecs-task-run-and-connect.py -d fk-test-aurora Found running task: arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxx:task/sample-ecs-cluster/0a0b8ec85b41405e84d0dfa1aa55b11f Starting session with SessionId: administrator-tc4a9rdh9yixl23c2dak2g7bau Port 13306 opened for sessionId administrator-tc4a9rdh9yixl23c2dak2g7bau. Waiting for connections...
終わりに
今回は、ECS on Fargate を踏み台にした RDS(Aurora) への接続について、ブログをまとめました。 どなたかのお役に立てれば幸いです。