Ruby
Git

ServerMan@VPSにgitlabをインストールする

More than 5 years have passed since last update.

なぜgitlabか?

有償ウェブサービス開発を前提として、クローズなリポジトリをチームで共有したい場合いくつか選択できる方法がある。
自分でシステムを管理できると、人に作業を委任することができるので必須だ。

判断のポイント
・CIサーバーと連携ができること
・有償のサービスを開発するためクローズなリポジトリであること
・リポジトリがチーム共有できること
・システム管理を自分でできること

結局マッチしたのはgitlabだったので採用することにした。

検討した方法

個人的な主観で作ったメリデメ表。
全部英語なので、チームメンバーに誘える人は最低でも英語を読めるひとだな。

git管理ツール メリット デメリット
github 有料サービスなので安心できる
使い方を知っている
月額課金
英語
安いプランではリポジトリをチームで共有ができない
bitbucket 無料でプライベートリポジトリが使える 自分でサービスを管理できない
英語
アカウントを登録する必要がある
使い方を知らない
gitlab プライベートリポジトリが管理できる
チームでプライベートリポジトリを共有できる
gitlabciと連携ができる
ウェブ上で管理できる
OSSなのでサポートなし
英語
インストール作業
運用が必要
使い方を知らない
gitolite シンプル 英語
インストール作業
CLIでの運用が必要

gitlabのインストール手順

この内容を読むひとへ、多分時が経ったらこの手順では動かないこともあると思うので、あくまで参考として使ってください。

サーバーの環境

VPS:ServerMan@VPS Entry
メモリー:512M〜1.2G
OS:debian 64bit

前提条件

ServerMan@VPSにRedmineをインストールするの環境が設定されていること
・管理用ユーザーで実行すること
・独自ドメインを取っていること

sudoの設定

前回のRedmineインストールの時はsu -でrootになって作業していたので、ちょっとだけセキュアにするために作業ユーザーにsudoの実行権を設定する

$ su -でrootになって、# visudoでwheelグループには全コマンドの実行権限を設定する。

初期構成ではwheelグループが登録されていないので登録し、管理用ユーザーにグループを追加する。

# groupadd -g 1000 wheel
# usermod -a -G wheel user
# visudo
%wheel ALL=(ALL) ALL

依存パッケージのインストール

ここからは、管理用ユーザーuserで作業する。
前回の作業でインストールでされてるかもしれないが、以下の依存パッケージをインストールする。
aptitudeは本当にパッケージを奇麗にマネージメントしてくれるので助かる。

$ sudo apt-get install -y build-essential \
zlib1g-dev libyaml-dev libssl-dev \
libgdbm-dev libreadline-dev libncurses5-dev \
libffi-dev curl git-core openssh-server \
redis-server postfix checkinstall \
libxml2-dev libxslt-dev libcurl4-openssl-dev \
libicu-dev

Pythonのバージョンを確認してっと、Python2系なので大丈夫はずなんだけどインストールした後にgitlabのチェックでpythonだけエラー扱いになる。
追記 GitLabはpython2を使うみたい。debianだとそんなのないからエラーになっていた。
python2のシンボリックリンクを貼ってやると動くようになった。

$ python --version
Python 2.6.6
$ sudo ln -s /usr/bin/python /usr/bin/python2

ユーザーの作成

GitlabはGitoliteをラップしたウェブアプリらしい、なんでgitoliteをインストールしたあと、gitlabをインストールするという手順になる。
参考サイトがあまりにも秀逸でほとんど直す事なかったので、主観だけを追記するくらいしかない。
ただ、本来なら/srv下にインストールしたかったけど初めてだったから一通り参考サイトどおりの手順で構築した。

Gitolite用のユーザー作成

$ sudo adduser \  
--system \  
--shell /bin/sh \  
--gecos 'Git Version Control' \  
--group \  
--disabled-password \  
--home /home/git \  
git

GitLab用のユーザー作成

$ sudo adduser --disabled-login --gecos 'GitLab' gitlab

gitグループに追加
$ sudo usermod -a -G git gitlab

SSHの鍵を作成
$ sudo -u gitlab -H ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa

Gitoliteのインストール

最新のGitoliteをクローンする。gitoliteはバージョン変わってもあまり使い方は変わらんとおもう。
バージョン:3.2

$ cd /home/git  
$ sudo -u git -H git clone -b gl-v320 https://github.com/gitlabhq/gitolite.git /home/git/gitolite  

gitユーザーの/home/git/bin/home/git/.profileexportを追記してパスを通して、Gitoliteのスクリプトが使えるようにする。

$ sudo -u git -H mkdir /home/git/bin  
$ sudo -u git -H sh -c 'printf "%b\n%b\n" "PATH=\$PATH:/home/git/bin" "export PATH" >> /home/git/.profile'  
$ sudo -u git -H sh -c 'gitolite/install -ln /home/git/bin'  

gitlabユーザーのSSHの公開鍵をコピーして、それを使ってgitlabがGitoliteの管理者になるように設定する。

$ sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub  
$ sudo chmod 0444 /home/git/gitlab.pub  
$ sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gitolite setup -pk /home/git/gitlab.pub"

パーミッションと所有権を修正する。

$ sudo chmod 750 /home/git/.gitolite/  
$ sudo chown -R git:git /home/git/.gitolite/  
$ sudo chmod -R ug+rwXs,o-rwx /home/git/repositories/  
$ sudo chown -R git:git /home/git/repositories/  

gitlabユーザーのknown_hostsにサーバーを登録するため、一度SSHで接続する。

$ sudo -u gitlab -H ssh git@localhost  
$ sudo -u gitlab -H ssh git@YOUR_DOMAIN_NAME  
$ sudo -u gitlab -H ssh git@YOUR_GITOLITE_DOMAIN_NAME  

gitlabユーザーでGitoliteに接続できることを確認する。

$ sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin  
$ sudo rm -rf /tmp/gitolite-admin  

Databaseのセットアップ

前回でMysqlはインストールしてるので、ここではDBの作成とユーザー追加だけ。

$ mysql -u root -p

GitLab用のユーザー/production DBを作成し、権限を変更しとく。

mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password';  
mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;  
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON `gitlabhq_production`.* TO 'gitlab'@'localhost';  
mysql> \q  

gitlabユーザーでGitLabのproduction DBに接続できるか確認する

$ sudo -u gitlab -H mysql -u gitlab -p -D gitlabhq_production

GitLabのインストール

gitlabユーザーのホームディレクトリで作業する。

$ cd /home/gitlab

GitLabのソースをクローンして4-1-stableをチェックアウトする。
なんか、もう4-2-stableがでてるらしい。
超早いな〜、Pragmatic Programmerだ。

$ sudo -u gitlab -H git clone https://github.com/gitlabhq/gitlabhq.git gitlab  
$ cd /home/gitlab/gitlab  
$ sudo -u gitlab -H git checkout 4-1-stable

GitLabの設定ファイルを作成する。

$ sudo -u gitlab -H cp config/gitlab.yml.example config/gitlab.yml  
$ sudo -u gitlab -H vi config/gitlab.yml

まだ、メールサーバーをインストールしてないけど、設定しておく。
・サーバーのhost名を変更する
・mailの送信アドレスを変更する
・サポートメールアドレスをコメントアウト

- host: localhost
+ host: yourdomain.com
- email_from: gitlab@localhost
+ email_from: gitlab@yourdomain.com
- support_email: support@localhost
+ #support_email: support@localhost

Gitoliteの設定を変更する

ServerMan@VPSではSSHのPortを変更されているので、そのPortを指定する。

- admin_uri: git@localhost:gitolite-admin
+ admin_uri: ssh://git@localhost:<port>/gitolite-admin
- # ssh_port: 22
+ ssh_port: <port>

gitlabユーザーが書き込み可能なようにlog/とtmp/ディレクトリのパーミッションを変更する。

$ sudo chown -R gitlab log/  
$ sudo chown -R gitlab tmp/  
$ sudo chmod -R u+rwX  log/  
$ sudo chmod -R u+rwX  tmp/  

satellitesディレクトリを作成する。

$ sudo -u gitlab -H mkdir /home/gitlab/gitlab-satellites

Unicornの設定ファイルをコピーする。これはまんまデフォなのだけど、一応記載しておく。
$ sudo -u gitlab -H cp config/unicorn.rb.example config/unicorn.rb

/home/gitlab/config/unicorn.rb
# uncomment and customize to run in non-root path
# note that config/gitlab.yml web path should also be changed
# ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab"

app_dir = "/home/gitlab/gitlab/"
worker_processes 1
working_directory app_dir

# Load app into the master before forking workers for super-fast
# worker spawn times
preload_app true

# nuke workers after 30 seconds (60 is the default)
timeout 300

# listen on a Unix domain socket and/or a TCP port,

#listen 8080 # listen to port 8080 on all TCP interfaces
#listen "127.0.0.1:8080"  # listen to port 8080 on the loopback interface
listen "#{app_dir}/tmp/sockets/gitlab.socket"

pid "#{app_dir}/tmp/pids/unicorn.pid"
stderr_path "#{app_dir}/log/unicorn.stderr.log"
stdout_path "#{app_dir}/log/unicorn.stdout.log"

# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
if GC.respond_to?(:copy_on_write_friendly=)
  GC.copy_on_write_friendly = true
end


before_fork do |server, worker|
  # the following is highly recomended for Rails + "preload_app true"
  # as there's no need for the master process to hold a connection
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

  ##
  # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
  # immediately start loading up a new version of itself (loaded with a new
  # version of our app). When this new Unicorn is completely loaded
  # it will begin spawning workers. The first worker spawned will check to
  # see if an .oldbin pidfile exists. If so, this means we've just booted up
  # a new Unicorn and need to tell the old one that it can now die. To do so
  # we send it a QUIT.
  #
  # Using this method we get 0 downtime deploys.

  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
      # someone else did our job for us
    end
  end
end

