Lチカ開発ブログ

https://l-chika.com/の開発ブログ

どうせRailsの環境構築するなら本番環境にも応用できるようにする

f:id:l-chika:20161218190851p:plain

Railsに限らず、Webサービスを開発する場合には開発する環境の整備が必要。 開発は普段自分のmacやWindowなどのローカルPCでしていると思いますが、最終的には本番環境で利用できるものでなければならない。 自分は以下の理由から、開発段階から本番環境に近しい環境での開発をしている。

  • OSが異なると、その環境固有の設定が必要になることがあり、それがかなり手間がかかる
  • 本番環境で問題が発生した場合に、ローカルでも再現できるようにしたい

では、どうしているかというと普通に「Vagrant」。 開発環境と本番環境(AWS EC2)で、ほぼ同じ設定で再利用することで、環境の差異をなくし、環境構築の手間を軽減。

前提

  • Virtualbox 5.0.16
  • Vagrant 1.8.6以上
  • ChefDK を利用(ローカルにbundle install でberksをインストールすると、ものすごく重かったので)。
  • Vagrantの環境。※適宜、必要な環境に設定を変更する

開発環境の構築手順

$ vagrant -v
Vagrant 1.8.6
$ vagrant plugin list
vagrant-omnibus (1.4.1)
vagrant-share (1.1.4, system)
vagrant-vbguest (0.11.0)
$ chef -v
Chef Development Kit Version: 0.18.26
chef-client version: 12.14.89
delivery version: master (d86679335580be3de22996ef294b20d525889d8d)
berks version: 5.1.0
kitchen version: 1.13.0

構築するディレクトリ用意とknife初期化

$ mkdir {VAGRANT_PATH} && cd $_
$ knife solo init .
$ vim Berksfile
Berksfile
source "https://api.berkshelf.com"

cookbook 'git', '~>4.1.0'
cookbook 'build-essential', '~>2.1.3'
cookbook 'ruby_build'
cookbook 'ruby_rbenv'
cookbook 'nginx'
cookbook 'mysql', '~> 5.3.6'
cookbook 'memcached-cookbook', '~> 0.3.2'
cookbook 'postfix', '~> 3.7.0'
cookbook 'nodejs', '~> 2.4.4'

cookbook取得

$ berks vendor

Vagrant

$ vagrant init
$ vim Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "phusion/ubuntu-14.04-amd64"
  config.vm.network "forwarded_port", guest: 3000, host: 3000
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.synced_folder "./applications", '/home/vagrant/applications', type: "nfs"
  config.omnibus.chef_version=:latest
  config.vm.provision :chef_solo do |chef|
    # Vagrant 1.8.1の場合にはコメントイン
    # chef.channel = 'stable'
    # chef.version = '12.10.24'
    chef.cookbooks_path = ["./berks-cookbooks", "./site-cookbooks" ]

    chef.add_recipe "apt"
    chef.add_recipe "ruby_build"
    chef.add_recipe "ruby_rbenv::system"
    chef.add_recipe "ruby_rbenv::user"
    chef.add_recipe "mysql::server"
    chef.add_recipe 'nginx'
    chef.add_recipe 'memcached-cookbook'
    chef.add_recipe 'postfix'
    chef.add_recipe 'postfix::sasl_auth'
    chef.add_recipe 'nodejs'
    # chef.add_recipe 'myapp' # 独自のレシピを入れる場合

    chef.json = {
      myapp: {
        name: 'fabric',
        server_name: '192.168.33.10'
      },
      rbenv: {
        user_installs: [{
          user: 'vagrant',
          rubies: ["2.2.3"],
          global: "2.2.3",
          gems: {
            "2.2.3" => [
              { name: "bundler" }
            ]
          }
        }]
      },
      mysql: {
        version: '5.6',
        port: '3306',
        server_root_password: ''
      },
      postfix: {
        main: {
          relayhost: '[smtp.gmail.com]:587',
          smtp_sasl_auth_enable: 'yes'
        },
        sasl: {
          smtp_sasl_passwd: 'your_password',
          smtp_sasl_user_name: 'your_username'
        }
      },
      nodejs: {
        install_method: 'binary',
        binary: { url: 'https://nodejs.org/dist/v6.6.0/node-v6.6.0-linux-x64.tar.xz',
                  # curl -L -s https://nodejs.org/dist/v6.6.0/node-v6.6.0-linux-x64.tar.xz | shasum -a 256
                  checksum: 'fdf4377ea4dc9ba2f09d81d9ad1eae42e7eb870c4b1b69f2761f22f28cb5ba31',
                },
        version: '6.6.0'
      }
    }

  end

  config.vm.provider "virtualbox" do |vb|
    # vb.gui = true
    vb.memory = "1024"
  end

end

アプリケーション用ディレクト

$ cd {VAGRANT_PATH}
$ mkdir applications && cd $_
$ git clone git@github.com:xxxx

vagrantとアプリケーションの起動

$ vagrant up --provider=virtualbox
※ 初回起動は10~15分くらいかかる
$ vagrant ssh
$ cd applications/{APP_PATH}
$ bundle install --path=vender/bundle
$ ./bin/rails s -b 0.0.0.0

本番環境(AWS)の構築手順

前提

  • AWSのアカウントはある

vagrant plugin

$ vagrant plugin list
dotenv (2.1.1)
vagrant-aws (0.7.2)
vagrant-omnibus (1.5.0)
vagrant-share (1.1.5, system)
vagrant-vbguest (0.13.0)

手順

box追加

