前にdockerでradikoを録音するようにした。
これを定期実行するためにVPSを借りているのだが、録音は1日のごくわずかな時間しか行わないので、録音していない時間は余計なコストがかかってしまう。また低スペックのVPSのためか、複数番組を同時に録音すると失敗することがある(まれに)。

Fargateでは実行している間だけしか金がかからないので安いはず。それに同時録音の問題も起きないだろう。というわけでFargateに乗り換えてみることにした。

(2021/11/30追記) この記事の続きを書いた

やりたいこと

  • Fargateを使ってradikoを録音するスクリプトを定期実行する
  • 音声ファイルはS3に保存する
  • 一連の構成はCloudFormationによって管理する

前提条件

  • dockerコマンドが入っている
  • AWSアカウントを持っている
    CloudFormationでIAMの設定をしたりするので、強い権限が必要。
  • AWS CLIが入っている
  • S3の保存先バケットが作成されている
  • 録音したい番組は関東エリアで放送されているもの
    Fargateが東京にしかないので。(radikoプレミアムに対応したスクリプト使えばいけるはず。)

できたもの

docker_rec_radiko

前に作ったやつにFargate版を追加した。CloudFormationはcfディレクトリ下にある。

作業手順

ECRにDockerイメージを登録

  1. リポジトリ作成

    aws ecr create-repository --repository-name <REPOSITORY_NAME>
    

    <REPOSITORY_NAME> には好きなリポジトリ名を入れる(たとえば docker_rec_radiko)。
    結果としてjsonが返る。その中の repositoryUri をあとで使う。

  2. dockerイメージをビルド・タグ付け

    docker build . -t <REPOSITORY_URI>
    

    <REPOSITORY_URI> には上で取得した repositoryUri を入れる。

  3. docker login認証コマンド文字列を取得

    aws ecr get-login --no-include-email
    
  4. ログイン
    上で取得したdocker login認証コマンド文字列をそのまま実行。
    これでECRにpushできるようになる。

  5. dockerイメージをECRにpush

    docker push <REPOSITORY_URI>
    
  6. ECRに登録されたことを確認
    AWSのコンソールを見てもいいが、コマンドでもわかる。

    aws ecr describe-images --repository-name <REPOSITORY_NAME>
    

CloudFormationの設定

各yamlファイルには Parameters セクションがあり、ここで名前などを設定している。基本的に何も変えなくてもいけるはずだが、問題がある場合は変更する。ただしタスク・スケジュールのyamlは修正必要。
また、yamlファイルが4つあるが、ここまで分ける必要はないかもしれない。

  1. ネットワーク(network.yaml)
    VPC、サブネット、セキュリティグループを作成。さらにゲートウェイやルートテーブルなどなども作成した。あれこれ設定しているが、たぶんこれが必要最小限のはず…。CIDRとかは適当に設定しているので問題があれば変える。

  2. ロール(roles.yaml)
    IAM関連はCloudFormationでなく、コンソールで管理すれば十分な気もする。今回はECSタスクを実行するロールなどの作成で試行錯誤していたらカオスになったのでCloudFormationで管理するようにした。

  3. ECSクラスタとLambda(cluster.yaml)
    ここで作成するLambdaは、ECSタスクを実行するだけのもの。本当はCloudWatchのイベントでECSタスクを実行したいのだが、現在はまだCloudFormationでその設定ができないようなので、間にLambdaを挟んでいる。

  4. ECSタスクとスケジュール(task.template.yamlをtasks/mytask.yamlとしてコピーして修正)
    Parametersセクションを必ず修正する。ECRのイメージ、cronパターン、放送局と録音時間、S3バケットなどを指定する。このyamlファイル1つがcronの1行に対応するイメージ。なので番組をいくつも録音したいときはその数だけyamlファイルを作る。
    CPUやメモリは現在最小限にしているが、番組によっては足りないかも。

    • ECSCommand
      <放送局ID>, <録音時間(分)>, <ファイルプレフィクス> の形式。放送局IDはここ参照。
    • ECSTaskSchedulerPattern
      cronパターンを書く。癖があるのでドキュメント参照。
      絶対にUTCで書く! 日本時間での記述には対応していない(めんどくせえ)。
    • ECSTaskName
      タスク名を書く。なんでもいいが、わかりやすく短い名前にした方がいい。
    • ImageName
      ECRで登録したイメージ名。
    • S3BucketName
      あらかじめ作成したS3バケット名を書く。

CloudFormationでリソース作成

ここではAWS CLIで実行する場合を書く。コンソール画面からそのままやっても問題ない。
が、いずれにせよ作成する順番はこの通りにすること(ネットワークとロールは入れ替え可能)。ネットワークとロールが作成完了したあとでないとECSクラスタなどを作成できない。
以下ではスタック名は適当につけている。

  1. ネットワーク

    aws cloudformation create-stack --stack-name docker-rec-radiko-network-stack --template-body file://./cf/network.yaml
    
  2. ロール
    IAM関連なので、コンソール画面で作成するときにはチェックボックスに確認のチェックをする作業がある。AWS CLIでもそれに対応するオプションをつける。

    aws cloudformation create-stack --stack-name docker-rec-radiko-roles-stack --template-body file://./cf/roles.yaml --capabilities CAPABILITY_NAMED_IAM
    
  3. ECSクラスタとLambda

    aws cloudformation create-stack --stack-name docker-rec-radiko-cluster-stack --template-body file://./cf/cluster.yaml
    
  4. ECSタスクとスケジューラ

    aws cloudformation create-stack --stack-name docker-rec-radiko-task-stack --template-body file://./cf/tasks/mytask.yaml
    
  5. 確認
    ECSタスクまで作成成功すれば録音できるようになっているはず。指定した時間にECSでタスクが実行され、録音終了すればS3に保存される。ログはCloudWatchで見れる。

課題とか

  • Lambdaを使わずに済ませたい
    これはAWSが対応してくれることを待つしかないようだ。
  • 日本時間でcronを書きたい
    これもAWSが対応するのを待つしかない(たぶんされない)。
    現在はUTCで書くしかない。計算が面倒。
  • CloudFormationスタック間の情報受け渡し
    今回はスタックで作成したリソース(たとえばサブネットやロール)をパラメータストアに入れることで、他のスタックから参照できるようにしている。
    だがこれだとスタックを作り直すと、それに依存するスタックも作り直さないといけない(パラメータストア内の値は、作り直す前のものなので)。
    たとえばネットワークやロールのスタックを作り直すと、クラスタやタスクのスタックも作り直さないといけない。
    何かうまい方法があればいいのだが…。
    あとProjectNameなどを複数のスタックでそれぞれ定義し直しているのも気持ち悪い。
  • CloudFormationスタック分割のベストプラクティスがわからない
    今回は練習の意味もあり、わりと細かく分割した。
    本来ならどのくらい粒度で分割するのがいいかよくわからない。
    たとえばECSタスクは1つ1つ別のスタックにしたが、タスクはすべて1つのスタックにまとめてしまうというのもありだと思う。

参考

ECR

CloudFormation

公式

各種記事

スケジュール関連

VPC