たけまるの日記

たけまるの日記です。web関係の技術ネタが多いですが、好きなことを適当に書いています。

vargrant+chefでつくるPHP5.5+MySQL5.6+CakePHP3環境

vargrant+chefでつくるPHP5.5+MySQL5.6+CakePHP3環境

巷で話題のvagrant、chefを試してみました。
折角なのでそれぞれ最新バージョンを積極的に入れてみることにしました。(結構苦労しました…)


とりあえず手っ取り早く環境を作る手順を書いて行きます。

前提環境

各種ソフトウェアのインストール

VirtualBox

仮想マシンソフトです。以下URLからダウンロードしてインストールします。
https://www.virtualbox.org/wiki/Downloads

vagrant

仮想マシン(ここではVirtualBox)の管理を便利にするツールです。以下URLからダウンロードしてインストールします。
http://www.vagrantup.com/

chef

サーバー設定ツールです。ホストマシンで以下のようにコマンドを流せばインストールされます。また、付随ツールのインストール、初期設定なども行います。

mac$ curl -L https://www.opscode.com/chef/install.sh | sudo bash
mac$ sudo gem install knife-solo
mac$ knife configure

knife configureで色々質問されますが、そのままENTERを押していればOKです。

omnibus

仮想マシンにchefを入れるvagrantのpluginです。ホストマシンで以下のように実行するとインストールされます。

mac$ vagrant plugin install vagrant-omnibus

仮想マシンの起動

今回作った設定ファイルとCakePHP3のファイルをまとめてgithubに置きましたので、とりあえずこれをcloneして進めます

mac$ git clone --recursive https://github.com/takemaru123/vagrant-cakephp3-sample.git
mac$ cd vagrant-cakephp3-sample
mac$ vagrant up

これだけで、vagrantのbox(仮想マシンテンプレート)がダウンロードされ、apache,php,mysqlなどが仮想マシン上に構築されます

以下のようにすると、仮想マシン上のコンソールに入ることができます

mac$ vagrant ssh

以下のように動作確認してみましょう。

centos$ cat /etc/redhat-release 
CentOS release 6.5 (Final)

centos$ php -v
PHP 5.5.7 (cli) (built: Dec 11 2013 07:13:20) 
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2013 Zend Technologies
    with Xdebug v2.2.3, Copyright (c) 2002-2013, by Derick Rethans

centos$ mysql --version
mysql  Ver 14.14 Distrib 5.6.15, for Linux (x86_64) using  EditLine wrapper

また、ホストマシンのブラウザから、以下のURLを実行すると、Internal Server Errorとなると思います。

http://192.168.33.10/

これはCakePHP周りの設定をまだ行っていないためですが、HTTPサーバーが起動している事はわかると思います。

cakephp3の設定

cloneしたレポジトリには、CakePHPのappディレクトリは含まれていますが、CakePHP本体は含まれていません。CakePHP本体はComposerというPHPのパッケージ管理ツールを用いて導入します。

仮想マシンのコンソールに入ります。

mac$ vagrant ssh

CakePHPのappディレクトリへ移動し、Composer関係の操作を実施します。
ちなみに、ホストマシンのvagrant-cakephp3-sampleディレクトリと、仮想マシンの/vagrantディレクトリが同期されているのがここでわかるとおもいます。

centos$ cd /vagrant/app
centos$ curl -sS https://getcomposer.org/installer | php
centos$ php composer.phar install

これでcomposerがインストールされ、composer.jsonに記載されていた必要なライブラリ類(CakePHP本体等)がインストールされました。

この時点で以下URLをホストマシンから叩くと、CakePHPの動作確認画面を確認することができます。

http://192.168.33.10/

折角MySQLも入れたので、CakePHPの設定ファイルを書き換え、MySQLへ繋がるようにします。
この操作はホストOS(mac)、仮想マシンどちらから行っても大丈夫です。

