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

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

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

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

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

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


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

##サーバーの環境
VPS：ServerMan@VPS　Entry
メモリー：512M〜1.2G
OS：debian 64bit

##前提条件
・[ServerMan@VPSにRedmineをインストールする](http://qiita.com/items/5a9fea281469d70b57cd "ServerMan@VPSにRedmineをインストールする")の環境が設定されていること
・管理用ユーザーで実行すること
・独自ドメインを取っていること

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

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

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

```
# groupadd -g 1000 wheel
# usermod -a -G wheel user
# visudo
```

```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/.profile`に`export`を追記してパスを通して、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の送信アドレスを変更する
・サポートメールアドレスをコメントアウト

```diff
- 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を指定する。

```diff
- 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を変更する

```diff
- 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

```diff
- listen YOUR_SERVER_IP:80 default_server;
+ listen 80 default_server;
- server_name YOUR_SERVER_FQDN;
+ server_name gitlab.yourdomain.com;
```

```/etc/nginx/sites-available/gitlab 
# 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アプリを２本動かすのもチャレンジャーなんだけど。

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

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

```
/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をインストールする