LoginSignup
4
5

More than 5 years have passed since last update.

privateなgemサーバー構築のお話

Last updated at Posted at 2017-04-08

目的

privateなgemサーバーを構築したい。
geminaboxやgemirroがよく使われているらしい。

ここではgeminaboxを使う。

構築環境

  • CentOS 7.2(vagrant bento)
  • geminabox
  • puma
  • nginx(yum package)

設置手順

rubyが設置されてない場合はyumやrbenvで設置する。この説明は割愛する。

bundlerの設置

gem install bundler

アプリケーションのディレクトリを生成する。

mkdir gembox
cd gembox
bundle init

アプリケーションサーバーとしてpumaを使う。
bundle initで生成されたGemfileを下記のように編集する。

# frozen_string_literal: true
source "https://rubygems.org"

# gem "rails"
gem "geminabox"
gem "puma"

別にglobalのruby環境やsystemのruby環境で設置しても構わない。
共通的なものだけglobalのruby環境に設置するのが自己ルールであるだけだ。

bundle install --path vendor/bundle

config.ruを生成する。

require "rubygems"
require "geminabox"

Geminabox.data = "./data" # ... or wherever
run Geminabox::Server

data、config、tmpディレクトリを生成する。
dataはgemファイルの保管箱である。
unixソケットを使うので、socketsディレクトリも作ろう。

mkdir data
mkdir config
mkdir -p tmp/pids
mkdir tmp/sockets

puma.rbを生成する。

mkdir config
vi config/puma.rb

app_root = "#{File.expand_path("../..", __FILE__)}"
pidfile "#{app_root}/tmp/pids/puma.pid"
state_path "#{app_root}/tmp/pids/puma.state"
bind "unix://#{app_root}/tmp/sockets/puma.sock"
directory app_root
threads 5,5
workers 2
environment 'production'
daemonize true

daemon化したいと思い、daemonize trueにしたがこのせいでsystemdで動けなくなり、とても苦労した。
あとで説明する。今は必要なので、そのままおいて。

bundle execは面倒だからpumaコマンドは生成しておく。

bundle binstubs puma

binディレクトリが生成されpumaやpumactlコマンドが生成されているはずだ。

ここまでするとプロジェクトの中身はこうなる。

.
├── Gemfile
├── Gemfile.lock
├── bin
│   ├── puma
│   ├── pumactl
│   └── rackup
├── config
│   └── puma.rb
├── config.ru
├── data
├── tmp
│   ├── pids
│   └── sockets
└── vendor
    └── bundle

pumaの起動・終了

bin/pumactl -F config/puma.rb start
bin/pumactl -F config/puma.rb stop

nginxの設置
epelが設置されていない場合は先に設置する。
yumリポジトリを登録ではなくyumパッケージで設置する。

sudo yum install epel-release -y
sudo yum install nginx -y

nginx.confファイルを下記のように編集する。

sudo vi /etc/nginx/nginx.conf

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user vagrant;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80;
        listen       [::]:80;
        server_name  gembox;
        client_max_body_size 100M;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
    }
}

vagrantユーザでpumaが実行されるので、nginxのworkerプロセスもvagrantで実行される必要がある。
そうしないと502 Bad Gatewayエラーが発生する。
そのときのエラーログはこうだ。

cat /var/log/nginx/error.log

...
2017/04/07 01:43:53 [crit] 13203#0: *1 connect() to unix:/home/vagrant/gembox/tmp/sockets/puma.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.33.1, server: _, request: "GET / HTTP/1.1", upstream: "http://unix:/home/vagrant/gembox/tmp/sockets/puma.sock:/", host: "gembox"
...
  • serverの設定
    • include /etc/nginx/conf.d/gembox_server.conf
upstream gembox {
  server unix:/home/vagrant/gembox/tmp/sockets/puma.sock;
}
  • locationの設定
    • include /etc/nginx/default.d/gembox_server.conf
