Deployment environment - Webアプリケーションの環境定義（本番/検証/開発/...） について考えてみる



## はじめに

<script src="https://gist.github.com/anfangd/9e74f88ae1d2330f5aa84bc3fab2ed65.js"></script>

Webブラウザ や スマートフォンのアプリケーションと連動する Webアプリケーションの実装をよくやるんですが、フルスクラッチで数ヶ月（〜５ヶ月前後）の期間で構築する案件が多めで、その度に新規顧客 や 新しく発足したプロジェクトチームごとに環境（本番/検証/開発/...）の定義が違ってしまい、チームで共通認識を得るのに難儀します。

環境分割の前提が身についているメンバーなら良いですが、エンドポイントや環境固有パラメータをハードコーディングしてしまい、環境の向き先変更で毎度修正しなきゃならない（そうならないように、パラメータで向き先変更出来るような仕組み作りのサポートをしなければならない）ことも多々あるので、このあたりはお作法として情報がまとまっていて欲しいのですが、日本語の文献をあまり見つけることができませんでした。

こういう情報はプロジェクトやサービス、予算や組織ごとに検討・最適化されるものであってベストプラクティスとして定義するのも難しいのかもしれません。

近年の Webアプリケーションは `.env` などで環境依存のパラメータを渡すことで、コードは全環境同じものを使う前提であることが多いと思うので、アプリケーションの実装者は深く意識しなくても **Web Application Framework** のお作法に従っておけば大きな問題は発生しないと思いますが、システム全体の設計をしたり、プロジェクト全体を見通して テスト実行環境 や クライアント・アプリケーションとの接続 、 外部連携アプリケーション との連動を考慮しなければならない身としては、もう少し一般的で抽象化された情報がまとまっていて欲しいと考えていました。

最近、Terraform で AWSを使用したアプリケーションのプラットフォームを構築する手順を整理したのですが、ここでも環境分割の定義に手間取ったので、メモがてら理想的な環境分割の定義と用途がどういうイメージになるのか考えてみました。

### 書いてる人

- IT業界8年目
- PM から PG 、企画や営業支援など
- OSSベースでWebアプリケーションを実装
- Mobileアプリ（スマホアプリ）と連携
- クラウドを使ったシステム基盤の構築（ Terraform, CloudFormation）
- フルスクラッチの受託開発多め（小型〜中型）

## システムの構成 と アプリケーション

### サーバ環境の変化

システムが稼働する環境はここ数年で大きく変わったように感じます。

私が IT業界に足を踏み入れた 2012年は クラウドという言葉はあっても、まだまだ サーバホスティング事業者の専有サーバや VPS がメインで使用されており、PaaS や mBaaS、 IaaS という概念はまだまだ一般的ではなかったように記憶しています。

また、過去を振り返ると、インターネットよりかなり前の時代は、大学や研究施設にある大型のコンピュータにターミナル接続して、そこのサービスを使用していたり、各企業の拠点にサーバルームがあって、基幹系のシステムはそういった場所から提供されるアプリケーションを利用していたというようなことを、何かの本で読みました。

