はじめに
それは、何の変哲もないデプロイでした。
変更内容は、たった1行。
外部サービスの所有権確認用に、
public/verify.txt
を追加しただけです。
DB変更なし。
コード変更ほぼなし。
verify.txt を置いただけでした。
ところが、デプロイ直後、Strapi で管理していたコーポレートサイト用 CMS の Content-Type とデータが消えました。
対象は自社コーポレートサイト用の CMS だったため、サービス本体や顧客データへの影響はありませんでしたが、社内向けにはかなり焦る事態でした。
今回は
- なぜそんなことが起きたのか
- なぜ当時その運用に違和感を持てなかったのか
- Strapi の Content-Type Builder をどう理解するべきだったのか
を、自戒も込めて整理します。
当時の構成
- Strapi v4.12.7 (Community Edition)
- PostgreSQL 12
- GitHub Actions
- Dokku
- Docker 運用
デプロイは GitHub Actions から Dokku へ push する構成でした。
この構成で、サーバー側は毎回 Git の状態へ同期されます。
今回の本質的な問題は、
- develop モード運用
- schema.json の扱い
- Strapi の「コード → DB」同期設計
を正しく理解できていなかったことでした。
事故の経緯
1. verify.txt を追加
外部 SaaS(CDN 系)の所有権確認のため、
public/verify.txt
を追加。
Strapi の public/ 配下に置いたファイルは、そのまま静的配信されるため、ただファイルを置くだけの作業でした。
2. デプロイ実行
GitHub Actions → Dokku 経由でデプロイ。
デプロイ自体は正常終了。
しかし、その直後。
- 一部 Content-Type が消失
- 管理画面からコレクションが消える
- データが参照不能になる
という異常が発生しました。
最初に疑ったこと
最初は PostgreSQL 側の事故を疑いました。
「DB が壊れた?」
「migration が誤実行された?」
「Dokku の volume が飛んだ?」
しかし DB ログを確認すると、
ALTER TABLE ... DROP COLUMN
さらに、
DROP TABLE ...
まで実行されていました。
つまり、
DB を消していたのは Strapi 自身でした。
原因
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
CMD ["yarn", "develop"]
当時は develop モード前提の運用になっていました。
なぜ develop モードに違和感を持てなかったのか
当時は、microCMS のような「管理画面でスキーマを編集する CMS」の感覚で Strapi を扱っていました。
しかし Strapi の Content-Type Builder は、実際には DB を直接編集する UI ではありません。
裏では、
src/api/*/content-types/*/schema.json
を書き換える、「コード生成ツール」に近い存在でした。
つまり、
「管理画面で DB を編集している」
つもりでも、実際には
「サーバー上のコードを書き換えている」
状態だったのです。
そして schema.json の不整合が発生した
ここから、一気に事故が加速します。
管理画面で編集された schema.json は、サーバー上にしか存在していませんでした。
Git にコミットしていなかったのです。
その状態でデプロイが実行され、結果的に古い schema.json がサーバーへ反映されました。
この時点では、まだ何が起きているか理解できていませんでした。
Strapi の自動同期が発動
ここで Strapi が起動します。
Strapi は起動時に、
schema.json- 実際の DB 構造
を比較し、コード側へ DB を同期します。
この時点で状態はこうなっていました。
Git にある古い schema.json
{
"attributes": {
"title": {
"type": "string"
}
}
}
実際の DB
-
fieldAカラムが存在 - 管理画面で追加した Content-Type が存在
Strapi はこう判断します。
「schema.json に存在しないので不要」
そして静かに、
ALTER TABLE articles DROP COLUMN "fieldA";
を実行。
さらに、コード上に存在しなかった Content-Type は、
DROP TABLE ...
によって削除されました。
なぜ起きたのか
今回の事故は、複数の条件が重なって発生しました。
① Strapi のスキーマは「コード」
管理画面の編集内容は DB ではなく schema.json に保存されます。
DB は二次的な投影に過ぎず、真実はコード側にあります。
② 本番なのに develop モード
CMD ["yarn", "develop"]
production モードでは、Content-Type Builder はロックされます。
つまり本来、
「本番管理画面からスキーマ変更する」
という運用自体ができません。
しかし今回は develop モードだったため、管理画面から schema.json を変更できる状態になっていました。
③ schema.json の差分が管理されていなかった
管理画面で変更された schema.json は Git 管理されておらず、デプロイ時に古い状態へ戻ってしまいました。
④ Strapi の同期は「コード → DB」
Strapi はコードを正として DB を同期します。
逆方向(DB → コード)への吸い上げは存在しません。
つまり、
コードに無い = DB から削除対象
です。
どう復旧したか
幸い、バックアップが残っていたため、DB 自体は復旧できました。
ただし、
schema.json- DB 状態
- Strapi 管理画面
の整合性が崩れていたため、一部 Content-Type は手動で再同期・再作成が必要でした。
今回の件で、「CMS のデータ」だけでなく、「CMS の構造」もバックアップ対象として扱う必要があることを痛感しました。
再発防止策
1. スキーマ変更はローカルのみ
- ローカルの Strapi(develop モード)で変更
- schema.json を Git コミット
- 本番へデプロイ
本番管理画面は「コンテンツ入力専用」にするべきです。
2. 本番は必ず production モード
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
CMD ["yarn", "start"]
production モードでは Content-Type Builder がロックされます。
つまり、
「Content-Type はコード管理するもの」
という Strapi 本来の運用に強制されます。
3. schema.json を必ず Git 管理する
Strapi の Content-Type Builder は便利ですが、本質的にはコード生成です。
管理画面で変更しただけでは終わりではなく、
git diff
git commit
まで含めてスキーマ変更だと考える必要があります。
4. DBバックアップを自動化する
Dokku なら、
dokku postgres:export
を CI のデプロイ前へ入れるだけでも命綱になります。
おわりに
当時は、
「管理画面でスキーマを編集している」
感覚でした。
しかし実際には、
サーバー上のコードを書き換えていた
のです。
Strapi の Content-Type Builder は便利ですが、その実態は「コード生成ツール」に近い存在です。
同じような感覚で運用している人は、本当に気をつけてください。


