こんにちは、ドリコムのsue445(末吉)です。

サーバサイドでアプリからインフラまでなんでもやるマンで、最近は itamaeServerspec など若干インフラ寄りです。

今期の嫁は 魔法つかいプリキュア!はーちゃん (成長前)です

はーちゃんかわいい

sue445さん(@sue445)が投稿した写真 –

©ABC・東映アニメーション

今回はGitLab CIの紹介と、実際にRailsアプリでテスト・静的解析・自動デプロイをする方法を紹介をしたいと思います

ドリコムとGitLab

ドリコムではソースコードのホスティングにOSSの GitLab を使っています。

2012年12月頃GitLabを導入しましたが、3年半でリポジトリが1600以上あります

GitLab導入の経緯に関してはアドベントカレンダーのエントリがあるのでご確認ください

ドリコムの開発を支えるGitリポジトリ – gussan

他にもOSSのGitリポジトリはたくさんあると思いますが、GitLabの大きな特徴はGitLab CIというCIツールがリポジトリに組み込まれてることです。

GitLab CIの特徴

私は Jenkins, Travis CI, Circle CI, Wercker など様々なCIツールを触っていますが、GitLab CIは他のCIとは異なる独特の特徴があります

  • リポジトリであるGitLabに組み込まれているのでGitLabを使っていれば導入は不要。設定も楽
    • GitLabを使ってればJenkinsを別に立てる必要がなくなります
  • GitLab CI単体ではCIはできずGitLab CI Runner(JenkinsでいうSlaveみたいなもの)をインストールしたサーバが必要
  • jobとstageの概念があり、例えばstage1のjob1とjob2を 並列 実行しそれらが全部終了したらstage2のjob3とjob4を 並列* 実行するというビルドパイプラインの制御ができる
    • Jenkinsでも頑張ればできると思いますが、頑張らなくてもymlをちょっと書くだけでできるのはよいです
  • ブランチをpushした時に自動でビルドが実行される
  • リポジトリのトップやMergeRequestの画面にビルド結果が表示される
repo
MR

詳しくは GitLab Continuous Integration | GitLab を読んでください。

GitLab CIの設定方法

以降は現時点の最新版の8.8.3をベースに説明します

1. GitLab CIを有効にする

Setting -> Project Settings -> Features

Buildsにチェックが入ってないならチェックを入れてください。(最近だとプロジェクト作成時にデフォルトでチェックが入ってるはずですが、古いバージョンからアップデートしてるとついてないかも)

2. リポジトリの設定をする

Runner

Shared runners

Shared runnerはGitLab全体で共有しているRunnerです

GitLab.comだと1台 Shared runnerが用意されています。

分かりづらいですが上記のようにボタンがオレンジ色になってれば有効になってます

Specific runners

リポジトリ個別でRunnerを建てることもできます

GitLabからsshできるサーバであればrunnerにできます。

使いたい時には https://about.gitlab.com/gitlab-ci/#gitlab-runner を参考にセットアップしてください

Runnerをセットアップしたら画面に表示されます

Variables

ビルドに必要なんだけどリポジトリに直接コミットしたくないような変数をいれておくことができます。(例:Slackのトークンやsshの秘密鍵など)

ここに設定しておけばジョブ実行時に環境変数として使うことができます

3. gitlab-ci.yml をリポジトリにコミットする

http://doc.gitlab.com/ce/ci/yaml/README.htmlhttp://doc.gitlab.com/ce/ci/quick_start/README.html を参考にファイルを作ってください

Railsアプリをテスト、静的解析、自動デプロイをするための設定サンプル

こちらになります

https://github.com/sue445/gitlab-ci-example

普通にRailsアプリをビルドするだけなら上記ファイルをコピペするだけでほぼいけると思います。アプリによって使ってる設定ファイルが微妙に異なってると思うのでその辺はいい感じに変えてください

設定ファイル(.gitlab-ci.yml)を上から順を追って解説します

image

ビルドに使う環境です。

image: drecom/ubuntu-ruby:2.3.1

Docker Hub のイメージ名を指定してください

上記の drecom/ubuntu-ruby は弊社のRuby実行用dockerイメージです。Ruby本体以外にもnodejsやmysql-clientなどアプリ実行に必要なパッケージが一通りインストールされています

https://hub.docker.com/r/drecom/ubuntu-ruby/

variables

ビルド中に設定される環境変数です。