/path/to/vagrant-cakephp3-sample/app/App/Config/app.php
又は
/vagrant/app/App/Config/app.php


以下のように書き換えます。

※ファイル : vagrant-cakephp3-sample3/app/App/Config/acl.php
※抜粋
        'Datasources' => [
                'default' => [
                        'className' => 'Cake\\Database\\Driver\\Mysql',
                        'persistent' => false,
                        'host' => 'localhost',
                        'login' => 'root',
                        'password' => '',
                        'database' => 'test',
                        'prefix' => false,
                        'encoding' => 'utf8',
                ],


再度ブラウザからアクセスし、「Cake is able to connect to the database.」と表示されれば成功です。

これで環境が一通りできあがりました。

Vagrantファイル

ここからは各種設定ファイルやレシピについて書いていきます。


まずVagrantを使用する仮想マシン毎に、ベースとなるディレクトリを作成します。このディレクトリ以下にVagrantの設定ファイルやchefのレシピを設置します。
また、このディレクトリ内は仮想マシンとの共有ディレクトリになりますので、開発するプログラムをここに設置すると、ホストマシンのエディタでコードを書き、仮想マシンで動作させるといった流れが可能になります。

mac$ mkdir vagrant-cakephp3-sample
mac$ cd vagrant-cakephp3-sample


次に、仮想マシンの設定を記述するVagrantファイルのひな形を作成します。

mac$ vagrant init


Vagrantの内容は以下のようになります。

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "CentOS_6.5_x86_64"
  config.vm.box_url = "https://github.com/2creatives/vagrant-centos/releases/download/v6.5.1/centos65-x86_64-20131205.box"
  
  config.vm.network :private_network, ip: "192.168.33.10"

  # cakephpを使うために必要
  config.vm.synced_folder "./", "/vagrant", mount_options: ['dmode=777', 'fmode=666']

  config.omnibus.chef_version = :latest

  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "./site-cookbooks"
    chef.add_recipe "base"
    chef.add_recipe "mysql56"
    chef.add_recipe "php55"

    chef.json = {
      httpd: {
        port: 80,
        docroot: "/vagrant/app/webroot"
      },
      php: {
        timezone: "Asia/Tokyo"
      },
      mysql: {
        password: ''
      },
    }
  end
end


以下抜粋です。

  config.vm.box = "CentOS_6.5_x86_64"
  config.vm.box_url = "https://github.com/2creatives/vagrant-centos/releases/download/v6.5.1/centos65-x86_64-20131205.box"

CentOSがインストールされている仮想マシンをネット上から取ってくるように設定しています。(有志の方が公開しているものです)
一度ダウンロードすればPC内にテンプレート(box)として保存され、また同じboxから仮想マシンを作る場合は、ローカルに保持しているboxが使われるようになります。

  config.vm.network :private_network, ip: "192.168.33.10"

ホストマシン(mac)から仮想マシンにアクセスする際のIPアドレスを設定しています。
仮想マシンを複数立ち上げる場合などは、適宜変更する必要があります。

  config.omnibus.chef_version = :latest

今回使ったboxにはchefがインストールされていないため、omnibusを使い、仮想マシンにchefを仮想マシンに自動インストールします。

    chef.cookbooks_path = "./site-cookbooks"
    chef.add_recipe "base"
    chef.add_recipe "mysql56"
    chef.add_recipe "php55"

仮想マシンが起動した後に実行するchefのレシピを定義しています。
ここではbase,mysql56,php55の3つのレシピが実行されます。

    chef.json = {
      httpd: {
        port: 80,
        docroot: "/vagrant/app/webroot"
      },
      php: {
        timezone: "Asia/Tokyo"
      },
      mysql: {
        password: ''
      },
    }

chef実行時の変数をここで指定しています。

レシピ:base

chefのレシピを記述して行きます。


まずはレシピのベースとなるテンプレートを作成します。

mac$ knife cookbook create base -o site-cookbooks/

自分で作成したレシピは、site-cookbooksというディレクトリに設置するのが決まりのようです。


このコマンドで、

vagrant-cakephp3-sample/site-cookbooks/base

というディレクトリが作成され、更にその中に複数のディレクトリやファイルが作成されました。


レシピの内容を記述していきます。

※ファイル : vagrant-cakephp3-sample/site-cookbooks/base/recipes/default.rb
# スワップ領域作成
# 参考:http://qiita.com/naoya@github/items/2059e3755962e907315e
bash 'create swapfile' do
  user 'root'
  code <<-EOC
    dd if=/dev/zero of=/swap.img bs=1M count=1024 &&
    chmod 600 /swap.img
    mkswap /swap.img
  EOC
  only_if "test ! -f /swap.img -a `cat /proc/swaps | wc -l` -eq 1"
end

mount '/dev/null' do # swap file entry for fstab
  action :enable # cannot mount; only add to fstab
  device '/swap.img'
  fstype 'swap'
end

bash 'activate swap' do
  code 'swapon -ae'
  only_if "test `cat /proc/swaps | wc -l` -eq 1"
end


# iptables無効
service "iptables" do
	action [:stop, :disable]
end


# yum関係
%w{gcc make wget telnet readline-devel ncurses-devel gdbm-devel openssl-devel zlib-devel libyaml-devel httpd}.each do |p|
	package p do
		action :install
	end
end


# httpd設定
service "httpd" do
	action [:start, :enable]
end

template "httpd.conf" do
	path "/etc/httpd/conf/httpd.conf"
	source "httpd.conf.erb"
	mode 0644
	notifies :restart, 'service[httpd]'
end

baseレシピでは、OSの基本設定や、CentOS標準のyumコマンドでインストールできるパッケージのインストール、Apacheのインストール、設定を行うようにしています。


以下抜粋です。

# スワップ領域作成
# 参考:http://qiita.com/naoya@github/items/2059e3755962e907315e
bash 'create swapfile' do
  user 'root'
  code <<-EOC
    dd if=/dev/zero of=/swap.img bs=1M count=1024 &&
    chmod 600 /swap.img
    mkswap /swap.img
  EOC
  only_if "test ! -f /swap.img -a `cat /proc/swaps | wc -l` -eq 1"
end

mount '/dev/null' do # swap file entry for fstab
  action :enable # cannot mount; only add to fstab
  device '/swap.img'
  fstype 'swap'
end

bash 'activate swap' do
  code 'swapon -ae'
  only_if "test `cat /proc/swaps | wc -l` -eq 1"
end

今回利用したboxではスワップ領域が無かったため、念のためスワップ領域を作成しています。

# iptables無効
service "iptables" do
	action [:stop, :disable]
end

開発環境なのでiptablesは無効とします。
ここではiptablesの停止、また、次回仮想マシンOS起動時にはiptablesを起動しないようにしています。

# yum関係
%w{gcc make wget telnet readline-devel ncurses-devel gdbm-devel openssl-devel zlib-devel libyaml-devel httpd}.each do |p|
	package p do
		action :install
	end
end

CentOS標準のyumコマンドで導入すべきパッケージをここでインストールしています。
本来であればpackageリソースはOSに合わせて、実際に実行されるコマンドがyumだったりapt-getだったりしますが、ここではCentOSで実行される前提で書いてしまっています。

# httpd設定
service "httpd" do
	action [:start, :enable]
end

Apacheの起動、OS起動時に自動的にApacheが起動するように設定しています。

template "httpd.conf" do
	path "/etc/httpd/conf/httpd.conf"
	source "httpd.conf.erb"
	mode 0644
	notifies :restart, 'service[httpd]'
end

chefのtemplateという機能を使って、httpd.confを設定しています。
また、設定変更後はnotifiesを使って、Apacheを再起動するように指定しています。


httpd.confはchefのtemplateで設定しているため、templateの設定を行います。
こののファイルのベースは、実際インストールしたApacheのhttpd.conf(仮想マシンの/etc/httpd/conf/httpd.conf)の内容です。
必要なところだけ以下の様に変数を埋め込める形にします。

※ファイル : vagrant-cakephp3-sample/site-cookbooks/base/templates/default/httpd.conf.erb
※抜粋
Listen <%= node[:httpd][:port] %>
DocumentRoot "<%= node[:httpd][:docroot] %>"
<Directory "<%= node[:httpd][:docroot] %>">
    〜
</Directory>

node〜で指定した変数は、Vagrantファイルのchef.json = 〜で設定した内容が読み込まれます。
これにより、可変部分のみをVagrantファイルに記述することができます。

レシピ:mysql56

MySQL5.6をインストールするレシピを作成します。
baseとは別のcookbookにした理由はなんとなくです。


概要としては、OS標準やサードパーティを含め、yumでMySQL5.6を導入する方法がないため、Oracleが公式で配布しているrpmパッケージをダウンロードし、インストールする方式をとっています。


レシピファイルは以下のようになります。

vagrant-cakephp3-sample/site-cookbooks/mysql56/recipes/default.rb


大部分は以下のページをほぼそのまま使わせていただきましたので、詳細はそちらをご参照ください。
MySQL5.6のchefの書き方の決定版が出来たので公開する。 - nigoblog


以下、追加した内容をご紹介します。

# サーバー起動
service "mysql" do
  action [:start, :enable]
end

MySQLサーバーを起動し、仮想マシン起動時にも自動起動するように設定します。

# my.cnf
template "my.cnf" do
	path "/usr/my.cnf"
	source "my.cnf.erb"
	mode 0644
	notifies :restart, 'service[mysql]'
end

Apache設定時にも利用したtemplate機能を使って、my.cnfを設定します。

# 初期パスワード設定
# 参考:http://blog.youyo.info/blog/2013/07/11/chef-mysql56/
script "Secure_Install" do
  interpreter 'bash'
  user "root"
  not_if "mysql -u root -p#{node[:mysql][:password]} -e 'show databases'"
  code <<-EOL
    export Initial_PW=`head -n 1 /root/.mysql_secret |awk '{print $(NF - 0)}'`
    mysql -u root -p${Initial_PW} --connect-expired-password -e "SET PASSWORD FOR root@localhost=PASSWORD('#{node[:mysql][:password]}');"
    mysql -u root -p#{node[:mysql][:password]} -e "SET PASSWORD FOR root@'127.0.0.1'=PASSWORD('#{node[:mysql][:password]}');"
    mysql -u root -p#{node[:mysql][:password]} -e "FLUSH PRIVILEGES;"
  EOL
end

chef実行時に、MySQLのパスワードを自動設定するようにしています。
MySQL5.6は初期パスワードとしてランダムパスワードが設定されるため、まずはそれを利用してパスワード設定コマンドを実行します。
パスワードはVagrantファイルで設定できるようにしています。


また、参考サイトではMySQLクライアントのみをインストールしておりますが、こちらではServerのインストールにも対応するため、attributeを以下にようにしました。

※ファイル : vagrant-cakephp3-sample/site-cookbooks/mysql56/attribute/default.rb
versions = "5.6.15-1.el6.x86_64"
default['mysql']['versions']   = versions
default['mysql']['file_name']  = "MySQL-#{versions}.rpm-bundle.tar"
default['mysql']['remote_uri'] = "http://ftp.jaist.ac.jp/pub/mysql/Downloads/MySQL-5.6/MySQL-#{versions}.rpm-bundle.tar"
default['mysql']['rpm'] = [
  {
    :rpm_file     => "MySQL-server-#{versions}.rpm",
    :package_name => "MySQL-server"
  },
  {
    :rpm_file     => "MySQL-client-#{versions}.rpm",
    :package_name => "MySQL-client"
  },
  {
    :rpm_file     => "MySQL-devel-#{versions}.rpm",
    :package_name => "MySQL-devel"
  },
  {
    :rpm_file     => "MySQL-shared-#{versions}.rpm",
    :package_name => "MySQL-shared"
  }
]

レシピ:php55

PHP5.5をインストールするレシピを作成します。
baseとは別のcookbookにした理由はなんとな(ry


概要としましては、こちらもOS標準のyumレポジトリには無いので、remiというサードパーティのレポジトリからインストールするようにしています。


まずはattributeを以下のように定義します。

※ファイル : vagrant-cakephp3-sample/site-cookbooks/php55/attribute/default.rb
default['remi']['file_name']  = "remi-release-6.rpm"
default['remi']['remote_uri'] = "http://rpms.famillecollet.com/enterprise/remi-release-6.rpm"


レシピファイルは以下のようになります。

※ファイル : vagrant-cakephp3-sample/site-cookbooks/php55/recipe/default.rb
# remi repositoryå°Žå…¥
remote_file "/tmp/#{node['remi']['file_name']}" do
  source "#{node['remi']['remote_uri']}"
  not_if { ::File.exists?("/tmp/#{node['remi']['file_name']}") }
end

package node['remi']['file_name'] do
  action :install
  provider Chef::Provider::Package::Rpm
  source "/tmp/#{node['remi']['file_name']}"
end


# phpインストール
%w{php php-devel php-mbstring php-mcrypt php-mysql php-phpunit-PHPUnit php-pecl-xdebug}.each do |p|
	package p do
		action :install
		options "--enablerepo=remi --enablerepo=remi-php55"
	end
end

# php設定
template "php.ini" do
	path "/etc/php.ini"
	source "php.ini.erb"
	mode 0644
	notifies :restart, 'service[httpd]'
end


以下抜粋です。

# remi repositoryå°Žå…¥
remote_file "/tmp/#{node['remi']['file_name']}" do
  source "#{node['remi']['remote_uri']}"
  not_if { ::File.exists?("/tmp/#{node['remi']['file_name']}") }
end

package node['remi']['file_name'] do
  action :install
  provider Chef::Provider::Package::Rpm
  source "/tmp/#{node['remi']['file_name']}"
end

remi導入のためのrpmパッケージをダウンロードし、インストールしています。

# phpインストール
%w{php php-devel php-mbstring php-mcrypt php-mysql php-phpunit-PHPUnit php-pecl-xdebug}.each do |p|
	package p do
		action :install
		options "--enablerepo=remi --enablerepo=remi-php55"
	end
end

PHP関係のパッケージをインストールします。
options "--enablerepo=remi --enablerepo=remi-php55" を指定するところがキモです。

# php設定
template "php.ini" do
	path "/etc/php.ini"
	source "php.ini.erb"
	mode 0644
	notifies :restart, 'service[httpd]'
end

templateの仕組みを使い、php.iniを設定しています。
また、php.ini変更時はApacheを再起動するようにしています。

※ファイル : vagrant-cakephp3-sample/site-cookbooks/php53/templates/default/php.ini.erb
※抜粋
date.timezone = '<%= node[:php][:timezone] %>'

timezoneの設定をVagrantファイル側から読み込むようにしています。

まとめ

長くなりましたが、Vagrant,chefを使い、CakePHP3を動作させる環境を作るところまでを行いました。
手探り状態で来たため、ここまでくるのに数日を費やしてしまいました。
自分でレシピを書いていこうとすると、最初はいろいろ試行錯誤の連続になるようです。
しかしインフラや開発環境をコード化して、git管理できるというのは大変魅力を感じました。
チーム開発の場合は開発環境を統一できますし、私の場合は自宅のデスクトップ機やノートなどの複数マシン間で開発環境を統一したいという目論見もありました。
今後はVagrant+chefの開発環境を布教すると共に、さくらVPSやEC2等ももchefで管理していけたらと思います。