経緯
今まで、ローカルPCでSAMを起動し、EC2踏み台サーバーを通して、プライベートサブネットのRDSに接続、SQLコマンドをPythonで叩いて、データ補完をしていました。
処理時間は、1日分の処理につき、実行時間が約1時間半かかるデータ補完処理です。
ローカルでDockerを起動するので、EC2インスタンス起動代だけなので、
お金はかかりませんが、「今後もデータ補完するときに課題になるな、、」と感じてました。
AWSのサポート様に問い合わせる
AWSのサポート様に、
「データ補完処理で困ってるんですが、良いサービスはありませんかね・・・?」と聞いてみました。
(AWSサポート様の回答) ECS使うと良いですよー。
なるほど。ECSですか。
良い機会なので、検証も兼ねて試してみることに。
爆速でデータ補完できた
実行環境 | ECS(Fargate) vCPU: 1vCPU メモリ:3 GB |
(従来) ローカルPCでの実行(SAM) |
---|---|---|
データ補完にかかる日数 | 1.7日 | 16.0日 |
ローカルPC実行との削減率 | 89% | - |
データ補完にかかる料金 | 374.4円 | 0円 |
[内訳]
ECSを1時間稼働させた時の料金: 9.0円
稼働時間: 41.6時間
データ補完にかかる料金: 9.0円 * 41.6時間 = 374.4円
ローカルPC実行(SAM)と、ECSを使った際の比較です。
驚異の89%の削減率!
料金も想定よりずっと安い!
処理時間も大幅に削減できました!
※料金について
AWS公式の料金表と、「ざっくりAWS様」にて算出しました。
大幅に短縮できた要因
処理時間が大幅に短縮できた要因としては、以下が考えられます。
※あくまで考察です。
1. ECSとRDSを同じプライベートサブネットに配置しているから
(※ローカルPC実行のように、EC2踏み台サーバーを経由する必要がなくなったから)
2. AWSの処理リソースである、Fargate自体が演算処理のリソースとして優秀だから
今回のAWS構成図
今回は、上記の構成で検証しました。
本記事では、サブネットの作成やRDSの配置・作成などは省略します。
※AWS Secrets Managerは、「シークレット名:postgres」で設定しています。
以下の3点に絞って、記事を投稿します。
1. DockerイメージをECRにPushする
2. ECS関係の設定をする
3. ECSを実行する
今回の記事にて、関係するAWSリソース
- Amazon ECS
- Amazon ECR
- AWS Fargate
- AWS Secrets Manager
- Amazon RDS for PostgreSQL
Amazon ECS
- AWSでDockerコンテナ実行する際のオーケストレーションサービス。(いわゆる、コンテナを管理するもの)
- このサービスは管理がメインなので、コンテナ実行は、AWS Fargateで行います。
Amazon ECR
- コンテナイメージをリポジトリとして管理するサービス。
- ECSは、このECRのリポジトリをPullしてきて、実行するようにします。
AWS Fargate
- サーバーレスで演算実行できるサービス。
- 従量課金制だが、実行環境のvCPUとメモリの設定を適切に設定(オートスケーリングなど)をすれば、金額は抑えられる。
AWS Secrets Manager
- データベース認証情報や API キーなどの機密情報を管理できるサービス。
Amazon RDS for PostgreSQL
- RDS。AWSでPostgreSQLを使えるサービス。
コード・ツリー図
今回は、ECSからRDSへ接続できるかを確認できる、
コードを準備します。
コードは、以下の記事を参考にさせて頂きました。
.
└── repo-ecs/
├── main.py
├── Dockerfile
└── requirements.txt
from time import sleep
import json
import psycopg2
import boto3
try:
print("RDS: 接続成功")
except Exception as e:
print("RDS: 接続失敗")
def connect_rds():
# SecretsManagerからRDSの認証情報を取得
client = boto3.client(service_name='secretsmanager')
get_secret_value_response = client.get_secret_value(
SecretId='postgres')
secret_info_rds = json.loads(get_secret_value_response['SecretString'])
# DBの接続設定
connection_config = {
'host': secret_info_rds['host'],
'port': secret_info_rds['port'],
'database': secret_info_rds['dbname'],
'user': secret_info_rds['username'],
'password': secret_info_rds['password'],
'connect_timeout': 3,
}
# 接続
connection = psycopg2.connect(**connection_config)
return connection
if __name__ == '__main__':
# RDSへ接続
con = connect_rds()
boto3
psycopg2
Dockerfile
# RUNはイメージをビルドする際に使用するコマンド
# WORKDIRは作業ディレクトリを指定するコマンド
# COPYはイメージにファイルやフォルダを追加するコマンド
# pythonの3.8をベースにする
FROM python:3.8-buster
# 作業ディレクトリを指定
WORKDIR /
# pipのアップグレード
RUN pip install --upgrade pip
# requirements.txtを配置
COPY requirements.txt /
# ライブラリをインストール
RUN pip install -r requirements.txt
# ソースコードの配置・実行
# Pythonはデフォルトで buffer をするようになっているため、"-u"で buffer をしないように設定する。
COPY main.py /
CMD [ "python", "-u", "/main.py" ]
設定手順
1. DockerイメージをECRにPushする
1.1 ECRにアクセスして、「リポジトリを作成」
1.2 リポジトリ名を入力して、作成
1.3 リポジトリをPushする
プッシュコマンドが表示されるので、案内通りにコマンドを打ちます。
コマンド実行後、ECRを確認すると、イメージがPushされたことが確認できます。
2. ECS関係の設定
次は、ECS関係の設定を行います。
2.1 セキュリティグループを作成する
以下の3つのセキュリティグループを作成します。
EC2の管理画面から、「セキュリティグループ」を選択し、作成します。
1. ECS用のセキュリティグループ(作成名:ecs-sg)
※インバウンドルールには、HTTPSのTCPポート番号443を設定してください。
2. RDS用のセキュリティグループ(作成名:rds-sg)
3. SecretsManager用のセキュリティグループ(作成名:sm-sg)
それぞれを作成後、インバウンドルールの編集で以下のようにルールを追加します。
1. ecs-sgに、rds-sgを追加
2. rds-sgに、ecs-sgを追加
3. sm-sgに、ecs-sgとrds-sgを追加
2.2 ECR用のエンドポイントを追加する
今回、Fargateの1.4.0を使うので、ECRのエンドポイントが必要になります。
EC2の管理画面から、「エンドポイント」を選択し、作成します。
1. com.amazonaws.region.ecr.dkr (作成名:ecr-dkr-endpoint)
2. com.amazonaws.region.ecr.api (作成名:ecr-api-endpoint)
3. com.amazonaws.region.s3(ゲートウェイ型)(作成名:ecr-CloudWatchLogs-endpoint)
作成する際には、ECS用のセキュリティグループ(作成名:ecs-sg)を選択してください。
以上で、ECR用のエンドポイントの追加は完了です。
2.3 ECSの設定・タスク定義を行う
ECSのコンソール画面を開き、左側のメニューから「タスク定義」を選択します。
「タスク定義とコンテナの設定」の設定を行います。
- タスク定義ファミリー:任意(今回:taskConnectionRDS)
- コンテナの詳細
- 名前:任意 (今回:containerConnectionRDS)
- イメージ URI:ECRのURI名(:latestまで入れましょう)
※ECRのURI名は、ECRのリポジトリで確認できます。
設定後、「次へ」を選択。
「環境、ストレージ、モニタリング、タグの設定」の設定 を行います。
- アプリケーション環境:Fargate
- タスクサイズ:任意
※スペックによって、料金が変わるので注意。
私の場合、1vCPU・3GBの初期設定でも十分な性能でした。 - タスクロール、タスク実行ロール:ecsTaskExecutionRole(このロールは自動で作成されます。)
2.4 ECSの設定・クラスター作成を行う
次は、クラスター作成を行います。
ECSのコンソール画面を開き、左側のメニューから「クラスター」を選択します。
「クラスターの作成」の設定
- クラスター名:任意 (今回:clusterConnectionRDS)
- ネットワーキング:
上記を設定後、作成を選択します。
クラスターが作成されました。
2.5 ecsTaskExecutionRoleロールに権限を付与する
IAMにて、ecsTaskExecutionRoleに以下の権限を付与しましょう。
- AmazonRDSFullAccess
- SecretsManagerReadWrite
- AmazonECSTaskExecutionRolePolicy
- EC2InstanceProfileForImageBuilderECRContainerBuilds
- AWSAppRunnerServicePolicyForECRAccess
ECSの設定は以上になります。
3. ECSを実行する
「タスク定義」を選択、作ったタスク定義を選択し、「デプロイ」、「タスクの実行」を選択します。
「作成」の設定を行います。
- 既存のクラスター:clusterConnectionRDSを選択
- ネットワーキング:
- VPC:任意のVPC
- サブネット:プライベートサブネットの2つ
※パブリックサブネットは選択しない点に注意。
- セキュリティグループ
- 既存のセキュリティグループを使用 「ecs-sg」を選択
- パブリックIP:オン
作成を押すと、タスク実行開始。 ECRのコードが実行されます。
CloudWatchでログを確認すると、RDSに接続できることが確認できました。
終わりに
以上の設定で、ECSからRDSに接続し、SQLコマンドを使ってSELECTやINSERTなどができるようになります。
処理スピードが早すぎて驚いていました。
設定はあまり難しくはないと思うので、色々試してみると面白いかもしれません。
指摘事項などいただけると幸いです!