Gitlab CI でカバレッジレポートを公開するメモ

Jenkins で PHPUnit 実行時に出力したカバレッジレポートを Jenkins 上で閲覧できるようにしているのですが、同じことを Gitlab CI でやるときのメモ。

Jenkins の場合

Jenkins なら HTML Publisher plugin でサクッと PHPUnit のカバレッジレポートを公開できます。

ビルドで↓のようにカバレッジレポートを HTML で出力して、

vendor/bin/phpunit --coverage-html=coverage/
# or
phpdbg -qrr vendor/phpunit/phpunit/phpunit --coverage-html=coverage/

ビルド後のアクションで↓みたいに公開するディレクトリを指定すれば OK です。

// jenkins dsl

job('test') {
    :
    publishers {
        publishHtml {
            report('coverage') {
                reportName('Coverage')
                reportFiles('index.html')
            }
        }
    }
}

Gitlab CI の場合

Gitlab CI で同じことをやるときは PHPUnit で出力したカバレッジレポートを Gitlab Pages で公開すると良いらしいです、下記によると。

下記のようなビルド設定でカバレッジレポートを Gitlab Pages で公開できます。

# .gitlab-ci.yml

before_script:
  - curl -fsSL https://getcomposer.org/download/1.4.2/composer.phar > composer.phar

phpunit:
  stage: test
  image: php:alpine
  script:
    - php composer.phar install --prefer-dist --no-progress --ansi --dev
    - phpdbg -qrr vendor/phpunit/phpunit/phpunit --coverage-html coverage/
  tags:
    - docker
  cache:
    paths:
      - vendor/
  # coverage/ ディレクトリを artifact として保存する
  artifacts:
    paths:
      - coverage/
    expire_in: 1 days

# Gitlab Pages のためのジョブ(pages という名前でなければならない)
pages:
  stage: deploy
  # phpunit ジョブの artifact を展開する
  dependencies:
    - phpunit
  # Pages で公開するファイルは public/ になければならない
  script:
    - mv coverage/ public/
  # artifact を移動させるだけならこうしとけば git clone/fetch や checkout されない
  variables:
    GIT_STRATEGY: none
  # Pages で公開するには artifact にしなければならない
  artifacts:
    paths:
      - public/
    expire_in: 1 days

Gitlab Pages のメモ

Gitlab Pages は要するに、pages というジョブのビルドの結果、 public というディレクトリが artifact として保存されれば、それが Gitlab Pages として公開される、です。GitHub Pages とはだいぶ感じが違います。

Gitlab Pages は最後にビルドされた結果しか公開されないので、ビルドごとのカバレッジレポートを閲覧したりはできなさそう。なのですべてのブランチでカバレッジレポートを保存するのではなく(Jenkins ではそうしてた)、master のときだけにしとくのが良さそう。トピックブランチのビルドで Gitlab Pages のカバレッジレポートが上書きされるのもどうかと思うので。

ただ、カバレッジレポートを artifact として保存しておけばダウンロードしてローカルで閲覧することはできるので、phpunit ジョブの artifact はそのままで、pages ジョブだけ特定ブランチに制限するのがよさそう。

ビルド履歴や成果物のメモ

artifact は有効期限を expire_in で指定しなければ無期限となるっぽい。expire_in を指定すると有効期限が切れると自動で削除されるが、ジョブの画面から Keep ボタンを押して有効期限をクリアする(無期限にする)こともできるっぽい。

成果物やビルドログはジョブの画面で Erase ボタンを押せば手動で消せる。artifact は上記の通り有効期限を付けて自動で消すこともできるけど、ビルドログは Erase ボタンで消さない限り消えなさそう。

Erase ボタンでもビルドログや成果物が消えるだけで、ビルドやパイプラインの履歴そのものは消せなさそう。一時的にパイプラインを無効→有効としても消えたりはしない。プロジェクトを削除すれば・・どうなるかは試していない。

Jenkins だとビルド履歴を世代数や日数で削除できるので、それができないことに違和感が無くもないけど、そもそもバージョン管理システムとはすべての履歴を残すためのものなんだから、ビルドの履歴が残るのもそういうものだと言われればそういうものな気もする。

強いて言えば試行錯誤した履歴まで残るのがちょっとかっこ悪い感じする。

アーティファクトのメモ

artifact、(この界隈では)日本語で成果物と訳されると思うけど、アーティファクトとカタカナで書くと、なんか、すごそう、すごい力を秘めてそうで違和感。

Gitlab CI を使ってみるメモ

Jenkins からの移行のために今更だけど使ってみたメモ。

なお、うちの Gitlab はソースから入れていてデータベースも MySQL です。たまにしかバージョンアップしていないのでちょっと古いです(8.17.2)。

参考

ざっくり

  • Gitlab 8.0 からは Gitlab に統合されている
  • Runner をどこかのサーバでセットアップする必要がある
    • shell とか docker とかでビルドが実行される環境
    • Gitlab と同じサーバじゃ無い方が良い
  • リポジトリルートに .gitlab-ci.yml を追加する
    • .gitlab-ci.yml は Runner に何をさせるかを記述する
  • どの Runner を使うかはプロジェクトごとに選択できる
    • タグ付けでさらに細かく制御できる

Runner とは

ビルドを実行するための環境。公式の実装として gitlab-ci-multi-runner があるけれども自前で実装することもできます、たぶん。

起動すると Gitlab に HTTP で常時接続して Gitlab からのビルドの通知を受け取ります。なので「Runner → Gitlab」の方向に HTTP で繋がるだけで良いです。

