Vagrantとdockerを使って快適な開発環境を作る（サンプルあり）

# Vagrantとdockerでローカル環境を作る！
ローカルの開発環境構築とか面倒ですよね。
転職とか転属とか繰り返しているせいで、プロジェクトが変わる度に開発環境を作るのですが
言語が違ったりライブラリが違ったりサーバー構成がよくわからなかったり
「本番だとサーバー構成が違うからこれは～」みたいなよくわからない突っ込みをもらったり
本当に面倒くさいです。

共有の開発サーバーがあるところとかもありましたが
なんか~~偉そうな~~エンジニアがカスタマイズしちゃってやっぱり本番とかい離したりとか
大規模な改修を入れたいがために平行開発ができなくなっちゃたりとか
まま問題があったりするわけです。

ローカルに本番と（スペックは別にして）ほぼ同等の構成のサーバーが作れれば
それは超素晴らしいことですよね？
ってわけで先人の知恵をお借りしながら作りました。
前職で使っていたものを ~~パクッて~~ 参考にさせていただいてサンプルを作りましたので共有致します。

## 「Vagrant」とか「docker」とか何なの？
~~ggrks~~公式をご参照ください
https://www.vagrantup.com/
https://www.docker.com/

## どうでもいいからさっさとひな形よこせ
ここにアルヨ～
https://github.com/htanaka0828/devbase_for_lamp_template

## 実現したいこと
- ローカル開発環境をチームで簡単に共有したい
- メンバーが同じ環境で開発、検証ができるようにしたい
- API連携とかで複数hostをまたぐようなサービスの開発をしないといけない
- サーバーにライブラリ導入したとしても、失敗したら簡単に巻き戻したい
- 複数のプロジェクトを跨いだ時にカスタマイズされまくった俺のマシン（笑）以外で動かないとかマジ困る
- ってか他人のPCに入っている開発環境がうまく動かないとか解決のしようがないからそんなところで躓きたくない
- 「Macじゃないから」とか林檎信者にdisられるのがよくわからない（windowsユーザー）
- でもIDEとかターミナルとかは普段使い慣れたものを使いたい

というとても身勝手な要望を叶えるために、新しいプロジェクトにアサインされて
「ローカル環境無いよ」と言われた時点ですぐにひな形の作成の着手しました。

