ラジオ番組をAWSFargateでS3へ

# 話の概要
dockerをAWSで動かすのならcopilotがお手軽だが、お手軽が故に注意しないといらん機能でコストがバク上げになるから注意してねと言う話。

https://note.com/nyadorya/n/n0b7f6425fe60

とリンクしますので、そちらもどうぞ。


# 前提
rec_radiko_tsをつかう。というか、いじりたくないため。

https://github.com/uru2/rec_radiko_ts

# 手順
こんな感じ。

1. dockerをつかってローカルでは動くようにする
1. AWSCLIにてcopilot init
1. 実行

# 手順詳細
cloudFoundationでつくるのがイマドキ風なのだが、必要なものを一式まるっと作るサポートしてくれるのがcopilotです。
というわけで、以下の手順は全力でcopilotを使って、dockerをFargateで動かすのを目指します。

## dockerをつかってローカルでは動くようにする
まぁいきなりcopilotをつかいながらガンガン更新して実行するのもいいけど、やっぱりローカルで実行できるようにしておくほうが問題の切り分けもできていいと思う。

```Dockerfile
FROM alpine:3.15.0 as tzdata
RUN apk --update add \
    --no-cache \
    tzdata=2021e-r0

FROM alpine:3.15.0

ENV GLIBC_VER=2.34-r0

RUN apk --update add \
    --no-cache \
    libxml2-utils=2.9.12-r2 \
    ffmpeg=4.4.1-r2 \
    curl=7.80.0-r0 \
    binutils \
    coreutils=9.0-r2 \
    && curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
    && curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk \
    && curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk \
    && curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk \
    && apk add --no-cache \
        glibc-${GLIBC_VER}.apk \
        glibc-bin-${GLIBC_VER}.apk \
        glibc-i18n-${GLIBC_VER}.apk \
    && /usr/glibc-compat/bin/localedef -i en_US -f UTF-8 en_US.UTF-8 \
    && curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip \
    && unzip awscliv2.zip \
    && aws/install \
    && rm -rf \
        awscliv2.zip \
        aws \
        /usr/local/aws-cli/v2/current/dist/aws_completer \
        /usr/local/aws-cli/v2/current/dist/awscli/data/ac.index \
        /usr/local/aws-cli/v2/current/dist/awscli/examples \
        /usr/local/aws-cli/v2/current/dist/docutils \
        glibc-*.apk \
    && find /usr/local/aws-cli/v2/current/dist/awscli/botocore/data -name examples-1.json -delete \
    && apk --no-cache del \
        binutils \
    && rm -rf /var/cache/apk/* \
    && cp /bin/date /usr/local/bin/date
    
COPY --from=tzdata /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
COPY ./getprogram.sh /usr/local/bin

ENV LC_ALL=en_US.UTF-8

RUN curl -s -o /usr/local/bin/rec_radiko_ts.sh -LO https://raw.githubusercontent.com/uru2/rec_radiko_ts/master/rec_radiko_ts.sh \
    && chmod +x /usr/local/bin/rec_radiko_ts.sh \
    && chmod +x /usr/local/bin/getprogram.sh

ENTRYPOINT /usr/local/bin/getprogram.sh

WORKDIR /recoded
```

ポイントは以下のとおり
・OSはdocker御用達のalpine linux。サイズが小さいのが正義
・タイムゾーンは加工したいよね。日本向けに。
・curl,ffmpeg,libxml2が必要というのでそれらは仕込む
・軽量がすぎてdateがpoorなので、計算が優秀な方のdateを別途入れる
・最終的にS3バケットに書き込みたいので、aws-cliも入れる
・途中で削っているのはAWSを動かすのに不要なファイルは極力消してファイルサイズを小さくするため。
・getprogram.shはrec_radiko_ts.shを呼び出すシェル。よって自分で作る。
・「WORKDIR /recoded」は書き込み可能で、まるごとS3バケットにコピーしていいならどこでもいい。

ちなみにgetprogram.shはあとから完成させる。