Runner には、特定のプロジェクトに固有のものと(Specific Runner)、すべてのプロジェクトで使用可能なものがあります(Shared Runner)。

Shared Runner は fair usage queue という方法でジョブをキューイングします。一方で Specific Runner は FIFO でキューイングされます。fair usage queue は、やたらたくさんビルドを要求するプロジェクトが原因で他のプロジェクトのビルドが滞るのを避けるためのアルゴリズムのようです。

Specific Runner は複数のプロジェクトで使いまわすこともできます。Shared Runner との違いはそれぞれのプロジェクトで個別に有効にする必要があるかどうかです。Shared Runner はデフォですべてのプロジェクトで有効になります。Specific Runner はプロジェクトの設定で選択しなければ有効になりません。Specific Runner は使い回しを禁止して特定のプロジェクトにロックすることもできます。

Shared Runner を登録するとき、普通は Runner に処理可能なジョブのタグを指定します。そうしないとすべてのジョブを実行しようとしてしまうので。もちろん Specific Runner でも特定の環境でだけ実行するジョブのためにタグを指定しても良い。

Shared Runner でジョブを実行する場合、同じ Runner で実行される他のプロジェクトのコードにアクセスできるので注意が必要。また、Runner のトークンが実行するコードで取得できるので、Runner のクローンを作成して誤ったジョブをサブミットできる??(Runner に間違ったビルドを支持できるということ? もしくは Runner を上書きできる? あるいは 任意の Runner が追加できてしまうということ?)

Runner のインストール

最新版だと今使ってる Gitlab とバージョンが合わなかったのでダウングレードします(最初からバージョン指定でインストールしても良い)。

curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh |
  sudo bash

sudo yum install gitlab-ci-multi-runner
sudo yum downgrade gitlab-ci-multi-runner-1.11.4

rpm -ql gitlab-ci-multi-runner
#=> /usr/bin/gitlab-ci-multi-runner
#=> /usr/bin/gitlab-runner
#=> /usr/share/gitlab-runner/clear-docker-cache
#=> /usr/share/gitlab-runner/post-install
#=> /usr/share/gitlab-runner/pre-remove

RPM に systemd のユニットファイルとかは含まれていませんが、インストール時に /usr/share/gitlab-runner/post-install で生成されているようなのですぐ開始できます(というかインストールした時点で開始されているっぽいですが)。

sudo systemctl start gitlab-runner.service
sudo systemctl status gitlab-runner.service
sudo systemctl enable gitlab-runner.service

Runner を Gitlab に登録

特定のプロジェクト用に Runner を登録してみる。

プロジェクトの CI/CD Pipelines を開いて Specific Runners のとこの URL とトークンをメモって、下記のコマンドで登録します。

sudo gitlab-runner register \
    --url http://gitlab.example.net/ci \
    --registration-token "$gitlab_ci_token" \
    --name ore-no-shell \
    --executor shell

Enter 連打で登録できる。Executor で shell を指定しているのでビルドはこのホスト上の gitlab-runner というユーザーを使ってそのままスクリプトが実行されます。

Docker の Runner も登録してみる。

sudo gitlab-runner register \
    --url http://gitlab.example.net/ci \
    --registration-token "$gitlab_ci_token" \
    --name ore-no-docker \
    --tag-list docker \
    --executor docker \
    --docker-image alpine:latest

タグを指定したのでこの Runner では docker というタグが付けられたジョブだけが実行されます。また、指定している Docker image は .gitlab-ci.yml で指定されなかったときのデフォルトになります。.gitlab-ci.yml で指定できるイメージのホワイトリストとかも指定できるようですね。

.gitlab-ci.yml

.gitlab-ci.yml をリポジトリルートに追加する。このファイルに Runner が何をするか記述します。

image: php:alpine

before_script:
  - uname -n
  - id
  - pwd
  - which php
  - php -v

job_shell:
  script:
    - echo "this is shell"

job_docker:
  script:
    - echo "this is docker"
  tags:
    - docker

before_script はすべてのジョブに先立って実行されます。job_shelljob_docker がジョブで任意の名前を付けることができる。ジョブの子要素には script が必須。

このファイルをリポジトリに追加してプッシュすると次のようにビルドが実行されます(見やすくするために少し編集)。

job_shell

Running with gitlab-ci-multi-runner 1.11.4 (7e2b646)
  on ore-no-shell (9b476e4f)
WARNING: image is not supported by selected executor and shell
Using Shell executor...
Running on ore.example.com...
Fetching changes...
HEAD is now at e20b44a .gitlab-ci.yml
From http://gitlab.example.net/ore/testing
   e20b44a..fc613e6  master     -> origin/master
Checking out fc613e6d as master...
Skipping Git submodules setup

$ uname -n
ore.example.com

$ id
uid=983(gitlab-runner) gid=981(gitlab-runner) groups=981(gitlab-runner)

$ pwd
/home/gitlab-runner/builds/9b476e4f/0/ore/testing

$ which php
/usr/bin/php

$ php -v
PHP 7.1.6 (cli) (built: Jun  7 2017 12:15:54) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.6, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans

$ echo "this is shell"
this is shell

Job succeeded

job_docker

Running with gitlab-ci-multi-runner 1.11.4 (7e2b646)
  on ore-no-docker (adea055c)
