EC2起動タイプのECSで運用しているアプリケーションを、外部サービスと連携したいとの要望があった。
ただ、連携したいサービスというのが、接続元のIPアドレスを指定して連携するタイプのサービスのため、IPアドレスを固定するのが要件。
EIPをアタッチしたEC2を別に立てて、そのサーバーを経由させるかと考えたが、EC2起動タイプのECSはbridgeネットワークのようなので、「クラスターとして作成されたEC2インスタンスにEIPを付与したらIPアドレス固定できるんじゃないか?」と思い付いた。
試してみたら、うまくいったのでメモ。
環境
Windows 10 Pro 64bit、AWS CLI v1.16.119、ECS CLI v1.12.1で確認。
コマンドは、Git v2.21.0のGit Bashで実行。
現在のIPアドレスの確認には、cman.jpのIPアドレス確認を使わせていただいた。
事前準備
作業ディレクトリに、docker-compose.ymlとindex.htmlを作成しておく。
docker-compose.ymlは以下。
version: "3" services: httpd: image: httpd:2.4.38-alpine ports: - "80:80" volumes: - /home/ec2-user/index.html:/usr/local/apache2/htdocs/index.html command: ["sh", "-c", "wget -q -O - https://www.cman.jp/network/support/go_access.cgi | grep keyHostName > /usr/local/apache2/htdocs/ip_address.js && httpd-foreground"]
index.htmlは以下。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>ip address check</title> <script src="ip_address.js"></script> <script> document.addEventListener('DOMContentLoaded', function(e) { document.getElementById('ip-address').textContent = 'ip address: ' + keyHostName; }); </script> </head> <body> <p id="ip-address"></p> </body> </html>
テスト実行
docker-compose.ymlとindex.htmlを作成したディレクトリをカレントディレクトリとして実行する。
ecs-cli up
直後に aws ecs list-container-instances
しても None
が返ってくるところでハマった。
結果を取得するには20秒程度待機が必要な模様。ひとまず、結果がNone以外になるまでwhileして待機した。
# 環境変数を設定 KEYPAIR=... CLUSTER_NAME=... EC2_SECRET=... # テストなのでEIPはコマンドで作成 EIP_ID=$(aws ec2 allocate-address --domain vpc --query AllocationId --output text) && echo "eip id > ${EIP_ID}" # EIPからIPアドレスを取得 EIP_ADDRESS=$(aws ec2 describe-addresses --allocation-ids ${EIP_ID} --query Addresses[0].PublicIp --output text) && echo "ip address > ${EIP_ADDRESS}" # クラスターの作成 ecs-cli up \ --capability-iam \ --keypair ${KEYPAIR} \ --instance-type t2.micro \ --size 1 \ --launch-type EC2 \ -c ${CLUSTER_NAME} # クラスターARNの取得、作成直後だとNoneが返るので繰り返す sleep 10s && CLUSTER_ARN=None && while [ 'None' = "${CLUSTER_ARN}" ]; do sleep 5s CLUSTER_ARN=$(aws ecs list-container-instances --cluster ${CLUSTER_NAME} --query containerInstanceArns[0] --output text) done && echo "cluster arn > ${CLUSTER_ARN}" # クラスターARNの「/」以降がコンテナIDのため切り出し CONTAINER_ID=${CLUSTER_ARN##*/} && echo "cluster id > ${CONTAINER_ID}" # EC2のIDを取得 EC2_ID=$(aws ecs describe-container-instances --cluster ${CLUSTER_NAME} --container-instances ${CONTAINER_ID} --query containerInstances[0].ec2InstanceId --output text) && echo "ec2 id > ${EC2_ID}" # EIPを設定 ASSOCIATE_ID=$(aws ec2 associate-address --allocation-id ${EIP_ID} --instance ${EC2_ID} --output text) && echo "associate id > ${ASSOCIATE_ID}" # EC2にindex.htmlをアップロード scp -i "${EC2_SECRET}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ./index.html ec2-user@${EIP_ADDRESS}:~/index.html # タスク起動 ecs-cli compose up -c ${CLUSTER_NAME} # ここでhttpにアクセス、EIPのアドレスが表示されていることを確認 read -p "check ip address > [http://${EIP_ADDRESS}]" # タスク停止 ecs-cli compose down -c ${CLUSTER_NAME} # EIPを外す aws ec2 disassociate-address --association-id ${ASSOCIATE_ID} # クラスターの削除 ecs-cli down -f -c ${CLUSTER_NAME} # 作成したEIPを削除 aws ec2 release-address --allocation-id ${EIP_ID}
振り返り
オートスケールは不要なアプリケーションのため、エラー処理など詰めていけば何とかなりそう。