GitLab CIをローカル環境で動かす<gitlab-ci-local>
はじめに
横浜銀行アジャイル開発チームのwatariです。
本記事では意欲的なツール、gitlab-ci-localの導入方法と活用ポイントをご紹介します。
GitLab CIをはじめ、例えばCircle CI、あるいはGithubActions。
多くの場合、まずは各サービスのCIサーバ上でジョブを実行するでしょう。
上手くいけば良いのですが、失敗した場合はエラーの調査・対応が必要です。
そのたびに、場合によって無料ではないクレジットがかかり、またコミットログが汚れていきます。
※コミットログは後でまとめられるにせよ、です。
こういった課題を解決するために、ローカル環境でCIパイプラインの挙動を再現し、効率的に検証・デバッグできる方法を検討しました。
ツール候補
-
GitLabの公式Runner(GitLab Runner)
GitLabの公式サイトによると、ローカルで動かせるということがわかったので検証しました。
確かにローカルで動くんですが、動かすにはpushしないといけません。
pushした結果、Runnerに登録されたローカルのIPを探しにいってCIがローカルで実行されるものに見えます。
ローカルのみで完結しないため、少し期待とは異なるものでした。
※1.16より前のrunnerだと、execというコマンドでローカル実行できたようです。 -
gitlab-ci-local
本記事で紹介するgitlab-ci-localです。
README冒頭の以下記載から、まさしく本課題を解決できるものと判断し、採用しました。firecow/gitlab-ci-local: Tired of pushing to test your .gitlab-ci.yml?
gitlab-ci-localのインストール
インストールはREADMEにある通りです。
WindowsのWSL(Ubuntu)環境を前提とし、Debianの手順でインストールします。
sudo wget -O /etc/apt/sources.list.d/gitlab-ci-local.sources https://gitlab-ci-local-ppa.firecow.dk/gitlab-ci-local.sources
sudo apt-get update
sudo apt-get install gitlab-ci-local
※WindowsやMacの手順もREADMEにあります!
ローカル実行
実行そのものはとても簡単でフレンドリーです。
gitlab-ci.yml
が置かれているディレクトリ(ほとんどの場合でプロジェクトルート)に移動して、以下を実行するのみです。
gitlab-ci-local {job}
複数実行も繋げるだけです。これはパイプラインの条件に縛られません。
例えばマージリクエスト作成時に走る、タグpush時に走る、といった条件の異なるジョブを一緒に動かせます。
gitlab-ci-local {job1} {job2}
その他の挙動についてはgitlab-ci-local --help
打てばusage出るので、そこから辿れます。
実行時のポイント
はまったポイント、動作の癖などをいくつか記載します。
並列実行
パイプラインというのは(少なからずbashやElixirなどのパイプからイメージすると)順々に実行されることを期待します。
ただ、これはデフォルトで並列実行のようです。
そのため以下のオプションを指定しました。
公式のほうで説明されているわけでなく少し強引ですが、シーケンシャルに動きます。
gitlab-ci-local --concurrency 1 {job1} {job2}
-
--concurrency
:並列に実行される数を指定
1を指定することで、直列になります。
dindを使用したjobの試行
docker in dockerについてです。
※dindの詳細な解説は本記事の範囲外としますので、必要に応じて関連ドキュメントをご参照ください。
これはenvファイルが必要です。幸い、公式に例があります。
PRIVILEGED=true
ULIMIT=8000:16000
VOLUME=certs:/certs/client
VARIABLE="DOCKER_TLS_CERTDIR=/certs"
これは.gitlab-ci.yml
と同じディレクトリにgitlab-ci-local-env
ファイルを置けば良いです。
設定値については、dindだけの設定ならPRIVILEGED
とULIMIT
だけで足ります。
VOLUME
やVARIABLE
は、tlsの設定があるときに必要で、certsは証明書です。
プロジェクトではno-tlsで扱っていたため、これら設定を入れていると逆に動きませんので消しました。
Issue?
GitLab CIで動くけれど、gitlab-ci-localだと動かない、という以下のような事象がありました。
rulesの記述だとartifactsが渡されない
例えばこのような記載の時、check-artifacts
ジョブのls
コマンドでhoge.txt
を確認できないためartifactsは連携されません。
- artifactsの連携
stages:
- move
- check
move-artifacts:
stage: move
image: mirror.gcr.io/cimg/node:20.19
script:
- mkdir test
- touch test/hoge.txt
- ls test/
artifacts:
paths:
- test/
expire_in: 1 hour
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
# only:
# refs:
# - merge_requests
check-artifacts:
stage: check
image: mirror.gcr.io/cimg/node:20.19
dependencies:
- move-artifacts
script:
- ls test/
ただ、yml中コメントアウトしているonlyを、rulesと置き換えるとcheck-artifacts
ジョブでhoge.txt
を確認できます。
rulesとartifactsは、あまり相関がない(あるならdependenciesやneedなど)と思っていました。
この考えのもと、onlyを使っているほうのjobは万事問題なく動くので、dependenciesとneedsを入れ替えたり変数別で定義したりと試行錯誤が続いたため、参考までに記載します。
GitLab CIにおいては、artifactsはどちらでも引き継がれます。
この辺りは、ローカルを模したものなので完璧でない部分はあるでしょう。
※ちなみに、onlyは(exceptも)非推奨とされています。
特段事情がなければ、rulesのほうを使いましょう。
本事象は、上記の簡単なサンプルで検証できました。
もう少し詳細を把握したのちに、必要であれば公式Issueに展開を検討します。
まとめ
本記事で紹介したgitlab-ci-localは、CI/CDの検証作業を効率化し、不要なリモートpushやコミットログの煩雑化を防ぐ上で非常に有用です。
特にlintやユニットテストなどの工程では、ローカル環境での迅速なフィードバックが可能となるため、開発効率向上に寄与します。
なお、本ツールを使ったCD・デプロイ工程のローカル実行には注意が必要です(ローカルマシンから対象にアクセスできる場合のみ可能ですが、問題ないかは都度確認が必要です)。
Discussion