バラ - DockerとNginxを利用し複数バージョンのアプリケーションを同時に動ける簡易環境を作ってみました

# 薔薇

# バラって何？

薔薇です。

ひとつのサーバ上おなじのアプリケーションを複数バージョンに動かす簡易のデプロイ環境です。

# 何ができる

複数バージョンのウェブサービスをDockerコンテナとして同時に動いて、リバースプロキシのNginxで特定のhttp headerを判断し、適当なコンテナにアクセスを振り分けること。

テストにも、A/Bテストにも、さらにgray deployも使えると思います。

アーキテクチャは下記の図のようです：

![bara-arch-jp.png](https://qiita-image-store.s3.amazonaws.com/0/2179/f18a0114-3afa-e890-6c81-e9bdddb4a683.png)


キーポイントはNginxです、とりわけ`proxy_pass`、`map`などの仕組み。

例えば、これはNginx設定ファイルの一部です：

```
{{upstream}}

location /{
  add_header u $u;
  proxy_pass http://backend_$u;
}
```

baraでは動的に複数の`upstream`を作成し、`map`の構造通じて、`$u`の値を求めて、該当するバックエンドにアクセスを委託します。

詳しいは[ソースコード](https://github.com/liubin/bara)をご確認ください。MITライセンスで配布されています。


# 使い方

以下、簡単な使いかたを(主にDev環境で)イメージして説明します。

## 事前設定事項

まずは、設定ファイルとして、下記のいくつのファイルを実際の環境にあわせて設定してください。


### Docker Daemon

`config/initializers/docker.rb`を編集し、Dockerへの接続情報を設定します。

### Nginx Server

`config/initializers/nginx.rb`を編集し、Nginxの設定ファイル場所と`nginx`実行ファイル場所を設定します。

### .envをを生成

`.env`にはDocker用証明書の格納場所、SMTPの設定とTokenなどを設定します。

```
cp .env.example .env
vi .env
source .env
```

## Rails を起動します

簡単に言えば、開発環境で`rake db:migrate`にしてから`rails s -b 0.0.0.0` で良いでしょうか。

`production`環境なら：

```
RAILS_ENV=production rake assets:precompile
RAILS_ENV=production rake db:migrate
RAILS_ENV=production rails s -b 0.0.0.0

```

## Nginx設定ファイルテンプレート

まずは、Nginxサーバ用の設定ファイルのテンプレートを用意します。

実際のNginxの設定ファイルは、デフォルト(緑の「Active」ラベルが付いている項目)になっているテンプレートに基づいて作成されます。

また、テンプレートに`{{upstream}}`というプレースホルダが書けます。書くと、Nginxの設定ファイルを生成する場合、実際に動いてるDockerコンテナをベースに`upstream`を動的に作成します。

テンプレートを編集する例：
![jp-edit-nginx-template.png](https://qiita-image-store.s3.amazonaws.com/0/2179/16354021-211d-b40a-4562-01e46c1ad696.png)

レンプレード一覧：

![jp-template-list.png](https://qiita-image-store.s3.amazonaws.com/0/2179/11a8efff-fa93-d3c9-f0b9-e4bc20ebddb8.png)

## Docker イメージ管理

baraは簡易なイメージ管理機能が備えています、`dokcer pull`、`docker rmi`、`docker inspect`など該当するコンマンド。

イメージ一覧：

![jp-image-list.png](https://qiita-image-store.s3.amazonaws.com/0/2179/372f3a1a-72da-6239-b80f-7c7057b5fd6e.png)

イメージをプルする：

![jp-pull-image.png](https://qiita-image-store.s3.amazonaws.com/0/2179/b0a95a6b-ea45-8aac-5d40-d6d23110cec8.png)

## コンテナをデプロイする

コンテナをプロイする画面：

![jp-deploy-container.png](https://qiita-image-store.s3.amazonaws.com/0/2179/defe385f-4221-d99d-4dd8-f119360681c6.png)

今の段階で設定できる項目は少ないです。ただコンテナ名、`CMD`に渡すパラメーテのみです。

パラメータは行ごと（改行で）に分けられます。

コンテナデ一覧画面にては、コンテナを停止、起動また削除することができます。

![jp-containers-list.png](https://qiita-image-store.s3.amazonaws.com/0/2179/574d8243-cb76-2cac-7e69-b1d0f4773c3f.png)


## Nginx設定ファイルを作成

Nginxサービス画面では、Nginx設定ファイルの生成、編集とNginxサーバの再起動(`nginx -s reload`または`service nginx restart`)などができます。


Nginx設定ファイルの生成は、デフォルトのテンプレートに基づいて、動いてるDockerコンテナ情報取得して作成されます。

![jp-nginx-conf.png](https://qiita-image-store.s3.amazonaws.com/0/2179/590e18bb-c720-261f-023d-d9c3c7ec013b.png)

中に：

```
  map $http_v, $u{
    ~aaa aaa;
    default default;
  }
```

`$http_v`はHTTP Headerの`v`を表すもの、その値に対し、$uに値を与えます。ブラウザにて設定したHTTP header `v`から、適当な`$u`を見つけ出し、バックエンドとして使われます。

もし作成した設定ファイルに不備があたら、その場で編集することもできます。

![jp-edit-nginx-conf.png](https://qiita-image-store.s3.amazonaws.com/0/2179/74e90fa1-cfef-44b9-8400-50dcc5dbae43.png)

設定ファイルが整えたら、Nginxサーバを再起動します。

## ModHeaderでアクセスしたいコンテナを指定します

指定したコンテナのアプリケーションにアクセスするのは、[ModHeader](https://chrome.google.com/webstore/detail/modheader/idgpnmonknjnojddfkpgkljpfnnfcklj)を利用しHTTP Headerを設定することで実現できます。

下記の図のように、`v` headerを適当な値を指定すれば、その名に一致するコンテナをNginxが振り分けます。

![jp-modheader.png](https://qiita-image-store.s3.amazonaws.com/0/2179/3e732cf4-9dea-418f-6c95-243f2e24d36f.png)

それにNginxの設定ファイルにもし`add_header u $u;`を追加すれば、ブラウザにてどのバックエンドが使われたのもはっきりわかっています。

![jp-response-header.png](https://qiita-image-store.s3.amazonaws.com/0/2179/5d5a1854-06b7-4a11-991b-a1ee7291c5e8.png)

# 制限事項

今はテスト環境で実際に使っています。ただ制限事項もいくつあります。使えるかどうか、多分これらの要因は決め手ではないでしょうか？

- `Volume`が使えない
- `-P`をしています
- 一つのサーバ上にしか動けない
- Nginx設定ファイルは一つしか預けられない。

自分はStateless主義なので、`-v`が使わないです。

`-P`は、全てのポートをホストに公開しています、でも普通の場合、一つのアプリが公開するポートは一つのはずです。これでも問題ない。

また第3点、今の段階では、うちにはその要求はないです。

第4点はややこしいです。ちょっとした複雑のアプリケーションは、Nginxの設定来るはいくつの設定ファイル分散化されています、その様なケースでは、今のbaraまだ対応できません。