Fargate + ECR + ECS 構成による FastAPI 阿呆&馬鹿データベースサービスの稼働
通常コンテナ更新時サマリー
リージョン | クラスター名 | タスク定義ファミリー | サービス名 |
---|---|---|---|
$REGION | $CONTAINER_NAME-cluster | $SCONTAINER_NAME-definition | $CONTAINER_NAME-service |
-
ローカル端末でのコンテナサービステスト
cd ~/aws/mongodb && source ./Local_Container_Service_Test.sh
-
既存のAWS ECSのクラスター、タスク定義、サービFVスに対して更新
cd ~/aws/mongodb && source ./Upadte_Cluster_TaskDef_Service.sh
-
更新したECSサービスのタスクのパブリックIPを取得しテストを実行 ※数分待ってから実行
cd ~/aws/mongodb && source ./Get_ECS_Service_task_IP_Address.sh
-
サービスの実行例
hoge_foo POST サービス
cd ~/aws/mongodb && source ./Get_ECS_Service_task_IP_Address.sh BAKA_ID=C202310250001 && BAKA_NMAE="阿保田 太郎" && BOKE_ID=B00001 && COMP_NUM=02 echo $PUBLIC_IP':'$BAKA_ID':'$BAKA_NMAE':'$BOKE_ID':'$COMP_NUM curl -X 'GET' 'http://'$PUBLIC_IP curl -X 'POST' \ 'http://'$PUBLIC_IP'/hoge_foo/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "foo": { "id_foo": "'$BAKA_ID'", "name": "'$BAKA_NMAE'" }, "job_description": { "bakatare_ID": "'$BOKE_ID'", "JD_Number": "'$COMP_NUM'" } }'
Dockerファイル
Dockerfile_$CONTAINER_NAME
FROM --platform=linux/amd64 tiangolo/uvicorn-gunicorn-fastapi:python3.11
#FROM --platform=linux/amd64 python:3.11.4-slim-buster
# 作業ディレクトリを設定する
WORKDIR /app
# 既存のディレクトリを削除
RUN rm -rf /app/*
# 必要なパッケージをインストールする
RUN apt-get update && apt-get install -y git
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" /dev/null
RUN git clone https://ghp_AAAABbbbbcccDDDDFFFFhhh@github.com/baka-mono/mongodb.git .
RUN pip install --upgrade pip
RUN pip3 install -r requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
# アプリケーションを実行する
ENV AWS_DEFAULT_REGION=us-east-1
ENV AWS_ACCESS_KEY_ID=ABCDEFGHIJKLMNOPQ
ENV AWS_SECRET_ACCESS_KEY=abcd123abcd123abcd123abcd123
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
シェルスクリプト
-
ローカル端末でのコンテナサービステスト
./Local_Container_Service_Test.sh
## 0. 環境変数を設定 export AWS_ACOUNT_ID=12345678901 export REGION=us-east-1 export AWS_PROFILE=bakaconf export CONTAINER_NAME=foo_bakatare export KIND=fastapi export IMAGE_MAME=$CONTAINER_NAME'-'$KIND ## 1. GitHubリモートリモートリポジトリの更新 git add . && git commit -m "regular update" && git push -u origin main ## 2. Dockerコンテナをビルド cd ~/aws/mongodb/ && docker ps -a && docker images && ./remove_container.sh $CONTAINER_NAME docker build -t $IMAGE_MAME -f Dockerfile_$CONTAINER_NAME . docker ps -a && docker images ## 3. Dockerコンテナサービスを実行 docker run -d -p 80:80 --name $IMAGE_MAME $IMAGE_MAME sleep 6 docker ps -a && docker images ## 4. Dockerコンテナの稼働状況ログを出力 docker logs $(docker ps -q --filter "name=$CONTAINER_NAME-fastapi") ## 5. ローカル端末でサービスをテスト echo "ーーー" && echo "【テスト】<foote テーブル>バカのヒートマップ用インデックス" curl -X 'POST' \ 'http://localhost/foo/heatmap/baaba/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"id_foo":"C202310250001","name":"阿保田 太郎"}' echo "ーーー" && echo "【テスト】<foote テーブル>ジジイの「現状の抜作」と「今後の間抜」ヒートマップ用インデックス" curl -X 'POST' \ 'http://localhost/foo/heatmap/booo/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"id_foo":"C202310250001","name":"阿保田 間抜け"}' echo "ーーー" && echo "【テスト】<aho_bakatareテーブル>バカのヒートマップ用インデックス" curl -X 'POST' \ 'http://localhost/job_description/heatmap/baaba/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"bakatare_ID":"B00001","JD_Number":"02"}' echo "ーーー" && echo "【テスト】<aho_bakatareテーブル>ジジイの「現状の抜作」と「今後の間抜け」ヒートマップ用インデックス" curl -X 'POST' \ 'http://localhost/job_description/heatmap/booo/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"bakatare_ID":"B00001","JD_Number":"02"}'
-
既存のクラスター、タスク定義、サービスに対して更新
./Upadte_Cluster_TaskDef_Service.sh
#--------------------------------------------------- # 既存のクラスター、タスク定義、サービスに対して更新をかける #--------------------------------------------------- ## 0. 環境変数を設定 export AWS_ACOUNT_ID=12345678901 export REGION=us-east-1 export AWS_PROFILE=bakaconf export CONTAINER_NAME=foo_bakatare export KIND=fastapi export IMAGE_MAME=$CONTAINER_NAME'-'$KIND ## 1. GitHubリモートリモートリポジトリの更新 git add . && git commit -m "regular update" && git push -u origin main ## 2. Dockerコンテナをビルドし、コンテナイメージにタグを付与 cd ~/aws/mongodb/ && docker ps -a && docker images && ./remove_container.sh $CONTAINER_NAME docker build -t $IMAGE_MAME -f Dockerfile_$CONTAINER_NAME . TAG_NAMING='docker tag '$IMAGE_MAME':latest '$AWS_ACOUNT_ID'.dkr.ecr.'$REGION'.amazonaws.com/'$IMAGE_MAME':latest' eval $TAG_NAMING docker ps -a && docker images ## 3. 認証トークンを取得し、レジストリに対して Docker クライアントを認証 echo $AWS_ACOUNT_ID' : '$REGION' : '$AWS_PROFILE' : '$CONTAINER_NAME' : '$KIND' : '$IMAGE_MAME aws ecr get-login-password --region $REGION --profile $AWS_PROFILE | docker login --username AWS --password-stdin $AWS_ACOUNT_ID.dkr.ecr.us-east-1.amazonaws.com ## 4. DockerイメージをECRにプッシュ docker push $AWS_ACOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$IMAGE_MAME ## 5. 新しいタスク定義を登録 aws ecs register-task-definition \ --family $CONTAINER_NAME-definition \ --network-mode awsvpc \ --requires-compatibilities FARGATE \ --cpu "256" \ --memory "512" \ --execution-role-arn arn:aws:iam::$AWS_ACOUNT_ID':role/ecsTaskExecutionRole' \ --container-definitions '[ { "name": "foo_bakatare-container", "image": "'$AWS_ACOUNT_ID'.dkr.ecr.'$REGION'.amazonaws.com/'$IMAGE_MAME':latest", "essential": true, "portMappings": [ { "containerPort": 80, "hostPort": 80 } ] } ]' \ --region $REGION ## 6. 新しいタスク定義のARNを取得 NEW_TASK_DEF_ARN=$(aws ecs describe-task-definition --task-definition $CONTAINER_NAME-definition --query 'taskDefinition.taskDefinitionArn' --output text) ## 7. 新しいタスク定義を使用して既存のサービスを更新 aws ecs update-service \ --cluster $CONTAINER_NAME-cluster \ --service $CONTAINER_NAME-service \ --task-definition $NEW_TASK_DEF_ARN \ --force-new-deployment \ --region $REGION
-
更新したECSサービスのタスクのパブリックIPを取得しテストを実行
./Get_ECS_Service_task_IP_Address.sh
#--------------------------------------------------- # 更新したECSサービスのタスクのパブリックIPを取得 #--------------------------------------------------- ## 0. 定数を設定 AWS_ACOUNT_ID=12345678901 && REGION=us-east-1 && AWS_PROFILE=bakaconf && CONTAINER_NAME=foo_bakatare && KIND=fastapi && IMAGE_MAME=$CONTAINER_NAME'-'$KIND ## 1. 実行中のタスクのARNを取得: TASK_ARN=$(aws ecs list-tasks --cluster $CONTAINER_NAME-cluster --service-name $CONTAINER_NAME-service --desired-status RUNNING --query 'taskArns[0]' --output text) echo $TASK_ARN ## 2. タスクの詳細を取得: ENI_ID=$(aws ecs describe-tasks --cluster $CONTAINER_NAME-cluster --tasks $TASK_ARN --query 'tasks[0].attachments[0].details[?name==`networkInterfaceId`].value' --output text) echo $ENI_ID ## 3. ENI(Elastic Network Interface)のパブリックIPを取得: PUBLIC_IP=$(aws ec2 describe-network-interfaces --network-interface-ids $ENI_ID --query 'NetworkInterfaces[0].Association.PublicIp' --output text) echo $PUBLIC_IP ## 4. パブリックIPを使用してサービスをテスト: echo "" && echo "【テスト】バカのヒートマップ用インデックス" curl -X 'POST' \ 'http://'$PUBLIC_IP'/foo/heatmap/baaba/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"id_foo":"C202310250001","name":"阿保田 間奴け"}' echo "" && echo "" && echo "【テスト】ジジイの「現状の抜作」と「今後の間抜け」ヒートマップ用インデックス" curl -X 'POST' \ 'http://'$PUBLIC_IP'/foo/heatmap/booo/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"id_foo":"C202310250001","name":"阿保だ 太郎"}' echo "" && echo "" && echo "【テスト】<aho_bakatareテーブル>バカのヒートマップ用インデックス" curl -X 'POST' \ 'http://'$PUBLIC_IP'/aho_bakataren/heatmap/baaba/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"bakatare_ID":"B00001","JD_Number":"02"}' echo "" && echo "" && echo "【テスト】<aho_bakatareテーブル>ジジイの「現状の抜作」と「今後の間抜」ヒートマップ用インデックス" curl -X 'POST' \ 'http://'$PUBLIC_IP'/aho_bakatare/heatmap/booo/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"bakatare_ID":"B00001","JD_Number":"02"}'
-
動作中のコンテナを停止し、イメージを削除する
./remove_container.sh
CONTAINER_NAME=$1 docker stop $CONTAINER_NAME-fastapi && docker rm -f $CONTAINER_NAME-fastapi docker rmi $(docker images $CONTAINER_NAME-fastapi --format "{{.ID}}") docker rmi -f $(docker images -q) docker ps -a && docker images
初回登録
-
AWS CLIの設定情報を確認
cat ~/.aws/config
実行結果
[default] region = us-east-1 aws_access_key_id = ABCDEFGHIJKLMNOPQ aws_secret_access_key = abcd123abcd123abcd123abcd123 [profile bakaconf] region = us-east-1 aws_access_key_id = ABCDEFGHIJKLMNOPQ aws_secret_access_key = abcd123abcd123abcd123abcd123 [profile usprod] region = us-east-1 aws_access_key_id = ABCDEFGHIJKLMNOPQ aws_secret_access_key = abcd123abcd123abcd123abcd123 [profile prod] region = ap-northeast-1 aws_access_key_id = ABCDEFGHIJKLMNOPQ aws_secret_access_key = abcd123abcd123abcd123abcd123 [profile dev] region = ap-northeast-1 aws_access_key_id = IJKLMNOPQRSTUVW aws_secret_access_key = dfususow8754dd
-
認証トークンを取得し、レジストリに対して Docker クライアントを認証
-
リージョン:
バージニア北部
の場合AWS_ACOUNT_ID=12345678901 && REGION=us-east-1 && AWS_PROFILE=bakaconf && CONTAINER_NAME=foo_bakatare && KIND=fastapi && IMAGE_MAME=$CONTAINER_NAME'-'$KIND aws ecr get-login-password --region $REGION --profile $AWS_PROFILE | docker login --username AWS --password-stdin $AWS_ACOUNT_ID.dkr.ecr.us-east-1.amazonaws.com
実行結果
Login Succeeded
<
details
-
-
Dockerコンテナをビルドし、コンテナイメージにタグを付与
cd ~/aws/mongodb/ && docker ps -a && docker images && ./remove_container.sh $CONTAINER_NAME docker build -t $IMAGE_MAME -f Dockerfile_$CONTAINER_NAME . 'docker tag '$IMAGE_MAME':latest '$AWS_ACOUNT_ID'.dkr.ecr.'$REGION'.amazonaws.com/'$IMAGE_MAME':latest' docker ps -a && docker images
-
FastAPIサービスのDockerコンテナをポート80でローカル端末でテスト実行
docker run -d -p 80:80 --name $IMAGE_MAME $IMAGE_MAME
- ローカルURL : http://localhost/docs
-
AWS ECRリポジトリを作成し、タグ付けしたコンテナイメージをプッシュ
aws ecr create-repository --repository-name $IMAGE_MAME docker push $AWS_ACOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$IMAGE_MAME':latest'
実行結果
{ "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:12345678901:repository/foo_bakatare-fastapi", "registryId": "12345678901", "repositoryName": "foo_bakatare-fastapi", "repositoryUri": "12345678901.dkr.ecr.us-east-1.amazonaws.com/foo_bakatare-fastapi", "createdAt": "2024-10-06T16:47:12.317000+09:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": false }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
The push refers to repository [12345678901.dkr.ecr.us-east-1.amazonaws.com/foo_bakatare-fastapi] f4e81d585f22: Pushed e46ea3317667: Pushed 0326df620ed2: Pushed 6ddff48d9c6e: Pushed 5f70bf18a086: Pushed 6d835c0b5006: Pushed 9ce5156d8e4e: Pushed 7cda1b8c5bbf: Pushed cf0e723ea047: Pushed 0a9ccad5eb69: Pushed 30bc2dab5899: Pushed 20d5b086fe88: Pushed ba8e44410c8a: Pushed 8628259c120e: Pushed e8b56a267ef1: Pushed 8325e8413ce3: Pushed 228e477f5903: Pushed dd3bb83a5529: Pushed 5dd1f684416f: Pushed 3a8081ce85fa: Pushed 045d8b74bf0d: Pushed 25879f85bbb0: Pushed 6abe10f2f601: Pushed latest: digest: sha256:f788e5906d33102f89921e6709122af205df824c2a798a16cb9e046c0f2630fa size: 5332
-
ECSでFargateを使用する【クラスター】を作成
aws ecs create-cluster --cluster-name $CONTAINER_NAME-cluster --region $REGION
実行結果
{ "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:12345678901:repository/foo_bakatare-fastapi", "registryId": "12345678901", "repositoryName": "foo_bakatare-fastapi", "repositoryUri": "12345678901.dkr.ecr.us-east-1.amazonaws.com/foo_bakatare-fastapi", "createdAt": "2024-10-06T16:47:12.317000+09:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": false }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
-
ECSでFargateを使用する【タスク定義】を作成
aws ecs register-task-definition \ --family $CONTAINER_NAME-definition \ --network-mode awsvpc \ --requires-compatibilities FARGATE \ --cpu "256" \ --memory "512" \ --execution-role-arn arn:aws:iam::$AWS_ACOUNT_ID':role/ecsTaskExecutionRole' \ --container-definitions '[ { "name": "'$CONTAINER_NAME'-container", "image": "'$AWS_ACOUNT_ID'.dkr.ecr.'$REGION'.amazonaws.com/'$IMAGE_MAME':latest", "essential": true, "portMappings": [ { "containerPort": 80, "hostPort": 80 } ] } ]' \ --region $REGION
実行結果
{ "name": "foo_bakatare-container", "image": "12345678901.dkr.ecr.us-east-1.amazonaws.com/foo_bakatare-fastapi:latest", "environment": [], "mountPoints": [], "volumesFrom": [], "systemControls": [] } ], "family": "foo_bakatare-definition", "executionRoleArn": "arn:aws:iam::12345678901:role/ecsTaskExecutionRole", "networkMode": "awsvpc", "revision": 1, "volumes": [], "status": "ACTIVE", "requiresAttributes": [ { "name": "com.amazonaws.ecs.capability.ecr-auth" }, { "name": "ecs.capability.execution-role-ecr-pull" }, { "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18" }, { "name": "ecs.capability.task-eni" } ], "placementConstraints": [], "compatibilities": [ "EC2", "FARGATE" ], "requiresCompatibilities": [ "FARGATE" ], "cpu": "256", "memory": "512", "registeredAt": "2024-10-06T17:42:50.486000+09:00", "registeredBy": "arn:aws:iam::12345678901:user/T_Sameshima" }
-
ECS上に【サービス】を新規作成
リージョン | クラスター名 | タスク定義ファミリー | サービス名 |
---|---|---|---|
$REGION | $CONTAINER_NAME-cluster | $CONTAINER_NAME-definition | $CONTAINER_NAME-service |
タスク実行ロール | セキュリティグループID | プロトコル | ポート範囲/ソース |
arn:aws:iam::$AWS_ACOUNT_ID':role/ecsTaskExecutionRole' | sg-sodkoasdokosakdos0 | HTTP / TCP | 80/0.0.0.0/0 |
サブネット1 | サブネット2 | サブネット3 | パブリックIPアドレス設定 |
subnet-jijadfisajiffs", "subnet-asfasfksaokfosakofkas" | "subnet-sfusfu8af8asf","subnet-fasf89sa89f8sa98f9" | "subnet-asff09sa0f90sa", "subnet-fsaf0jfoasjof | 有効 |
-
コマンド
aws ecs create-service \ --cluster $CONTAINER_NAME-cluster \ --service-name $CONTAINER_NAME-service \ --task-definition $CONTAINER_NAME-definition \ --desired-count 1 \ --launch-type FARGATE \ --network-configuration '{ "awsvpcConfiguration": { "subnets": ["subnet-jijadfisajiffs", "subnet-asfasfksaokfosakofkas", "subnet-sfusfu8af8asf", "subnet-fasf89sa89f8sa98f9", "subnet-asff09sa0f90sa", "subnet-fsaf0jfoasjof"], "securityGroups": ["sg-sodkoasdokosakdos0"], "assignPublicIp": "ENABLED" } }' \ --region $REGION
実行結果
{ "service": { "serviceArn": "arn:aws:ecs:us-east-1:12345678901:service/foo_bakatare-cluster/foo_bakatare-service", "serviceName": "foo_bakatare-service", "clusterArn": "arn:aws:ecs:us-east-1:12345678901:cluster/foo_bakatare-cluster", "loadBalancers": [], "serviceRegistries": [], "status": "ACTIVE", "desiredCount": 1, "runningCount": 0, "pendingCount": 0, "launchType": "FARGATE", "platformVersion": "LATEST", "platformFamily": "Linux", "taskDefinition": "arn:aws:ecs:us-east-1:12345678901:task-definition/foo_bakatare-definition:1", "deploymentConfiguration": { "deploymentCircuitBreaker": { "enable": false, "rollback": false }, "maximumPercent": 200, "minimumHealthyPercent": 100 }, "deployments": [ { "id": "ecs-svc/222222222222222", "status": "PRIMARY", "taskDefinition": "arn:aws:ecs:us-east-1:12345678901:task-definition/foo_bakatare-definition:1", "desiredCount": 0, :...skipping... { "service": { "serviceArn": "arn:aws:ecs:us-east-1:12345678901:service/foo_bakatare-cluster/foo_bakatare-service", "serviceName": "foo_bakatare-service", "clusterArn": "arn:aws:ecs:us-east-1:12345678901:cluster/foo_bakatare-cluster", "loadBalancers": [], "serviceRegistries": [], "status": "ACTIVE", "desiredCount": 1, "runningCount": 0, "pendingCount": 0, "launchType": "FARGATE", "platformVersion": "LATEST", "platformFamily": "Linux", "taskDefinition": "arn:aws:ecs:us-east-1:12345678901:task-definition/foo_bakatare-definition:1", "deploymentConfiguration": { "deploymentCircuitBreaker": { "enable": false, "rollback": false }, "maximumPercent": 200, "minimumHealthyPercent": 100 }, "deployments": [ { "id": "ecs-svc/222222222222222", "status": "PRIMARY", "taskDefinition": "arn:aws:ecs:us-east-1:12345678901:task-definition/foo_bakatare-definition:1", "desiredCount": 0, "pendingCount": 0, "runningCount": 0, "failedTasks": 0, "createdAt": "2024-10-06T20:43:04.919000+09:00", "updatedAt": "2024-10-06T20:43:04.919000+09:00", "launchType": "FARGATE", "platformVersion": "1.4.0", "platformFamily": "Linux", "networkConfiguration": { "awsvpcConfiguration": { "subnets": [ "subnet-jijadfisajiffs", "subnet-asfasfksaokfosakofkas", "subnet-sfusfu8af8asf", "subnet-fasf89sa89f8sa98f9", "subnet-asff09sa0f90sa", "subnet-fsaf0jfoasjof" ], "securityGroups": [ "sg-06dd2174e159caea2" ], "assignPublicIp": "ENABLED" } }, "rolloutState": "IN_PROGRESS", "rolloutStateReason": "ECS deployment ecs-svc/222222222222222 in progress." } ], "roleArn": "arn:aws:iam::12345678901:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS", "events": [], "createdAt": "2024-10-06T20:43:04.919000+09:00", "placementConstraints": [], "placementStrategy": [], "networkConfiguration": { "awsvpcConfiguration": { "subnets": [ "subnet-jijadfisajiffs", "subnet-asfasfksaokfosakofkas", "subnet-sfusfu8af8asf", "subnet-fasf89sa89f8sa98f9", "subnet-asff09sa0f90sa", "subnet-fsaf0jfoasjof" ], "securityGroups": [ "sg-sodkoasdokosakdos0" ], "assignPublicIp": "ENABLED" } }, "schedulingStrategy": "REPLICA", "deploymentController": { "type": "ECS" }, "createdBy": "arn:aws:iam::12345678901:user/T_Sameshima", "enableECSManagedTags": false, "propagateTags": "NONE", "enableExecuteCommand": false }