Using Docker executor with image php:alpine ...
Pulling docker image php:alpine ...
Running on runner-adea055c-project-42-concurrent-0 via ore.example.com...
Cloning repository...
Cloning into '/builds/ore/testing'...
Checking out fc613e6d as master...
Skipping Git submodules setup

$ uname -n
runner-adea055c-project-42-concurrent-0

$ id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

$ pwd
/builds/ore/testing

$ which php
/usr/local/bin/php

$ php -v
PHP 7.1.6 (cli) (built: Jun 28 2017 20:57:42) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

$ echo "this is docker"
this is docker

Job succeeded

CI Lint

Gitlab の Pipelines のページから CI Lint に移動できます。その画面で .gitlab-ci.yml の検証ができる。

Docker cache

Docker でジョブを実行するとき、composer install で毎回パッケージがダウンロードされたのではビルドが遅くなりすぎて辛いので、ビルドの終了時に一部のディレクトリをキャッシュして次回のビルドで使うようにできます。

.gitlab-ci.yml でキャッシュするディレクトリを指定します。

image: php:alpine

phpunit:
  script:
    - php composer.phar install --prefer-dist --no-progress --ansi --dev
  tags:
    - docker
  cache:
    paths:
      - vendor/

ビルドの終了時に指定していたディレクトリがアーカイブされて保存されます。次回の実行時はそのアーカイブが展開してからビルドが開始します。

ちなみにアーカイブは自動的に作成された Docker Volume に保存されています。docker volume ls で見れるアレです。

下記のように登録時に --docker-cache-dir を指定するとホストのディレクトリが使われるので Docker Volume がぼこぼこ作成されることはなくなります。

sudo gitlab-runner unregister \
    --url http://gitlab.example.net/ci \
    --name ore-no-docker

sudo gitlab-runner register \
    --url http://gitlab.example.net/ci \
    --registration-token "$gitlab_ci_token" \
    --name ore-no-docker \
    --tag-list docker \
    --executor docker \
    --docker-image alpine:latest \
    --docker-cache-dir "/srv/gitlab-runner/cache/"

特定の処理だけ実行する Runner を作る

gitlab-runner--pre-build-script でスクリプトを指定すると、この Runner に固有のビルド前の処理が実行できます。

さらに、指定したスクリプトはビルドのジョブの script と繋げられて1つのスクリプトとして実行されるので、次のように exec とかしてやるとジョブの script が実行されずにジョブが終了します。

sudo gitlab-runner register \
    --url http://gitlab.example.net/ci \
    --registration-token "$gitlab_ci_token" \
    --name ore-no-task \
    --tag-list ore-no-task \
    --executor shell \
    --builds-dir /srv/gitlab-runner/builds \
    --pre-build-script 'exec /opt/gitlab-runner/pre-build-script.sh'

sudo mkdir -p /opt/gitlab-runner/

cat <<'EOS'| sudo tee /opt/gitlab-runner/pre-build-script.sh
#!/bin/bash
set -x
id
pwd
echo "CI_PROJECT_PATH=$CI_PROJECT_PATH"
git show -s
EOS

sudo chmod +x /opt/gitlab-runner/pre-build-script.sh

こんな感じに実行されます。.gitlab-ci.ymlscript に何を書いていてもここで止まります。

Running with gitlab-ci-multi-runner 1.10.8 (2c34bd0)
Using Shell executor...
Running on ore.example.com...
Fetching changes...
HEAD is now at e20b44a .gitlab-ci.yml
Checking out e20b44a6 as master...
Skipping Git submodules setup

$ exec /opt/gitlab-runner/pre-build-script.sh

+ id
uid=983(gitlab-runner) gid=981(gitlab-runner) groups=981(gitlab-runner)

+ pwd
/srv/gitlab-runner/builds/ce74c254/0/ore/testing

+ echo CI_PROJECT_PATH=ore/testing
CI_PROJECT_PATH=ore/testing

+ git show -s
commit e20b44a678298d9280ce0f6e90128512c078a955
Author: ore <ore@example.com>
Date:   Fri Jun 30 12:22:44 2017 +0900

    .gitlab-ci.yml

Build succeeded

複数のプロジェクトで横断的に特定のホストである決まった処理を実行するために使えそうです。

Jenkins を置き換える

今は Jenkins で下記のような感じで CI/CD してます。

  • 開発環境を Jenkins Slave としてセットアップ
    • 世間ではステージングと呼ばれるかも
  • リポジトリにプッシュされたらテストを実行
    • composer install とか
    • migration とか
    • phpunit とか
    • php-cs-fixer とか
    • phan とかもやりたい
  • master ブランチでテストが通れば開発環境の公開ディレクトリへデプロイ
    • Jenkins のワーキングディレクトリを公開ディレクトリに指定してる
    • ので Jenkins がファイルを撒くまでやってくれる(チェックアウトするだけ)
    • マイグレーションとかサービスのリスタートとかだけ後処理でやってる
  • さらに master ブランチを Redmine にチェックアウトして fetch changesets で反映
    • Redmine も Jenkins Slave として登録している
    • トピックブランチは Redmine に反映したくない

これらを Jenkins の WebUI で設定するのは流石にしんどいので Jenkins DSL で設定しているのですが・・それはそれでツラミあります。あと、現状のビルドの一部を並列化して両方終わったらデプロイを実行、とかが Jenkins DSL だとかなりつらいです。Jenkins Pipeline で多少マシになっているっぽいですが。。。

Gitlab CI ならこんな感じでできそう(phan はそれっぽい Docker Image を作った)。