$ vagrant box add dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
$ mkdir {VAGRANT_PATH} && cd $_
$ knife solo init .
$ vim Berksfile
$ berks vendor
$ vim .env
$ vagrant init
$ vim Vagrantfile

※ Berksfileは開発環境と同じ

.envの設定

AWS_SSH_USERNAME="ec2-user" # AWSにSSHアクセスする際のユーザ名(ec2-user or ubuntu)
AWS_SSH_KEY="~/.ssh/vagrant.pem" # 作成した秘密鍵のパス
AWS_ACCESS_KEY_ID="" # ユーザ作成時のAccess Key Id
AWS_SECRET_ACCESS_KEY="" # ユーザ作成時のSecret Access Key
AWS_KEYPAIR_NAME="vagrant" # 作成したキーペア名
AWS_SECURITY_GROUP="vagrant" # セキュリティグループ名
# -*- mode: ruby -*-
# vi: set ft=ruby :

Dotenv.load

Vagrant.configure(2) do |config|
  config.vm.box = 'dummy'
  # config.vm.box_url = 'https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box'
  config.omnibus.chef_version = :latest

  config.vm.provider :aws do |provider, override|
    # AWS認証情報
    provider.access_key_id = ENV['AWS_ACCESS_KEY_ID']
    provider.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
    provider.keypair_name = ENV['AWS_KEYPAIR_NAME']

    # EC2インスタンスの設定
    provider.region = 'ap-northeast-1'
    provider.availability_zone = 'ap-northeast-1c'

    provider.ami = 'ami-a21529cc' # Ubuntu Server 14.04 LTS
    # provider.ami = 'ami-0919cd68' # Ubuntu Server 16.04 LTS

    provider.instance_type = 't2.micro'
    provider.instance_ready_timeout = 120
    provider.terminate_on_shutdown = false
    # provider.subnet_id = "xxxxxx"

    # セキュリティグループ
    provider.security_groups = [ENV['AWS_SECURITY_GROUP']]
    # タグ(任意)。インスタンスに分かりやすい目印を付けたい場合。
    provider.tags = { Name: 'vagrant-aws', Description: 'Boot from vagrant-aws' }

    # ログイン後、sudo できるようにする
    provider.user_data = <<-USER_DATA
    #!/bin/sh
    sed -i -e 's/^\\(Defaults.*requiretty\\)/#\\1/' /etc/sudoers
    USER_DATA

    # AWSへの接続ユーザおよび秘密鍵の指定
    override.ssh.username = ENV['AWS_SSH_USERNAME']
    override.ssh.private_key_path = ENV['AWS_SSH_KEY']
    override.ssh.pty = true

    # Ubuntuの場合
    override.nfs.functional = false
    # override.vm.synced_folder ".", "/home/ec2-user/vagrant", disabled: true
  end

  config.vm.provision :chef_solo do |chef|
    # Vagrant 1.8.1の場合にはコメントイン
    # chef.channel = 'stable'
    # chef.version = '12.10.24'
    chef.cookbooks_path = ['./berks-cookbooks', './site-cookbooks']

    chef.add_recipe 'apt'
    chef.add_recipe 'ruby_build'
    chef.add_recipe 'ruby_rbenv::system'
    chef.add_recipe 'ruby_rbenv::user'
    chef.add_recipe 'mysql::server'
    chef.add_recipe 'nginx'
    chef.add_recipe 'memcached-cookbook'
    chef.add_recipe 'postfix'
    chef.add_recipe 'postfix::sasl_auth'
    chef.add_recipe 'nodejs'
    chef.add_recipe 'myapp'

    chef.json = {
      myapp: {
        name: 'fabric',
        server_name: '192.168.33.10',
        wwww_dir: { owner: 'ubuntu', group: 'ubuntu' }
      },
      rbenv: {
        user_installs: [{
          user: 'ubuntu',
          rubies: ["2.2.3"],
          global: "2.2.3",
          gems: {
            "2.2.3" => [
              { name: "bundler" }
            ]
          }
        }]
      },
      mysql: {
        version: '5.6',
        port: '3306',
        server_root_password: ''
      },
      postfix: {
        main: {
          relayhost: '[smtp.gmail.com]:587',
          smtp_sasl_auth_enable: 'yes'
        },
        sasl: {
          smtp_sasl_passwd: 'your_password',
          smtp_sasl_user_name: 'your_username'
        }
      },
      nodejs: {
        install_method: 'binary',
        binary: { url: 'https://nodejs.org/dist/v6.6.0/node-v6.6.0-linux-x64.tar.xz',
                  # curl -L -s https://nodejs.org/dist/v6.6.0/node-v6.6.0-linux-x64.tar.xz | shasum -a 256
                  checksum: 'fdf4377ea4dc9ba2f09d81d9ad1eae42e7eb870c4b1b69f2761f22f28cb5ba31',
                },
        version: '6.6.0'
      }
    }
  end
end

vagrant起動

$ vagrant up --provider=aws

最後に

簡単にではあるば、開発環境とAWSで利用できる設定を記述。本番ではDBやメール、ファイルサーバー、Memcache等のミドルウェアが異なるがWebサーバーはほぼ同じ設定を利用できることで、何か障害が発生しても問題の切り分けがしやすくなる。

関連・参考本

Chef実践入門 ~コードによるインフラ構成の自動化 (WEB+DB PRESS plus)

Chef実践入門 ~コードによるインフラ構成の自動化 (WEB+DB PRESS plus)

実践 Vagrant

実践 Vagrant