## 根本の構想
たなかはwindowsユーザーなので、ローカルマシンでUnixの技術を使わなければいけない場面が非常に困ります。
上記のわがままをある程度叶えるために[DockerCompose](https://docs.docker.com/compose/)を使うのはとても良い手段ですが
DockerはUnixのコンテナ技術を使ったものですので、Windowsマシンとは相性が悪いです。
そんなわけで、dockerコンテナを立てるためのホストマシンとしてVagrantでUbuntuを立てます。
ローカルマシンからの参照はVagrantとdockerのディレクトリ共有機能で良いかなと思いました。

技術背景のみを知っていても作業をしていないと色んなところでずっこけるものです。
そのあたりも触れつつちょっとずつ構築をしていきます。

以降この記事では

- ローカルマシン：俺のマシン（たなかの場合はwindows）
- ホストマシン/vagrantマシン：vagrantで立ち上げた仮想マシン（今回はUbuntu）
- コンテナ：ホストマシン上で立ち上げたdockerコンテナのこと（今回はいわゆるLAMP構成）
で記述していきます。

## とりあえず必要なものをインストールする
ローカルマシンに必要なのは

- vagrant
- virtualBox

です。
インストールの仕方とかはググって下さい。
後述しますが、dockerで立ち上げた複数のマシンのサブドメインの管理をするためにローカルマシンのhostsに勝手に書き込みをしてもらうため
vagrantのプラグイン「vagrant-hostsupdater」も入れておきましょう

vagrantのインストール後に
`vagrant plugin install vagrant-hostsupdater` でOKです。

## VagrantFileを書いていく
まずはホストマシンの設定を書いていきます。
細かい話は基本的に公式から引いてくれればいいと思うのですが、以下の設定を行っています。

- ホストマシンのOSはdockerが扱いやすいようにUbuntu
- ローカルマシンからホストマシンを参照するネットワークの設定
    - IPの設定とポートの設定、ドメインの設定をしています
- ホストマシンのドメインは `htanaka0828.devbase.dev` にする
    - ダサいけど他に思いつかなかった・・・
- hostsに記述してもらうドメインを登録する
    - 今回は"sample.htanaka0828.devbase.dev"を設定しています
- PHP動かす予定なので、メモリは多めに取る
    - defaultだと1028になっているっぽいので、configの配列作ったらメモリリーク起こした
- ソフトとかツールのインストールは別途shellファイルに書いて初回起動時に実行させる

という感じです。
詳細はこちら
https://github.com/htanaka0828/devbase_for_lamp_template/blob/master/Vagrantfile

初回起動の時にはシェルで以下のことをしています。

- dockerのインストール
- docker-composeのインストール
- docker-composeで使うネットワークの追加
- ソースを置くためのディレクト追加と権限の設定
- sambaのインストールと設定と開始

という感じです。
https://github.com/htanaka0828/devbase_for_lamp_template/blob/master/init.sh

### 何でホストマシンにsamba入れるの？
~~俺がお祭り野郎だから~~

実はホストマシンに置いたファイルをローカルマシンにディレクトリ共有しつつdockerにも共有してdockerを立ち上げようとしたら
「パーミッションがないでござる」って言われてdockerコンテナの起動がこける事態にみまわれました。
「SELinuxかな？」と思って色々やってみたのですが、おそらくディレクトリ共有機能の競合のせいだろうという結論に至りました。（未解決）
詳しい人がいたら教えてくらさい・・・

ホストマシンからローカルマシンへの共有機能をsambaに任せたところ解決したので、ソースの共有部分はsambaに任せています。

### 「hostsに記述してもらうドメイン」って？
ホストマシンが持っているipはひとつだけですが、dockerで複数のコンテナを立ち上げ、それぞれがドメインを持つ前提なので
それらをローカルマシンから名前解決してもらうためにローカルマシンのhostsファイルに書き込みをしてもらいます。
たとえば「[http://www.oredomain.com](https://www.google.co.jp/#q=%E6%8A%BC%E3%81%99%E3%81%AA%E3%82%88%EF%BC%81%E7%B5%B6%E5%AF%BE%E6%8A%BC%E3%81%99%E3%81%AA%E3%82%88%EF%BC%81)」も「[http://admin.oredomain.com](https://www.google.co.jp/#q=%E6%8A%BC%E3%81%99%E3%81%AA%E3%82%88%EF%BC%81%E7%B5%B6%E5%AF%BE%E6%8A%BC%E3%81%99%E3%81%AA%E3%82%88%EF%BC%81)」も同一のホストマシン上の別々のdockerコンテナを参照してほしいわけなので


## vagrantを起動してsshで接続する
`vagrant up` をしたら `ssh vagrant@htanaka0828.devbase.dev` でログインしてみましょう。
無事に入れたら一安心です。

### OSのインストールしなくて良いの？
「vagrant 環境構築」とかでググると、「imageをインストールして～」みたいなのがよくありますが
Vagrantfileにどのimageを使うかを記述しておけば手動でvirtualBoxにインストールする必要はありません。
全てが魔法のように勝手に解決されます。
そう、vagrantならね。
もちろん優秀なエンジニア諸兄はちゃんとどうなっているかを知っているべきだとは思っています。

## dockerの設定を書いていく
dockerは基本的に1コンテナ1ホスト（機能）の原則で書いていきます。
LAMP環境だとHTTPサーバーとDBサーバーが別々のコンテナで動くことになります。
ユーザー側と管理側で別々のHTTPサーバーが必要なら別々のコンテナで動かします。
そうなると、コンテナ間のネットワークの設定が面倒ですよね？
そのために「docker-compose」と「jwilder/nginx-proxy」イメージを使います。

### 「jwilder/nginx-proxy」って？
nginxが稼働するdockerイメージです。
https://github.com/jwilder/nginx-proxy

いわゆるプロキシサーバーの役割をします。
docker-composeで一緒に立ち上げてあげればhttpリクエストを受け取って各dockerコンテナに流してくれます。
dockerコンテナを立ち上げる順番はなんでも構わないらしいのですが
立ち上げたdockerコンテナの環境変数に自分に割り振りたいドメインと解放するポート（80とか443とか）の記述
そしてdockerのnetworksの設定が必要らしいです。
同一のnetworksで動いていればdockerコンテナ同士が同じネットワーク内にいるということになり
コンテナ間の通信ができるとか・・・
便利でございます。

## httpサーバーの設定
いわゆる普通のCentOSのサーバーです。
使用するOS、ドメイン、ポートの設定と、ネットワークの設定をしてあげます。
httpサーバーは細かい設定をしたい事も多いので、コンテナ上で解決出来ることはDockerfileに、
ホストマシンのリソースを使わないといけないところは起動用のshellファイルに記述していきます。
今回は、httpとphpの設定ファイルをホストマシンからコンテナにコピーしてapacheの起動をする部分をDockerfileに
接続確認用のindex.phpの生成をshellに書いています。
担当プロジェクトでは、`composer install`とかはコンテナを立ち上げた後に、shellから改めてコンテナにコマンドを送っています。
環境設定の領域ではなくアプリケーション寄りの話なのでこれで良いかなと思っているのですが
そもそも実行できないことに若干の違和感を持っています。

### どうも起動にタイムラグがあるっぽい
dockerコンテナの起動が終わってすぐにdockerに対して何か操作をしようとすると
うまく接続ができない事があります。
コンテナ自体が立ち上がっていてもhttpdプロセスが立ち上がっていないとかよくあるみたいなので
必要に応じてプロセスの監視機構を入れるようにしています（先人の知恵）

### 設定ファイルの共有って必要？
apacheとphpの設定ファイルの共有については、単純にローカライズの問題があったので外から注入するようにしています。
apacheの設定ファイルに関しては、デフォルト部分をなるべく変更したくなかったので、DocumentRootの設定とかは
`/etc/httpd/conf.d`にバーチャルホストの設定を記載したファイルを置きに行くことで解決しています。

## dbとproxyサーバーの設定
これは正直定型句みたいなもんなので、ファイルを見てもらった方が早いかなと。
DBの方
https://github.com/htanaka0828/devbase_for_lamp_template/tree/master/lib/rdb

proxyの方
https://github.com/htanaka0828/devbase_for_lamp_template/tree/master/lib/nginx

DBはmysqlのdockerイメージを使っていますが、DBの設定を環境変数に突っ込まないと起動がこけます。
DBサーバーはhttpサーバーから参照されるので、こちらにもちゃんとVIRTUAL_HOSTの設定をしてあげます。

## いざ起動！！
`docker-compose up -d` で起動！
というのをよく見ますが、設定変更した時とかに前のimageが残っていたりとかで結構煩わしかったので
起動用のコマンドを作っています。
止めて->消して->buildして->立ち上げる
っていうことをdocker-composeでしています。

## ブラウザでアクセス
http://sample.htanaka0828.devbase.dev
にアクセスすると、スタートページが表示されます。
お疲れさまでしたm(_ _)m

# まとめ
転職したばっかりですが、エンジニアの人数が少な~~っていうか社員でエンジニアがたなかしかいな~~くて
一緒に技術を楽しんでくれる仲間がとても欲しい状態です。
「話してみたい！」とか「俺の方ができる」とか思ったら[Wantedly](https://www.wantedly.com/projects/71652)からご連絡ください！
新しい技術の導入もサービス作るのも勉強もかなり自由なので、一緒に面白いもの作っていきましょう！