vagrant、chefを利用してCentOS7にPHP7の環境を構築する

# 構築したい環境

* CentOS7
* PHP7
* Apache
* MySQL5.7

# 序論

仕事でPHPを使うことになりそうだったので、勉強がてらPHPの動作環境を構築した。
今後、頻繁に使うことになると思うので手順をメモしておく。

なお、ホストOSは、EI Capitanであり、vagrant、virtual boxは、ホストOSに導入済であることを前提としている。

CentOS7上では、chef-clientのlocal modeでchefを実行する。
chefを実行するためのrubyは、rvmでruby 2.3をインストールする。

なお、rvm、ruby、chefのインストール及びchefの実行は、Vagrantのプロビジョニングで実行した。
また、今回使用したchefのクックブックは、予めGitHubに登録しておき、cloneするようにしている。
chefのクックブックの作成手順は、本記事の末尾に記載している。

その後のMySQLの初期設定は、自動化できそうもないのでサーバにログインした状態で実施した。

# インストール

## vagrantでcentos7の初期設定をする。

```
% vagrant init centos/7
```

## ネットワークの設定とプロビジョニングの設定をする。

実行するコマンドを単純に羅列しただけだと、所定のアプリケーション(rvmやruby)のインストール後に、インストールしたアプリケーションのパスが即有効にならずにエラーになる。
これを回避するためにプロビジョニング内でxxx_install_scriptと何個かに分割している。
もう少しスマートな回避策はないものか…。

```
% vi Vagrantfile
# config.vm.network :private_network, ip: "192.168.33.10"
    ↑このコメントアウトを外す。IPは適当に。

<省略>

  first_install_script = <<SCRIPT
    # TimeZone : UTC -> JST
    timedatectl set-timezone Asia/Tokyo

    # install rvm, ruby2.3
    gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
    curl -L https://get.rvm.io | sudo bash -s stable
    gpasswd -a vagrant rvm
SCRIPT

  second_install_script = <<SCRIPT
    sudo -i -u vagrant rvm install 2.3 --default
SCRIPT

  third_install_script = <<SCRIPT
    # gem install for chef
    sudo -i -u vagrant gem install bundler
    sudo -i -u vagrant gem install chef
    sudo -i -u vagrant gem install knife-solo
SCRIPT

  fourth_install_script = <<SCRIPT
    # install git for to download cookbook repository
    yum -y update
    yum -y install git

    sudo -u vagrant git clone https://github.com/eidera/chef-php-env.git

    # execute chef
    cd /home/vagrant/chef-php-env && rvmsudo_secure_path=1 /usr/local/rvm/bin/rvmsudo chef-client --local-mode -j nodes/chef.json -c chef.rb
SCRIPT

  config.vm.provision :shell, :inline => first_install_script
  config.vm.provision :shell, :inline => second_install_script
  config.vm.provision :shell, :inline => third_install_script
  config.vm.provision :shell, :inline => fourth_install_script
```

## 仮想マシンを立ち上げる。

```
% vagrant up
```

## 通常のsshコマンドでログインできるように設定する。

```
% vagrant ssh-config --host local.phpdev >> ~/.ssh/config
% ssh local.phpdev
```

# MySQLの設定

rootの初期パスワードを確認する。

```
% sudo less /var/log/mysqld.log
temporary passwordを検索して、rootの初期パスワードを確認
```

mysqlの初期設定(rootパスワード変更など)

```
% mysql_secure_installation
指示通り入力していく
```

ユーザー(username)を追加する。
なお、下記では、全てのデータベースに対して192.168.以下全てのIPからの外部接続を許可している。
この辺りの設定は環境に応じて、適宜修正する必要がある。

```
% mysql -u root -p
新規パスワード入力
mysql> GRANT ALL PRIVILEGES ON *.* TO username@localhost IDENTIFIED BY 'passwd_hogehoge';
mysql> GRANT ALL privileges ON *.* TO username@"192.168.%.%" IDENTIFIED BY 'passwd_hogehoge' WITH GRANT OPTION;
mysql> flush privileges;
mysql> select user,host from mysql.user;
```

なお、ローカルの開発環境なのでパスワードを簡単にしたいという場合には、
以下のように設定すれば例えば、長さやポリシーを変更できる。

```
mysql> SET GLOBAL validate_password_length=4;
mysql> SET GLOBAL validate_password_policy=LOW;
mysql> SHOW VARIABLES LIKE 'validate_password%';
  →設定の確認
```

# Apacheの開発環境用初期設定

ホストOS側で修正するために、DocumentRootをシンボリックリンクに変更する。
但し、SELinuxのデフォルトでは、シンボリックリンクはForbiddenになってしまう。
開発環境なのでSELinuxを無効にした。

```
% sudo mv /var/www/html /var/www/html.orig
% cd /var/www && sudo ln -s /vagrant/html
% sudo setenforce 0
```

なお、ホスト側でファイルを変更する度にrsyncで同期するためには、以下のコマンドを実行しておく。