location / {
  proxy_pass http://gembox;
  proxy_set_header Host $http_host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

nginxの起動・終了・状態・リロード

sudo systemctl start nginx.service
sudo systemctl stop nginx.service
sudo systemctl status nginx.service
sudo systemctl reload nginx.service

おまけにsystemdについて

ここまでするとちゃんとgeminaboxのページが表示されるはずだが、もし表示されなかった場合は80ポートLISTENされているのか、確認する。
firewalld含めて確認する必要がある。

geminaboxページが表示されたら、gemファイルを1個選んでアップロードしてみよう。
必ずアップロードするんだ。アップロードするとgem保管箱の仕組みが作られるみたい。
空いていたdataディレクトリにファイルやディレクトリが生成される。

data
├── _cache
├── _temp
├── gems
├── latest_specs.4.8
├── latest_specs.4.8.gz
├── prerelease_specs.4.8
├── prerelease_specs.4.8.gz
├── quick
├── specs.4.8
└── specs.4.8.gz

gemファイル1個だけアップロードする場合はこれでも悪くないが、複数のgemをアップロードするにはコマンドが便利。

mac(ホスト) - vagrant(ゲスト、geminaboxサーバー)

vi /private/etc/hosts
192.168.33.10 gembox

ホストからゲストへ複数のgemファイルをアップロードしてみよう。

gem inabox *.gem -g http://gembox

500エラーが発生した。

Pushing yard-0.9.8.gem to http://gembox/...
ERROR:  Error (500 received)

<html>
<head><title>500 Internal Server Error</title></head>
<body bgcolor="white">
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.10.2</center>
</body>
</html>

nginxのworkerプロセスはvagrantなので、「/var/lib/nginx」をownerがvagrantではないとgemファイルのアップロードができない。
そのときのエラーログはこうだ。

2017/04/07 10:58:21 [crit] 4488#0: *15 open() "/var/lib/nginx/tmp/client_body/0000000001" failed (13: Permission denied), client: 192.168.33.1, server: gembox, request: "POST /upload HTTP/1.1", host: "gembox"

ownerをvagrantに変更する。(vagrant、ゲスト側)

sudo chown -R vagrant /var/lib/nginx

もう一度やってみる。
アップロードファイルのサイズが大きい場合はエラーが発生する。

Pushing nokogiri-1.7.0.1.gem to http://gembox/...
ERROR:  Error (413 received)

<html>
<head><title>413 Request Entity Too Large</title></head>
<body bgcolor="white">
<center><h1>413 Request Entity Too Large</h1></center>
<hr><center>nginx/1.10.2</center>
</body>
</html>

そのときのエラーログはこうだ。(vagrant、ゲスト側)

2017/04/07 11:50:52 [error] 4488#0: *70 client intended to send too large body: 9148319 bytes, client: 192.168.33.1, server: gembox, request: "POST /upload HTTP/1.1", host: "gembox"

このようなときは、nginx.confファイルの中でclient_max_body_sizeを適当に大きいサイズで変更しよう。

もう一度やってみる。
アップロードしたgemファイルが表示されるはずだ。

http://gembox

これでおわり!
ではない。

pumaをsystemdのサービスに登録して使う。

sudo vi /etc/systemd/system/puma.service

[Unit]
Description=Puma HTTP Server
After=network.target

[Service]
Type=simple
User=vagrant
Group=vagrant
PIDFile=/home/vagrant/gembox/tmp/pids/puma.pid
WorkingDirectory=/home/vagrant/gembox
ExecStart=/usr/bin/bash -lc 'bin/pumactl -F config/puma.rb start'
ExecReload=/bin/kill -s USR1 $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
TimeoutSec=300
Restart=always

[Install]
WantedBy=multi-user.target

systemdの詳細は割愛する。
Software Design 2015年2月号のLinux systemd入門を参考

おまけにpuma関連signal

ExecStartがサービスをstartするとき実行されるコマンドだが、「/usr/bin/bash -lc 'puma起動コマンド'」で実行しないといけない。
そうしないとvagrantではないrootユーザーのログインシェルで実行される。

puma.rbファイルからdaemonize trueの設定を消す!
systemdのサービスがdaemon化してくれることだから要らないし、むしろこれのせいでサービスがずっとfailedになってしまう。

おしまい。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5