酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

test-kitchenでインフラのTDDに挑戦[Rails/Nginx/MySQL/rbenv]

これまでVagrantやChefをつかってインフラのコード化を勉強してきましたが、今回は更に一歩進めてserverspecを使ったインフラのテストと、『test-kitchen』を使ったTDDにチャレンしてみました!

慣れてくるとtest-kitchenのコマンドで設定をやり直し => インフラのテストがソースコードを書くような感覚で、インフラを構築できるのがすごく心地よかったです。

ようやくですが、localのvagrantと『AWS EC2』、『Digital Ocean』に対応しました。コマンド一つでChefを適用したり、serverspecでリモートの環境をテストすることができます!

(05-02 08:35) Rubyサーバ・デプロイまでのチェックリストを追加


今回のソースコード

Vagrant/Digital Ocean/AWS EC2上にNginx/MySQL/rbenv/Ruby 2.1.0/Ubuntu 12.04のおなじみのサーバ構成の構築/テストを行うtest-kitchenのソースコードをGitHubに公開しました。また、Vagrant x CentOS 6.5 /Nginx/MySQL/rbenv/Ruby 2.1.0も作成しました。

morizyun/test-kitchen-rails

手っ取り早くVagrantでRailsサーバを立ち上げたり、serverspecでテストしてみたい方は是非使ってみてください!Pull Requestも大歓迎です^^

環境準備

Vagrant

Vagrant 公式サイト
パッケージをDLしてインストール。

vagrantをインストールしたら、boxでchefを使えるようにするためのプラグインをインストール。

1
vagrant plugin install vagrant-omnibus

VirtualBox

VirtualBox 公式サイト
パッケージをDLしてインストール。

簡単なtest-kitchen環境の作り方

Cookbookの作成

1
berks cookbook test-kitchen && cd test-kitchen

Gemfileのセットアップ

次にvim Gemfileでセットアップ。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
source 'https://rubygems.org'

gem 'berkshelf'
gem 'foodcritic'
gem 'rubocop'
gem 'busser'
gem 'serverspec'
gem 'dotenv'

# test-kitchen
gem 'test-kitchen'
gem 'kitchen-vagrant'
gem 'kitchen-digitalocean'
gem 'kitchen-ec2'

完了したらbundlerでgemを導入。

1
bundle install --binstubs=bin

vim bin/kitchenでdotenvを読み込むように設定を追記。

1
2
require 'dotenv'
Dotenv.load

この設定は本来は良くないと思います。bundle installのたびに設定を描き直さないといけないので、もっといい方法があれば是非教えて下さい!

busserプラグインの設定

次にプラグインの設定。

1
busser plugin install serverspec

Berksfileのセットアップ

vim BerksfileでBerkshelfの設定。
(まだ試行錯誤中なので、最新はGitHubをご参照ください)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
site :opscode

metadata

cookbook "apt",
  git: "https://github.com/opscode-cookbooks/apt.git"
cookbook "build-essential",
  git: "https://github.com/opscode-cookbooks/build-essential.git"
cookbook "git",
  git: "https://github.com/opscode-cookbooks/git.git"
cookbook "nginx",
  git: "https://github.com/opscode-cookbooks/nginx.git"
cookbook "vim",
  git: "https://github.com/opscode-cookbooks/vim.git"
cookbook "mysql",
  git: "https://github.com/myplanetdigital-experimental/chef-mysql.git"
cookbook 'rbenv',
  git: "https://github.com/fnichol/chef-rbenv.git"
cookbook 'database',
  git: "https://github.com/opscode-cookbooks/database.git"

cookbook 'base', path: 'site-cookbooks/base'

設定画完了したら、Berkshelfの設定を反映。

1
bundle exec berks vendor cookbooks

.kitchen.ymlの設定

vim .kitchen.ymlでtest-kitchen用の設定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
---
provisioner:
  name: chef_solo

driver_config:
  require_chef_omnibus: true

platforms:
  - name: va-ubuntu-12.04
    driver:
      name: vagrant
      network:
        - ["private_network", {ip: "192.168.33.33"}]
      synced_folders:
        - ["vagrant", "/usr/share/nginx", "create: true, type: :nfs"]
    provider: virtualbox
    driver_config:
      box: opscode-ubuntu-12.04
      box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box
      customize:
        memory: 1024
        cpuexecutioncap: 100
   - name: va-centos-6.5
    driver:
      name: vagrant
      network:
        - ["private_network", {ip: "192.168.33.32"}]
      synced_folders:
        - ["vagrant", "/usr/share/nginx", "create: true, type: :nfs"]
    driver_config:
      box: opscode-centos-6.5
      box_url: http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.5_chef-provisionerless.box