- [カッコウはコンピュータに卵を産む　上](https://amzn.to/31lOqUw)
- [カッコウはコンピュータに卵を産む　下](https://amzn.to/2ZXz1gp)

この↑あたりの話がとくに、そういった時代のことだったと思います。

メインフレームや、クライアント独立のパーソナルコンピュータの時代から、90年代以降のインターネット接続が全盛の時代、2000年代後半以降のモバイル端末が一般に広がった時代、2010年代中盤以降のクラウドが一般的となった流れを振り返り、そこで稼働していたシステム（アプリケーション）の種類を考えると、システムの利用者や用途も大きく変わっていったのだろうということは想像に難くありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/4cc9366f-56b4-b53d-3978-20d31eeaa801.png)


システムの調達にかかるコストや手間は、この10年でも大きく削減されました。

**昔はWebアプリケーションを一般に公開するために、物理サーバを調達し、外部・内部のネットワーク環境を整備し、アプリケーションを実装して、デプロイ・テストして、ドメイン登録や切り替えをして** というような煩雑な作業が多くあったはずです。

しかし現在では、AWS や GCP、 Azure などを使用すれば、IaCのコード流し込みで、そこそこ大きめのシステムでも早ければ1時間以内にアプリケーションのシステム基盤構築が完了し、簡単にアプリケーションを公開出来るようになりました。

何が言いたいかというと、アプリケーションが稼働する環境を用意するのが面倒だった時代は、１つのプラットフォームで複数の環境を賄うこともあり、例えば Apache の VirtualHost を使用して、１台のサーバが複数環境のアプリケーションを抱えており、DBサーバへの接続や関連ミドルとの接続も、各アプリケーションごとにハードコードされる時代もあったのだろうな、ということです。

また、仮想化の仕組みが整備されておらず、ローカルPCで開発したアプリケーションを ローカルPCでそのまま実行確認できなかった場合には、共有の開発サーバにアプリケーションをデプロイして確認する訳ですが、インフラやミドルの自動構成スクリプトが無い時代は、それこそデプロイやパラメータ設定などもかなりの労力があったのだろうなと思います。

### 近年の Mobile / Web Application アーキテクチャ

2019年09月現在の一般的な Mobile と Web のアプリケーション・アーキテクチャは次のような構成が一般的かと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/155cc0f9-1b68-acf0-f00e-e0abf9fae1ea.png)

Webアプリケーションの部分は IaaS 、 PaaS 、 FaaS のどれを使用するかや、 Managed Service の使用有無によって細かな表現の差があるかもしれませんが、基礎的な構成を考えると、外部からの http(s)  Request を受けつける Webサーバが存在し、そこから処理要求に応じて処理を実行する Applicationがあり、その先に 関係データベースやストレージ領域でデータを保持する役割を担う データリソースが存在するという構成は変わらないと思います。

## 環境の定義と用途

やっと本題です。

### Deployment environment

