Vagrant+Dockerなんて使わなければよかった・・・

と思わないために環境構築時や開発時のはまり所やひっかかった所を共有します。

Vagrant+Dockerで以下の環境を構築して開発を行っています。

* 開発環境
ホスト機(windows)<->Vagrant(centos)<->Docker(centos)

* ステージング・検証環境
centos<->Docker(centos)

# 環境構築時
## Dockerfileの作成
Dockerfileに下記のような記述をして、mysql起動後に初期データベースを作ろうとしても失敗します。

```docker
RUN service mysql start
RUN mysql -uhoge -phogehoge -e"CREATE DATABASE hoge CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'"
```

DockerはRUN毎にプロセスを持っているようなので、何かを起動した後に実行したい処理がある時は&&で繋げる必要があります。

```docker
RUN service mysql start &&
mysql -uhoge -phogehoge -e"CREATE DATABASE hoge CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'"
```

cdなどでカレントディレクトリを移動する場合も同様です。
WORKDIRというコマンドがありますので、これを使えば&&で繋げる必要もなくなります。

またDockerfileでchkconfig mysqld onなどで自動起動設定していても、コンテナの起動時にはmysqlは起動されていません。initスクリプトの実行はdockerではスキップされる為です。

Docker起動時に起動したいサービスがある場合、ENTRYPOINTやCMDを使うか、起動スクリプトをdocker run時に指定してやる必要があります。

## Vagrant+Dockerの連携
vagrant upするだけでWebシステムをブラウザで確認でき、
ソースもホスト機でデバッグ可能、mysqlなどのデータベースも
ツールで確認可能になる状態にする事ができます。

ポイントはポートフォワード、ファイル共有、vagrant up時の自動起動設定です。

### ポートフォワード
Docker上のwebサーバーにアクセスするにはホスト機->vagrant->dockerを
ポートフォワードで繋げてやれば、アクセス可能です。

Vagrantfileでホスト機とvagrantのポートフォワード

```cl:Vagrantfile
config.vm.network "forwarded_port", guest: 8081, host: 8081
```

docker runコマンドでvagrantとdockerのポートフォワード指定

```cl
docker run -d -i --name hoge -p 8081:80 -t hoge /bin/bash
```

### ファイル共有
dockerに展開しているソースでそのままデバッグなどしたい場合は、
ホスト機<->vagrant<->dockerをファイル共有などで繋げてやる必要があります。

Vagrantfileでホスト機とvagrantのファイル共有

```cl:Vagrantfile
config.vm.synced_folder "src", "/vagrant", :mount_options => ["dmode=777", "fmode=777"]
```
docker runコマンドでvagrantとdockerのマウント指定

```cl
docker run -v /vagrant:/var/www -i --name hoge -p 8081:80 -t hoge /bin/bash
```

### vagrant起動時にdocker起動
あらかじめDockerコンテナを作成しておき、vagrant起動時、
Dockerとコンテナが起動するように構成します。

```cl:Vagrantfile
  config.vm.provision "shell", inline: <<-SHELL
    sudo service docker start
    sudo docker start hoge
  SHELL
```

後、sshのポートもポートフォワードしてやれば、
Dockerコンテナにsshで入る事やdbにsshトンネルで繋げる事も可能になります。

ここまで設定してやれば、vagrant upするだけで即、開発デバッグを行える状態になります。

## Docker永続化
DockerでくぐっているとDocker永続化とか、mysql永続化とか、永続化という言葉が出てきます。
私は言葉をそのまま捉えて、最初はDockerは**オンメモリ**で動くのだと思っていましたが、そうではありません。
**Dockerコンテナ自体は永続化で保存**されています。

以下のような場合、Dockerコンテナはimageなどに保存しておかないと使えなくなります。

* Dockerのバージョンアップを行い、以前バージョンとコンテナファイルの認識などに差分が発生した。
* ENTRYPOINTなどに指定した起動時の処理が失敗するような場合、コンテナ自体の起動ができなくなります。

