GitLab CI/CD 導入の手引き
こんにちは。8日目のアドベントカレンダー記事を書かせていただきます、エンジニアの山門です!
現在は旅行プラットフォーム事業部で大手旅行会社のシステム開発を担当しています。
突然ですが皆さん、CI/CD しているでしょうか?
社内ではレポジトリ管理にGitLabを使用しているのですが、これまでGitLab CI/CD は使用していませんでした。
ここ最近になり、GitLab CI/CD の魅力に気づいた社内の各所で使われ始め、私自身も使い始めてみたので、そもそもどうやって使うんだ?という導入部分の紹介ができればと思います。
そもそも CI/CD って?
ここ最近 CI/CD というワードをよく耳にするようになりましたが、実際どういったものなのでしょう。
ざっくり以下のような役割を果たしており、開発段階の効率をあげるプロセスがCIで、運用段階の効率をあげるプロセスがCDのようなイメージです。
- CI(Continuous Integration): 継続的インテグレーション
- ビルド
- 単体テスト
- 結合テスト
- CD(Continuous Delivery): 継続的デプロイ
- ソースコードレビュー
- ステージング環境へのデプロイ
- 本番環境へのデプロイ
GitLab CI/CDはこのどちらの機能も有している便利ツールなのです。
今回はCIにフォーカスして、その導入を実践していただければと思っています。
GitLab CI/CDとは
GitLab CI/CDは GitLabの機能の一機能で、アプリケーションのビルドや単体テストのオペレーションを自動化し、品質維持を手助けしてくれるツールです。
GitLab CI/CDで動作する各jobはプロジェクトに関連しているため、プロジェクトの特定のブランチ更新や、mergeをトリガーにしてjobを呼び出します。
- こんな感じのイメージ
レポジトリにpushした後にGitLabがjobをキックし、テスト等々実行してくれるものだと思っておいていただけると良いかと思います。
メリット
フォルシアでは以下のような点が良いと感じ、GitLab CI/CDの利用を開始しました。
- 社内のレポジトリ管理にGitLabを使っているため、GitLab上でbuildやtestが完結し、使うツールをまとめることができる
- レポジトリと結びついているので、branchやMRとの連携が容易
- 設定を
.gitlab-ci.yml
というファイルでコード管理することができる
GitLab Runner
GitLab CI/CDを利用するにあたってGitLab Runnerの存在が不可欠です。GitLab RunnerはGitLabがmerge等のトリガーを検知した際に、実際にjobを実行し、結果をGitLabに返してくれるツールです。中身はGoで書かれており、GNU/Linux, macOS, Windowsといった様々な環境で動作可能なのが特徴です。
また、Executorというjobの実行形式を変えることで、各人の環境に合わせた選択をすることが可能です。
Runnerの種類
RunnerにはShered RunnersとSpecific Runnersの2種類の利用方法があります。
- Shared Runners
- 複数のプロジェクトのjob実行を共有のRunnerで処理する方式
- 現在実行されているjobの数が最も少ないプロジェクトから処理が実行される
- Specific Runners
- 特定のプロジェクトのjobのみを実行する方式
- 基本的に実行リクエストが来た順に処理が実行される
Executorの種類
Runnerはjobを実行するプラットフォームに応じてExecutorとよばれるjobの実行形式を選択します。
主なExecutorとして、以下のようなものがあり、フォルシアでは推奨でもあるDocker
Executorを利用しています。
- Shell Executor
- Runnerが導入されているサーバー上で、build,test等を実行
- Docker Executor
- Docker APIを通してDocker Engineと接続することによりコンテナから各build,test等を実行
- Virtual Box Executor
- VM上のSSHを経由してbuild,test等を実行
- SSH Executor
- RunnerからSSH接続可能なサーバに対して、コマンドをSSH経由で送信してbuild,test等を実行
- Kubernetes Executor
- Kubernetes API経由でクラスタ上のPodを作成してbuild,test等を実行
準備
Runnerのinstall
フォルシアではオンプレでGitLabを利用しており、そこに新しくCI/CDの実行環境を用意しました。
ここでは事前準備としてRunnerのinstallをします。
ここでは、以下の前提の上で話を進めます。
- GitLab が乗っているサーバがある -- A
- Runnerを動かすサーバ(Dockerがinstallされている)がある -- B
- A,Bがネットワーク的につながっている
RunnerのContainerを実行
今回はRunnerをDocker imageでinstallしていきます。
こちらの公式ドキュメントが参考になるかと思います。まずはRunnerのContainerを起動。
docker run -d --name gitlab-runner --restart always \ -v /srv/gitlab-runner/config:/etc/gitlab-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ gitlab/gitlab-runner:latest
Runnerの登録
次にRunnerの登録を行うのですが、登録にはあらかじめurlとtokenが必要になるので、各自取得する必要があります。登録するRunnerの種類によって以下の流れでurlとtokenを知ることができます。
- Specific Runners登録の場合
- 各自追加したいレポジトリの
CI/CD -> Ruuners
- 各自追加したいレポジトリの
- Shared Runners 登録の場合
- 管理者権限で
Admin Area -> Runners
- 管理者権限で
- Specific Runners登録の場合のurlとtokenの記載場所例
- モザイク箇所にurlとtokenが記載されています
情報が揃った方は実際に登録してみましょう。下記コマンドを打つと、対話ベースでRunnerの登録が行えます。
docker run --rm -t -i -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register
Runtime platform arch=amd64 os=linux pid=6 revision=577f813d version=12.5.0 Running in system-mode. Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): <取得したGitLab url> Please enter the gitlab-ci token for this runner: <取得したtoken> Please enter the gitlab-ci description for this runner: [3b2bf8a2a755]: <このrunnerを表す名称(gitlab-runner01)> Please enter the gitlab-ci tags for this runner (comma separated): <カンマ区切りでタグを設定(docker,sample)> Registering runner... succeeded runner=snZhRtXu Please enter the executor: docker-ssh, ssh, docker-ssh+machine, kubernetes, docker, parallels, shell, virtualbox, docker+machine, custom: <使用するexecutorを入力(docker)> Please enter the default Docker image (e.g. ruby:2.6): <使用するexecutorを入力(alpine:latest)> Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
問題なく完了すれば、無事Runnerの登録完了です!
登録したレポジトリのCI/CD -> Ruuners
を見ると、登録したRunnerが以下のように画面に表示されているはずなので、早速動かしていきましょう!
早速始めてみる
社内ではShared Runnerを使用しているため、以下Shared Runnersのケースで進めます。
.gitlab-ci.yml
の違いはtagsの設定くらいなので、Specific
Runnersの方は、公式を参考にtagsの設定を適宜入れていただければと思います。
まずは自身がいじれるレポジトリでissueなどを使って適当にbranchを作成します。
その後、レポジトリルートに .gitlab-ci.yml
を作成し、以下コードを追加してみましょう。
image: node test1: script: - npm install - npm run test
(testがない方は echo "this is test1"
のようにechoするだけでも問題ありません)
追加したらadd&commit&pushでレポジトリに反映しましょう。
自分のレポジトリの CI/CD
-> Pipelines
を見てみると、以下のようにgit上でtestが実行されるはずです。
注意
- submodule周りで怒られているとなった場合、以下記述をimageプロパティと同じ高さに記載するとうまくいくかもしれません
variables: GIT_SUBMODULE_STRATEGY: recursive
- GitLab CI/CDはデフォルトではsubmoduleを引っ張ってこないため、対象のレポジトリがsubmoduleを持っている場合に必要になるプロパティです
設定 | 内容 |
---|---|
none(デフォルト) | submoduleは引っ張ってこない |
normal | トップレベルのsubmoduleのみ引っ張ってくる |
recursive | submoduleの中にあるsubmoduleといった入れ子構造も引っ張ってくる |
参考 |
やったこと
今書いていただいたのは、ミニマムでGitLab CI/CDを利用する方法です。
GitLab CI/CDは
.gitlab-ci.yml
という設定ファイルを、レポジトリルートに配置することで実行することができます。
image
- 使用するDocker イメージを指定
- 今回はnpmを使う関係でnodeのイメージを利用しています
- 使用するDocker イメージを指定
test1
- job名
- job名は
.gitlab-ci.yml
の中で一意になっている必要があります
- job名は
- job名
script
- Runner上で実行されるスクリプトやコマンドを指定
- scriptはjobの中で必須
stage, pipelineを追加してみる
お次はstageという考えを導入し、pipelineを組んでみましょう。
先ほどの.gitlab-ci.yml
に少し記述を追加します。
image: node stages: - build - test build: stage: build script: - echo "this is build stage" test1: stage: test script: - npm install - npm run test
ここでは新たにstagesパラメータを導入し、build,testの2つのステージを追加します。
また、jobにstageパラメータを追加し、どのjobがどのstageに属するかを指定しています。
stages
- ビルド、テスト、デプロイといった大きな塊を表す定義の一覧
stage
- 各jobをどのステージに割り当てるかを指定
- 同じステージのjobは並列で実行される
- 基本的に前のステージのjobが全て成功しないと、次のステージのjobは実行されない
この状態で更新してpushしてみると、GitLab上でpipelineが自動的に組まれます。簡単ですね。これにより、ビルドが成功したらテストをやってデプロイまで、といった流れを簡単に組むことができます。
注意
- 1jobに対して1コンテナが立ち上がるので、各jobは独立していることに注意しましょう
- ES6やTSのプロジェクトで、build jobで
npm run build
したからといって、testのjobでbuildせずにtestを走らせると失敗してしまいます!
- ES6やTSのプロジェクトで、build jobで
jobの並列実行
引き続き今度は、同じstageで複数のjobを設定し、jobを並列で実行してみましょう。
image: node stages: - build - test build: stage: build script: - echo "this is build stage" test1: stage: test script: - npm install - npm run test test2: stage: test script: - echo "test1 and test2 are run simultaneously"
そろそろ皆さん慣れてきたかもしれませんが、testステージにtest2というjobを追加しました。この状態でpushすると、buildステージが成功した後に、testステージのjobが並列で実行されるはずです。
もう少しやってみる
最低限の導入という意味ではここまでで十分なのですが、せっかくなので以下2点も合わせてやってみましょう。
- branchによる実行jobの変更
- 各jobの前後への処理の追加
image: node stages: - build - test before_script: - npm install after_script: - echo "this is executed after each job" build: stage: build script: - echo "this is build stage" only: - branches except: - master test1: stage: test script: - echo "this is test1" - npm run test only: - branches except: - master test2: stage: test script: - echo "this is test2" only: - branches except: - master test3: stage: test before_script: - echo "before_script is overwritten" script: - echo "this is test3" only: - master
いきなり増えましたが、追加したパラメータの説明を以下に記載します。
before_script
- scriptの前に行うタスクを定義
- 環境の設定や、npm installなどの、どのjobでも実行されるようなタスクを記載
- scriptの前に行うタスクを定義
after_script
- scriptの後に行うタスクを定義
only
- 指定したブランチ、およびタグの更新があった場合のみjobを実行
except
- 指定した以外のブランチ、およびタグの更新があった場合のみjobを実行
- onlyパラメータと併用することが多い
- 指定した以外のブランチ、およびタグの更新があった場合のみjobを実行
やりたいことが増えてくると、jobの数が増加し、pipeline実行にかかる時間が長くなってきてしまうのですが、こういったパラメータを利用することで、時間の短縮や、必要な場面でのみjobを実行することができるようになります。
パラメータはネストが深い方で上書きする(グローバル宣言したものよりローカル宣言したものが強い)ようになっており、test3では、グローバルに宣言されているbefore_script
を上書きし、npm install
が実行されないようになっています。
- 補足: 特定のjobだけ別のimageを使いたいという意図で、jobの中にimage指定をして上書きすることはよくあります
この状態でpushするとbuild,test1,test2が実行され、masterにmergeされた際はtest3だけが実行されます。
パラメータはこの他にもたくさんあり、例えば以下のようなパラメータを使用することもできます。
設定 | 内容 | 記述例 |
---|---|---|
variables | job内で利用される変数定義 | variables: GIT_SUBMODULE_STRATEGY: recursive |
tags | 実行するRunerのタグを指定 | tags: docker |
allow_failure | 失敗することを許可するか否かを指定 | allow_failure: true |
when | 特定の条件にマッチした場合のみjobを実行 | when: on_failure |
retry | 失敗したときのretry回数を設定 | retry: 2 |
公式のページがかなり丁寧に書かれているので、困ったらそちらを見ると良いと思います。
MRの作成
.gitlab-ci.yml
を導入することでMRでも恩恵を受けることができます。
実際にMRを作成し、画面を見てみると、これまでなかったpipelineの表示が出てくるため、pipelineが成功してmergeという運用が新たにできるようになります。
対象のMRのpipelineが実行中の場合、mergeボタンが「Merge when pipeline
succeeds」という表示になり、レビュアーがOKと判断し、このボタンを押しておけば、pipeline成功時に自動でmergeをしてくれるようになります。
buildや単体テストによるチェックはCIに任せて開発効率をじゃんじゃん上げていきましょう!
(ちょうどいい画像が用意できなかったため公式から引っ張ってきました)
参考までに実際に今回のMRをmergeしたときに走るpipelineです。
設定した通りmasterではtest3のみ実行されています。
終わりに
駆け足でしたが、ざっとGitLab CI/CDについて理解・実践していただき、導入コストの低さと利便性を感じていただけたのではないかと思います!これを機に導入を検討されてみてはいかがでしょうか。
フォルシアでは技術の知見を共有しあうdevゼミという試みがあり、本記事もそこでの発表を元に、まとめ直したものをご紹介しております(devゼミについての紹介はこちらをご覧ください)。
GitLab CI/CD は公式ドキュメントがかなり丁寧に書かれており、そちらを見れば何かしらヒントがあるので、導入の際はぜひ読んでいただければと思います。
1push,1MR単位でCIを実施して、ソースコードの品質維持・向上を担ってくれているので、実際に開発者、レビュワーが実装に集中して業務に取り組めるようになったと感じています。
GitLab CI/CD に限らず、今後CI/CDが当たり前のものになっていくといいですね。
山門 峻
2017年新卒入社のエンジニア。大手旅行会社のシステムを担当。
休日はおいしいものを食べたり、写真を撮ったりして楽しんでいます。