suites:
  - name: rails
    run_list:
      - recipe[base::prepare]
      - recipe[build-essential]
      - recipe[git]
      - recipe[vim]
      - recipe[nginx]
      - recipe[mysql::server]
      - recipe[mysql::client]
      - recipe[ruby_build]
      - recipe[rbenv::system]
      - recipe[base]
      - recipe[base::rails]
    attributes:
      git:
        version: 1.9.1
      nginx:
        application_name: 'sample'
      mysql:
        server_debian_password: "passw0rd"
        server_root_password: "passw0rd"
        server_repl_password: "passw0rd"
      rbenv:
        rubies: ['2.1.0']
        global: '2.1.0'
        gems:
          '2.1.0':
            - name: 'bundler'
              options: '--no-ri --no-rdoc'
            - name: 'gem'
              options: '--no-ri --no-rdoc'
            - name: 'rails'
              options: '--no-ri --no-rdoc'
            - name: 'rake'
              options: '--no-ri --no-rdoc'
            - name: 'therubyracer'
              options: '--no-ri --no-rdoc'

Vagrant/Ubuntu編

まずはvagrantでローカルにubuntuを立ち上げます。

セットアップ

vagrantのセットアップを行います。

1
kitchen setup rails-va-ubuntu-1204

servespecテスト

serverspecで立ち上げたvagrantのテストを行います。

1
2
3
4
5
6
kitchen verify rails-va-ubuntu-1204
# 次のように出れば成功
# Finished in seconds
# 15 examples, 0 failures
#       Finished verifying <rails-va-ubuntu-1204>
# -----> Kitchen is finished

Vagrant/CentOS編

まずはvagrantでローカルにCentOSを立ち上げます。

セットアップ

vagrantのセットアップを行います。

1
kitchen setup rails-va-centos-65

servespecテスト

serverspecで立ち上げたvagrantのテストを行います。

1
2
3
4
5
6
kitchen verify rails-va-centos-65
# 次のように出れば成功
# Finished in seconds
# 15 examples, 0 failures
#       Finished verifying <rails-va-ubuntu-1204>
# -----> Kitchen is finished

Digital Ocean編

次は『Digital Ocean』に鯖を立ち上げます。

事前準備

以下、『Digital Ocean』での作業。

1) Digital Oceanでユーザー登録
2) ユーザー画面内の左メニュー「Billing」からPayPalで$5を支払い
3) ユーザー画面内の左メニュー「API」で"Client ID"と"API Key"を作成
4) ユーザー画面内の左メニュー「SSH Keys」でSSHキーを登録

事前準備で取得した”Client ID”と”API Key”を元にSSH Key IDを取得。

1
wget -q -O- https://api.digitalocean.com/ssh_keys/?client_id=[Client ID]&api_key=[API Key]

登録した情報を.envに登録

取得した情報をvim .envで登録。DIGITALOCEAN_SSH_KEY_PATHにはDigital Oceanに登録したSSHキーの秘密鍵へのパスを設定。

1
2
3
4
DIGITALOCEAN_CLIENT_ID="1234"
DIGITALOCEAN_API_KEY="5678"
SSH_KEY_IDS="1234, 5678"
DIGITALOCEAN_SSH_KEY_PATH="~/.ssh/id_rsa"

.kitchen.ymlを設定

1
2
3
4
5
6
7
8
9
10
platforms:
  - name: do-ubuntu-12.04
    driver:
      name: digitalocean
      ssh_key: <%= ENV['DIGITALOCEAN_SSH_KEY_PATH'] %>
    driver_config:
      image_id: 3101045
      region: San Francisco 1
      flavor: 512MB
      private_networking: false

セットアップ

Digital Oceanのインスタンスのセットアップを行います。

1
kitchen setup rails-do-ubuntu-1204

Digital Oceanのユーザー画面内の左メニュー「Droplets」で立ち上がっているインスタンスを確認することができます。

スクリーンショット_2014-04-12_12_38_11

servespecテスト

serverspecで立ち上げたvagrantのテストを行います。

1
2
3
4
5
6
kitchen verify rails-do-ubuntu-1204
# 次のように出れば成功
# Finished in seconds
# 15 examples, 0 failures
#       Finished verifying <rails-do-ubuntu-1204>
# -----> Kitchen is finished

AWS EC2編

次は『AWS EC2』に鯖を立ち上げます。

事前準備

以下、『AWS EC2』での作業。