before_script:
  - curl -fsSL https://getcomposer.org/download/1.4.2/composer.phar > composer.phar

phan:
  image: ngyuki/php-phan
  script:
    - php composer.phar install --prefer-dist --no-progress --ansi --no-dev
    - phan --version
    - phan -l src/ -l vendor/ -3 vendor/
  tags:
    - docker
  cache:
    paths:
      - vendor/

cs-fixer:
  image: php:alpine
  script:
    - php composer.phar install --prefer-dist --no-progress --ansi --dev
    - vendor/bin/php-cs-fixer fix --dry-run --diff --ansi -vvv -- src/
  tags:
    - docker
  cache:
    key: vendor
    paths:
      - vendor/

phpunit:
  image: php:alpine
  script:
    - php composer.phar install --prefer-dist --no-progress --ansi --dev
    - vendor/bin/phpunit
  tags:
    - docker
  cache:
    key: vendor
    paths:
      - vendor/

deploy:
  stage: deploy
  script:
    - php composer.phar install --prefer-dist --no-progress --ansi --no-dev --optimize-autoloader
    - ln -sfn -- "$PWD" /opt/myapp/current
  only:
    - master
  tags:
    - dev

redmine:
  stage: deploy
  script: |
    set -eu
    mkdir -p -- "/srv/gitlab-runner/repos/${CI_PROJECT_PATH%/*}"
    ln -sfn -- "$PWD/.git" "/srv/gitlab-runner/repos/${CI_PROJECT_PATH}"
    git branch --force -- "$CI_BUILD_REF_NAME" "$CI_BUILD_REF"
    git symbolic-ref HEAD "refs/heads/$CI_BUILD_REF_NAME"
    curl -kfs "https://redmine.example.net/sys/fetch_changesets?id=ore"
  only:
    - master
  tags:
    - redmine

最後の redmine のジョブは gitlab-runner--pre-build-script を使って Shared Runner でやると良さそう。

特定のユーザーで Runner を実行する

Runner がどのユーザーで実行されるかは gitlab-runner run の引数で決まるのだけど、これは systemd のユニットファイルで指定されている。

cat /etc/systemd/system/gitlab-runner.service  | grep ExecStart
#=> ExecStart=/usr/bin/gitlab-ci-multi-runner "run" ... "--user" "gitlab-runner"

このファイルは gitlab-runner install で生成されるので、下記のようにすれば別のユーザーで実行させることができる。

gitlab-runner uninstall
gitlab-runner install -d /tmp -u ore
systemctl restart gitlab-runner

なお gitlab-runner register で登録する Runner ごとには変更できないっぽい。

CentOS で GitLab を 5.3 から 6.1 にバージョンアップ

CentOS で GitLab を 5.3 から 6.1 にバージョンアップしたのでそのときの手順を残しておきます。

参考

はじめに

すべての作業は git アカウントで行います。root が必要な作業は sudo しています。基本的に参考URLの手順通りです。

5.3 から 6.1 に一気にバージョンアップしようかとも思ったのですが、6.0 から 6.1 のバージョンアップ手順 に「6.1 の前に 6.0 にしておくべし」とあったので、面倒ですが順番にバージョンアップしました。

おそらく、5.4 は飛ばしたり、gitlab-shell は 5.3 から 6.1 まで一気にバージョンアップしても大丈夫だと思いますが、失敗すると面倒なので1つ1つ順番にやりました。

Backup

$ cd /home/git/gitlab
$ RAILS_ENV=production bundle exec rake gitlab:backup:create

Stop server

$ sudo service gitlab stop

From 5.3 to 5.4

Get latest code(5.4)

$ cd /home/git/gitlab
$ git fetch
$ git checkout 5-4-stable

Update gitlab-shell

$ cd /home/git/gitlab-shell
$ git fetch
$ git checkout v1.5.0

Install libs, migrations, etc.

$ cd /home/git/gitlab
$ bundle install --without development test postgres --deployment
$ bundle exec rake db:migrate RAILS_ENV=production
$ bundle exec rake assets:precompile RAILS_ENV=production

From 5.4 to 6.0

Get latest code(6.0)

$ cd /home/git/gitlab
$ git checkout 6-0-stable
error: Your local changes to the following files would be overwritten by checkout:
        db/schema.rb
Please, commit your changes or stash them before you can switch branches.
Aborting

エラーになりました。db/schema.rb がローカル側で変更されているようです。

$ git diff
diff --git a/db/schema.rb b/db/schema.rb
index 348272e..585264e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -203,14 +203,14 @@ ActiveRecord::Schema.define(:version => 20130614132337) do

   create_table "snippets", :force => true do |t|
     t.string   "title"
-    t.text     "content"
-    t.integer  "author_id",                    :null => false
+    t.text     "content",    :limit => 2147483647
+    t.integer  "author_id",                                          :null => false
     t.integer  "project_id"
-    t.datetime "created_at",                   :null => false
-    t.datetime "updated_at",                   :null => false
+    t.datetime "created_at",                                         :null => false
+    t.datetime "updated_at",                                         :null => false
     t.string   "file_name"
     t.datetime "expires_at"
-    t.boolean  "private",    :default => true, :null => false
+    t.boolean  "private",                          :default => true, :null => false
     t.string   "type"
   end

大丈夫そうなので -f で上書きします。

$ git checkout -f 6-0-stable

Update gitlab-shell

$ cd /home/git/gitlab-shell
$ git checkout v1.7.0

Install additional packages

