本記事は Ateam Finergy Inc. Advent Calendar 2020 19日目の記事です。
はじめに
みなさん、GitLab CIを使っているでしょうか?
エイチームフィナジーではプロジェクト管理にGitLabを使用しており、自動化などのためにGitLab CIを活用しています。
GitLab CIは機能が豊富な反面、書いていない期間が長いと、しばしば書き方を忘れがちになります。
今回はGitLab CIの知っておくと便利な機能について紹介します。
ちなみに、この記事で出てくる例は、Ruby on Railsのプロジェクトを前提としている物が多いですが、ご容赦ください。
service
依存するミドルウェアを立てます。
example
たとえば、DBです。
プロジェクトでDBにMySQLを使っているとして、単体テストをするのにMySQLに接続する必要があります。
そのMySQLを用意するということです。
servicesにはDockerイメージを使用するため、MySQLのDockerを参考に設定します。
https://hub.docker.com/_/mysql
services:
- name: mysql:5.6
variables:
MYSQL_DATABASE: app_test
MYSQL_ROOT_PASSWORD: app
これでホスト名がmysql
でMySQLに接続できるようになります。
応用編
実際のプロジェクトでは、しばしばMySQLのホスト名を変えたかったり、MySQLの起動オプションをつけたい場合があります。
その場合alias
command
を使います
alias
別の名前でコンテナに接続できます。
それによってMySQLを別のホスト名として接続できます。
下記はホスト名をdbにする例です。
services:
- name: mysql:5.6
alias: db
variables:
MYSQL_DATABASE: app_test
MYSQL_ROOT_PASSWORD: app
command
commandを指定できます。
下記はMySQLにinnodb_large_prefixオプションを設定する例です。
services:
- name: mysql:5.6
command:
- "mysqld"
- "--innodb_large_prefix=ON"
- "--innodb_file_format=Barracuda"
- "--innodb_file_format_max=Barracuda"
variables:
MYSQL_DATABASE: app_test
MYSQL_ROOT_PASSWORD: app
cache
キャッシュはビルド時間の短縮に繋がります。
example
例えば、npm install
でインストールしたファイルをキャッシュしておくことによって、ビルド時間が減らせます。
cache:
paths:
- node_modules
応用編
cache:key:files
たとえば、cache:key:files
を設定することによって、特定のファイルが変わったときにキャッシュキーを変更することができます。
下記はyarn.lock
ファイルをキャッシュキーにしている例です。
cache:
key:
files:
- yarn.lock
paths:
- node_modules
needs
ジョブの依存関係を記述することによって、並列でジョブを実行します。
例えば、stageが別れていると前のstageが終わるまで待っておかないといけないというパターンがあります。
needsを使えば、前のステージを待たずに、複数のステージで同時にジョブを実行できます。
つまり、下記のようになります。
needs未使用
needs未使用のdeploy_jobは、testステージのジョブが終わるのを待っているのに対して、needs使用のものはtestステージが終わるのを待たずにdeploy_jobを実行できます。
example
stages:
- build
- test
- deploy
build_job:
stage: build
script:
- echo build # build script
test_job:
stage: test
script:
- echo test # test script
deploy_job:
stage: deploy
script:
- echo deploy # deploy script
needs:
- build_job
extends
設定を使い回せます。
example
たとえばRubyのプロジェクトで、Ruby製のツールを使用するときは、事前にbundle install
をする必要があります。
その設定を使い回す例は下記となります。
stages:
- rubocop
- rspec
.ruby:
before_script:
- apk add build-base mysql-client mysql-dev tzdata
- bundle config set path vendor/bundle
- bundle install -j $(nproc)
rubocop:
stage: rubocop
extends: .ruby
script:
- bundle exec rubocop
rspec:
stage: test
extends: .ruby
script:
- bundle exec rspec
応用編
ネスト
extendsしようとするものの中で、extendsできます。
先程のbundle install
する例に加えて、rule
を追加した例が下記となります。
stages:
- rspec
- staging
.ruby:
before_script:
- apk add build-base mysql-client mysql-dev tzdata
- bundle config set path vendor/bundle
- bundle install -j $(nproc)
rspec:
stage: test
extends: .ruby
script:
- bundle exec rspec
.deploy:
extends: .ruby
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
staging:
stage: staging
extends: .deploy
script:
- bundle exec cap staging ecs:deploy
artifacts
成果物を残せます。
example
たとえば、webpackなどでビルドした結果を残すものは下記となります。
build:frontend:
stage: build
before_script:
- apk add yarn
- cd frontend
- yarn install
script:
- yarn build
artifacts:
paths:
- frontend/public
pages
GitLab Pagesにデプロイします。
example
pages:
artifacts:
paths:
- public
注意点
- job名は
pages
でなければなりません。 - artifactsで
public
を指定しなければなりません。
dependencies
他のjobで作ったartifactsを使います。
example
たとえば、rspecのカバレッジ結果をSimpleCovを使ってGitLab Pagesに出したいとします。
SimpleCovはrspecを実行するとcoverageというディレクトリにファイルを出力します。
そのcoverageファイルをpagesジョブで使いたい場合は、下記のようになります。
rspec:
stage: test
script:
- bundle exec rspec
artifacts:
paths:
- coverage/
pages:
stage: pages
dependencies:
- rspec
script:
- mv coverage public
artifacts:
paths:
- public
リファレンス
今回紹介した機能を全部使ったサンプル
ちなみに、全部使ったサンプルのプロジェクトがこちらとなります。
よければ参考にしてみてください。
# This file is a template, and might need editing before it works on your project.
# Official language image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/ruby/tags/
image: "ruby:2.7.2-alpine"
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
stages:
- build
- rubocop
- test
- pages
- staging
- production
build:frontend:
stage: build
before_script:
- apk add yarn
- cd frontend
- yarn install
script:
- yarn build
artifacts:
paths:
- frontend/public
cache:
key:
files:
- yarn.lock
paths:
- node_modules
build:docker:
stage: build
image: docker:19.03.13
services:
- docker:19.03.13-dind
script:
- apk add aws-cli
- aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 887840435665.dkr.ecr.ap-northeast-1.amazonaws.com
- docker build -t rails-ci-sample .
- docker tag rails-ci-sample:latest 887840435665.dkr.ecr.ap-northeast-1.amazonaws.com/rails-ci-sample:$CI_COMMIT_SHA
- docker push 887840435665.dkr.ecr.ap-northeast-1.amazonaws.com/rails-ci-sample:$CI_COMMIT_SHA
.ruby:
cache:
key:
files:
- Gemfile.lock
paths:
- vendor/bundle
before_script:
- apk add build-base mysql-client mysql-dev tzdata
- bundle config set path vendor/bundle
- bundle install -j $(nproc)
rubocop:
stage: rubocop
extends: .ruby
script:
- bundle exec rubocop
needs: []
rspec:
stage: test
extends: .ruby
services:
- name: mysql:latest
alias: db
variables:
MYSQL_DATABASE: app_test
MYSQL_ROOT_PASSWORD: app
RAILS_ENV: test
script:
- bin/rails db:create
- bin/rails db:migrate
- bin/rspec
artifacts:
paths:
- coverage/
needs: []
pages:
stage: pages
needs:
- rspec
dependencies:
- rspec
script:
- mv public _public
- mv coverage public
artifacts:
paths:
- public
.deply:
extends: .ruby
needs:
- build:frontend
- build:docker
staging:
stage: staging
extends: .deply
script:
- bundle exec cap staging ecs:deploy
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
production:
stage: production
extends: .deply
script:
- bundle exec cap production ecs:deploy
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: manual
おわりに
いかがでしたでしょうか。
今回は、GitLab CIの知っておくと便利な機能について紹介しました。
GitLab CIを設定する際の参考にしていただければ幸いです。