1) AWS EC2でユーザー登録
2) EC2 => 自分が作成するリージョン(Tokyo)でセキュリティグループを作成
3) EC2 => Key Pairで鍵を作成(もしくはImportして登録)
4) 右上のメニュー「Security Credential」=> Access Keyを作成

登録した情報を.envに登録

取得した情報をvim .envで登録。DIGITALOCEAN_SSH_KEY_PATHにはDigital Oceanに登録したSSHキーの秘密鍵へのパスを設定。

1
2
3
4
5
6
7
AWS_ACCESS_KEY_ID="xxxx"
AWS_FLAVOR_ID="m1.small"
AWS_IMAGE_ID="ami-f397eef2"
AWS_SECRET_ACCESS_KEY="xxxx"
AWS_SECURITY_GROUP_ID="sg-xxxxx"
AWS_SSH_KEY="~/.ssh/aws.pem"
AWS_SSH_KEY_ID="xxxx"

.kitchen.ymlを設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
platforms:
  - name: ec2-ubuntu-12.04
    driver:
      name: ec2
      region:  ap-northeast-1
      availability_zone: ap-northeast-1c
      flavor_id: <%= ENV['AWS_FLAVOR_ID'] %>
      image_id: <%= ENV['AWS_IMAGE_ID'] %>
      aws_ssh_key_id: <%= ENV['AWS_SSH_KEY_ID'] %>
      aws_access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
      ssh_key: <%= ENV['AWS_SSH_KEY'] %>
      aws_secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
      username: ubuntu
      security_group_ids: ["<%= ENV['AWS_SECURITY_GROUP_ID'] %>"]
      port: 22
      ebs_optimized: false

セットアップ

EC2のインスタンスのセットアップを行います。

1
kitchen setup rails-ec2-ubuntu-1204

AWSマネージメントコンソール => EC2画面で立ち上がっているインスタンスを確認することができます。

スクリーンショット_2014-04-12_15_01_08

servespecテスト

serverspecで立ち上げたvagrantのテストを行います。

1
2
3
4
5
6
kitchen verify rails-ec2-ubuntu-1204
# 次のように出れば成功
# Finished in seconds
# 15 examples, 0 failures
#       Finished verifying <rails-do-ubuntu-1204>
# -----> Kitchen is finished

サーバのセットアップ完了 => Railsアプリデプロイまでの手順

(1) test-kitchenの実行 => テスト実行

(2) Elastic Block Storeを設定

(3) 鯖側にdeploy用のキーを作成 => 公開鍵をGitHubに登録

(4) MySQLのユーザー作成
GRANT ALL PRIVILEGES ON DB_NAME.* TO USER_NAME@localhost IDENTIFIED BY ‘PASSWORD';
FLUSH PRIVILEGES;

(5) ローカルでcapistranoを使ったデプロイ
cap production deploy:starting
cap production deploy:check
cap production deploy # dbがないのでコケる

(6) 鯖のreleaseフォルダで、bundle exec rake RAILS_ENV=production db:create

(7)cap production deploy

初回デプロイ時にDBが無いときに先にDBを作成する方法は、もっといい方法があるはずなのでご存じの方がいれば、コメントを頂ければ幸いです!

Capistrano 3系でRails4.1のデプロイ
Capistrano 3の設定はこちらがおすすめ。

次のステップ

残念ながら今回は挫折しましたが、Dokkuをまる2日位ためしてみました。まだまだ実用レベルとは言いづらいですが、可能性をすごく感じるプロダクトです!今回は調査していた中で見つけたサイトをメモがてら書いておきます。

ChefでDocker&Dokkuをインストール

fgrehm/chef-dokku - GitHub

bflad/chef-docker - GitHub

progrium/dokku - GitHub

rlister/chef-dokku-simple - GitHub

hughfletcher/dokku-mysql-plugin - GitHub

Special Thanks

Chef で Elasticsearch クラスタを EC2 上に作る
こちらのブログでtest-kitchenの使い方を知ることが出来ました。多謝です!

dotenvを利用して環境ごとでVagrantfileの設定値を変更してみる

test-kitchen/kitchen-digitalocean

変更来歴

(04/12 12:45) Digital OceanとAWS EC2を適用
(04/14 23:35) Docker & Dokkuに関するメモ書きを追記
(04/23 22:50) CentOS 6.5 x Vagrantを追加、バグフィックス
(04/25 23:00) ちょこちょこミスがあった点を修正
(05-02 08:35) Rubyサーバ・デプロイまでのチェックリストを追加

おすすめの書籍