variables:
  CAP_USER: "deployer"
  BUNDLE_CACHE: "vendor/bundle/"
  RAILS_ENV: "test"
  CI: "true"

シェルの中で export するのと同じなので好みに応じて使ってください。

cache

ビルド中に生成されたファイルをキャッシュするための設定です。

cache:
  untracked: true
  key: "$CI_BUILD_NAME"
  paths:
    # variables.BUNDLE_CACHEと同じものを指定する
    - vendor/bundle/

ビルド終了後に下記のようにアーカイブされます。(ビルドに失敗したらアーカイブされないので注意)

  • untracked : git管理下にないファイルをキャッシュするかどうか
  • key : cacheのキー
    • デフォルトだとjob名とbranch名ごとなのですが、それだとMergeRequestのトピックブランチで毎回フルで bundle install が実行されて嫌なので job名のみにしています
  • paths : キャッシュ対象ディレクトリ
    • コメントにも書いてますが variables.BUNDLE_CACHE と同じものを指定してください

その他詳しいことは http://docs.gitlab.com/ce/ci/yaml/README.html#cache を参照

services

ビルドで使いたいserviceです

services:
  - mysql:5.7
  - redis:2.8
  - memcached:1.4

これもDocker hubのイメージを指定してください。Railsアプリのビルドならたぶんこの辺で十分かと。

before_script

各job(.gitlab-ci.ymlrspecrubocop など)の直前に実行される処理です

before_script:
  - ./gitlab-ci/setup.sh

.gitlab-ci.yml にシェルを全部書いてもいいんですが、それだとシンタックスハイライトが効かなくて編集しづらいのでスクリプトを別途作ってそれを呼び出しています

./gitlab-ci/setup.sh でやってることは

  • sshの秘密鍵の設置
  • テストで使う設定ファイルの設置
  • DB初期化

くらいです。

設定ファイルの注意点

rspecを実行する時のDBやredisの接続先はだいたいlocalhostだと思いますが、GitLab CI(のDockerイメージ内)でビルドする場合はservice名(servicesの項で書いたmysql, redis, memcachedなど)を指定してください

test:
  adapter: mysql2
  encoding: utf8
  database: myapp_test
  pool: 5
  username: root
  password:
  host: mysql # <= これがservice名

stages

ビルドのstage(各jobをグルーピングしたもの)の実行順を定義します

stages:
  - test
  - deploy

上記だと stage: test がついているjobが 並列で 実行され、それらが全部終了した後に stage: deploy が実行されます

詳しいこと http://docs.gitlab.com/ce/ci/yaml/README.html#stages

[testステージ] rspec, rubocop

rspec:
  stage: test
  script:
    - ./gitlab-ci/rspec.sh

rubocop:
  stage: test
  script:
    - ./gitlab-ci/rubocop.sh
  allow_failure: true

allow_failure: true をつけているとjobが失敗してもビルド全体を失敗にしないことができます。(jobが失敗したことは表示されます)

rubocopでOffensesが出るとexit 1で終了するので、rubocopでOffenses見つかってもMergeRequest自体はアクセプトしたい場合はallow_failure: true 推奨です。(Offensesが1つでもあったらアクセプトもしたくない場合はこの限りではありません )

[deployステージ] deploy_staging

deploy_staging:
  stage: deploy
  script:
    - ./gitlab-ci/deploy.sh staging
  only:
    - develop

特定のブランチのみで実行したい場合は only でブランチを指定します。(逆に特定のブランチのみ除外したい場合は except

上記だとdevelopブランチを常にstagingにデプロイするような設定です

GitLab CI 所感

Jenkinsに比べたらお手軽だけど、CircleCIとかに比べたらそんなにお手軽感はないと思います。

CircleCIとかはリポジトリの構成を見て暗黙的に bundle install とか rspec などをデフォルトで実行してくれるけど、GitLab CIの場合結局ビルドスクリプトは全部書く必要があります。

CIツールはいろいろ使ってますが、機能面やお手軽さは Jenkins と CircleCIの中間かなぁという感じです。(とは言え、暗黙的にやってることを知らなかったらたまにハマるので一長一短)

元々Jenkinsでビルドスクリプトをガッツリ書いていた人であればとっつきやすいのではないかと思います。

まとめ

GitLab CIはGitLabとも親和性が高くGitLabでCIをするには便利です。是非ご活用ください。