Chefのコマンド一発でサービスを作れる状態へ(CentOS6.6)


この投稿は私がCentOS6.6の環境を構築する時に色々調べたりしたことをまとめたものです。
(2015年6月17日現在)

Chefを使って環境を整えたい、VPS契約したけど初期設定めんどくさいという人が対象です。
読者が30分以内ですぐに開発に取り掛かれるようになることがゴールです。

やること

* セキュリティ関連のセットアップ(開発ユーザー作成、sudo権限付与、rootログインできないようにする、パスワードログインできないようにする、iptablesを設定)
* nginxを入れる(バージョン:1.9.2)
* DB(MySQL)を入れる(5.6)
* Ruby(rbenv:2.2.2), Go(1.4)を入れる

## せっかちな方のために
Gitで公開しているので、cloneしたら後はコマンド一発です。
https://github.com/Islands5/vps_settings.git

最低限やることは
site-cookbooks/site-user/recipes/default.rb
の公開鍵を編集

nodes/192.168.33.200.json
のmysqlのパスワードを編集

任意:sshのポートを変更する(触った場合ファイアーウォールの設定もしてね)
等を行う必要があります。

## Chefのセットアップ
Chefをまだ入れてないよという人はここでセットアップしてください。
Knife-soloも入れます。

http://qiita.com/hamichamp/items/d3ca7c365353285a564b


## VPS環境を整える

chefリポジトリを作成します。

```sh:
$ chef exec knife solo init chef-repo
$ cd chef-repo
#以下ここを作業のホームディレクトリにします
```


Berksfileの一行目
site :opscode
を
source "https://supermarket.chef.io"
に変更

### 開発を行うユーザー(dev01)を追加

Berksfileを編集します。
cookbook 'user'
を追加してください

次に
site-cookbooks以下にsite-userというクックブックを作ります。

```sh:
$ chef exec knife cookbook create site-user -o site-cookbooks/
```

レシピを編集します。

```ruby:site-cookbooks/site-user/recipes/default.rb
user_account 'dev01' do
  action :create
  ssh_keys ['ssh-rsa ...']   #=> cat ~/.ssh/id_rsa.pubを実行して出てくる文字列
end
```

次にサーバーに適用するレシピを選択します。
jsonを開きます。

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]"
	]
}
```

### sudo権限を追加する
dev01にsudo権限をつけます。

Berksfileを編集します。
cookbook 'sudo'
を追加してください

このクックブックは追加のレシピが必要ないので
アトリビュートを設定します。
jsonを開きます。

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]",
		"recipe[sudo]"
	],
	"authorization": {
		"sudo": {
			"users": ["dev01"],
			"passwordless": "true"
		}
	}
}
```

### rootログイン、パスワードログインを禁止に
Berksfileを編集します。
cookbook 'openssh'
を追加してください

jsonを編集します。

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]",
		"recipe[sudo]",
		"recipe[openssh]"
	],
	"authorization": {
		"sudo": {
			"users": ["dev01"],
			"passwordless": "true"
		}
	},
	"openssh": {
		"server": {
			"permit_root_login": "no",
			"password_authentication": "no"
		}
	}
}
```

### iptablesを設定する
自作のiptables設定を使います。
クックブックを作ります。

```sh:
$ chef exec knife cookbook create site-iptables -o site-cookbooks/
```

レシピを編集します。

```ruby:site-cookbooks/site-iptables/recipes/default.rb
template "/etc/sysconfig/iptables" do
  source "iptables.erb"
  owner "root"
  group "root"
  mode 0644
end

service "iptables" do
  action [ :enable, :start ]
  supports :status => true, :restart => true
