地方でリモートワーク

プログラミング、先物、fx,仮想通貨なんでもやります

github x wercker x capistranoの設定の記録

スポンサーリンク

f:id:ihatov08:20160926122207j:plain

github x wercker x capistranoの設定の記録です。

  • werckerでユーザー登録 githubアカウントでサクッと作成できる。

  • 新しいapplicationを登録する。

  • repositoryの追加

githubを選択

  • githubから対象にするrepositoryの選択

  • owner userの選択

  • アクセス方法を選択

今回は公開鍵をgithubに登録する方法を選択(1番上)

Make my app publicにチェックを入れると、後ほど出てくるbadgeをクリックしたさいに、deploy情報を公開できるようになります。 (今回チェックをつける)

  • pipelineの作成

production-deployというpipelineを作成。 masterブランチにpushされたらproductionサーバーにdeployしてくれるようにする。

ここにenviroment variablesとして WERCKER_DEPLOYTARGET_NAMEをproduction WERCKER_CAP_PRIVATE_KEY(この値は後で入れる) を作成。 SSH Key variablesも作成 名前はWERCKER_SSH_KEY

  • 環境変数の登録 環境変数を登録しているようなら、wercker上でrspecを走らせる時にエラーが起きる可能性があるので、enviromentタブから環境変数を登録する。

  • wercker.yml

今回は下記のように作成。該当ブランチにpushするとrspecを自動で走らせて、capistranoも走ってくれる。

box: ruby
build:
  steps:
    - script:
        name: set timezone
        code: |
          export TZ="Asia/Tokyo"
    - script:
        name: echo timezone
        code: |
          date
    - script:
        name: Display version
        code: |
          cat /etc/issue

    - script:
        name: Update packeages
        code: |
          sudo apt-get update && sudo apt-get upgrade -y

    - script:
        name: Install Node.js
        code: |
          sudo apt-get install -y nodejs
    - script:
        name: Install MySQL
        code: |
          sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password wercker_test_password'
          sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password wercker_test_password'
          sudo apt-get -y install mysql-server
          sudo /etc/init.d/mysql start
          mysql -uroot -pwercker_test_password -e "CREATE DATABASE app_name_test CHARACTER SET utf8 COLLATE utf8_general_ci;"
          mysql -uroot -pwercker_test_password -e "CREATE USER appname@localhost IDENTIFIED BY 'password';"
          mysql -uroot -pwercker_test_password -e "GRANT ALL PRIVILEGES ON app_name_test.* TO appname@localhost IDENTIFIED BY 'appname';"
          mysql -uroot -pwercker_test_password -e "FLUSH PRIVILEGES;"

    - bundle-install:
        jobs: 4

    - script:
        name: echo ruby information
        code: |
          echo "ruby version $(ruby --version) running"
          echo "from location $(which ruby)"
          echo -p "gem list: $(gem list)"

    - script:
        name: Set up db
        code: |
          bundle exec rake db:create RAILS_ENV=test
          bundle exec rake db:schema:load RAILS_ENV=test
          bundle exec rake db:seed_fu RAILS_ENV=test

    - script:
        name: RSpec
        code: bundle exec rspec --color -f d

staging-deploy:
  steps:
    - bundle-install:
        jobs: 4
    - script:
        name: make .ssh directory
        code: mkdir -p "$HOME/.ssh"
    - create-file:
        name: write ssh key
        filename: $HOME/.ssh/id_rsa
        overwrite: true
        hide-from-log: true
        content: $WERCKER_SSH_KEY_PRIVATE
    - script:
        name: set permissions for ssh key
        code: chmod 0600 $HOME/.ssh/id_rsa
    - cap:
        stage: $WERCKER_DEPLOYTARGET_NAME
        tasks: deploy

production-deploy:
  steps:
    - bundle-install:
        jobs: 4
    - script:
        name: make .ssh directory
        code: mkdir -p "$HOME/.ssh"
    - create-file:
        name: write ssh key
        filename: $HOME/.ssh/id_rsa
        overwrite: true
        hide-from-log: true
        content: $WERCKER_SSH_KEY_PRIVATE
    - script:
        name: set permissions for ssh key
        code: chmod 0600 $HOME/.ssh/id_rsa
    - cap:
        stage: $WERCKER_DEPLOYTARGET_NAME
        tasks: deploy
  • とりあえずpush wercker.ymlを作成したので、githubにpushする。

  • ユーザーの作成とpasswordの設定

