はじめに
生成AIにアプリケーションコードやTerraformを書いてもらう機会が増えました。動くものを作るまでの時間は短くなりました。そのコードをどの環境へ、どんな権限で、どうデプロイして運用するかも、あわせて考えておきたいところです。
例えばAIに「ECSで動くWebアプリを作って」と依頼すると、アプリケーション、Dockerfile、タスク定義、データベース接続の設定まで一気に出てきます。各ファイルがそれらしく見えても、接続先がコードに埋まっていないか、タスクが再起動した際にデータが消えないか、終了時にリクエストを処理し切れるかは、確認しておきたい点です。
そこで思い出したのが、The Twelve-Factor App(以下、12FA)です。アプリケーションと実行環境の責任を分けて考える共通言語として、AIを使う開発にも参考になるのではないかと感じています。
この記事では12FAを簡潔に紹介し、インフラ開発の目線から、AIに何を伝え、生成された変更をどう検証して本番へ届けるかを整理します。AIを製品機能として組み込む話ではなく、AIを開発者の補助として使う場面を対象にします。
12FAとは
12FAは、サービスとして動かすアプリケーションを設計・開発するための方法論です。セットアップの自動化、実行環境との明確な契約、開発と本番の差の縮小、スケールしやすさなどを目指しています。特定の言語やクラウドサービスの使い方を定めたものではありません。
12の原則は次の通りです。ここでは原典の見出しを、この記事での確認事項に言い換えてまとめます。
| 原則 | 確認したいこと |
|---|---|
| I. コードベース | どのコードが、どのアプリのデプロイにつながるか |
| II. 依存関係 | 必要なライブラリやランタイムが明示されているか |
| III. 設定 | 環境ごとの差分をコードから分離できているか |
| IV. バックエンドサービス | DBなどを接続可能な外部リソースとして扱えるか |
| V. ビルド、リリース、実行 | 同じ成果物を環境ごとの設定と組み合わせて動かせるか |
| VI. プロセス | プロセス内の状態に永続性を期待していないか |
| VII. ポートバインディング | アプリ自身がサービスを公開する境界が明確か |
| VIII. 並行性 | 必要な処理をプロセス単位で増やせるか |
| IX. 廃棄容易性 | 起動と終了、再配置を前提にできているか |
| X. 開発/本番一致 | 環境差による不具合を増やしていないか |
| XI. ログ | アプリがイベントを出し、基盤で収集できるか |
| XII. 管理プロセス | マイグレーションなどを一回限りの処理として実行できるか |
すべてを機械的に満たそうとするより、利用する環境に合わせて読みたい原則です。例えばローカル開発と本番で同じマネージドDBを使う必要はありませんし、ステートフルなワークロードにプロセスの無状態性をそのまま当てはめることもできません。どこに状態や設定を置き、誰が管理するかを話し合うきっかけとして使えそうです。
AIでコードを作ると、なぜ12FAが気になるのか
AIは指示した範囲のコードを素早く生成します。アプリが置かれる組織や実行環境には、指示に書かなければ伝わりにくい前提もあります。インフラ開発の目線から、その前提をどのように共有できるか考えてみます。
ここでは12FAを、設計上の問いを見つけるための道具として使ってみます。「前提を渡す→変更を作る→動作と運用を確認する→リリースする」という流れに沿って、特に気になった四つを取り上げます。
1. コードと環境の境界を、AIへの入力でも伝える
設定、バックエンドサービス、ビルド・リリース・実行の原則は、アプリのコードと環境固有の値を切り分けます。AIに「DB接続機能を作って」とだけ頼むと、接続先や認証情報をどこから受け取るかまで任せることになります。
依頼の段階で、例えば次のような前提を伝えておくと、生成物をレビューしやすくなりそうです。
- 接続先は実行時の設定から受け取り、リポジトリに本番用の値を置かない
- 認証情報は適切なシークレット管理と実行時の権限で受け渡す
- 一つのイメージをビルドし、環境ごとに設定を変えてリリースする
- DBやキューなどの接続先は、アプリの外部にあるリソースとして扱う
12FAの「環境変数に設定を置く」は、シークレットの保管方法まで決めてくれるわけではありません。どこで値を保管し、誰が取得でき、ログやデバッグ出力へ漏れないかは、基盤側でも考えたい点です。Terraformに機密値を直書きしないことも同じ話です。
AIが生成したコードのレビューでは、設定値そのものに加えて、設定を受け取るインターフェースを見ます。変数名、必須・任意、未設定時の挙動、タイムアウト、接続失敗時の動作まで決まっていると、アプリと基盤を独立して変更しやすくなります。
2. 再起動しても正しいかを、最初から確かめる
AIが作った試作品は、ローカルで一度動いた時点で完成に見えがちです。しかし本番ではデプロイ、オートスケール、障害復旧でプロセスが入れ替わります。12FAのプロセス、並行性、廃棄容易性は、その状況を考える助けになります。
例えば、ファイルアップロードの保存先をコンテナ内のディレクトリにしていないか。セッション情報を一つのプロセスのメモリにだけ持っていないか。ワーカーが終了する際、処理中のメッセージを失ったり二重処理したりしないか。これらはアプリコードだけを眺めても見落としやすいところです。
無状態性は「状態を持ってはいけない」という意味ではなく、永続化すべき状態をプロセス外に置くという話です。AIが生成したアプリでも、保存先がコードに書かれているかだけで判断せず、再起動や複数タスクでの動作を試します。キューを扱うなら、処理途中の終了と再実行をテストし、必要に応じて冪等性を設計します。
ECSやKubernetesを使う場合は、アプリの終了処理にも目を向けたいです。起動時の依存サービス確認、ヘルスチェック、終了シグナルの処理、ドレイン時間を組み合わせて試してみると、基盤の設定とアプリの実装の接点が見えてきます。
3. ログと障害調査の要件を、実装前に渡す
12FAでは、アプリはログをイベントストリームとして出力し、その配送や保存は実行環境が担います。現在のコンテナ環境なら標準出力への出力と基盤側の収集が、まず考えやすい構成です。ただし、標準出力に何でも書けば十分という話でもありません。
AIにロギング実装を依頼すると、成功・失敗を標準出力へ書くだけで終わることがあります。障害調査に必要な情報はアプリによって違うため、リクエストID、処理段階、依存先、エラーの分類など、何を追いたいかを先に渡します。一方でリクエスト本文、認証情報、個人情報を無条件にログへ出さないことも要件に含めます。
生成後のレビューでは、障害を一つ想定し、どこまで調査できるかを試してみてもよさそうです。必要に応じてメトリクスやトレースも考えます。これは原典の12項目をそのまま言い換えたものではなく、イベントを運用で使える情報にするための補足です。ログ収集基盤の設定とアプリが出すフィールドの対応も、確認対象になります。
4. 生成から本番反映までの経路を追えるようにする
12FAはビルド、リリース、実行を分け、開発環境と本番環境の差を小さくします。AIにコード変更を依頼する回数が増えるほど、何がいつ本番へ入ったのかを追跡できることが大切になります。
例えばアプリコード、Dockerfile、IaCの変更を同時に出した場合、それぞれの差分だけでなく、組み合わせが正しいかを確認します。イメージを一度ビルドして識別可能な成果物として扱い、設定やシークレットの参照先と合わせてリリースする。DBマイグレーションは通常のアプリ起動から切り離し、実行順序と失敗時の対処を決める。必要なら旧版と新版が同じDBスキーマを使う時間も想定します。
AIを使うと変更の量や速度が上がることがあります。自動テスト、IaCの差分確認、権限のレビュー、段階的な反映と切り戻しの手順を、開発の流れの中でどう扱うか考えておきたいです。AIの提案を適用する際には、何を確認できたら安心して進められるかをチームで共有できるとよさそうです。
特にIaCは、構文が通っても意図した構成とは限りません。新規の公開経路、広すぎる権限、リソースの置換、想定外の課金につながる設定を、planや差分から確認します。AIには「修正案に加えて、影響するリソースと検証方法を説明して」と依頼できますが、その説明も変更内容と照合します。
具体例:AIにECSアプリを作ってもらうなら
小さなWebアプリをECS Fargateで動かす想定なら、例えば次のような前提を渡す方法が考えられます。
アプリとDockerfileを作成してください。DB接続先は実行時に受け取り、認証情報をコードやイメージへ含めないでください。永続データはコンテナ内へ保存せず、標準出力へ構造化ログを出してください。ヘルスチェック用のエンドポイントを設け、終了シグナルを受けたら新規受付を止め、処理中のリクエストを終了してください。DBマイグレーションはWebプロセスの起動と分けて実行できるようにしてください。必要な設定項目と未設定時の挙動をREADMEに記載してください。
あわせて「変更したファイル、前提にした事項、実施したテスト、未検証の項目を報告してください」と依頼すると、レビューの手がかりになります。生成後には、例えば次のような点を見ていきます。
| 確認対象 | 具体的な問い |
|---|---|
| アプリとタスク定義 | ポート、ヘルスチェック、CPU・メモリ、終了猶予は整合しているか |
| 権限と設定 | タスクの実行権限とアプリの権限を分け、必要な値だけ渡しているか |
| 状態 | コンテナが入れ替わっても、セッションや処理結果が失われないか |
| リリース | イメージを識別でき、マイグレーションとアプリ更新の順番を説明できるか |
| 観測 | 障害時にリクエストから依存サービスまで追えるか |
この表はECS特有のベストプラクティスを網羅したものではありません。12FAの考え方を、アプリとインフラの間で具体的な確認項目へ変換した例です。確認結果をPRに残し、コードとIaCの変更を一緒にレビューすると、次の修正時にも前提をたどれます。
個人のプロンプトからチームの開発手順へ
毎回同じ前提を書き直すのは大変です。ポートやヘルスチェック、設定の受け渡し、シークレット、ログ、終了処理といった共通の約束を、リポジトリのREADMEや開発ガイドに置いてAIにも参照させる方法があります。環境ごとに違う値と、共通のルールを分けて書くと伝わりやすそうです。
文章に書いた前提を、どのように確かめられるでしょうか。12FAを手がかりにすると、次のような確認が考えられます。
- 設定一覧をREADMEに記載し、必須値が欠けた場合の起動失敗をテストする
- コンテナの再起動と複数タスクで、永続データやセッションが維持されるか確認する
- 終了シグナルを送るテストで、処理中のリクエストやジョブの扱いを見る
- CIでテストとビルドを行い、IaCの差分はPRで人が確認する
- リリース後にヘルスチェックと主要なログ・指標を確認し、切り戻し条件を決める
こうした確認のうち、繰り返せるものは自動化できそうです。残る判断をチームで行うときにも、12FAはアプリと基盤の接点で何を確認するかを話す足場になると思います。
12FAとあわせて考えること
12FAはアプリケーションの構造やデプロイを考える土台です。権限、ネットワーク、暗号化、コスト、依存ライブラリの管理などは、別の観点からも確認します。AIの説明を読むときは、テスト結果や設定の差分、実際の動作と照らし合わせたいです。
また、AIに渡す情報の範囲も考えておきたいです。既存のリポジトリ規約やアーキテクチャは共有しつつ、実際のシークレットや顧客データを例示に使う代わりにダミーの値を使えます。利用するツールの取り扱い方針も確認します。これは12FAの項目そのものではなく、AIを開発プロセスに組み込む際の前提です。
おわりに
AIのおかげで、アプリを形にする速度は上がっています。その一方で「ローカルでは動いた」と「変更を重ねながら本番で動かせる」の間には、依然として距離があります。
12FAを読み直すと、アプリと基盤の境界にある前提を言葉にすることに役立つと感じます。設定の受け渡し、永続化する状態、プロセスの終了、ログの経路、リリース単位。これらをAIへの依頼やテスト、PRのレビューで少しずつ確認していくと、生成したコードを継続的な開発へつなげやすくなるのではないでしょうか。
参考資料
- The Twelve-Factor App — 12の原則と方法論の原典
- The Twelve-Factor App: Config — 設定とコードの分離
- The Twelve-Factor App: Processes — プロセスの無状態性
- The Twelve-Factor App: Disposability — 起動と終了
- The Twelve-Factor App: Logs — ログをイベントストリームとして扱う