$ sudo yum install python-docutils

Install libs, migrations, etc.

$ cd /home/git/gitlab
$ bundle install --without development test postgres --deployment
$ bundle exec rake db:migrate RAILS_ENV=production

次の手順で yes/no プロンプトが表示されるので yes と入力します。

6.0 の変更で Team が無くなり Group がメンバーを持つようになったため、Group の所有者をメンバーに追加するかどうかのプロンプトだと思います。

$ bundle exec rake migrate_groups RAILS_ENV=production
This will add group owners to group membership
Do you want to continue (yes/no)? yes

次の手順でグローバルプロジェクトがプロジェクトの所有者の名前空間に移動されるのだと思いますが、グローバルプロジェクトを使っていなかったので関係ありませんでした。

$ bundle exec rake migrate_global_projects RAILS_ENV=production
No global projects found. Proceed with update.

次の手順で yes/no プロンプトが表示されるので yes と入力します。

表示された Issue によると、6.0 からSSH公開鍵の一意性が公開鍵のコメントを除いて行われるようになったため、それが原因で重複してしまう公開鍵を削除するかどうかのプロンプトのようです。

$ bundle exec rake migrate_keys RAILS_ENV=production
This will add fingerprint to ssh keys in db
If you have duplicate keys https://github.com/gitlabhq/gitlabhq/issues/4453 all but the first will be deleted
Do you want to continue (yes/no)? yes

作業を進めます。

$ bundle exec rake migrate_inline_notes RAILS_ENV=production
$ bundle exec rake gitlab:satellites:create RAILS_ENV=production
$ bundle exec rake cache:clear RAILS_ENV=production
$ bundle exec rake assets:clean RAILS_ENV=production
$ bundle exec rake assets:precompile RAILS_ENV=production

From 6.0 to 6.1

Get latest code(6.1)

$ cd /home/git/gitlab
$ git checkout 6-1-stable

Update gitlab-shell

$ cd /home/git/gitlab-shell
$ git checkout v1.7.1

Install libs, migrations, etc.

$ cd /home/git/gitlab
$ bundle install --without development test postgres --deployment
$ bundle exec rake db:migrate RAILS_ENV=production

次の手順で Issues/Merge Requests/Milestones の id がプロジェクト毎の連番になるようにリナンバリングされます。

$ bundle exec rake migrate_iids RAILS_ENV=production

作業を進めます。

$ bundle exec rake assets:clean RAILS_ENV=production
$ bundle exec rake assets:precompile RAILS_ENV=production
$ bundle exec rake cache:clear RAILS_ENV=production

Update config files

gitlab.yml を修正します。あらかじめ 5.3 でどのように修正していたかを確認し、それを参考に 6.1 の gitlab.yml.example をコピペ修正します。

$ cd /home/git/gitlab/config/
$ git diff --color 5-3-stable:config/gitlab.yml.example gitlab.yml
$ cp gitlab.yml.example gitlab.yml
$ vi gitlab.yml

production の gitlab/hostgitlab/email_fromgitlab/support_emailgit/bin_path 辺りが要修正箇所です。

@@ -17,3 +17,3 @@ production: &base
     ## Web server settings
-    host: localhost
+    host: gitlab.ore.example.jp
     port: 80
@@ -35,6 +35,6 @@ production: &base
     # Email address used in the "From" field in mails sent by GitLab
-    email_from: gitlab@localhost
+    email_from: gitlab@ore.example.jp

     # Email address of your support contact (default: same as email_from)
-    support_email: support@localhost
+    support_email: support@ore.example.jp

@@ -171,3 +171,3 @@ production: &base
   git:
-    bin_path: /usr/bin/git
+    bin_path: /usr/local/bin/git
     # Max size of a git object (e.g. a commit), in bytes

アプリケーションサーバが puma から unicorn に変わった(戻った)ので unicorn.rb.example をコピーして unicorn.rb を作成します(内容は修正していません)。

$ cp unicorn.rb.example unicorn.rb

gitlab-shell が GitLab にアクセスするURLを修正します。

$ cd /home/git/gitlab-shell
$ cp config.yml.example config.yml
$ vi config.yml

次のように修正しました。

@@ -4,3 +4,3 @@
 # Url to gitlab instance. Used for api calls. Should end with a slash.
-gitlab_url: "http://localhost/"
+gitlab_url: "http://localhost:8080/"

Update Init script

CentOS 用の init スクリプトと Apache 用の conf を差し替えます。

$ sudo rm /etc/init.d/gitlab
$ sudo rm /etc/httpd/vhost.d/gitlab.conf
$ sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init/sysvinit/centos/gitlab-unicorn
$ sudo curl --output /etc/httpd/vhost.d/gitlab.conf https://raw.github.com/gitlabhq/gitlab-recipes/master/web-server/apache/gitlab.conf
$ sudo chmod +x /etc/init.d/gitlab

ruby は GitLab 用にソースからインストールしているので init スクリプトにパスを記述します。

$ sudo vi /etc/init.d/gitlab

RVM を使っているわけではありませんが、RVM_PATH にパスを書いておけばよさそうなのでそうしました。

RVM_PATH="/home/git/ruby-versions/2.0.0-p247/bin"

Apache でモジュールが足りなかったので追加します。

$ sudo vi /etc/httpd/conf/httpd.conf

mod_rewritemod_proxy_balancer を追加しました。

LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

Apache のバーチャルホスト設定を修正します。

