GitLabでCIを実行する方法を調べてみた
今回はGitLabを利用してどのようにCIを実行するかについて試してみました。私自身今までGitHub Actionsしか使ってこなかったので、今回試してみました。
GitLabとは
GitLabはGitLab社が展開しているGitを利用するためのバージョン管理システムのサービスになります。DevOpsだけでなくDevSecOpsのワークフローを意識したサービスとなっています。
以下が公式ページとなっております。
CIとは?
CIとは継続的インテグレーション、英語にするとContinuous Integrationの頭文字をとってCIとなります。CIはソフトウェア開発において、頻繁に変更されるコードを統合して、それに対してコードフォーマットチェックやテスト、ビルドなどを自動で行うためのプロセスとなります。トリガーは様々ですが、CIを用いることでコードの品質の担保ができ、特にアジャイル開発のようにクイックに開発サイクルを回す場合は特に重要です。
GitLabでCIを動かしてみる
CIの実装方法
GitLabでCIを実装する場合はGitHub Actionsと同様にYAMLファイルを作成します。パイプラインを定義するには.gitlab-ci.yml
というファイル名で定義します。
それではまずはテストとしてHello Worldと表示されるパイプラインを実装してみます。
Hello-World:
stage: test
script:
- echo "Hello World"
これをpushするとパイプラインが実行され、以下のようなログとなりました。パイプライン終盤をみるとHello Worldと表示あsれていることがわかります。
Pythonコードを実装してテストを実行させてみる
次は簡単なPythonコードを作成して、pytestでテストをさせてみます。
まず環境構築にはuv
を利用しました。コマンドは以下になります。
uv init -p 3.12
uv add pytest
次に関数を定義します。func.py
というファイルで四則演算を実装しました。
def add(x: int, y: int) -> int:
return x + y
def sub(x: int, y: int) -> int:
return x - y
def mul(x: int, y: int) -> int:
return x * y
def div(x: int, y: int) -> float:
if y == 0:
raise ZeroDivisionError
return float(x) / y
そしてtest.py
にテストコードを実装します。
from func import add, sub, mul, div
import pytest
def test_add():
assert add(1, 1) == 2
assert add(-1, 1) == 0
assert add(0, 0) == 0
def test_sub():
assert sub(1, 1) == 0
assert sub(-1, 1) == -2
assert sub(0, 0) == 0
def test_mul():
assert mul(1, 1) == 1
assert mul(-1, 1) == -1
assert mul(0, 0) == 0
def test_div():
assert div(1, 1) == 1
assert div(-1, 1) == -1
assert div(1, 2) == 0.5
def test_div_zero_div():
with pytest.raises(ZeroDivisionError):
div(1, 0)
それではCIパイプラインを実装しましょう。今回はuv
の公式にて提供されているイメージを利用して作成してみます。公式ページは以下になるので、参照してください。
variables:
UV_VERSION: "0.5"
PYTHON_VERSION: "3.12"
BASE_LAYER: bookworm-slim
# GitLab CI creates a separate mountpoint for the build directory,
# so we need to copy instead of using hard links.
UV_LINK_MODE: copy
exceute-pytest:
stage: test
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
script:
- uv sync
- uv run pytest
こちらを実行すると以下のようなログになります。結果を見ると、uv
の設定も適切になされtest_func.py
に定義されたテスト全てが成功していることが確認できました。
ステージの利用
GitLabのCIではステージを定義することで、実行順を制御することができます。最も基本的な方法はstages
を利用し方法です。ここでは例としてジョブAとジョブBを連続して実行させてみます。
stages:
- stage_a
- stage_b
job_a:
stage: stage_a
script:
- echo "Message from stage a"
job_b:
stage: stage_b
script:
- echo "Message from stage b"
このワークフローを実行してみます。パイプラインを見ると、以下のようにjob_aが完了した後にjob_bが実行されていることがわかります。
これを応用すると、例えば一つのステージ内で複数のジョブがあるようなフローも作成できます。
stages:
- stage_a
- stage_b
- stage_c
job_a:
stage: stage_a
script:
- echo "Message from stage a"
job_b_1:
stage: stage_b
script:
- echo "Message from stage b"
job_b_2:
stage: stage_b
script:
- echo "Message from stage b"
job_b_3:
stage: stage_b
script:
- echo "Message from stage b"
job_c:
stage: stage_c
script:
- echo "Message from stage c"
実行すると、ステージAが完了した後にステージBの3つのジョブが完了してからステージCが実行されることが確認できました。
ちなみに、ステージ内でエラーを発生させると次のステージには進めないようになります。試しに、先ほどのjob_b_3
を以下のように書き換えてみます。
job_b_3:
stage: stage_b
script:
- exit 1
実行すると以下のようにjob_b_3
が失敗したことでjob_c
が実行されていないことがわかります。
GitHub Actionsと比較して
今回利用している範囲ではGitHub ActionsでCIを構築するのと大きな差は感じませんでした。実行の依存関係も定義できますし、ワークフローも事前定義されたものが提供されているので、CIの作成には困ることはないかなと思います。また、YAMLで定義するという点も同じなので独自の実装方式をキャッチアップする必要も少なく導入ハードルは低いと思います。
まとめ
今回はGitLabでCIを実装してみました。とても使い勝手が良く、CIを簡単に実装できました。私自身GitHub Actionsでの実装経験はありましたが、GitLabでも同様に実装でき、とても使い勝手がよかったです。次はCDの実装であったり、より複雑なCIも実装してみたいと思います。
Discussion