Windows7でAnsibleを使ってVagrantの環境を構築・運用（Apache+PHP+Postgresql）

#何ができるようになるのかと、前置き
* 今まで：インストール→設定（依存とかあって結構ややこしい。。）、というのを開発者一人ひとりがやっていた
![before.png](https://qiita-image-store.s3.amazonaws.com/0/66816/73f5f4a4-0d07-3978-d77f-08d682e91e23.png)

* 使うと：コマンド一つでみんなが同じ環境をさくっと手に入れられる
![after.png](https://qiita-image-store.s3.amazonaws.com/0/66816/49f64bbd-70cd-59b3-9948-b9aec7184756.png)

* Vagrantだけでもかなり便利だけど、処理すべきコマンドがいくつもあると面倒なので
AnsibleとかChefとか使ってファイルさえ作っておけば使いまわせて便利。
* この記事を書いた時点の実情：とりあえず全部入って、box配布くらいはできるようになったかも、というレベル
* 運用方法に関してまで言及しているサイトがなくてちょっと不安。。実はもっといい感じの運用方法があるのでは・・？

#作業説明

##実行環境
* 自端末：Windows7
* 仮想環境：CentOS-6.5-64

##やることざっくりまとめ
【環境構築者の作業】
1. VirtualBoxをインストール
　（Vagrantがあるので特にこれを使ってると意識するタイミングはない）
2. Vagrantをインストール
3. Vagrantで仮想サーバを2台用意
　（WindowsからAnsibleが使えないので、Ansible導入用と開発環境用の計2台）
4. Ansibleをインストール
5. Ansibleで開発環境を作るためのファイル（playbook）を準備する
6. Ansibleで作ったファイルを実行して開発環境を作成
7. boxを作って各開発者に配布

【各開発者の作業】
1. VirtualBoxをインストール
2. Vagrantをインストール
3. 配布されたboxを環境に入れる
4. ソースを配置して、ふつうに開発

#環境構築編
##Ansibleを導入
###VirtualBox／Vagrantをインストール
マニュアルに従ってインストールすればOK

###事前準備
* Windowsでlinux的なコマンドを実行できるようにする
* Gitを導入しているのであればGitBashを使うのが良い
* 導入していなければGowを入れるとかだけど、gitをいれた瞬間以下のエラーがでるようになるので注意。。<br>

> The `ssh` executable found in the PATH is a PuTTY Link SSH client.
Vagrant is only compatible with OpenSSH SSH clients. Please install
an OpenSSH SSH client or manually SSH in using your existing client
using the information below.

###Vagrantでサーバを2台用意
* 事前準備でいれたツールを立ち上げて適当なディレクトリに移動
* boxを落としてきて初期化（ここではCentOS-6.5-64を利用）<br>

```text:
$ vagrant add box CentOS-6.5-64 https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box
$ vagrant init CentOS-6.5-64
```

* 当該ディレクトリに作成されるVagrantfileに以下を追記<br>

```text:Vagrantfile
  config.vm.define :makeplaybook（←ここ任意の名称） do |node|
    node.vm.box = "CentOS-6.5-64"
    node.vm.network :forwarded_port, guest: 22, host: 2001, id: "ssh"
    node.vm.network :private_network, ip: "192.168.33.11"
  end
  config.vm.define :target（←ここ任意の名称） do |node|
    node.vm.box = "CentOS-6.5-64"
    node.vm.network :forwarded_port, guest: 22, host: 2002, id: "ssh"
    node.vm.network :private_network, ip: "192.168.33.12"
    node.vm.synced_folder "C:/*/test", "/var/www/html/", rsync__exclude: [".git/", "node_modules"]
    node.vm.synced_folder "C:/*/test/project", "/var/www/html/project"
  end
```

※解説
サーバー2台
・makeplaybook→Ansibleを入れてtargetを操作するためのサーバー
・target→操作されるほうのサーバー

| 対象 | 意味 |
|:-----------|:------------|
| node.vm.box = "CentOS-6.5-64" | vagrant add box ***でつけた名称で<br>サーバーに導入するboxを指定 |
| node.vm.network :forwarded_port, guest: 22, host: 2001, id: "ssh" | ホスト（自端末Windows7）へのアクセスを<br>ゲスト（makeplaybook/target）へのアクセスとして転送 |
| node.vm.network :private_network, ip: "192.168.33.12" | 内部ネットワーク上でのipを指定 |
| node.vm.synced_folder "A" "B" | 共有ファイルの指定。ソース等、ローカルの変更をtargetにも即時反映するための設定で、A：ホストのローカルディレクトリ／B：ゲスト（target）のディレクトリを指定。指定の仕方に関しては、高速になるように[ここ](http://qiita.com/derui@github/items/44977e0de5b892009b2f)を参考にさせてもらった |

* 環境を立ち上げる<br>
主なVagrantコマンドは以下。まずはvagrant up で環境を立ち上げる

```text:
$ vagrant up *** # 開始（***でノード名：target等を指定することも可能。しなければVagrantfileにあるすべてを実行対象に）
$ vagrant halt *** # 停止
$ vagrant destroy *** # 削除
$ vagrant reload *** # 再起動
$ vagrant ssh-config # 環境の情報を見る
$ vagrant ssh *** # 指定した環境にssh接続
```

* targetとmakeplaybookを通信できるように設定

```text:
$ vagrant ssh-config makeplaybook > ssh_config
$ vagrant ssh-config target>> ssh_config
$ scp -F ssh_config */.vagrant.d/insecure_private_key（Vagrantのprivatekeyを指定） makeplaybook:.ssh/id_rsa
```

※2つ目のコマンドまでで環境情報をファイルに書き出し、
　その情報をもとにscpコマンドの-Fオプションでローカルからmakeplaybookにprivatekeyを送っている

###makeplaybookにAnsibleを導入（EPEL経由）・targetへの疎通確認
* ssh通信でmakeplaybookにはいる（vagrant ssh makeplaybook）
* 普通にはいるとvagrantユーザになるので、rootに入りたいときはpasswordのデフォルトがvagrantなのでsuコマンドで切り替える
* そこで、以下のコマンドを実行してmakeplaybookにAnsibleを入れる

```text:
$ sudo yum install wget
$ wget http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6
$ sudo rpm --import RPM-GPG-KEY-EPEL-6
$ wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
$ sudo rpm -ivh epel-release-6-8.noarch.rpm
$ sudo yum install -y ansible
```

* Ansibleのhostsにtargetを上書き、疎通確認

```text:
$ cd /etc/ansible/
$ echo 192.168.33.12 > hosts
$ ansible -i hosts 192.168.33.12 -m ping
```

最後のコマンドが通ればtargetとの疎通ができる状態になっている

* Tips:いちいち接続確認されるのが面倒なので、確認されないように設定するには・・<br>
/etc/ansible/ansible.cfgのhost_key_checking を falseに変更

##Ansibleのplaybookを作成・実行

```text:実行コマンド 
$ ansible-playbook -i hosts start.yml 
```

* チェックモードは--check、デバッグは-vvv
* 分岐までやると複雑になるので以下main.yml一択の最低限の簡単な感じでしか作ってません。。

###[参考]フォルダ構成

```text:
ansible
|-- start.yml
|-- hosts
|-- ansible.cfg
|-- roles/
|   |-- ansible-role-gitbucket/
|       |-- tasks/
|           |-- main.yml
|   |-- apache/
|       |-- handlers/
|           |-- main.yml
|       |-- tasks/
|           |-- main.yml
|       |-- templates/
|           |-- main.yml
|   |-- php/
|       |-- tasks/
|           |-- main.yml
|       |-- templates/
|           |-- main.yml
|   |-- postgresql/
|       |-- handlers/
|           |-- main.yml
|       |-- tasks/
|           |-- main.yml
|       |-- templates/
|           |-- main.yml
|       |-- vars/
|           |-- main.yml
```

###[参考]情報が少なかったpostgresqlだけ載せておく

```yml:roles/postgresql/tasks/main.yml
---

- name: Check PostgreSQL yum repository installed
  command: test -f /etc/yum.repos.d/pgdg-94-centos.repo
  register: yum_pg_installed
  ignore_errors: yes

- name: Install PostgreSQL official yum repository
  yum: name={{ postgresql_rpm }} state=present
  when: yum_pg_installed|failed

- name: Install PostgreSQL server packages
  yum: name={{ item }} state=present
  with_items:
    - postgresql94-server
    - postgresql94-contrib
    - python-psycopg2

- name: Initialize PostgreSQL database
  shell: service postgresql-9.4 initdb
         creates=/var/lib/pgsql/9.4/data/postgresql.conf

- name: Install PostgreSQL configuration file
  template: src=postgresql.conf.j2 dest=/var/lib/pgsql/9.4/data/postgresql.conf
            owner=postgres group=postgres mode=0600

- name: Install PostgreSQL client authentication configuration file
  template: src=pg_hba.conf.j2 dest=/var/lib/pgsql/9.4/data/pg_hba.conf
            owner=postgres group=postgres mode=0600

- name: Start PostgreSQL
  service: name=postgresql-9.4 state=started enabled=yes

- name: Create PostgreSQL DB
  postgresql_db: name={{dbname}}

- name: Ensure User Has Access to Database
  postgresql_user: db={{dbname}} name={{dbuser}} password={{dbpassword}} priv=ALL

- name: Ensure User Doesnot Have Unnecessary Privilege
  postgresql_user: name={{dbuser}} role_attr_flags=NOSUPERUSER,NOCREATEDB
```

###[参考]エラー対応

1. msg: Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!<br>
発生原因も不明だけれど、[ここ](http://sankakuvalidator.hatenablog.com/)を見てansible-role-gitbucketというロールを追加したらなおった
2. postgresqlのインストールでエラー<br>
/var/lib/pgsql/9.4/data/pg_log以下にログがあるので探ったところ、<br>
templateで上書きしていた設定ファイルの1行目のコメントアウトが抜けていた。。
3. postgresqlのDB作成でエラー<br>
postgresql_dbを使おうとすると「the python psycopg2 module is required」と怒られる。。<br>
パッケージ追加するときitemにpython-psycopg2を追加したら使えるようになった<br>
[参考](https://github.com/ansible/ansible-examples/blob/master/language_features/postgresql.yml)
4. FAILED: No authentication methods available<br>
rootユーザで実行していたため。。

##Tips
###仮想サーバにファイルを転送
WinSCPとかの転送ツールでプライベートipを指定すればふつうに接続できる。
意外と忘れがちな事実。。

###targetサーバに入っているpostgresqlにpgadminからアクセス<br>
基本的なことだけど、以下2ファイルをplaybookのtemplate編集してtargetサーバー設定時に上書きすることで接続可能になる

```conf:pg_hba.conf
host    all         all         192.168.33.0/0        trust
```

```conf:postgresql.conf
port = 5432
```

###PHPがApacheに認識されない
httpd.confのLoadModule php5_module をいれたかったんだけど、
ディレクトリ構成がWindowsと違うので戸惑った。。
結果的には以下の感じ。
> LoadModule php5_module /usr/lib/httpd/modules/libphp5.so

##boxを作成する
* 各開発者に配布する用のboxを作成する

```text:
$ vagrant package
```

* カレントディレクトリにpackage.boxが作成されたのを確認し、各開発者に配布

#運用編
##事前準備
* 各開発者も同じくVirtualBoxとVagrantを端末にインストール
* 環境構築編の事前準備と同じように、WindowsでもLinux的なコマンドを使えるツールをいれる

##boxを追加する
* 配布されたboxを配置し、以下のコマンドでvagrantに追加

```text:
$ vagrant box add ***(任意の名称) package.box
```

##環境作成
* 同じように環境を初期化して、Vagrantfileを編集→立ち上げる
* makeplaybookはいらないのでtargetだけ作るように以下の感じで

```text:Vagrantfile
  config.vm.define :target（←ここ任意の名称） do |node|
    node.vm.box = "CentOS-6.5-64"
    node.vm.network :forwarded_port, guest: 22, host: 2002, id: "ssh"
    node.vm.network :private_network, ip: "192.168.33.12"
    node.vm.synced_folder "C:/*/test", "/var/www/html/", rsync__exclude: [".git/", "node_modules"]
    node.vm.synced_folder "C:/*/test/project", "/var/www/html/project"
  end
```

* あとは、自端末のC:/*/test/project以下にソースを配置して、普通に開発すればOK

##Tips
###vagrant up時にエラー

```text:
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

ARPCHECK=no /sbin/ifup eth1 2> /dev/null

Stdout from the command:

Device eth1 does not seem to be present, delaying initialization.

Stderr from the command:
```

　boxの作り方がまずいのかなんなのか、ネットワークがらみのエラーが発生。
　以下のコマンドでクリアすればOK。

```text:
$ vagrant ssh target
$ sudo ln -s -f /dev/null /etc/udev/rules.d/70-persistent-net.rules
```

###apacheとpostgresqlの立ち上げを手動で実行したい場合

```text:
$ sudo service httpd start
$ sudo service postgresql-9.4 start
```

###デバッグについて
もともとSublimeTextとXdebugでデバッグしていたのですが、
仮想環境になるとリモートデバッグが必要になる→SublimeTextでデバッグできない問題に。。
通常の開発はSublimeTextでやって、デバッグが必要になったとき用にIDE入れるしかないのかなあ。。