$ sudo cp /etc/httpd/vhost.d/gitlab.conf /etc/httpd/vhost.d/gitlab.conf.orig
$ sudo vi /etc/httpd/vhost.d/gitlab.conf

サーバ名とログファイル名を変更しました。

@@ -7,5 +7,5 @@
 #  mod_proxy_http
 <VirtualHost *:80>
-  ServerName gitlab.example.com
+  ServerName gitlab@ore.example.jp
   ServerSignature Off

@@ -24,5 +24,5 @@
     BalancerMember http://127.0.0.1:8080
     ProxyPassReverse http://127.0.0.1:8080
-    ProxyPassReverse http://gitlab.example.com:8080
+    ProxyPassReverse http://gitlab@ore.example.jp:8080
   </Proxy>

@@ -41,9 +41,6 @@
   </Location>

-  LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b" common_forwarded
-  ErrorLog  /var/log/httpd/logs/gitlab.example.com_error.log
-  CustomLog /var/log/httpd/logs/gitlab.example.com_forwarded.log common_forwarded
-  CustomLog /var/log/httpd/logs/gitlab.example.com_access.log combined env=!dontlog
-  CustomLog /var/log/httpd/logs/gitlab.example.com.log combined
+  ErrorLog  logs/gitlab-error_log
+  CustomLog logs/gitlab-access_log combined

 </VirtualHost>

Start application

GitLab の起動と Apache の再起動を行います。

$ sudo service gitlab start
$ sudo service httpd restart

Check application status

GitLab のステータスを確認します。

$ cd /home/git/gitlab
$ bundle exec rake gitlab:env:info RAILS_ENV=production
$ bundle exec rake gitlab:check RAILS_ENV=production

gitlab:check で「Init script up-to-date?」が no になりますが Ubuntu/Debian の手順にある lib/support/init.d/gitlab を使わない限りそうなるので無視します。

さいごに

ブラウザで閲覧したり、Git で fetch/Push できればバージョンアップ成功です!

幾つか互換性の無い変更点があるので注意が必要です。

Global projects

グローバルプロジェクトがなくなり、すべてのプロジェクトはなんらかの(user or group)名前空間に属することになります。

バージョンアップ作業時にグローバルプロジェクトが存在する場合、そのプロジェクトのオーナーの名前空間に移動されます。

Teams

Team がなくなって、代わりに Group がメンバーを持つようになりました。

バージョンアップ作業時に Team が削除され、Group のオーナーが Group の最初のメンバーになります。

Global issue numbers

Issue 番号がプロジェクト毎に採番されるようになりました(たぶん MR と Milestone も)。

バージョンアップ作業時にリナンバリングされます。 古い番号の URL は新しい番号の URL にリダイレクトされますが、古い方の番号が別のチケットの番号に使われるとリダイレクトされません。

GitLab 5.0 を CentOS 6.4 にインストールした

追記 2013/04/08

単に GitLab を動かすだけなら ruby をシステムグローバルにインストールする必要は無いので rvm とか rbenv とか、もしくは /home/git/ruby-1.9.3/ あたりにインストールする方がいいかもしれない。


なんかいろいろ変わったらしいので入れてみました。

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

epel リポジトリを追加します。

rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

開発ツールをインストールします。

yum groupinstall 'Development Tools'

その他の必要なパッケージをインストールします。 おおむね gitlab-recipes/install/CentOS_6.md の通りですが、 あきらかに不要そうなパッケージは除いています。

yum install vim-enhanced httpd readline readline-devel ncurses-devel gdbm-devel glibc-devel \
            tcl-devel openssl-devel curl-devel expat-devel db4-devel byacc \
            sqlite-devel gcc-c++ libyaml libyaml-devel libffi libffi-devel \
            libxml2 libxml2-devel libxslt libxslt-devel libicu libicu-devel \
            python-devel redis sudo mysql-server wget \
            mysql-devel crontabs logwatch logrotate \
            perl-Time-HiRes

最新にアップデートして再起動しておきます。

yum update
reboot

CheckInstall のインストール

ruby を RPM にするために checkinstall をインストールします。

checkinstall は x64 だといろいろ問題がありますが、修正したものがあるのでそれを使います。

cd /usr/local/src
git clone https://github.com/ngyuki/checkinstall.git
cd checkinstall/
make
make install
mkdir -p ~/rpmbuild/SOURCES
checkinstall --pkgversion=1.6.3
rpm -ivh ~/rpmbuild/RPMS/x86_64/checkinstall-1.6.3-1.x86_64.rpm

Ruby 1.9.3 のインストール

CentOS6 の標準レポの ruby-1.8.7 だと動作しないので ruby-1.9.3 を入れます。

configure--disable-install-doc をつけないと checkinstall の「tempディレクトリにファイルをコピー..」という段階で致命的に時間がかかります(数時間とかのオーダーでかかるらしいです)。 GitLab のサーバ上で ruby でコーディングすることは無いのでドキュメントのために無駄に時間をかける必要もないでしょう。

cd /usr/local/src
wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p392.tar.gz
tar xvzf ruby-1.9.3-p392.tar.gz
cd ruby-1.9.3-p392
./configure --prefix=/usr --disable-install-doc
make

checkinstall で RPM を作成します。そこそこ時間がかかりますが途中で中断しないようにしてください。 途中で中断してからもう一度 checkinstall すると中途半端な RPM になってしまいます。

checkinstall --fstrans=no --pkgname=ruby --pkgversion=1.9.3 --pkgrelease=p392 --exclude=$(pwd)