after_fork do |server, worker|
  # Unicorn master loads the app then forks off workers - because of the way
  # Unix forking works, we need to make sure we aren't using any of the parent's
  # sockets, e.g. db connection

  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
  # Redis and Memcached would go here but their connections are established
  # on demand, so the master never opens a socket
end

GitLabのDBの設定ファイルを作成する。

$ sudo -u gitlab -H cp config/database.yml.mysql config/database.yml  
$ sudo -u gitlab -H vi config/database.yml  

productionのusernameとpasswordを変更する

- username: root
- password: "secure password"
+ username: gitlab
+ password: "「Databaseのセットアップ」で設定したパスワード"

GitLabの依存Gemをインストールする。

$ sudo gem install charlock_holmes --version '0.6.9'  
$ sudo -u gitlab -H bundle install --deployment --without development test postgres

gitlabユーザーのgitのglobal設定を行う

$ sudo -u gitlab -H git config --global user.name "GitLab"  
$ sudo -u gitlab -H git config --global user.email "gitlab@your.domain.name" 

GitLabのHookスクリプトをセットアップする。

$ sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive  
$ sudo chown git:git /home/git/.gitolite/hooks/common/post-receive

セットアップ

$ sudo -u gitlab -H bundle exec rake gitlab:setup RAILS_ENV=production
※AdministratorのログインIDとパスワードが表示されるのでメモっておく

login........admin@local.host  
password.....5iveL!fe  

起動スクリプトを作成する
そのまんまで全く問題なく動く。

$ sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab  
$ sudo chmod +x /etc/init.d/gitlab  
$ sudo update-rc.d gitlab defaults 21  

ここまでの設定がうまくできているか確認する

$ sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production

※以下を実行することで詳細な検証が可能

$ sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production

GitLabを開始する
$ sudo service gitlab start
もしくは
$ sudo /etc/init.d/gitlab restart

Nginxのセットアップ

サイトの設定ファイルを作成する

$ sudo curl --output /etc/nginx/sites-available/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab  
$ sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab  

$ sudo vi /etc/nginx/sites-enabled/gitlab

nginxでRedmineとgitlabを共存するので、IPは指定しないことにした。
サーバー名をサブドメインで設定した。DNSの話はまたいつか?
サブドメイン:gitlab.yourdomain.com

- listen YOUR_SERVER_IP:80 default_server;
+ listen 80 default_server;
- server_name YOUR_SERVER_FQDN;
+ server_name gitlab.yourdomain.com;
# GITLAB
# Maintainer: @randx
# App Version: 4.0

upstream gitlab {
  server unix:/home/gitlab/gitlab/tmp/sockets/gitlab.socket;
}

server {
  listen 80;         # e.g., listen 192.168.1.1:80;
  server_name gitlab.yourdomain.com;     # e.g., server_name source.example.com;

  # individual nginx logs for this gitlab vhost
  access_log  /var/log/nginx/gitlab.access.log;
  error_log   /var/log/nginx/gitlab.error.log;

  location / {
    root /home/gitlab/gitlab/public;
    # serve static files from defined root folder;.
    # @gitlab is a named location for the upstream fallback, see below
    try_files $uri $uri/index.html $uri.html @gitlab;
  }

  # if a file, which is not found in the root folder is requested,
  # then the proxy pass the request to the upsteam (gitlab unicorn)
  location @gitlab {
    proxy_read_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694
    proxy_connect_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694
    proxy_redirect     off;

    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_set_header   Host              $http_host;
    proxy_set_header   X-Real-IP         $remote_addr;

    proxy_pass http://gitlab;
  }
}

nginxを再起動する

$ sudo /etc/init.d/nginx restart

動作確認

ブラウザでアクセスしてみて表示されることを確認する。
初期Adminのユーザー名/パスワードは共通なので、パスワードを変更して終了。

参考
https://gist.github.com/ryosms/4632650

まとめ

今回はインストールとかセットアップ自体はあんま考えなくも、参考サイトが強力すぎてまんまで構築できたので拍子抜けた。
ただし、nginxのバーチャルホストで一番はまった。
Railsのアプリをnginxで共有するとunicornがバカバカとリソースを食いまくりメモリが足りなくてアプリが上がんなかったりとか。
もういいよってくらい 502 Bad Gateway ばっかりだった。
結局、redmineとgitlabのworker_processes 1にしてなんとか動いてる。
Redmineとgitlabの操作感はめっさ早い。
ひとりアジャイルなら全然いけんじゃね?という感じ、チーム開発するようになってもたつき始めたらスペックあげるかな。
まあ、512MのメモリーでRailsアプリを2本動かすのもチャレンジャーなんだけど。

ただ、今後はここ変えれば思い通りってことのポイントは十分すぎるほど頂けたので感謝する。

おまけ

今回もログローテーションを設定した。

/etc/logrotate.d/gitlab 
/home/gitlab/gitlab/log/*.log {
    daily
    missingok
    rotate 20
    compress
    delaycompress
    notifempty
    copytruncate 
    create 0640 gitlab gitlab   
    dateext
}

次回予告

ServerMan@VPSにpostfixをインストールする