```
% vagrant rsync-auto
```

以上で環境構築は終了。

# chefのクックブックの作成手順

クックブックの作成手順を備忘録として残しておく。
phpやApacheの設定ファイルなど追加していったものはここに記載していないので、GitHubの[リポジトリ](https://github.com/eidera/chef-php-env)を直接確認した方がよい。

```
% cd
% mkdir chef-php-env
% cd chef-php-env
% knife solo init .
% knife cookbook create develop_tools_cookbook -o site-cookbooks
% knife cookbook create php7_cookbook -o site-cookbooks
% knife cookbook create apache_cookbook -o site-cookbooks
% knife cookbook create mysql_cookbook -o site-cookbooks
```

開発関連のツールのcookbookに、gitやdevelopment toolsなどのレシピを作成する。

``` ruby:chef-php-env/site-cookbooks/develop_tools_cookbook/recipes/default.rb
packages = %w(zsh git screen unzip fontconfig-devel)
packages.each do |pkg|
  package pkg do
    action :install
  end
end

execute "development_tools" do
  user "root"
  command 'yum -y groupinstall "Development Tools"'
  action :run
end
```

PHP7用のレシピを作成する。

``` ruby:chef-php-env/site-cookbooks/php7_cookbook/recipes/default.rb
# epel
package 'epel-release.noarch' do
  action :install
end

# remi
remote_file "#{Chef::Config[:file_cache_path]}/remi-release-7.rpm" do
    source "http://rpms.famillecollet.com/enterprise/remi-release-7.rpm"
    not_if "rpm -qa | grep -q '^remi-release'"
    action :create
    notifies :install, "rpm_package[remi-release]", :immediately
end

rpm_package "remi-release" do
    source "#{Chef::Config[:file_cache_path]}/remi-release-7.rpm"
    action :nothing
end

# php7
package 'php' do
  flush_cache [:before]
  action :install
  options "--enablerepo=remi --enablerepo=remi-php70"
end

%w(php-openssl php-common php-mbstring php-xml).each do |pkg|
  package pkg do
    action :install
    options "--enablerepo=remi --enablerepo=remi-php70"
  end
end

# composer
bash 'install_composer' do
  not_if { File.exists?("/usr/local/bin/composer") }
  user 'root'
  cwd '/tmp'
  code <<-EOH
    curl -sS https://getcomposer.org/installer | php -- --install-dir=/tmp
    mv /tmp/composer.phar /usr/local/bin/composer
  EOH
end
```

Apache用のレシピを作成する。

``` ruby:chef-php-env/site-cookbooks/apache_cookbook/recipes/default.rb
package 'httpd' do
  action :install
end

bash 'service_setting' do
  user 'root'
  code <<-EOH
    systemctl restart httpd.service
    systemctl enable httpd.service
  EOH
end
```

MySQL用のレシピを作成する。

``` ruby:chef-php-env/site-cookbooks/mysql_cookbook/recipes/default.rb
# mysql rpm
remote_file "#{Chef::Config[:file_cache_path]}/mysql57-community-release-el7-7.noarch.rpm" do
  source "http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm"
  not_if "rpm -qa | grep -q '^mysql57'"
  action :create
  notifies :install, "rpm_package[mysql57]", :immediately
end

rpm_package "mysql57" do
  source "#{Chef::Config[:file_cache_path]}/mysql57-community-release-el7-7.noarch.rpm"
  action :nothing
end

package 'mysql-community-server' do
  action :install
end

cookbook_file "/etc/my.cnf" do
  source "my.cnf"
  mode 00644
  owner 'root'
  group 'root'
end

bash 'service_setting' do
  user 'root'
  code <<-EOH
    systemctl restart mysqld.service
    systemctl enable mysqld.service
  EOH
end
```

cookbook_fileに設定してmy.cnfは以下。最後の2行をデフォルトのものに追加している。

* utf8にする。
* passwordの有効期限を無期限にする。

``` :chef-php-env/site-cookbooks/mysql_cookbook/files/default/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

character-set-server = utf8
default_password_lifetime = 0
```

``` ruby:chef-php-env/chef.rb
current_dir = File.absolute_path( File.dirname(__FILE__) )
cookbook_path [ "#{current_dir}/site-cookbooks" ]
role_path "#{current_dir}/roles"
```

``` json:chef-php-env/nodes/chef.json
{
  "run_list": [
    "recipe[develop_tools_cookbook]",
    "recipe[php7_cookbook]",
    "recipe[apache_cookbook]",
    "recipe[mysql_cookbook]"
  ]
}
```

### chefの実行

```
$ rvmsudo_secure_path=1 rvmsudo chef-client --local-mode -j nodes/chef.json -c chef.rb
```

# 参考にさせて頂いたサイト

http://qiita.com/Esfahan/items/8f47382e9e712253feee
http://qiita.com/makoto_kw/items/53a84380559c087eb8fb
http://tanakakns.hatenablog.com/entry/20140401/1396337863