はじめに
今回は既存のLambdaで実行していたpythonプログラムを、Fargateでも実行できるように試行錯誤した備忘録を記録する。前提として、ECRやECS、Task定義は設定済。ECRやECS、Task定義などの設定の記録については以下記事に記録してある。↓
また、今回最終的に構築したいのは以下のような構成だが、本記事ではとりあえずPublisher Fargateを手動で起動(Task Run)できたところまでを記録する。
ちなみに、FargateではなくLambdaを用いた元々の構成を構築するまでの記録は以下記事に残してある。
(以下記事からさらに遡って追っていく必要があるのは申し訳ない。興味ある人だけ。)↓
今回は以下の順序で実施記録を整理していく。
- 実行したいDockerイメージをECRにプッシュ
- Task実行とエラー
- エラーを解決して再度Task実行して動作確認
実行するpythonプログラムを含むDockerイメージをECRにプッシュ
python
本来はAPIリクエストから受け取るメッセージ内容をMessage
にセットしたいが、とりあえず固定文字で進めていく。
import base64
import boto3
from datetime import datetime
import json
client = boto3.client('sns', region_name='ap-northeast-1')
def main():
print('fargate started')
params = {
'TopicArn': 'arn:aws:sns:ap-northeast-1:123456789012:myFirstTopic_std',
'Subject' : 'Published From: deliverTopicToSNS_Test01',
'Message' : 'fargate message'
}
try:
response = client.publish(
TopicArn = params['TopicArn'],
Subject = params['Subject'],
Message = params['Message']
)
print(json.dumps(response))
return {
'statusCode': 200,
'body': json.dumps('A new message has been published')
}
except Exception as e:
print(e)
raise e
main()
ちなみにboto3.client()
としているところで、region_name
を指定していないとFargateでの実行時にNoRegionError
が発生した。Lambdaで記述していた時には不要なパラメータだったが、Fargateでは必要なのだろうか?
Dockerfile
pythonは元々Lambdaで動かしていた3.8を指定。
ENV PYTHONBUFFERED=1
としている。
ENTORYPOINT ["python", "./topic_publisher.py"]
としている。
このように記述することでpythonプログラムのprint()
の内容がCloudWatch Logsで確認できるようになるらしい。(詳しい方その原理を教えてください。)
FROM python:3.8
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY topic_publisher.py ./
ENV PYTHONUNBUFFERED=1
# CMD ["python", "./topic_publisher.py"]
ENTRYPOINT ["python", "./topic_publisher.py"]
ちなみにpythonのバージョンを指定していないと(恐らく)最新のバージョンが利用されるのだと思う。その場合に以下の記事にもあるCode ImportError
が発生した。今回はバージョンを3.8に指定することで解決した。
requirement.txt
以下のように利用boto3を指定
boto3==1.9.183
DockerイメージをECRへプッシュ
ECRコンソールから確認できるプッシュ手順に従ってコマンドを打っていく。まずはECRへの認証。
Taskを作成してRun
ECRにイメージがプッシュされて実行準備が整ったので、新規Taskをコンソールから作成して実行してみる。以下のTaskを実行(デプロイ)する。
このNetworkingの設定のところでインタネットに出るルーティングがされていないSubnetを選択していたり、Public IP付与をOFFにしているとCannotPullContainerError
が発生する。
エラー
ログを見てみるとUnable to locate credentials
と出ている。
こちらの参考記事にある通り、このエラーはECSのTaskロールがうまく設定されていないと発生するっぽい。
Task定義を確認してみると、確かにTaskロールの方は設定されていなかった。Task execution roleとは別に付与が必要らしい。
以下のようにTaskロールの方にも同じロールを付与し(本来は別々のロールが良いかと思うが、ここでは同じロールを使おうと思う)、
当該ロールに対して、AmazonSNSFullAccess
も付与しておく。SNSトピックを配信しているのでおそらく必要なポリシーだろう。
再実行
同じようにTaskを作成して再度Run。
今度は無事にTopicがpublishされた!
後続のLambdaなども想定通り動き、DynamoDBに新規Itemが格納され、手元にメールが届いたことも確認できました。
おわりに
所感として、ECS(Fargate)はLambdaよりも実行キャパが大きかったり時間制限がなかったりと、イベントドリブンでかつ処理が重いような機能の実行基盤としては向いていると思います。今回はコンソールから手動でTaskをRunしましたが、これをAPI Gateway経由で実行するようなところをこの後検証していこうと思います。
その他参考サイト