それでも気分は高専生

元高専生が自分のやってきたことを記事として残すためのてきとーなブログ

Nginxを使ったRailsAppとJenkinsの同棲計画

雑記

おおよそ1年半ぶりの投稿になりますが…… 今回からは色々と挑戦してみたことの技術的備忘録として活用していく予定. (但し予定≒未定)

今回はdeployしたRailsAppとJenkinsを同一server上に置いてやろうぜ!ということをやってみました. ちなみに背景としては

  1. RailsApp作ってdeployする必要が生じる
  2. 自宅サーバ置いたら(物理的に)炎上
  3. cloud借りるか (Microsoft Azureの無料試用期間でVM使うことに)
  4. どうせならJenkinsでCIやりてぇ
  5. cloud/VPS高い, 複数借りるのなんてムリィ!
  6. RailsAppとJenkins共存させよ

目指す構成

目指している構成はこんな感じ. Nginxをreverse proxy serverとして, request URLのprefixで判断し, RailsAppとJenkinsに振り分ける. f:id:takahiro0914:20160625223337p:plain 理由としては

  • 可搬性を考えて(試用期間終わったらどっか他の安いところに移設予定)全部Docker containerにぶち込みたい
  • Docker contianer使うならOSはDocker導入が一番楽な(というかdefaultで入ってる)CoreOS使おう
  • VPSやCloudのお引越しの度にport設定をし直すの面倒臭い
    • Dockerのport forwardingで複数のportを使わない
    • 代わりにDocker container内のNginxをプロキシにしてsub directoryでRailsAppとJenkinsを使いわける

早速構成していく

  1. Core OSにssh login transmission !
  2. DockerHubからUbuntuのimageをpull
  3. Dockerでport forwarding(hostの80番とguestの80番を直結), でもってdive!
docker run -d -it -p 80:80 --name hoge ubuntu /bin/bash
docker -it exec hoge /bin/bash
  1. NginxとJenkinsはapt-getなんかを使ってうまいこと入れる (googleれば幾らでも出てくるさ)
  2. Rails環境もうまいこと入れる (僕の場合はrbenv使ってruby 2.2.0-devとRails5.0.0rcを導入)
  3. rails newする (ここではRailsAppのdirectoryを/var/app/rails_appとする)

RailsAppとJenkinsをNginxに繋げる

ここでの説明はcurrent directoryを/var/app/rails_appであることを前提として進める.

./config/puma.rbに以下を追記するぅ!

_proj_path = "#{File.expand_path("../..", __FILE__)}"  # RailsAppの絶対path
_proj_name = File.basename(_proj_path)  # RailsAppのおなまえ

pidfile "/var/run/#{_proj_name}.pid"  # Puma serverが動作しているprocess idを/var/run/rails_app.pidにぶち込むよう指定 (Puma serverはdaemonとして動作させた際に止めたい時, こいつが必要)
bind "unix:///var/run/#{_proj_name}.sock"  # Puma serverは/var/run/rails_app.sockからHTTP requestを頂く
directory _proj_path  # working directoryをRailsAppのpathに

/etc/nginx/conf.d/rails_app.conf(/etc/nginx/conf.d/*.confを読むようになっているので, 名前は多分なんでも可)を作成して以下を追記 (serverのIP addressはx.x.x.xを想定)

error_log /var/log/nginx/error.log warn;

upstream rails_app {
    server unix:/var/run/rails_app.sock fail_timeout=0; # /var/run/rails_app.sock を介してPumaとやりとりするよ
}

server {
    listen 80;  # port80で受け付けるよ
    server_name x.x.x.x;  # x.x.x.xでrequest来たら対応するよ

    error_page 500 502 503 504 /500.html
    client_max_body_size 4G;
    keepalive_timeout 10;

    include /etc/nginx/mime.types;
    try_files $uri/index.html $uri @rails_app

    location /rails_app/ {  # URLがhttp://x.x.x.x/rails_app/...だった場合
        root /var/app/rails_app/public;  # web pageなんかはpublicにぶち込まれるよ
        proxy_pass http://rails_app;  #  Pumaに横流しするよ
        proxy_set_header X-Forwarded-For $proxy_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header off;
    }
    location /jenkins/ {  # URLがhttp://x.x.x.x/jenkins/...だった場合
        proxy_pass http://127.0.0.1:8080;  # localhost:8080 (jenkisがわさわさしてるport) にぶん投げるよ
    }
}

ちなみにNginxの設定ファイルが「本来書いてはいけない場所に書いていないか」「文法的に間違っていないか」を確認するには以下を実行するとチェックできる.

nginx -t

次に /etc/default/jenkinsを以下のように変更

# JENKINS_ARGS = "hoge" を以下に変更 (Jenkinsのroot pathをx.x.x/jenkins/に変更)
JENKINS_ARGS = "hoge --prefix=/jenkins"

RailsAppのroutingにprefixを追加 (以下の内容を./config/routes.rbを以下のように変更)

Rails.application.routes.draw do
  # 全部のrouting pathの先頭に/rails_appを装着
  scope '/rails_app' do
    # All routing descriptions
  end
end

このままではJSや画像ファイルなどのassets以下が機能しなくなるので./config/public/environments/development.rb, ./config/public/environments/test.rb, ./config/public/environments/production.rbのRails.application.configure内に以下を追記

config.assets.prefix = '/rails_app/assets'

以下NginxとPuma, JenkinsをContainer起動時に自動で動作するよう設定 (Ubuntuだとchkconfがないっぽいのでsysv-rc-confで代用)

sysv-rc-conf nginx on
sysv-rc-conf puma on
sysv-rc-conf jenkins on

とするとどうもダメみたいですww バカ正直にcontainer侵入後に以下を実行.

cd /var/app/rails_app
bundle exec puma -d
# Pumaを停止させる場合は bundle exec pumactl -P /var/run/rails_app stop
service jenkins start
service nginx start

ちなみに今回はsocket通信を行うWebAppの開発ではないので, Action Cableの設定に関しては考慮していない.

以上, だいたいこんな感じでやってました. 何か不備, 間違いなどがありましたらどんどん指摘してください.

Tips

socket fileが仕事しているかを見るにはcurl --no-buffer -XGET --unix-socket /var/run/rails_app.sock http:/events でsocket fileを叩ける

参考サイト