end
```

source部分にiptables.erbという記述があります。
テンプレートを使用します。

```erb:site-cookbooks/site-iptables/templates/default/iptables.erb
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:SERVICES -    [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 4 -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p tcp -m state --state NEW -j SERVICES
-A INPUT -p udp --sport 53 -j ACCEPT
-A INPUT -p udp --sport 123 --dport 123 -j ACCEPT
-A SERVICES -p tcp --dport 22 -j ACCEPT
-A SERVICES -p tcp --dport 80 -j ACCEPT
-A SERVICES -p tcp --dport 443 -j ACCEPT
-A SERVICES -p tcp --dport 3306 -j ACCEPT
COMMIT
```

この設定は
http://dotinstall.com/lessons/basic_sakura_vps/8010
から引用しました。

run_listにrecipe[site-iptables]を追加します。

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]",
		"recipe[sudo]",
		"recipe[openssh]",
		"recipe[site-iptables]"
	],
	"authorization": {
		"sudo": {
			"users": ["dev01"],
			"passwordless": "true"
		}
	},
	"openssh": {
		"server": {
			"permit_root_login": "no",
			"password_authentication": "no"
		}
	}
}
```

### nginx(1.9)を入れる
クックブックを作成します。
普通に入れると古いnginxが入るので...

```ruby:site-cookbooks/nginx/recipes/default.rb
template "nginx.repo" do
  path '/etc/yum.repos.d/nginx.repo'
  source "nginx.repo.erb"
  mode 0644
  owner 'root'
  group 'root'
end

yum_package "nginx" do
  action :install
  flush_cache [:before]
end

service "nginx" do
  action [:enable, :start]
  supports :status => true, :restart => true, :reload => true
end
```

レシピを適用するためにjsonを編集します。

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]",
		"recipe[sudo]",
		"recipe[openssh]",
		"recipe[site-iptables]",
		"recipe[nginx]"
	],
	"authorization": {
		"sudo": {
			"users": ["dev01"],
			"passwordless": "true"
		}
	},
	"openssh": {
		"server": {
			"permit_root_login": "no",
			"password_authentication": "no"
		}
	}
}
```

### MySQL(5.6)を入れる
Berksfileを編集します
cookbook 'mysql', '~> 5.3.6'
を追加します

アトリビュートを設定します。
jsonに直接指定する方式をとります。
注)mysql::serverというレシピもrun_listに追加しています。
目立たないですが、忘れないで下さいw

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]",
		"recipe[sudo]",
		"recipe[openssh]",
		"recipe[site-iptables]",
		"recipe[nginx]",
		"recipe[mysql::server]"
	],
	"authorization": {
		"sudo": {
			"users": ["dev01"],
			"passwordless": "true"
		}
	},
	"openssh": {
		"server": {
			"permit_root_login": "no",
			"password_authentication": "no"
		}
	},
	"mysql":{
		"server_name": "default",
		"version": "5.6",
		"port": "3306",
		"server_root_password": "password",
		"remove_anonymous_users": true,
		"remove_test_database":true
	}
}
```

### Ruby環境(rbenv)を入れる
ほとんどChef実践入門(pp157-162)からの引用です。
しかし、そのままだとエラーが出るので一部追加 + ruby2.2系を入れます。

クックブックを作成します。
```sh
$ chef exec knife cookbook create ruby-env -o site-cookbooks/
```

```ruby:site-cookbooks/ruby-env/recipes/default.rb
%w{gcc git openssl-devel sqlite-devel}.each do |pkg|
    package pkg do
        action :install
    end
end

git "/home/#{node['ruby-env']['user']}/.rbenv" do
    repository node["ruby-env"]["rbenv_uri"]
    action :sync
    user node['ruby-env']['user']
    group node['ruby-env']['group']
end

template ".bash_profile" do
    source ".bash_profile.erb"
    path "/home/#{node['ruby-env']['user']}/.bash_profile"
    mode 0644
    owner node['ruby-env']['user']
    group node['ruby-env']['group']
    not_if "grep rbenv ~/.bash_profile", :environment => { :'HOME' => "/home/#{node['ruby-env']['user']}" }
end

directory "/home/#{node['ruby-env']['user']}/.rbenv/plugins" do
    owner node['ruby-env']['user']
    group node['ruby-env']['group']
    mode 0755
    action :create
end

git "/home/#{node['ruby-env']['user']}/.rbenv/plugins/ruby-build" do
    repository node["ruby-env"]["ruby-build_uri"]
    action :sync
    user node['ruby-env']['user']
    group node['ruby-env']['group']
end

execute "rbenv install #{node['ruby-env']['version']}" do
    command "/home/#{node['ruby-env']['user']}/.rbenv/bin/rbenv install #{node['ruby-env']['version']}"
    user node['ruby-env']['user']
    group node['ruby-env']['group']
    environment 'HOME' => "/home/#{node['ruby-env']['user']}"
    not_if { File.exists?("/home/#{node['ruby-env']['user']}/.rbenv/versions/#{node['ruby-env']['version']}") }
end

execute "rbenv global #{node['ruby-env']['version']}" do
    command "/home/#{node['ruby-env']['user']}/.rbenv/bin/rbenv global #{node['ruby-env']['version']}"
    user node['ruby-env']['user']
    group node['ruby-env']['group']
    environment 'HOME' => "/home/#{node['ruby-env']['user']}"
end

%w{rbenv-rehash bundler}.each do |gem|
    execute "gem install #{gem}" do
        command "/home/#{node['ruby-env']['user']}/.rbenv/shims/gem install #{gem}"
        user node['ruby-env']['user']
        group node['ruby-env']['group']
        environment 'HOME' => "/home/#{node['ruby-env']['user']}"
        not_if "/home/#{node['ruby-env']['user']}/.rbenv/shims/gem list | grep #{gem}"
    end
end
```

