ECS on Fargate を踏み台にした RDS(Aurora) への接続について(CFn付き)

記事タイトルとURLをコピーする

こんにちは。AWS CLI が好きな福島です。

はじめに

プライベート環境の EC2 には、SSM の Session Manager(以降、Session Manager) を使うことで踏み台サーバーなしで接続できますが、RDS への接続には通常、踏み台サーバーが必要になります。

多くの場合、踏み台には EC2 を利用しますが、先日 ECS on Fargate を踏み台として RDS に接続する検証を行いました。

この方法については既に多くの方がブログで紹介されていますが、備忘録として私もまとめておきます。

参考

イメージ図

図の通り、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 を利用する場合、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 に変更

前提

  • 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) への接続について、ブログをまとめました。 どなたかのお役に立てれば幸いです。

福島 和弥 (記事一覧)

2019/10 入社

AWS CLIが好きです。