出来上がった RPM をインストールします。

rpm -ivh ~/rpmbuild/RPMS/x86_64/ruby-1.9.3-p392.x86_64.rpm

bundler も必要なのでインストールしておきます。

gem install bundler --no-rdoc --no-ri

理由はわかりませんが charlock_holmes をバージョン指定でインストールしておく必要があるようです。

gem install charlock_holmes --version '0.6.9' --no-rdoc --no-ri

/usr/bin/ruby は ruby-1.8.7-p357.i386 に必要とされています」というエラー

ruby の RPM のインストールで「/usr/bin/ruby は ruby-1.8.7-p357.i386 に必要とされています」というエラーになる場合、中途半端な RPM になっています。

/usr/bin/ruby などに ruby 関連のファイルが作成されているはずなので、それらを全て手動で削除してから checkinstall をやり直してください。

MySQL の設定と起動

MySQL を開始して mysql_secure_installation します。

chkconfig mysqld on
service mysqld start
mysql_secure_installation

GitLab のためのユーザとデータベースを作成します。パスワードは適当に要変更です。

mysql -u root -p mysql
CREATE USER gitlabhq@localhost IDENTIFIED BY 'password';
CREATE DATABASE gitlabhq_production;
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON gitlabhq_production.* TO gitlabhq@localhost;

Redis の起動

Redis が必要らしいので起動しておきます。

chkconfig redis on
service redis start

Git アカウント

git アカウントを作成します。

adduser --system --shell /bin/bash --comment 'GitLab' --create-home --home-dir /home/git git
su - git

.ssh/authorized_keys を適切なパーミッションで作成しておきます。これをやっておかないと git push で怒られます(sshd に)。

mkdir .ssh
touch .ssh/authorized_keys
chmod 700 .ssh
chmod 600 .ssh/authorized_keys

ついでに git config しておきます。

git config --global user.name  "GitLab"
git config --global user.email "gitlab@example.com"

GitLab Shell のセットアップ

GitLab Shell をクローンして 5.0 のためのバージョンをチェックアウトします。

git clone https://github.com/gitlabhq/gitlab-shell.git
cd gitlab-shell
git checkout -b v1.1.0 v1.1.0

config.yml.example をコピーして gitlab_url を書き換えます。

cp config.yml.example config.yml
sed -i 's|http://localhost/|http://localhost:3000/|' config.yml
diff -u config.yml.example config.yml
--- config.yml.example  2013-04-02 22:00:28.813622014 +0900
+++ config.yml  2013-04-02 22:01:06.584622431 +0900
@@ -2,7 +2,7 @@
 user: git
 
 # Url to gitlab instance. Used for api calls
-gitlab_url: "http://localhost/"
+gitlab_url: "http://localhost:3000/"
 
 # Repositories path
 repos_path: "/home/git/repositories"

最後に次のコマンドを実行して GitLab Shell のセットアップは完了です。

./bin/install

GitLab のセットアップ

GitLab をクローンして 5-0-stable ブランチをチェックアウトします。

cd ~
git clone https://github.com/gitlabhq/gitlabhq.git gitlab
cd gitlab
git checkout 5-0-stable

config/gitlab.yml.example をコピーしてホスト名やメールアドレスを変更します。

cp config/gitlab.yml.example config/gitlab.yml
vi config/gitlab.yml
diff -u config/gitlab.yml.example config/gitlab.yml
--- config/gitlab.yml.example   2013-04-02 22:04:42.552625248 +0900
+++ config/gitlab.yml   2013-04-02 22:07:09.330628529 +0900
@@ -15,7 +15,7 @@
   ## GitLab settings
   gitlab:
     ## Web server settings
-    host: localhost
+    host: gitlab.example.com
     port: 80
     https: false
     # Uncomment and customize to run in non-root path
@@ -27,10 +27,10 @@
 
     ## Email settings
     # Email address used in the "From" field in mails sent by GitLab
-    email_from: gitlab@localhost
+    email_from: gitlab@example.com
 
     # Email address of your support contact (default: same as email_from)
-    support_email: support@localhost
+    support_email: support@example.com
 
     ## Project settings
     default_projects_limit: 10

書込可能ディレクトリのオーナーとパーミッションを設定します(不要?)。

chown -R git log/
chown -R git tmp/
chmod -R u+rwX log/
chmod -R u+rwX tmp/

config/unicorn.rb.example をコピーして listen を変更します。

cp config/unicorn.rb.example config/unicorn.rb
sed -i config/unicorn.rb -e '/^listen/{
  a listen 3000
  s/^listen/#listen/
}'
diff -u config/unicorn.rb.example config/unicorn.rb
--- config/unicorn.rb.example   2013-04-02 22:03:39.954624770 +0900
+++ config/unicorn.rb   2013-04-02 22:07:33.742626105 +0900
@@ -17,7 +17,8 @@
 
 #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"
+#listen "#{app_dir}/tmp/sockets/gitlab.socket"
+listen 3000
 
 pid "#{app_dir}/tmp/pids/unicorn.pid"
 stderr_path "#{app_dir}/log/unicorn.stderr.log"

config/database.yml.mysql をコピーして username と password を変更します。

cp config/database.yml.mysql config/database.yml
vi config/database.yml
diff -u config/database.yml.mysql config/database.yml
--- config/database.yml.mysql   2013-04-02 22:03:39.953624770 +0900
+++ config/database.yml 2013-04-02 22:12:23.071238884 +0900
@@ -7,8 +7,8 @@
   reconnect: false
   database: gitlabhq_production
   pool: 5
