とにかく動く環境をまず作ってみる、Vagrant + chef-soloで開発できるイメージを持つ、ことを重視して作りました。
開発環境の概要
大体こんな感じの環境を作ります。 今回はFedora20上のVirtualBoxに仮想サーバを構築しています。 もちろんWindows上でもOSX上でも構築可能です。
※Windowsの場合、以降で説明するコマンドと少し違った手順が必要になる可能性があります。
「PHP」となっている部分も、Rubyなど他の言語にも置き換えが効くと思いますが、 今回はPHPで構築しています。 ソースコードを共有フォルダで参照するというやり方も、 他にもっといいやり方があるかもしれませんがとりあえずこれで。
Vagrant, chef-solo って?
Vagrant
乱暴に言うと、コマンドラインからVirtualBoxなどの仮想化ソフトウェアを操作できるツールです。 「仮想マシンのフロントエンド」というような説明がされることも多いようです。
VirtualBoxにあたる部分はプロバイダと呼ばれ、プロバイダにはVMwareやAmazonEC2も使えるようです。 Vagrantを使わなくても、VirtualBoxだけで仮想サーバを構築することはできます。 ただ、
- 仮想サーバの構築・破棄を素早く行う
- Chefなどのインフラ構築自動化ツールと連携する
ようなことが、Vagrantを使うことによって実現できます。 そのため、より柔軟で素早く、再現性の容易な開発環境を構築することができるようになります。
chef-solo
インフラ構築を自動化してくれるツール「Chef」のスタンドアロン版です。 (Chef ServerとChef Clientによる、クライアント/サーバー版もあります)
インフラの構築作業をコードで記述することができるため、 構築する環境ごとに手動で構築作業をする必要がなく、 記述した通りの環境を正確に何度でも再構築することができるようになります。
必要なツールのインストール
開発環境構築に必要なツールをインストールしていきます。
VirtualBox
https://www.virtualbox.org/wiki/Downloads からパッケージをダウンロードしてインストールします。
今回はFedora 20を使って構築するため、
http://download.virtualbox.org/virtualbox/4.3.12/VirtualBox-4.3-4.3.12_93733_fedora18-1.x86_64.rpm
をダウンロードしてインストールします。
$ sudo yum install VirtualBox-4.3-4.3.12_93733_fedora18-1.x86_64.rpm
Vagrant
http://www.vagrantup.com/downloads.html からパッケージをダウンロードしてインストールします。
今回はFedora 20を使って構築するため、
https://dl.bintray.com/mitchellh/vagrant/vagrant_1.6.3_x86_64.rpm
をダウンロードしてインストールします。
$ sudo yum install vagrant_1.6.3_x86_64.rpm
Vagrantがインストールされていることを確認します。
$ vagrant -v Vagrant 1.6.3
vagrant-omnibus
vagrant up(privision)の際に、仮想サーバにchefを自動インストールしてくれるvagrantのプラグインです。
$ vagrant plugin install vagrant-omnibus Installing the 'vagrant-omnibus' plugin. This can take a few minutes... Installed the plugin 'vagrant-omnibus (1.4.1)'!
プラグインのリストを確認します。
$ vagrant plugin list vagrant-login (1.0.1, system) vagrant-omnibus (1.4.1) vagrant-share (1.1.0, system)
Ruby、RubyGems
後述するknife-soloのインストールにRubyGemsが必要なため、 RubyとRubyGemsをインストールします。インストールの詳細は割愛します。 私はRVMでインストールしています。
knife-solo
gemを使って、knife-solo をインストールします。
knifeとは、作成したクックブックをサーバに適用するためのコマンドを提供するツールです。
knife-soloはknifeのプラグインで、リモートサーバに対してローカルのクックブックやレシピを適用することができます。 knife-soloのインストールに伴って、依存関係のあるknifeも同時にインストールされます。
$ gem install knife-solo
また、knifeの初期設定も行っておきます。
いくつか設定項目を聞かれますが、すべてデフォルトのままで作成します。
$ knife configure
全体のディレクトリ構造
以下のディレクトリ構造となるように作業を進めていきます。
phpms/ ├── Vagrantfile -- Vagrant設定ファイル(vargant init で作成) ├── chef/ -- chefリポジトリ(knife solo init で作成) └── src/ -- ソースコード └── phpms/ -- PHPソースコード
必要なディレクトリを作成して、移動しておきます。
$ mkdir -p phpms/src/phpms $ cd phpms
Vagrantの設定
boxの追加、Vagrantfileの作成
vagrant initコマンドを実行します。VagrantfileというVagrantの設定ファイルが作成されます。
OSのboxイメージは、http://www.vagrantbox.es/ こちらに公開されているものから、CentOS6.5を使います。
$ vagrant init phpms https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box A `Vagrantfile` has been placed in this directory. You are now ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.
作成されたVagrantfileの中を確認すると、以下の項目が自動作成されています。
config.vm.box = "phpms" config.vm.box_url = "https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box"
config.vm.box_url
‘vagrant up’コマンドで仮想サーバーを起動した際に、 boxがローカルにあればそれを適用して起動、ローカルに無ければbox_urlのアドレスからboxを取ってきて起動、という動作をしてくれます。
他にも、開発環境として利用するためにいくつか項目を追加する必要がありますが、とりあえずデフォルトのままにしておきます。Chefのクックブックやレシピを作成した後で編集します。
(参考) vagrant box add を使った作成
‘vagrant box add’, ‘vagrant init’ コマンドを使うことでも、boxの追加とVagrantfileの作成ができます。 ただしこの場合、Vagrantfile内の”config.vm.box_url”項目が自動作成されないようです。
他のメンバーにVagrantfileを渡した際に、’vagrant up’一発で仮想サーバー起動ができるようにしたかったため、今回は’vagrant init’コマンドで、box_urlを自動作成してもらうようにしました。
(手動でbox_url追加しても同じ話、なわけですが)
Vagrant起動
ここで一旦Vagrantで仮想サーバを起動します。 初回起動はboxのダウンロードも必要なため少し時間がかかります。
$ vagrant up ==> default: Box 'phpms' could not be found. Attempting to find and install... default: Box Provider: virtualbox default: Box Version: >= 0 ==> default: Adding box 'phpms' (v0) for provider: virtualbox default: Downloading: https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box ==> default: Successfully added box 'phpms' (v0) for 'virtualbox'! ==> default: Importing base box 'phpms'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: phpms_default_1402016740766_62758 ==> default: Fixed port collision for 22 => 2222. Now on port 2200. ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 22 => 2200 (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2200 default: SSH username: vagrant default: SSH auth method: private key default: Warning: Connection timeout. Retrying... ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM... ==> default: Mounting shared folders... default: /vagrant => /path/to/phpms
==> default: Box 'phpms' could not be found. Attempting to find and install...
とあるように、phpmsというbox名が見つからないため、追加(インストール)してくれています。 box一覧を確認します。
$ vagrant box list phpms (virtualbox, 0)
ホーム配下の.vagrant.dディレクトリにも仮想マシン用ファイルが作成されています。
~/.vagrant.d/boxes/ ├── phpms │ └── 0 │ └── virtualbox │ ├── Vagrantfile │ ├── box-disk1.vmdk │ ├── box-disk2.vmdk │ ├── box.ovf │ └── metadata.json
起動した仮想サーバにsshでアクセスすることもできます。
$ vagrant ssh
Chefリポジトリの作成
vagrantを使って仮想サーバの起動ができたので、 起動されたサーバに適用するインフラ構成をChefで定義していきます。
まずはknifeを使って、Chefの実行に必要なChefリポジトリを作ります。 リポジトリの名前(ディレクトリ名)は”chef”とします。
$ knife solo init chef Creating kitchen... Creating knife.rb in kitchen... Creating cupboards...
chefリポジトリの中には、 Chefの実行に必要なファイルとディレクトリが格納されています。
リポジトリのディレクトリ構成
knifeで作成されたリポジトリのディレクトリ構成です。
chef/ ├── cookbooks ├── data_bags ├── environments ├── nodes ├── roles └── site-cookbooks
多くのディレクトリやファイルがありますが、今回は、
- site-cookbooks
しか使いません。
クックブックの作成
PHP + MySQL環境に必要な以下パッケージのクックブックを作成します。
- apache
- php
- mysql
- remi
- localedef
自作のクックブックはsite-cookbooksに置くそうなので、site-cookbookに作成します。
※自作ではないクックブックというのは、コミュニティクックブックと言って、 WEB上に公開されているクックブックのことです。
$ cd chef/ $ knife cookbook create apache -o ./site-cookbooks $ knife cookbook create php -o ./site-cookbooks $ knife cookbook create mysql -o ./site-cookbooks $ knife cookbook create remi -o ./site-cookbooks $ knife cookbook create localedef -o ./site-cookbooks
レシピ、テンプレートの作成
インフラ構成を定義するためのレシピと、レシピが利用するテンプレートを書いていきます。
レシピは、各クックブックのrecipes配下に、テンプレートファイルは、各クックブックのtemplates/default配下に作成します。
作成するファイルを以下に示します。
各クックブックのrecipes/default.rb は”knife cookbook create”実行時に自動的に作成されています。
chef/ └── site-cookbooks ├── apache │ ├── recipes │ │ ├── default.rb -- apacheインストール、起動、自動起動設定 │ │ └── phpms.rb -- phpms.vm.conf の配置 │ └── templates │ └── default │ ├── httpd-2.2.conf.erb -- httpd.confのテンプレート │ └── phpms.vm.conf.erb -- phpms.vm.confのテンプレート(NameVirtualHost設定) ├── localedef │ └── recipes │ └── default.rb -- localedef実行 ├── mysql │ ├── recipes │ │ ├── createdb_phpms.rb -- データベース、ユーザー、テーブル作成 │ │ └── default.rb -- MySQLインストール、起動、自動起動設定 │ └── templates │ └── default │ ├── create_schema_phpms.sql.erb -- テーブル作成SQLテンプレート │ ├── createdb.sql.erb -- データベース作成SQLテンプレート │ └── createuser.sql.erb -- DBユーザー作成SQLテンプレート ├── php │ └── recipes │ └── default.rb -- PHPインストール └── remi └── recipes └── default.rb -- remiインストール
localedef/recipes/default.rb
ファイル中の日本語を正常に読み込むためにロケール設定用のクックブックを作成します。
※これ分かるまで、日本語の文字化け状態が解消できずに結構ハマりました。。
bash 'localedef' do code 'localedef -f UTF-8 -i ja_JP ja_JP.UTF-8' end
remi/recipes/default.rb
各パッケージの新しいバージョンをインストールするために、外部yumリポジトリremiのクックブックを作成します。
remote_file "#{Chef::Config[:file_cache_path]}/remi-release-6.rpm" do source "http://rpms.famillecollet.com/enterprise/remi-release-6.rpm" action :create end rpm_package "remi-release-6" do source "#{Chef::Config[:file_cache_path]}/remi-release-6.rpm" action :install end
apache/recipes/default.rb
Apacheインストールのレシピです。
%w[ httpd httpd-devel mod_ssl ].each do |pkg| package "#{pkg}" do action :install end end service 'httpd' do supports :status => true, :restart => true, :reload => true action [ :enable, :start ] end template "/etc/httpd/conf/httpd.conf" do source "httpd-2.2.conf.erb" end
serviceブロックの説明
supportでは、サービスが使えるアクションを定義するらしく、とりあえず指定しておきます。
actionでは、:enableで自動起動設定、:startでサービスの起動を指示します。
templateブロックの説明
「ローカルの”http-2.2.conf.erb”を 仮想サーバの”/etc/httpd/conf/httpd.conf”として配置する」
という意味になります。
apache/recipes/phpms.rb
後述のphpms.vm.confを配置するためのレシピです。
template "/etc/httpd/conf.d/phpms.vm.conf" do source "phpms.vm.conf.erb" end
apache/templates/default/httpd-2.2.conf.erb
httpd.confのテンプレートです。
NameVirtualHostを有効にするために、http2.2のインストール時に作成されるhttpd.confファイルをコピーしてきて、 以下の内容を追記しただけ。
NameVirtualHost *:80
apache/templates/default/phpms.vm.conf.erb
ホスト名”phpms.vm”でアクセスした際の設定ファイルのテンプレートです。
<VirtualHost *:80> ServerName phpms.vm DocumentRoot /var/www/src/phpms/public <Directory /var/www/src/phpms/public> Options All AllowOverride All Order allow,deny Allow from all </Directory> </VirtualHost>
php/recipes/default.rb
PHPをインストールします。 PHP5.5をインストールするために、”remi-php55″を有効にしています。
%w[ php php-pdo php-mbstring php-mysqlnd ].each do |pkg| package "#{pkg}" do action :install options '--enablerepo=remi-php55' end end
mysql/recipes/default.rb
新しいMySQLをインストールしたいので、mysql-commnityリポジトリを追加してからインストールします。
# add mysql yum repository remote_file "#{Chef::Config[:file_cache_path]}/mysql-community-release-el6-5.noarch.rpm" do source 'http://repo.mysql.com/mysql-community-release-el6-5.noarch.rpm' action :create end rpm_package "mysql-community-release" do source "#{Chef::Config[:file_cache_path]}/mysql-community-release-el6-5.noarch.rpm" action :install end # install mysql community server yum_package "mysql-community-server" do action :install flush_cache [:before] end service "mysqld" do supports :status => true, :restart => true, :reload => true action [ :enable, :start ] end
mysql/recipes/createdb_phpms.rb
データベース、ユーザーを作成し、テーブルを作成するスキーマ定義スクリプトも実行します。
# create database db_name = 'phpms' execute "createdb" do command "/usr/bin/mysql -u root < #{Chef::Config[:file_cache_path]}/createdb.sql" action :nothing not_if "/usr/bin/mysql -u root -D #{db_name}" end template "#{Chef::Config[:file_cache_path]}/createdb.sql" do owner 'root' group 'root' mode 644 source 'createdb.sql.erb' variables({ :db_name => db_name, }) notifies :run, 'execute[createdb]', :immediately end # create database user user_name = 'phpms' user_password = 'phpms' execute 'createuser' do command "/usr/bin/mysql -u root < #{Chef::Config[:file_cache_path]}/createuser.sql" action :nothing not_if "/usr/bin/mysql -u #{user_name} -p#{user_password} -D #{db_name}" end template "#{Chef::Config[:file_cache_path]}/createuser.sql" do owner 'root' group 'root' mode 644 source 'createuser.sql.erb' variables({ :db_name => db_name, :username => user_name, :password => user_password, }) notifies :run, 'execute[createuser]', :immediately end # create schema schema_file = 'create_schema_phpms.sql' execute "create_schema_phpms" do command "/usr/bin/mysql -u root #{db_name} < #{Chef::Config[:file_cache_path]}/create_schema_phpms.sql" action :nothing not_if "/usr/bin/mysql -u #{user_name} -p#{user_password} -D #{db_name} -e 'show tables' | wc -l | xargs expr 1 /" end template "#{Chef::Config[:file_cache_path]}/create_schema_phpms.sql" do owner 'root' group 'root' mode 644 source 'create_schema_phpms.sql.erb' notifies :run, 'execute[create_schema_phpms]', :immediately end
mysql/templates/default/createdb.sql.erb
CREATE DATABASE <%= @db_name %> CHARACTER SET utf8;
mysql/templates/default/createuser.sql.erb
GRANT ALL ON <%= @db_name %>.* TO '<%= @username %>'@'localhost' IDENTIFIED BY '<%= @password %>'; GRANT ALL ON <%= @db_name %>.* TO '<%= @username %>'@'%' IDENTIFIED BY '<%= @password %>'; FLUSH PRIVILEGES;
mysql/templates/default/createuser.sql.erb
CREATE TABLE test ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(64), CONSTRAINT pk_test PRIMARY KEY (id) ); INSERT INTO test (name) VALUES ('テストデータ1'); INSERT INTO test (name) VALUES ('テストデータ2'); INSERT INTO test (name) VALUES ('テストデータ3'); INSERT INTO test (name) VALUES ('テストデータ4'); INSERT INTO test (name) VALUES ('テストデータ5');
PHPコードの記述
srcディレクトリ配下に、PHPの動作確認用のコードを追加しておきます。
src └── phpms └── public └── select_test.php
src/phpms/public/select_test.php
<?php $dsn = 'mysql:dbname=phpms;host=localhost'; $user = 'phpms'; $pass = 'phpms'; $db = null; try { $db = new PDO($dsn, $user, $pass); } catch (Exception $e) { echo $e->getMessage(); } $sql = 'SELECT id, name FROM test'; foreach ($db->query($sql) as $row) { var_dump($row); } // end of file
Vagrantfileの編集
以下のようにVagrantfileを設定します。
# -*- mode: ruby -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "phpms" config.vm.box_url = "https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box" config.vm.network "private_network", ip: "192.168.33.104" config.vm.synced_folder "./src", "/var/www/src", :create => true, :owner => 'vagrant', :group => 'vagrant', :mount_options => ['dmode=777', 'fmode=666'] config.vm.provision "chef_solo" do |chef| chef.cookbooks_path = "chef/site-cookbooks/" chef.run_list = %w[ recipe[localedef] recipe[remi] recipe[apache] recipe[apache::phpms] recipe[php] recipe[mysql] recipe[mysql::createdb_phpms] ] end config.omnibus.chef_version = :latest end
主な設定項目
config.vm.network
private_network(ホストオンリーネットワーク)として、任意のIPアドレスを設定します。
ホストオンリーネットワークとは、ホストOSとゲストOS間でのみ通信できるネットワークです。
ホストOSから仮想サーバにアクセスする際には、ここで設定したIPアドレスを使用します。
config.vm.synced_folder
共有フォルダを設定します。
ここで設定したホストOSのフォルダは、ゲストOSからマウントされます。 この仕組みを利用して、ホストOSに存在するPHPソースコードを、ゲストOSから参照できるようにします。
config.vm.provision “chef_solo”
vagrantのプロビジョニングにchef soloを使うための設定です。
後述するvagrant upを実行すると、仮想マシンの起動とプロビジョニングが実行されます。
そのプロビジョニングの際にchef_soloを使うよう設定しています。
run_listには、実行するレシピを記述します。
config.omnibus.chef_version
先述の vagrant-omnibus を使って、 仮想サーバにchefがインストールされていない場合、自動的に最新バージョンをインストールしてもらうための設定です。
:latest という値からも、最新バージョンであることが読み取れるかと思います。
仮想サーバのプロビジョニング
以上のインフラ設定を、仮想サーバに適用します。
$ vagrant provision
PHP動作確認
PHPの動作確認をします。動作確認前に、hostsに想定するホスト名を設定します。
hostsの設定
phpms.vm というホスト名を想定しているため、hostsファイルに記述します。 Vagrantfileのprivate_networkに設定したIPアドレスを記述します。
192.168.33.104 phpms.vm
動作確認
下記のURLにアクセスすると、PHPが動作していることが確認できます。
- http://phpms.vm/select_test.php
まとめ
以上のように、仮想サーバの環境構築を自動化することで、
- 会社で作った環境を自宅で再現する
- チームメンバーに開発環境を配布する
などのことが簡単にできるようになります。
今回作成したファイルは、githubにもpushしておきました。参考になれば幸いです。
https://github.com/shusatoo/phpms
ダウンロードしたファイルを適当なディレクトリに配置して、”vagrant up”を実行すれば仮想サーバーが起動します。 (VirtualBox, Vagrant, knifeがインストール済みであること)
Chefの正しい知識を身につけるならこの本で。
(購入しましたが、本記事はこの本読む前に書いてしまいました)
参考URL
以下のページを参考にさせていただきました。ありがとうございます。
今っぽい Vagrant + Chef Solo チュートリアル
ChefでMySQL5.6をインストール
構成管理ツール「Chef」の一歩進んだ使い方 ―独自のResourceを定義する―
Chef Soloの正しい始め方
仮想環境構築ツール「Vagrant」で開発環境を仮想マシン上に自動作成する
サーバー設定ツール「Chef」応用編:knife-soloとData Bagを使う
nanapi勉強会でVagrant + Berkshelfについて発表しました
最近のコメント