こんにちは、ドリコムのsue445(末吉)です。
サーバサイドでアプリからインフラまでなんでもやるマンで、最近は itamae や Serverspec など若干インフラ寄りです。
今期の嫁は 魔法つかいプリキュア! の はーちゃん (成長前)です
©ABC・東映アニメーション
今回はGitLab CIの紹介と、実際にRailsアプリでテスト・静的解析・自動デプロイをする方法を紹介をしたいと思います
目次
ドリコムとGitLab
ドリコムではソースコードのホスティングにOSSの GitLab を使っています。
2012年12月頃GitLabを導入しましたが、3年半でリポジトリが1600以上あります
GitLab導入の経緯に関してはアドベントカレンダーのエントリがあるのでご確認ください
他にも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みたいなもの)をインストールしたサーバが必要
- GitLab CI Runnerにはsshでつないでビルドを実行したり、dockerコンテナ内でビルドを実行するなどいろんな使い方がある
- https://gitlab.com/gitlab-org/gitlab-ci-multi-runner
- jobとstageの概念があり、例えばstage1のjob1とjob2を 並列 実行しそれらが全部終了したらstage2のjob3とjob4を 並列* 実行するというビルドパイプラインの制御ができる
- Jenkinsでも頑張ればできると思いますが、頑張らなくてもymlをちょっと書くだけでできるのはよいです
- ブランチをpushした時に自動でビルドが実行される
- リポジトリのトップやMergeRequestの画面にビルド結果が表示される
詳しくは 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.html や http://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名のみにしています
- デフォルトだとjob名とbranch名ごとなのですが、それだとMergeRequestのトピックブランチで毎回フルで
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.yml
の rspec
や rubocop
など)の直前に実行される処理です
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
- https://github.com/sue445/gitlab-ci-example/blob/master/gitlab-ci/rspec.sh
- https://github.com/sue445/gitlab-ci-example/blob/master/gitlab-ci/rubocop.sh
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をするには便利です。是非ご活用ください。