-  username: root
-  password: "secure password"
+  username: gitlabhq
+  password: password
   # host: localhost
   # socket: /tmp/mysql.sock

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

cd ~
mkdir gitlab-satellites

bundle で Gem をインストールします。

cd gitlab
bundle install --deployment --without development test postgres

データベースを初期化します。

bundle exec rake gitlab:setup RAILS_ENV=production

root に戻ります。

exit

init スクリプトの設置

サービス起動のための init スクリプトを設置します。

curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab-centos

ただし、この init スクリプトは GitLab 4.1 用で、そのままでは動かないので修正します。

sed -i.orig 's/USER=\$NAME/USER=git/' /etc/init.d/gitlab
diff -u /etc/init.d/gitlab.orig /etc/init.d/gitlab
--- /etc/init.d/gitlab.orig     2013-04-02 22:19:57.585375138 +0900
+++ /etc/init.d/gitlab  2013-04-02 22:19:59.838364486 +0900
@@ -20,7 +20,7 @@
 NAME=gitlab
 
 # The username and path to the gitlab source
-USER=$NAME
+USER=git
 APP_PATH=/home/$USER/gitlab
 
 # The PID and LOCK files used by unicorn and sidekiq

init スクリプトを有効にします

chmod +x /etc/init.d/gitlab
chkconfig --add gitlab

インストールの確認

うまくインストール出来ているかどうか確認します。この作業は git アカウントで行います。

su - git
cd gitlab

以下のコマンドでいろいろ情報を表示します。

bundle exec rake gitlab:env:info RAILS_ENV=production

次のような内容が表示されます。

System information
System:         CentOS release 6.4 (Final)
Current User:   git
Using RVM:      no
Ruby Version:   1.9.3p392
Gem Version:    1.8.23
Bundler Version:1.3.4
Rake Version:   10.0.3

GitLab information
Version:        5.0.0
Revision:       8b76157
Directory:      /home/git/gitlab
DB Adapter:     mysql2
URL:            http://gitlab.example.com
HTTP Clone URL: http://gitlab.example.com/some-project.git
SSH Clone URL:  git@gitlab.example.com:some-project.git
Using LDAP:     no
Using Omniauth: no

GitLab Shell
Version:        1.1.0
Repositories:   /home/git/repositories/
Hooks:          /home/git/gitlab-shell/hooks/
Git:            /usr/bin/git

以下のコマンドでいろいろチェックします。

bundle exec rake gitlab:check RAILS_ENV=production

次のような内容が表示されます。Running? と Init script up-to-date? が赤字の no になると思います。

Checking Environment ...

Git configured for git user? ... yes
Has python2? ... yes
python2 is supported version? ... yes

Checking Environment ... Finished

Checking Gitlab Shell ...

GitLab Shell version? ... OK (1.1.0)
Repo base directory exists? ... yes
Repo base directory is a symlink? ... no
Repo base owned by git:git? ... yes
Repo base access is drwxrws---? ... yes
post-receive hook up-to-date? ... yes
post-receive hooks in repos are links: ... can't check, you have no projects

Checking Gitlab Shell ... Finished

Checking Sidekiq ...

Running? ... no
  Try fixing it:
  sudo -u git -H bundle exec rake sidekiq:start RAILS_ENV=production
  For more information see:
  doc/install/installation.md in section "Install Init Script"
  see log/sidekiq.log for possible errors
  Please fix the error above and rerun the checks.

Checking Sidekiq ... Finished

Checking GitLab ...

Database config exists? ... yes
Database is SQLite ... no
All migrations up? ... yes
GitLab config exists? ... yes
GitLab config outdated? ... no
Log directory writable? ... yes
Tmp directory writable? ... yes
Init script exists? ... yes
Init script up-to-date? ... no
  Try fixing it:
  Redownload the init script
  For more information see:
  doc/install/installation.md in section "Install Init Script"
  Please fix the error above and rerun the checks.
Projects have satellites? ... can't check, you have no projects

Checking GitLab ... Finished

git アカウントでの作業は完了です。

exit

GitLab 開始

service コマンドで開始します。

service gitlab start

次のURLでログイン画面が表示されます。

http://gitlab.example.com:3000/

次の通りに入力してログインできます。

Email: admin@local.host
Password: 5iveL!fe

Apache の設定と起動

多分そのままでも使えますが、Apache 経由のアクセスになるように変更します。

vi /etc/httpd/conf.d/gitlab.conf

次の通りに gitlab.conf を作成します。

<VirtualHost *:80>
    ServerName gitlab.example.net
    ProxyRequests Off
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>
    ProxyPreserveHost On
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/
</VirtualHost>

Apache を起動します。

chkconfig httpd on
service httpd start

次のURLでアクセス出来ます。

http://gitlab.example.com/

使ってみた感じ

GitLab 3.0.3(今使ってるバージョン) と比べると、下記のような点が良い感じだと思いました。

  1. gitolite がいらないのでインストールがめちゃくちゃ楽

  2. GitHub のようにリポジトリのURLが username/repository のようになった

  3. ↑にともないグループ(GitHub でいうところの組織?)を作れるようになった

  4. リポジトリを任意で public にできる(プロトコルは HTTP)

  5. Wiki が Git でアクセスできる!(GitHub の Gollum という Wiki エンジンが使われているらしい)
    「ローカルで編集 → Git で Push」で Wiki が更新できる