nazolabo

なぞさんのブログ

ワンポイントTwelve-Factor App(10) : 開発/本番一致

この記事は、The Twelve-Factor Appを補足し、実際に現代的なWebアプリケーションで適用する場合の注意点などを紹介するシリーズです。下記の原文を読んだ上でのワンポイント解説になります。

12factor.net

概要

  • 開発環境と本番環境の差異を最小限にする
  • 似たようなバックエンドを吸収するアダプタのようなものは使わない・使ってもバックエンドは開発と本番で同種にする

これは何を表しているか

「手元では動いたが本番で動かない」というのは開発あるあるです。これを防ぐには、開発環境と本番環境がほぼ同一になっているのがベストです。

環境の差異というのは、大きく「コードそのものの差異」と「周辺環境の差異」の2つに分かれます。

「コードそのものの差異」というのは、コードベースが本番と開発で大きく離れてしまうということです。リリースのできない大きな開発が続くとこのような状態になります。小さなコード量を短時間で少しずつリリースし、なるべく本番と開発のコードの量の差を減らすことが重要です。リリースの単位が大きくなると、影響範囲も大きくなり、障害の検知の難易度が上がります。細かくリリースすることで細かなフィードバックを得ることができます。

「周辺環境の差異」は、例えば「キャッシュストレージに開発ではメモリを使うが本番ではRedisを使う」「ファイルストレージに開発ではローカルファイルシステムを使うが本番ではAWS S3を使う」といったことが考えられます。ActiveRecordのようなものを使うと、DBすら「開発ではSQLite、本番ではMySQL」のような構成が可能になります(現実にはかなり厳しいですが)。しかし、これらは似ているようで違うものなので、詳細な挙動の差異により「本番だけ動かない」といったケースが発生する恐れがあります。「似ているから」「アダプタが吸収してくれるから」といって開発と本番で違うバックエンドを使うことは避けたほうがよく、避けることにより「本番で動かない」可能性を最小限にすることができます。

「3. 設定」でも出てきた通り、環境毎に設定ファイルを作ってしまうと環境の差異が大きくなります。開発環境ではデバッグ用ツールなどで多少の差異が生まれることもありますが、極力どの環境もほぼ同じの構成にするようにしましょう。

実際に運用する場合

リリースのサイクルを早めるには、開発手法の見直しが必要です。大きな機能の開発の場合でも、例えば他に影響を与えないコードは先にリリースしてしまう・バックエンドの処理だけ先にリリースしてしまうという方法でリリースの粒度を小さくすることができます。

環境の差異に関しては、開発環境ではDockerを使うことで本番とほぼ同等のバックエンドサービスを用意することができます。S3のようなマネージドサービスでも最近はminioのような互換システムがありますので(金とセキュリティが問題なければ開発時もS3を使うのが一番良いです)、通常の開発時ではdocker-composeで必要なバックエンドサービスを一発でローカルで起動できる状態にすることは容易になったと思います。

開発環境を本番に近づけるにはDocker上(あるいはもっと厳密な仮想環境)で動かすのが良いですが、実際の開発時にアプリケーションがDocker上で動くと処理速度などの点で不利なことが多いので使わないこともあります。その場合でも、例えば非開発者がローカルで動作確認したいという場合を考慮して、 docker-compose up の1コマンドだけで確実に上がる環境を用意しておくと良いです。その環境が用意できると本番でDockerで運用するのも簡単になります。

開発者が全Docker環境を使うかどうかは好みの問題があると思いますが、私は前述の通りDockerでアプリを動かすのは速度面などで不利になることが多いので、「MySQLなどのミドルウェアのみDockerで用意し、PHPRuby、Node.jsといった環境はホスト側で直接起動する」という構成が一番良いと思っており、2バージョンで起動できる環境を用意するようにしています。またこの構成だとgit pre-commit hookなども使いやすいところが良いと思います。

Dockerは仮想化ツールとは違いますので、カーネルのバージョンなどで埋められない差異が多少存在することは頭に入れておきましょう。しかし、一般的な開発でそこが問題になることはあまりありません。