他にもコンテナを誤って`rm`してしまったなどのケースがあると思います。
このような場合は永続化すべきデータがあっても戻す事ができません。
よって**Dockerコンテナは破棄される前提**で考えていた方がよく、
永続化が必要なデータファイルなどは下記のような永続化対策を行っていた方がいいです。
[Docker でデータのポータビリティをあげ永続化しよう](http://qiita.com/mopemope/items/b05ff7f603a5ad74bf55)

Dockerの永続化はこのような抽象的な意味あいで使われるようです。

## Dockerコンテナのディスクサイズ割り当て
Dockerコンテナは初期設定では(仮想)ディスクサイズの割り当てが10GBに設定されています。
永続化対策をして、サイズが大きくなりそうなディレクトをマウントなどすれば、10GB以上になる事はほとんどないかもしれませんが、10GB以上に設定変更する場合は、一旦、Dockerイメージをすべて削除して設定し直す必要があります。
本番運用が始まった後にDockerイメージをすべて削除するのは難しい場合もあると思いますので、運用前には永続化も含めて、ディスクサイズ割り当ても考慮しておいた方がいいです。

## DockerのCPUアーキテクチャの依存
**DockerはCPUアーキテクチャに依存**します。x84ベースのDockerはx64では動きません。最近ではほとんどx64ベースになるので問題にはならないと思いますが、折角Dockerイメージを苦労して作ったのに本番環境では使えなかった、という事がないようにしましょう。

# 開発時
## VagrantのDockerが消えた・・・
ある日、vagrant upをすると起動はしたのですが、
インストールしているはずのDockerが消えさってました。
原因はよく分かりません。周りにはvagrant destroyを
したのではないかと言われましたが、その時は
そのコマンド自体知らなかったので、ありえないです。
この現象を2回経験しています。
1回目の時はvagrantをbox化していなかったので、
構築し直し、2回目の時はboxから戻しました。
vagrantはタイミングを見てbox化しておいた方が、後々良さそうです。

## Vagrantの容量が足らなくなった
vagrantにいろいろなdockerイメージを入れたり、
buildしたりしていたのですが、公式のvagrant boxのcentosの
ディスクサイズは8Gぐらいしかなく、docker buildができなくなりました。

[vagrantのbox容量を拡張する方法](http://gyagya1111.blogspot.jp/2015/06/vagrantbox.html)

上記を参考にさせてもらいboxを拡張しましたが、
結構時間がかかります。開発時は時間が取れない時もあるので、
できれば容量は構築時に大目に拡張しておくのがいいと思います。

## cssの変更が反映されない
cssを変更しても、ブラウザに反映されないという現象に当たりました。
ブラウザのキャッシュなどはクリアしても反映されません。

[静的ファイルがキャッシュされる（ブラウザキャッシュじゃない場合）](http://qiita.com/sugiii8/items/233e88aa26f00b290f38)

VirtualBoxの共有フォルダに設定したディレクトリは、外部ストレージ的な扱いになり、その際、apacheがファイルの更新を検知できないようです。

httpd.confにキャッシュしない設定を追記し、再起動する事で、この現象は回避できます。

```apache:
<Directory [対象のディレクトリ]>
EnableMMAP Off
EnableSendfile Off
</Directory>
```

## phpのソースの大文字・小文字の判別が環境で違う
開発環境ではHogeclassをhogeclassとして記述しても、エラーになりませんでしたが、ステージング環境ではエラーになってしまいます。同じdocker imageを使っているので、環境的な差異はないはずです。

[class_exists でのオートロード](http://qiita.com/ArimaRyunosuke/items/f47b4f0a0e98bea434a8)
上記が原因ぽいですが、df -Tでファイルシステムを確認する限り、
開発もステージングもextとなっていました。
これは原因はまだよく分かっていないです。

## Dockerコンテナの起動ができなくなった
httpd.confの設定をいじり、コンテナをexitで抜け、終了しました。
しばらくしてコンテナをstartさせようとするとapacheの起動エラーで
コンテナの起動自体ができない自体に陥りました。
ENTRYPOINTでDocker起動時に起動させるサービスが
起動エラーとなった場合、コンテナ自体の起動ができなくなるようです。

## Dockerコンテナをexitで抜けてしまう
docker attachしてDocker内に入り、その後exitするとコンテナを抜けると同時に起動しているDockerコンテナを終了してしまいます。コンテナを終了せずに抜ける必要がある場合は**Ctrl+p,q**をする必要があります。

このようなDockerの仕様があるのですが、sshの癖で無意識にexitで抜けてしまいます。開発やステージングではいいですが、本番でこれをやるとサービスが一時的でもダウンしてしまうので気を付ける必要があります。

[CoreOS で起動中のコンテナの中に入る](http://qiita.com/spesnova/items/8121615d4634500a331c)
docker execで入ればプロセス注入なのでexitしてもDockerコンテナが終了する事はないようです。Dockerコンテナに入るのはdocker execで入る習慣化しておいた方がよさそうです。