IBM Cloudのツールチェーンを使って快適なDevOpsを実現する。(Laravel)


# 始めに
この記事は、`Bluemix Users Group`で開催された**2018_GWもくもく会**の活動ログです。
私は主催者ではありませんが、このグループは非常に活動が活発で、困った時に皆さんが助けてくれる温かいコミュニティと思います。
既に`IBM Cloud`を使っている方も、これから使ってみたいという方も、ぜひぜひ、参加してみてください。
[https://bmxug.connpass.com/](https://bmxug.connpass.com/)

# 環境について
ツールチェーンでは、様々なバージョン管理の仕組みが提供されていますが、ソース管理はGitHubを使っている前提とします。
また、この記事でデプロイする対象は`Laravel`です。ただ、他の言語やフレームワークでも応用が効くと思います。
↓↓ちなみに、LaravelをIBM Cloudに乗せる方法はこちら↓↓
[IBM CloudにLaravelをデプロイする方法](https://qiita.com/motuo/items/b7d1fdf297349daca9fd)

# 実現したこと
現在、個人の開発でIBM Cloud(ライトアカウント)を使っています。これまでは

1. ソースを修正
2. GitHubにコミット&Push
3. 環境変数(.envファイル)をローカル環境からサーバー用に書き換え
4. 手動でIBM Cloudにデプロイ

この流れで開発をしていました。このやり方でも決して開発は出来るのですが、.envを書き換え忘れていらぬ不具合を起こしたりと、あまりスマートな手法ではありませんでした。

という事で、IBM Cloudには`ツールチェーン`を使って、GitHubへのPush以降を自動で行えるようにしてみます。

【新しい流れ】
1. ソースを修正
2. GitHubにコミット&Push
3. GItHubの更新をIBM Cloudが検知して、アプリケーションをビルド
4. ビルドされたアプリケーションを自動でデプロイ

# 実際の手順について

## ツールチェーンを設定する
Cloud Foundryアプリを開き、画面左側の概要をクリック。画面右下に「継続的デリバリー」があるので、「有効化」をクリック

![キャプチャ1.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/97aca0f6-49af-b3f3-c070-c670ab4be1a0.png)

下記の画面が出るので、「作成」をクリック

![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/1b868a49-c5bb-5728-72c9-eb8dc29c4a86.png)

今回はGitHubを使うので、デフォルトのGitを削除(キャプチャはIssueを削除しようとしていますが、Gitを削除すれば両方とも消えます)
![キャプチャ3.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/c4d95893-76be-7a43-26a2-56e4e0575783.png)


画面右上のツールの追加より、GitHubを追加。認証が求められるので、GitHubのアカウントを認証。
![キャプチャ4.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/0f69787e-62ce-520a-c1f5-970d9fdabd7e.png)

今回は既存のリポジトリを使うので、リポジトリ―タイプを「既存」に変更し、ソースリポジトリのURLを入力して「統合の作成(または保存)」をクリック
![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/ab835839-66b6-2a6a-0cbd-297c4fb5afbc.png)

これで基本的な連携は出来るようになりました。
![キャプチャ6.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/8888c3ea-a640-10af-d01e-6ae50ca29039.png)


## Delivery Pipelineを設定する。

### Build Stageの設定
Delivery Pipelineをクリックすると、デフォルトで「Bulid Stage」と、「Deploy Stage」が用意されています。
Build Stageを変更していきましょう。
Build Stageの右上の歯車マークから、「ステージの構成」をすると…
![キャプチャ7.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/da32354e-0a67-34a5-a73c-8bdbe262fcbb.png)

下記の画面が表示されます。まずは、「入力」の設定をしていきいます。
![キャプチャ8.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/3f6c8012-925a-4916-f5c0-6dc9bcb51483.png)


Gitリポジトリで、自分のリポジトリを選択します。ブランチも必要に応じて変更しましょう。

#### Laravelの環境変数を設定する。

変更したら、ジョブの設定をします。ビルダータイプをシェルスクリプトに変更します。
ちなみに、シンプルの場合はGitリポジトリからクローンをするだけの様です。これをシェルスクリプトに変更する事でクローン後の処理を定義する事が出来ます。

シェルスクリプトの例は下記の通りです。

```bash

#!/bin/bash
# your script here

# change .env
# Database
cp ./htdocs/.env.example ./htdocs/.env

# DB_HOSTをローカルサーバから、ClearDBに変更
sed -i -e "s/DB_HOST=127.0.0.1/DB_HOST=cleardb.net/g" ./htdocs/.env
# 以下、チェンジをしていく
```

`Laravel`の環境変数である、`.env`をリポジトリにある`.env.sample`からコピーしてサーバ環境用に置換する処理です。(これが無いと、後続のComposer updateで失敗します)

# ↑↑記事訂正↑↑
先日はこの様に書きましたが、実はLaravelは
> .envファイルにあるすべての変数は、サーバレベルやシステムレベルで定義されている、外部の環境変数によってオーバーライドすることができます。

でした…[詳細はこちら](https://readouble.com/laravel/5.5/ja/configuration.html)

というわけで、シェルで環境変数を書き換えていくのはあまり良い手段ではないです。セキュリティ上もあまりお勧めではないので、Cloud Foundryの環境変数を定義してしまいましょう。
環境変数はランタイム⇒環境変数⇒ユーザー定義から可能です。
(下記の例としては、`APP_DEBUG`を`false`にしています。同様にDBへの接続情報等も定義してしまいましょう。)
![キャプチャ9.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/bc4f12d4-8af6-c7a9-93c3-486fb6544d38.png)


こうすればシェルの中では、
```bash
cp ./htdocs/.env.example ./htdocs/.env
```
をするだけでOKです。それすら面倒な場合は、環境変数で`APP_ENV`を`produtction`等としたうえで、`.env.production`をダミーで作っておくと良いと思います。(内容は`.env.sample`と同じでOK)

### Deploy Stageの設定
Build Stageと同様に「ステージの構成」をクリックすると、デプロイ・スクリプトの構成が出来ます。
私の環境だけかもしませんが、認証のコマンドを入れないと、Deployに失敗します。(自動でやってくれれば良いのに…)

```bash
#!/bin/bash

bluemix api https://api.xxx-xxx.bluemix.net
bluemix login -u test@example.com -o testProject -s testSpace -p Password

cf push "${CF_APP}"

# View logs
# cf logs "${CF_APP}" --recent
```

# 最後に
上記の設定を行う事で、GitHubの更新後に更新したソースを自動でデプロイする事が出来るようになりました。
ツールチェーンにはこれ以外にも様々な機能があるので、試してみるのも面白いと思います。

# 番外編
上記の手法に至るまで、様々な試行錯誤がありました。
`composer.json`に.envのコピーを組み込み、cloud foundryの環境変数で上書きする、というものでした。
これをしてしまうと、`composer.json`がIBM Cloudに依存してしまいローカルで動かなくなってしまうので私は採用しなかったのですが、
非常に参考になるスクリプトでしたので、残しておきます。

```json
"post-update-cmd": [
    "echo post-update-cmd",
    "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
    "sed -i -e s/DB_CONNECTION=mysql/DB_CONNECTION=pgsql/g .env",
    "sed -i -e s/DB_HOST=127.0.0.1/DB_HOST=`echo $VCAP_SERVICES | jq .elephantsql[0].credentials.uri | awk -F\/ '{print $3}' | awk -F: '{print $2}' | awk -F'@' '{print $2}'`/g .env",
    "sed -i -e s/DB_USERNAME=homestead/DB_USERNAME=`echo $VCAP_SERVICES | jq .elephantsql[0].credentials.uri | awk -F\/ '{print $3}' | awk -F: '{print $1}'`/g .env",
    "sed -i -e s/DB_DATABASE=homestead/DB_DATABASE=`echo $VCAP_SERVICES | jq .elephantsql[0].credentials.uri | awk -F\/ '{print $4}' | rev | cut -c 2- | rev`/g .env",
    "sed -i -e s/DB_PASSWORD=secret/DB_PASSWORD=`echo $VCAP_SERVICES | jq .elephantsql[0].credentials.uri | awk -F\/ '{print $3}' | awk -F: '{print $2}' | awk -F'@' '{print $1}'`/g .env",
    "sed -i -e s/DB_PORT=3306/DB_PORT=`echo $VCAP_SERVICES | jq .elephantsql[0].credentials.uri | awk -F\/ '{print $3}' | awk -F: '{print $3}'`/g .env",
    "mkdir -p /tmp/app/bootstrap/cache",
    "mkdir -p /tmp/app/storage/framework/sessions",
    "mkdir -p /tmp/app/storage/framework/views",
    "mkdir -p /tmp/app/storage/framework/cache",
    "Illuminate\\Foundation\\ComposerScripts::postUpdate",
    "php artisan key:generate"
],
```