rootユーザーでログインして、

passwd ユーザー名

でpasswordの再設定をする。 このpasswordを後で利用する。

$ ssh-keygen

いろいろ出るが、enter連打。 これで.ssh/id_rsaと.ssh/id_rsa.pubができる。 id_rsaの秘密鍵をwercker側のenviroment valiableに設定する。 これはpipelineのenviroment valiableでも、enviromentのどちらでもいいみたい。 名前はWERCKER_CAP_PRIVATE_KEYでprotectedにチェックをつけること。

  • デプロイ先サーバーの公開鍵設定 本番環境サーバーにて行う。 .ssh/authorized_keysディレクトリの作成。 .ssh/authorized_keysにid_rsa.pubを入れる。 また、werckerの公開鍵もここに入れておく。

  • githubに公開鍵を登録

デプロイ先サーバーdepoyユーザーの公開鍵をgithubに登録。名前はproduction_server_keyにでもしておく。 id_rsa.pubの中身をコピペ。

  • known_hosts このディレクトリが存在する。自動で作られるのか? 過去コマンドを検索しても出てこない。

  • liked_filesは自動的に作成されない

linked_filesは自動的に作成されないので、手動で追加する。

config/deploy.rb

namespace :deploy do
  desc 'Restart application'
  task :restart do
    invoke 'unicorn:start'
  end

  desc 'Upload database.yml'
  task :upload do
    on roles(:app) do |host|
      if test "[ ! -d #{shared_path}/config ]"
        execute "mkdir -p #{shared_path}/config"
      end
      upload!('config/database.yml', "#{shared_path}/config/database.yml")
    end
  end

  before :starting, 'deploy:upload'
  after :finishing, 'deploy:cleanup'
end

こんな感じでデプロイ時にアップロードするように設定もできる。

  • deviseのsecret_keyを作成

Devise.secret_key was not set. Please add the following to your Devise initializer: こんなエラーメッセージが。 deviseのsecret_keyを作成すればOK

  • nginxの設定確認

/etc/nginx以下の設定ファイルの確認。 unicornと対応するように!

upstream unicorn_server {
 # This is the socket we configured in unicorn.rb
 server unix:/home/team_name/current/tmp/sockets/unicorn.sock
 fail_timeout=0;
}

server {
    listen       80 default_server;
    client_max_body_size 4G;

    keepalive_timeout 5;
    root /home/team_name/current/public;

    location / {
        #auth_basic "Restricted";
        #auth_basic_user_file /etc/nginx/.htpasswd;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://unicorn_server;
            break;
        }
    }

#    location ~ ^/assets/ {
#       expires 1y;
#       add_header Cache-Control public;

#       add_header ETag "";
#       break;
#    }

#   location ~ ^/(assets)/  {
#       root /home/team_name/current/public;
#       gzip_static on;
#       expires max;
#       add_header Cache-Control public;
#   }


        location @unicorn_server {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_redirect off;
          proxy_pass http://unicorn_server;
        }


    error_page   500 502 503 504  /500.html;
    location = /500.html {
        root /home/team_name/current/public;
    }
}
  • 権限の変更
$ chmod 755 /home/team_name/
  • secret_key_base これを設定しないと画面真っ白! capstranoでデプロイするとき毎回更新する羽目になるので、dotenv gemに登録することにした。
$ bundle exec rake secret RAILS_ENV=production
  • pidの向きの変更

今回unicorn.pidの名前を少しいじっていたので、向き合っていなかった模様。

http://blog.hypermkt.jp/failed-to-restart-unicorn-by-capistrano3-unicorn/

config/deploy/production.rb

set :unicorn_pid, "#{sahred_path}/tmp/pids/unicorn_team_name.pid"
  • ユーザーに注意 rootユーザーでunicornを立ち上げているとダメなので、stopしておく。

  • unicorn.rake