せっかくalpineを使ったのに、いろいろ必要なものを突っ込んだらまぁまぁのサイズに…
まぁそれでもzipで200Mbぐらいかな。

## AWSCLIにてcopilot init
ローカルで動くことを確認したら、いざAWSへ。

前提1:aws configure を実行しておく

```
AWS Access Key ID [None]: 各自で
AWS Secret Access Key [None]: 各自で
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

前提2:Amazon ECS CLIで設定
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/ECS_CLI_Configuration.html
を参考にして。

以下、手順はいかのとおり。
copilot initを実行する。が、デプロイ前で止めておく
copilot app initを実行する。
copilot env initを実行する。
copilot deployを実行する。
copilot storage initを実行する。

ここまでするとS3バケットができるのでそのバケット名をgetprogram.shに記載する。
```getprogram.sh
/usr/local/bin/rec_radiko_ts.sh -s TBS -f `date -d -1week+friday +\%Y\%m\%d`0000 -d 60 -o "/recoded/`date -d -1week+friday +\%Y\%m\%d`_ハライチのターン.m4a"

aws s3 cp /recoded s3://(できたバケット) --exclude "*" --include "*.m4a" --recursive
```
バケット名ですが…下のような感じでまぁまぁ長い名前のものができます。
ragat-ragat-env-ragat-jb-addonssta-ragattkobucket-1jdzxibnnrulk

copilot deployを実行する。

これで実行環境はできる。
なお、今回はWebサーバとかじゃなくてバッチ実行環境なので注意

## 実行
実行は画面から可能。

# 初回以降のデプロイ
以下のとおり。

```
docker images
docker rmi $(docker images -f "dangling=true" -q)
docker rmi (docker名)
docker rmi (ユーザID).dkr.ecr.ap-northeast-1.amazonaws.com/(各々の定義による)

docker build -t (docker名):latest .
docker tag (docker名):latest (ユーザID).dkr.ecr.ap-northeast-1.amazonaws.com/(各々の定義による)

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin (ユーザID).dkr.ecr.ap-northeast-1.amazonaws.com
docker push (ユーザID).dkr.ecr.ap-northeast-1.amazonaws.com/(各々の定義による)
```
ポイントは以下のとおり
・タスク定義のリビジョンを上げる(コンテナイメージを変えるためだけに)
・stepfunctionの定義も変える(タスク定義のリビジョンを上げたから)
これをワンセットでようやく変わる。


# これで動くは動くけど
copilotっていろいろやってくれるけど、ともあれ「全部いり」で作るのでやや冗長。
冗長だけですめばいいけど、費用面にビックリすることになる。

というわけで、お金に余裕がある人には不要だが、以下はやったほうがいい。

## 費用面対策
・DNSホストゾーン削除:AWS Cloud Map　名前空間　(ragat-env.ragat.local)消す
・キー削除:AWS KMS削除
・ECSのタスク定義してる json からCOPILOT_SERVICE_DISCOVERY_ENDPOINT の環境変数消す

## 実行スケジュール対策
・Amazon EventBridgeのスケジュールを変更する(変更しないといらん回数実行することになるかも)

## 費用面改善
FargateもEC2に比べれば十分優秀だが、バッチ処理的な使い方をするならfargate_SPOTにしたほうがいい。
・クラスターでfargate_SPOTを指定する

https://inokara.hateblo.jp/entry/2020/04/22/212519

…-StateMachineRoleにecs:RunTaskの許可を追加

# 終わりに
copilotって自動で整えてくれてお手軽便利。
でも、どこに何を作ったのか
そしていらないように思えるけど削っていいのか、けずるならどこからどう削るのか
とかいろいろ突き詰めると面倒。
iamの権限もかなーり甘め。copilotでつかうS3バケットも作られてしまう。
何かと美しくはない。
お手軽に動くことを考えたらよいが、最終的にはできたものを見ながら学ばないとベストにはならない。

今回のようにちょっとしたshellを実行したい(実行時間が15分以下)ならlambdaのほうがよいと思う。

https://qiita.com/damacchi/items/15486c125d2dd41d14e1

ほんじゃあ