Wikipedia の [**Deployment environment**](https://en.wikipedia.org/wiki/Deployment_environment) の項目には、ソフトウェアのデプロイに関して次の記述があります。

| Environment/Tier Name | Description |
|:--|:--|
| Local | Developer's desktop/workstation |
| Development/Trunk | Development server acting as a sandbox where unit testing may be performed by the developer |
| Integration | CI build target, or for developer testing of side effects |
| Testing/Test/QC/<br>Internal Acceptance | The environment where interface testing is performed. A quality control team ensures that the new code will not have any impact on the existing functionality and tests major functionalities of the system after deploying the new code in the test environment. |
| Staging/Stage/Model/<br>Pre-production/<br>External-Client Acceptance/<br>Demo | Mirror of production environment |
| Production/Live | Serves end-users/clients |

- 引用：[Deployment environment - Wikipedia](https://en.wikipedia.org/wiki/Deployment_environment)

これらをすべて使用するかは別として、システム開発プロジェクトとして使用する環境の用途の分類としては分かりやすい表現です。

この表を ~~乱暴に~~ シンプルにまとめてしまうと次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/e3c062e5-f259-39ff-cdcb-7ca126fd39d9.png)

### 環境の用途と本番リリースまでのデプロイの流れ

それでは、定義した環境を **誰が** **どのように** 使用するのでしょうか？

しばらく前に投稿された [こちらの記事](https://dltj.org/article/software-development-practice/) を参考に、各環境の利用の流れをまとめてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/4462fb60-0401-6977-987b-216314137098.png)

- PlantUML Code: [Deployment_Environments_and_Deployment_Flow.md - GitHub Gist](https://gist.github.com/anfangd/9e74f88ae1d2330f5aa84bc3fab2ed65)

### 実装目線で見た環境定義と呼称

クラウド環境に各環境を構築する場合のイメージは次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/fb1f9043-3f5d-c4b4-4465-7c4efbbb60e2.png)

また、Webアプリケーションの実装を行う際に具体的に意識する環境名や実行環境、 git のブランチ名について考えると次のようになります。

|#|環境名（英名）|環境名（和名）|場所|`.env`|git branch|
|:--|:--|:--|:--|:--:|:--|
|1|Production|本番環境|Remote|OSに定義した<br>環境変数|master|
|2|Staging|準本番環境、デモ環境、<br>ステージング環境|Remote|OSに定義した<br>環境変数|release|
|3|Test|テスト環境|Remote|OSに定義した<br>環境変数|develop|
|4|Integration|システム統合環境|Remote|OSに定義した<br>環境変数|develop|
|5|Development|開発環境|Local|○|feature|
|6|Local|ローカル環境、実装環境|Local|○|feature|

`.env` については、[こういうもの](https://qiita.com/closer/items/f8d8ba00ae86d7051764)です。

なお、 git のブランチ構成については、次のような [git-flow](https://datasift.github.io/gitflow/IntroducingGitFlow.html) に従ったものをイメージしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/9db72dc2-c254-e152-9f4e-0224ce47e096.png)

- 引用：[A successful Git branching model](https://nvie.com/posts/a-successful-git-branching-model/)

### 環境を十分に用意できない場合の失敗

例えば、こういう環境ごとに用途を分類せずに、 **Production と Local の2つの環境しか用意していない場合**、ローカルPCでのコード修正をいきなり本番に上げることしかできず、適切なテストを実施できなかったり、ビジネスや品質の部門が適切に動作確認や機能検証を行うことができません。

大部分の訓練されたエンジニアからすれば「何を当たり前のことを...」という感覚になるかと思いますが、新規プロジェクトで顔なじみのないプロジェクトメンバーでプロジェクトを推進しなければならないときや、駆け出しエンジニアと少数でプロジェクトを進める際には、こういった基礎的なことを図や具体的な文書で定義して共通認識を描いておかないと、予算の都合で十分な環境を手配できなかったり、テストが始まる段階で手痛いバグを踏んだりしてしまいます。

これは サーバ側で実行される Webアプリケーションに限らず、iOS や Android 向けのアプリケーションについても同様です。
ビルドの方法や、WebAPI の向き先、使用する証明書やキー情報がハードコーディングされるケースが往々にしてあります。１度実装してしまえばその後はメンテナンスのみとなり、頻繁に変更がかかる部分ではないので見落とされがちになり Webの記事 にもなりづらく、サービスの運用経験や構築経験が浅い場合は想定もしない部分なのかもしれません。

## おわりに

なるだけ汎用的に使えるような知識としてまとめることを意識して記事を書き始めてみましたが、いざやってみると難しかったです。思った通りまとめられた気がしません。

Wikipedia の Deployments environment の記事を参考に 6つも環境を分ける方法を記載しましたが、いつもは次の４つは最低でも構築するようにしています。

|#|環境名（英名）|環境名（和名）|場所|`.env`|git branch|備考|
|:--|:--|:--|:--|:--:|:--|:--|
|1|Production|本番環境|Remote|OSに定義した<br>環境変数|master||
|2|Staging|準本番環境、<br>デモ環境、<br>ステージング環境|Remote|OSに定義した<br>環境変数|release|テスト環境もここ|
|5|Development|開発環境|Remote|OSに定義した<br>環境変数|develop|統合環境もここ|
|6|Local|ローカル環境、<br>実装環境|Local|○|feature|ここで UnitTest も<br>実行する|

システム開発をする際、動くもの（本番環境）だけを意識してプロジェクトが進むことがありますが、「環境」という概念の基で、適切に運用・管理が必要だということが少しでも広まれば良いかな。

## 参照

- [本番環境・検証環境・開発環境は、英語で何？](http://www-creators.com/archives/4818)
- [ステージング環境とは？開発環境、検証環境との違いと役割](http://www-creators.com/archives/780)
- [Deployment environment - Wikipedia](https://en.wikipedia.org/wiki/Deployment_environment)
- [Professional Programming: DTAP – Part 1: What is DTAP?](https://www.phparch.com/2009/07/professional-programming-dtap-%E2%80%93-part-1-what-is-dtap/)
- [DTAP is dead - The Art Of Coding](https://wouterdekort.com/2019/01/15/dtap-is-dead/)
- [Traditional Development/Integration/Staging/Production Practice for Software Development](https://dltj.org/article/software-development-practice/)