やはりしっかり作りこまれているので、柔軟性が高いです。
見習いたい...^^;
アトリビュートによってバージョン等をコントロールできます。

```ruby:site-cookbooks/ruby-env/attributes/default.rb
default['ruby-env']['user'] = "dev01"
default['ruby-env']['group'] = "dev01"
default['ruby-env']['version'] = "2.2.2"
default['ruby-env']['rbenv_uri'] = "https://github.com/sstephenson/rbenv"
default['ruby-env']['ruby-build_uri'] = "https://github.com/sstephenson/ruby-build"
```

クックブックを適用します。

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]",
		"recipe[sudo]",
		"recipe[openssh]",
		"recipe[site-iptables]",
		"recipe[nginx]",
		"recipe[mysql::server]",
		"recipe[ruby-env]"
	],
	"authorization": {
		"sudo": {
			"users": ["dev01"],
			"passwordless": "true"
		}
	},
	"openssh": {
		"server": {
			"permit_root_login": "no",
			"password_authentication": "no"
		}
	},
	"mysql":{
		"server_name": "default",
		"version": "5.6",
		"port": "3306",
		"server_root_password": "password",
		"remove_anonymous_users": true,
		"remove_test_database":true
	}
}
```

### Go(1.4)言語環境を入れる
Berksfileを編集します。
cookbook "golang", git: "https://github.com/NOX73/chef-golang", branch: "master"
を追加します。

run_listにrecipe[golang]を追加します。

```json:nodes/192.168.33.200.json
{
	"run_list":[
		"recipe[user]",
		"recipe[site-user]",
		"recipe[sudo]",
		"recipe[openssh]",
		"recipe[site-iptables]",
		"recipe[nginx]",
		"recipe[mysql::server]",
		"recipe[ruby-env]",
		"recipe[golang]"
	],
	"authorization": {
		"sudo": {
			"users": ["dev01"],
			"passwordless": "true"
		}
	},
	"openssh": {
		"server": {
			"permit_root_login": "no",
			"password_authentication": "no"
		}
	},
	"mysql":{
		"server_name": "default",
		"version": "5.6",
		"port": "3306",
		"server_root_password": "password",
		"remove_anonymous_users": true,
		"remove_test_database":true
	}
}
```

クックブックの準備は以上です

## 締め
散々書き込んだBerksfileですが、まだクックブックのダウンロードを行っていないので、やります

```sh:
$ chef exec berks vendor cookbooks/
```

サーバーにchefを適用します。

```sh:
$ chef exec knife solo bootstrap root@192.168.33.200
```

でエラーがでなければ完了

## まとめ
さんざん書きましたが結局

やっていることは

* セキュリティ関連のセットアップ(開発ユーザー作成、sudo権限付与、rootログインできないようにする、パスワードログインできないようにする、iptablesを設定)
* Webサーバーとしてnginxを入れる
* DB(MySQL)を入れる
* Ruby(rbenv), Goを入れる

です。

実際に使う時は
site-cookbooks/site-user/recipes/default.rb
の公開鍵を編集

nodes/192.168.33.200.json
のmysqlのパスワードを編集

任意:sshのポートを変更する(ファイアーウォールの設定もしてね)

等を行う必要があります。

## 2015/06/19時点でインストールされたバージョン
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
nginx version: nginx/1.9.2
mysql  Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using  EditLine wrapper
go version go1.4 linux/amd64


## 参考
Chef実践入門
[さくらVPSの初期設定をChefsoloでやってみた](http://tsuchikazu.net/vps_chef_solo/)
[ドットインストール](http://dotinstall.com/lessons/basic_sakura_vps/8010)