namespace :unicorn do
  ##
  # Tasks
  ##
  desc "Start unicorn for development env."
  task(:start) {
    env = ENV['RAILS_ENV']
    if env.blank?
      env = 'development'
    end
    config = Rails.root.join('config', 'unicorn', "#{env}.rb")
    sh "bundle exec unicorn_rails -c #{config} -E #{env} -D"
  }

  desc "Stop unicorn"
  task(:stop) { unicorn_signal :QUIT }

  desc "Restart unicorn with USR2"
  task(:restart) { unicorn_signal :USR2 }

  desc "Increment number of worker processes"
  task(:increment) { unicorn_signal :TTIN }

  desc "Decrement number of worker processes"
  task(:decrement) { unicorn_signal :TTOU }

  desc "Unicorn pstree (depends on pstree command)"
  task(:pstree) do
    sh "pstree '#{unicorn_pid}'"
  end

  def unicorn_signal signal
    Process.kill signal, unicorn_pid
  end

  def unicorn_pid
    begin
      env = ENV['RAILS_ENV']
      if env.blank? || env == 'development'
        File.read("/tmp/unicorn.pid").to_i
      elsif env == 'staging'
        File.read("/home/team_name/current/tmp/pids/unicorn.pid").to_i
      elsif env == 'production'
        File.read("/home/team_name/current/tmp/pids/unicorn.pid").to_i
      end
    rescue Errno::ENOENT
      raise "Unicorn doesn't seem to be running"
    end
  end

end
  • config/deploy.rb
# config valid only for current version of Capistrano
lock '3.4.1'

set :application, 'app_name'
set :repo_url, 'git@github.com:team_name/app_name.git'
set :keep_releases, 5

set :rvm_type, :auto
set :rvm_ruby_version, '2.3.0'
set :pty, true
set :ssh_options, {
    forward_agent: true,
    keys: %w(/home/team_name/.ssh/id_rsa),
    auth_methods: %w(publickey password),
    password: 'password'
}

set :log_level, :debug

set :linked_files, %w{config/database.yml .env}
set :linked_dirs, %w{bin bundle log tmp/pids tmp/cache tmp/sockets public/system public/uploads}

set :default_env, {
    ###
}
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }

set :unicorn_rack_env, 'development'

SSHKit.config.command_map[:rake] = 'bundle exec rake'

namespace :deploy do

  desc 'Create Database'
  task :db_create do
    on roles(:db) do |host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :rake, 'db:reset'
          execute :rake, 'db:setup'
          execute :rake, 'db:migrate'
          execute :rake, 'db:seed_fu'
        end
      end
    end
  end

  task :restart do
    invoke 'unicorn:restart'
  end

  after :publishing, :restart

  after :finishing, :cleanup
end
  • config/unicorn/production.rb
@app_path = '/home/app_name'
working_directory @app_path + "/current"

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
preload_app true
timeout 30
listen "#{@app_path}/current/tmp/sockets/unicorn.sock", :backlog => 64
pid "#{@app_path}/current/tmp/pids/unicorn.pid"

stderr_path "#{@app_path}/shared/log/unicorn.stderr.log"
stdout_path "#{@app_path}/shared/log/unicorn.stdout.log"

before_fork do |server, worker|
  ENV['BUNDLE_GEMFILE'] = "#{@app_path}/current/Gemfile"
end

before_exec do |server|
  Dotenv.overload
end

before_fork do |server, worker|
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end
  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
      rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

after_fork do |server, worker|
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end
end
  • config/deploy/production.rb
# server-based syntax
# ======================
# Defines a single server with a list of roles and multiple properties.
# You can define all roles on a single server, or split them:

# server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value
# server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value
# server 'db.example.com', user: 'deploy', roles: %w{db}

set :rails_env, "production"
set :branch, ENV['BRANCH'] || 'master'
set :deploy_to, '/home/team-name/'
set :unicorn_rack_env, 'production'
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
server 'ip-address', user: 'team-name', roles: %w{web app db}

# role-based syntax
# ==================

# Defines a role with one or multiple servers. The primary server in each
# group is considered to be the first unless any  hosts have the primary
# property set. Specify the username and a domain or IP for the server.
# Don't use `:all`, it's a meta role.

# role :app, %w{deploy@example.com}, my_property: :my_value
# role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value
# role :db,  %w{deploy@example.com}
pro_server =  "user_name@ip-address"
role :app, pro_server
role :web, pro_server
role :db,  pro_server


 set :ssh_options, {
   forward_agent: false,
   keys: %w(~/.ssh/id_rsa),
   auth_methods: %w(publickey)
 }