Fargateでradikoを録音してS3に保存するCloudFormation
2019-09-19
- プログラミング
前にdockerでradikoを録音するようにした。
これを定期実行するためにVPSを借りているのだが、録音は1日のごくわずかな時間しか行わないので、録音していない時間は余計なコストがかかってしまう。また低スペックのVPSのためか、複数番組を同時に録音すると失敗することがある(まれに)。
Fargateでは実行している間だけしか金がかからないので安いはず。それに同時録音の問題も起きないだろう。というわけでFargateに乗り換えてみることにした。
(2021/11/30追記) この記事の続きを書いた。
やりたいこと
- Fargateを使ってradikoを録音するスクリプトを定期実行する
- 音声ファイルはS3に保存する
- 一連の構成はCloudFormationによって管理する
前提条件
- dockerコマンドが入っている
- AWSアカウントを持っている
CloudFormationでIAMの設定をしたりするので、強い権限が必要。 - AWS CLIが入っている
- S3の保存先バケットが作成されている
- 録音したい番組は関東エリアで放送されているもの
Fargateが東京にしかないので。(radikoプレミアムに対応したスクリプト使えばいけるはず。)
できたもの
前に作ったやつにFargate版を追加した。CloudFormationはcfディレクトリ下にある。
作業手順
ECRにDockerイメージを登録
-
リポジトリ作成
aws ecr create-repository --repository-name <REPOSITORY_NAME>
<REPOSITORY_NAME>
には好きなリポジトリ名を入れる(たとえばdocker_rec_radiko
)。
結果としてjsonが返る。その中のrepositoryUri
をあとで使う。 -
dockerイメージをビルド・タグ付け
docker build . -t <REPOSITORY_URI>
<REPOSITORY_URI>
には上で取得したrepositoryUri
を入れる。 -
docker login認証コマンド文字列を取得
aws ecr get-login --no-include-email
-
ログイン
上で取得したdocker login認証コマンド文字列をそのまま実行。
これでECRにpushできるようになる。 -
dockerイメージをECRにpush
docker push <REPOSITORY_URI>
-
ECRに登録されたことを確認
AWSのコンソールを見てもいいが、コマンドでもわかる。aws ecr describe-images --repository-name <REPOSITORY_NAME>
CloudFormationの設定
各yamlファイルには Parameters
セクションがあり、ここで名前などを設定している。基本的に何も変えなくてもいけるはずだが、問題がある場合は変更する。ただしタスク・スケジュールのyamlは修正必要。
また、yamlファイルが4つあるが、ここまで分ける必要はないかもしれない。
-
ネットワーク(network.yaml)
VPC、サブネット、セキュリティグループを作成。さらにゲートウェイやルートテーブルなどなども作成した。あれこれ設定しているが、たぶんこれが必要最小限のはず…。CIDRとかは適当に設定しているので問題があれば変える。 -
ロール(roles.yaml)
IAM関連はCloudFormationでなく、コンソールで管理すれば十分な気もする。今回はECSタスクを実行するロールなどの作成で試行錯誤していたらカオスになったのでCloudFormationで管理するようにした。 -
ECSクラスタとLambda(cluster.yaml)
ここで作成するLambdaは、ECSタスクを実行するだけのもの。本当はCloudWatchのイベントでECSタスクを実行したいのだが、現在はまだCloudFormationでその設定ができないようなので、間にLambdaを挟んでいる。 -
ECSタスクとスケジュール(task.template.yamlをtasks/mytask.yamlとしてコピーして修正)
Parametersセクションを必ず修正する。ECRのイメージ、cronパターン、放送局と録音時間、S3バケットなどを指定する。このyamlファイル1つがcronの1行に対応するイメージ。なので番組をいくつも録音したいときはその数だけyamlファイルを作る。
CPUやメモリは現在最小限にしているが、番組によっては足りないかも。
CloudFormationでリソース作成
ここではAWS CLIで実行する場合を書く。コンソール画面からそのままやっても問題ない。
が、いずれにせよ作成する順番はこの通りにすること(ネットワークとロールは入れ替え可能)。ネットワークとロールが作成完了したあとでないとECSクラスタなどを作成できない。
以下ではスタック名は適当につけている。
-
ネットワーク
aws cloudformation create-stack --stack-name docker-rec-radiko-network-stack --template-body file://./cf/network.yaml
-
ロール
IAM関連なので、コンソール画面で作成するときにはチェックボックスに確認のチェックをする作業がある。AWS CLIでもそれに対応するオプションをつける。aws cloudformation create-stack --stack-name docker-rec-radiko-roles-stack --template-body file://./cf/roles.yaml --capabilities CAPABILITY_NAMED_IAM
-
ECSクラスタとLambda
aws cloudformation create-stack --stack-name docker-rec-radiko-cluster-stack --template-body file://./cf/cluster.yaml
-
ECSタスクとスケジューラ
aws cloudformation create-stack --stack-name docker-rec-radiko-task-stack --template-body file://./cf/tasks/mytask.yaml
-
確認
ECSタスクまで作成成功すれば録音できるようになっているはず。指定した時間にECSでタスクが実行され、録音終了すればS3に保存される。ログはCloudWatchで見れる。
課題とか
- Lambdaを使わずに済ませたい
これはAWSが対応してくれることを待つしかないようだ。 - 日本時間でcronを書きたい
これもAWSが対応するのを待つしかない(たぶんされない)。
現在はUTCで書くしかない。計算が面倒。 - CloudFormationスタック間の情報受け渡し
今回はスタックで作成したリソース(たとえばサブネットやロール)をパラメータストアに入れることで、他のスタックから参照できるようにしている。
だがこれだとスタックを作り直すと、それに依存するスタックも作り直さないといけない(パラメータストア内の値は、作り直す前のものなので)。
たとえばネットワークやロールのスタックを作り直すと、クラスタやタスクのスタックも作り直さないといけない。
何かうまい方法があればいいのだが…。
あとProjectNameなどを複数のスタックでそれぞれ定義し直しているのも気持ち悪い。 - CloudFormationスタック分割のベストプラクティスがわからない
今回は練習の意味もあり、わりと細かく分割した。
本来ならどのくらい粒度で分割するのがいいかよくわからない。
たとえばECSタスクは1つ1つ別のスタックにしたが、タスクはすべて1つのスタックにまとめてしまうというのもありだと思う。
参考
ECR
- Amazon ECR における Docker の基本 - Amazon ECR
dockerイメージをECRにpushする方法。
CloudFormation
公式
- テンプレートスニペット - AWS CloudFormation
CloudFormationテンプレートのサンプル。 - テンプレートの分析 - AWS CloudFormation
CloudFormationテンプレートの基本的な枠組みについて。 - パラメータ - AWS CloudFormation
Parametersセクションの書き方。 - リソース - AWS CloudFormation
Resourcesセクションの書き方。 - AWS リソースおよびプロパティタイプのリファレンス - AWS CloudFormation
リソース一覧。とにかくECSリソースやCloudWatchリソース、IAMリソースなどなど、リソースを書くときはここから探す。 - 組み込み関数リファレンス - AWS CloudFormation
テンプレートで使える組み込み関数。Fn::Sub
やFn::GetAtt
など。 - Fn::GetAZs - AWS CloudFormation
Fn::GetAZs
を使って、サブネットのAvailabilityZoneを設定する例がある。これならAvailabilityZoneを直に指定しなくていい。 - AWS コマンドラインインターフェイスの使用 - AWS CloudFormation
AWS CLIでCloudFormationを操作する方法。
各種記事
- CloudformationでFargateを構築する | DevelopersIO
似たようなことをやってるので参考にした。 - Fargateでバッチサーバを作る - Qiita
似たようなことをやってるので参考にした。 - CloudFormationテンプレート間で値を渡す3つの方法 - Qiita
stack間で値を共有する方法。今回はこの「Parameter Storeを使う」でやった。 - amazon web services - InsufficientCapabilitiesException [CAPABILITY_NAMED_IAM] when creating a stack with IAM policies - Stack Overflow
AWS CLIでCloudFormationのIAM関連の操作をするとエラーになる。その対処法。 - amazon web services - AWS Stack update error: Requires capabilities : [CAPABILITY_IAM] - Stack Overflow
同上。
スケジュール関連
- ルールのスケジュール式 - Amazon CloudWatch Events
CloudWatchイベントでのcronの書き方。 - Amazon ECS タスクのスケジューリング - Amazon Elastic Container Service
ECSをスケジュール機能で動かす。 - Fargateがタスクスケジュールをサポートし定期実行処理の幅が超広がりました! | DevelopersIO
Fargateをスケジュール機能で動かす。(コンソール画面での方法。)これをCloudFormationでできればいいのだが、できないよう。 - amazon web services - creating a 'Target' for a cloudwatch event rule via cloudformation for a fargate launchtype task - Stack Overflow
CloudFormationでは、Fargateをスケジュール機能で動かすことができないので、Lambdaと連携して動かそうという話。
VPC
- VPC とサブネット - Amazon Virtual Private Cloud
VPC全般。 - インターネットゲートウェイ - Amazon Virtual Private Cloud
インターネットアクセスを有効にする方法。 - インターネットゲートウェイを作成して VPC に接続する
同上。