Strapi をできるだけ低コストで Fargate 化したけどうまくいかなかった


背景

Headless CMS を自前で運用してみたかったので、Docker Image が提供されている Strapi を動かしてみようと試みたが、うまくいかなかった記録。

ローカルで動かすのはストレージ故障などの不安があり、一方で AWS 上で動かすと常時稼働分リソースの料金が気になる。どうしたものかと考えたところ、以下の構成に落ち着いた。

構成

  • Fargate
    • 使うときに ecs:RunTask して FARGATE_SPOT の Strapi を起動
    • 使い終わったら ecs:StopTask
  • Aurora Serverless
    • プライベートな利用なのでスリープからの復帰時間が生じても問題ない

ポイント

Strapi の Docker Image は、初期起動時に yarn build などのセットアップを行う。環境によっては十分以上かかることもある。
Fargate 起動のたびにこれが生じるとさすがに待ち時間が辛いため、ローカルでセットアップさせ、完了後のコンテナを docker commit で改めてイメージ化し、Fargate で稼働させる。

リポジトリ

Terraform で以下を構築している。

  • VPC
  • Subnet
  • IGW
  • Route Table
  • Security Group
  • Aurora Serverless Cluster
  • ECR
  • ECS Cluster
  • ECS Task Definition
  • CloudWatch Logs

構築・起動

# インフラ構築
cd terraform
terraform apply -var 'master_password=XXX'

# ローカルでセットアップ開始
cd ..
docker compose up -d

# イメージ作成
make commit
# -> (1)

# イメージをプッシュ
make login
make push

# Fargate を RunTask
cd ..
make run_task
# -> (2)

生じた問題

(1) docker commit しても一部ファイルがイメージに含まれない

Strapi がセットアップ時に生成したファイルが、commit したイメージに含まれていなかった。
原因は以下。

コンテナ内でマウントされているボリュームに含まれるデータは、コミット作業に含まれません。
http://docs.docker.jp/v19.03/engine/reference/commandline/commit.html

WORKDIR でもある /srv/app が、 Dockerfile で VOLUME 指定されている。

公式の Dockerfile をコピーして、VOLUME しないように書き換えることで回避は可能そうだが、少し気持ち悪い。
本問題を解消しなくても Fargate 上で再度セットアップされるだけなので、一旦はそのままにした。

(2) KnexTimeoutError

Fargate を RunTask すると KnexTimeoutError が発生し、Strapi の起動に失敗した。

調べてみると上記がヒットした。データベースのスペックが低いことに依るものとの記載があり、Aurora Serverless ゆえの問題かもしれない。
また、上記記事では yml を書き換えることでも解消したとの記載があった。やはり自前で Dockerfile を用意する必要があり、ここで力尽きた。

まとめ

  • せこいことをやろうとするとうまくいかない、という好例であった。
  • 素直に API Gateway + Fargate + Aurora (not Serverless) という構成にすれば、おそらくすんなりと動いてくれるはずである。