はじめに

こんにちは、テクマトリックスの長久保です。
CI/CDパイプラインの構築は、現代の開発チームにとって非常に有効な効率化の手段の一つです。
そこで今回は、セルフホストGitLab環境でWindows端末を用いてGitLab Runnerを構築する手順と、チーム開発で活用できる.gitlab-ci.ymlの作成方法、そして構築時に遭遇しそうなトラブルシューティングなどについてまとめてみました。

前提

GitLab:Windows環境上にDocker Desktopを用いて構築。v15.0.2
Windows:Windows 11 Pro
本ブログは2025年6月5日時点の情報を元に作成しています。

今回のゴール

セルフホストのGitLab環境に、WindowsマシンをGitLab Runnerとして登録し、CI/CD環境を構築する。

そもそもGitLab Runnerとは?

GitLab Runnerとは、GitLabのCI/CDパイプラインで定義されたジョブを実際に実行するエージェントソフトウェアです。 GitLabサーバーとは別のマシンにインストールすることで、ビルドやテストなどの処理を分散実行できます。

Windows環境でGitLab Runnerを使用することで、.NETアプリケーションやWindows固有のツールを使用したビルド・デプロイが可能になります。

主な特徴:

  • 複数の実行環境をサポート。今回はWindowsで構築しましたが、Linuxはもちろん、Docker、Kubernetes等でも構築可能です。
  • 並列実行による高速化
  • タグベースのジョブ割り当て

GitLab Runnerの詳細については以下のページを参照ください。
GitLab Runner

手順

まずはWindows環境にGitLab Runnerをインストールし、シンプルなCI環境を構築します。

1.事前準備

  • Git for Windowsのインストール(Gitコマンドが実行できる状態)
  • (ユーザーアカウントを用いて実行する場合)ユーザーアカウントのユーザー名とパスワード
  • 可能であればシステムロケールを「英語(米国)」に設定(文字エンコーディング問題の回避

2.GitLab Runnerのダウンロードと配置

任意のフォルダーを作成し、公式ページから実行用のバイナリファイルを取得します。
本ブログでは、C:\GitLab-Runnerフォルダを作成し、名称をgitlab-runner.exeとして保存します。

管理者権限でPowerShellを開き、例えば以下のコマンドを実行します。実行しなくてもGitLab Runnerは動作しますが、一般ユーザーが任意のコードを実行できないように制限するために実行します。

icacls "C:\GitLab-Runner" /inheritance:r /grant:r "SYSTEM:(OI)(CI)F" /grant:r "Administrators:(OI)(CI)F"

3.GitLabへのRunner登録

Runnerディレクトリに移動し、登録コマンドを実行します。

cd C:\GitLab-Runner
.\gitlab-runner.exe register

上記のコマンドを実行すると対話式で情報の入力が求められるので、順次入力していきます。

  • GitLabサーバーのURL:https://gitlab.example.com/
  • 登録トークン:GitLab > Admin Area > Overview > Runnersをクリックし、Register an instance runnerをクリックするとトークンが発行されます。
  • Runnerの説明:blog-demo(任意の値)
  • Runnerのタグ:blog-demo(任意の値)
  • 実行エグゼキュータ:今回はshellを選択。どの項目がどういったことができるのかはExecutorsのページを参照ください。

登録が完了すると、GitLab上からもRunnerが登録されていることが確認できるようになります。

4.Windowsサービスとしてインストール

GitLabへの登録が完了したら、Windowsサービスとして登録・起動します。

.\gitlab-runner.exe install
.\gitlab-runner.exe start

ローカルシステムユーザーでサービス登録をせず、特定のユーザー権限で実行する場合は、以下のコマンドで登録します。

.\gitlab-runner.exe install --user ENTER-YOUR-USERNAME --password ENTER-YOUR-PASSWORD
.\gitlab-runner.exe start

GitLab > Admin Area > Overview > Runnersをクリックし、該当のRunnerがonlineになっていれば成功です。

5.設定ファイルの調整

設定の変更をする場合は、C:\GitLab-Runner\config.tomlを編集します。例えば並列で実行するジョブの数を増やしたい場合、以下のようにconfig.tomlの設定を変更します。

concurrent = 4  # 同時実行ジョブ数
check_interval = 0
shutdown_timeout = 0
・・・

設定変更後はサービスの再起動が必要です。
それ以外の項目の詳細については、Advanced configurationのページを参照ください。

6.シンプルなパイプラインの実行

パイプラインを実行するには.gitlab-ci.ymlを対象プロジェクトのルートに配置します。今回は単にファイルを出力するのみのyamlファイルを作成し、実行します。

stages:
  - build
  - test

build_job:
  stage: build
  tags:
    - blog-demo
  script:
    - echo "Start building the application..."
    - mkdir build
    - echo "Build process completed." > build/build.log
  artifacts:
    paths:
      - build/  # build フォルダを次のジョブに引き継ぐ

test_job:
  stage: test
  tags:
    - blog-demo
  script:
    - echo "Start running tests..."
    - type build\build.log

該当プロジェクトに対して更新すると、自動的にパイプラインが実行されます。

パイプラインの詳細な記載方法については、CI/CD pipelinesページを参照ください。

よくあるトラブルと解決方法

まず、Troubleshooting GitLab RunnerWindows troubleshootingのページを参照ください。
いくつか注意したほうがよさそうな点をピックアップします。

ネットワーク接続

RunnerマシンからGitLabサーバーへの通信へHTTP/HTTPSでの接続ができることが必要となります。
また、通常はRunnerはHTTP/HTTPSでリポジトリを取得するため、こちらも同じ80/443ポート経由の通信となり、特別な許可は不要です。ただし、SSHクローンを行う場合は、TCP接続をするためデフォルト設定の場合22ポートの解放も必要です。
プロキシについては、http_proxy環境変数を読み取ってくれるようです。そのため、HTTP_PROXYとHTTPS_PROXYの環境変数にプロキシサーバーの情報を登録します。

Dockerコンテナを用いたRunner登録の場合、Running GitLab Runner behind a proxyも併せて参照ください。

証明書の構成

GitLab Runnerはデフォルトではシステム証明書ストアを読み取り、システムに保存された証明書認証局(CA)に基づいてGitLabサーバーを検証します。
ただし、セルフホストGitLabが自己署名証明書やプライベートCAで署名された証明書を使用している場合、以下のエラーが発生することがあります。

Couldn't execute POST against https://hostname.tld/api/v4/jobs/request:
Post https://hostname.tld/api/v4/jobs/request: x509: certificate signed by unknown authority

この場合、例えば以下のように、CA証明書を指定してWindowsサービスに登録する、またはWindowsの証明書ストアに追加するといった対応で解決できます。

# 例:CA証明書を指定してWindowsサービスに登録
.\gitlab-runner.exe register --tls-ca-file="C:\certs\company-ca.crt"

# 例:管理者権限で実行
Import-Certificate -FilePath "C:\certs\company-ca.crt" `
  -CertStoreLocation Cert:\LocalMachine\Root

詳しくはこちらのリンクを参照ください。
Supported options for self-signed certificates targeting the GitLab server

文字化け

ビルドログで日本語が「?????」と表示されたり、日本語ファイル名が正しく認識されない場合があります。
こちらについては以下のIssueで議論されています。
Add support for non-UTF8 character set
本ブログ作成の2025/6/5時点で公式から案内されている対応方法としては、「システムロケールを英語(米国)にする」になります。

実行コマンド

GitLab Runnerがサポートしているshellの種類にも注意が必要です。
Windows環境の場合、GitLab Runner 14.0以降、デフォルトはpwshとなっているので、pwshを利用できるようにするか、もしくはconfig.tomlで設定を変更する必要があります。

また、batファイルを実行する場合は注意が必要です。

上記のように、公式ドキュメントで詳細としてissue 1025が案内されていますが、案内先に従ってconfig.tomlのshell = “cmd”に変更し実行すると次のようにエラーになりました。shell = “cmd”についてはGitLab 11.11で非推奨になり、17.0で完全に廃止されました。
Remove support for the CMD shell for Windows from GitLab RunnerというIssueでもこちらの話題について触れられているので、併せて参照ください。

CMDを実行したい場合、こちらのCall CMD From Default PowerShell in GitLab CIの内容が参考になるかと思います。
また、shell = “pwsh”のまま、以下の様な形でもbatファイルは実行可能です。

  script:
    - cmd /c exec.bat    

その他

実行ユーザーの権限(ローカルシステムアカウントとユーザーアカウント)や、パス長(WindowsのMAX_PATH制限(260文字))などのエラーなども考えられます。
また、Windowsのドキュメントは情報が更新されていなかったり、情報が散っていたりするため注意が必要だと感じました。

運用上の懸念事項

タイムアウト設定について

タイムアウトについては「最大実行時間」(実行中のジョブのタイムアウト時間)と「待機中の待ち時間」(キューにたまっている状態)があり、異なる概念として扱われるようです。

「最大実行時間」については、以下に記載の通り、デフォルトで60分です。
また、プロジェクト単位で10分から1ヶ月の間で設定が可能です。
Set a limit for how long jobs can run

「待機中の待ち時間」に関して、現在は待機時間が1時間を超えると自動的に失敗扱いになります。
こちらは問題としてGitLabのIssuesに起票されています。
Separate CI queue time from CI job timeout

同じようにForumにも同様の問題が記載されていますが、こちらでも具体的な解決策の記述はありませんでした。
CI Queue times

Separate CI queue time from CI job timeoutのIssueに記載されている通り、GitLab Runnerではジョブのpending時間の最大値は1時間で固定になっており、これを超えたジョブはstuck(実行不能ジョブ)と判定されるようです。また、stuck状態のジョブを除去するためのタスクが定期的(デフォルトでは1時間に1回)に実行されており、このタスクがstuck状態のジョブをfailedにしているようです。
回避方法につきましては、公式ドキュメントからは見つけることが出来ませんでした。
また、Issueが現在Openになっていることから、現在も再現する問題かと思われます。そのため、基本的に「待機中の待ち時間」を正式な方法で一時間以上にする方法はなさそうです。
補足情報として、ハードコーディングされている以下の値をコードから直接修正することにより、ペンディング時間を延ばすことが出来るようです。しかし、こちらの挙動について、効果についても様々な意見があるようです。詳しくはIssueを参照ください。

修正箇所としては以下になりますが、公式のドキュメントでも明確な回避策とは述べられていないため、あくまで参考情報にとどめておく方が無難かと思います。また、バージョンアップの都度、ハードコーディングされているコードを修正するのは現実的ではないでしょう。
drop_pending_service.rbコード内の該当の箇所

このpending時間の判定については、以下のCronで行われているようなので、こちらのCronの判定をすべて無効にすることで本現象については回避できるかもしれません。
Admin Area -> Monitoring -> Background Jobs -> Cron
ただ、それ以外の影響範囲についてすべて検証することが出来ないため、私個人としては推奨いたしません。

ジョブが実行される順番について

GitLab RunnerのスコープにはInstance runnersGroup runnersProject runnersがあります。今回上記で作成したのはInstance runnersになります。
Instance runnersの場合、ジョブが実行される順は「fair usage queue」という形式で実行されます。
検証用に、以下のstageを3つもつパイプラインを作成し、「ForBlog1」「ForBlog2」の2つプロジェクトに設定し、ジョブを順にキューに入れます。

stages:
  - stage1
  - stage2
  - stage3

stage1_job:             
  stage: stage1
  tags:
    - blog-demo
  script:
    - pwsh -NoProfile -Command "Start-Sleep -Seconds 10"

stage2_job:           
  stage: stage2
  tags:
    - blog-demo
  script:
    - pwsh -NoProfile -Command "Start-Sleep -Seconds 10"

stage3_job:            
  stage: stage3
  tags:
    - blog-demo
  script:
    - pwsh -NoProfile -Command "Start-Sleep -Seconds 10"

以下は「ForBlog1」のstage1_jobが実行完了したタイミングになります。「ForBlog1」のstage1_job完了後に「ForBlog1」のstage2_jobが実行されるのではなく、「ForBlog2」のstage1_jobが実行されます。そして、次は「ForBlog1」のstage2_jobが実行されます。

Statusのpassedとrunning、pendingに注目

こちらの仕様については、How instance runners pick jobsで解説されています。

FIFO方式での実行や、特定のジョブを優先的に実行したいといった場合は、Instance runnersではなく、Group runners、Project runnersで作成する必要があります。

ジョブ一覧の参照箇所について

どれだけジョブがキューに溜まっているか、また、上記の「fair usage queue」での実行順もあり、自分のジョブがいつ終わるのかという確認をしたくなるタイミングもあると思います。

個別のプロジェクトのジョブの実行状況については該当のプロジェクト > CI/CDから参照することが可能ですが、全体のジョブの実行状況について確認するためにはAdminエリアの参照権限が必要です。

ジョブのキューの待ち時間

今回「ジョブが実行される順番について」セクションの内容を検証していて、気になった点になります。ジョブが完了してから次のジョブの実行が始まるまで、若干の待ち時間が発生していました。
Forumで類似の問題を調べたところ、Job queue timesというスレッドが見つかりました。

ランナーが完了するまでに 30 秒かかるジョブが、スケジュールされるまでに 4 ~ 5 分間停止することがよくあります。
時には本当に極端な場合があり、私のジョブの 1 つは、ランナーがアイドル状態だったときに、なんと 45 分後に実行するようにスケジュールされました。

https://forum.gitlab.com/t/job-queue-times/77853/1 より機械翻訳をして引用(2025/06/5)

config.tomlで対応できそうではありますが、記載内容を確認する限り正式な解決策ではないように見えます。タイムアウト設定についてでも触れましたが、キューに溜まっている時間が長いとタイムアウト処理がされてしまうため、実運用中に実行されないジョブが発生する懸念があるように思います。

まとめ

今回、セルフホストGitLab環境でのWindows GitLab Runner構築について、実際の手順とトラブルシューティングをまとめました。

ポジティブな点として、非常にスムーズにWindowsのサービスとしてGitLab Runnerを構築することができました。
Windows環境では文字エンコーディングやパス長制限など、Linux環境では遭遇しない問題に対処する必要がありますが、 今回紹介した対策を事前に実施することで、多くのトラブルを回避できると思います。

ただその一方ネガティブな点もあります。
今回本ブログ作成にあたり、GitLabのドキュメントを確認した際に、非常に情報が散っているという感想を持ちました。
また、運用上の懸念事項として記載しましたが、実運用上問題になりそうなIssueも残っている印象です。
単に構築して実行するという点ではトラブルなく構築できましたが、 実運用をしていると問題になりそうな点も散見されましたので、注意が必要という感想を持ちました。

構築にあたり参考になれば幸いです。

By nagakubo

主にCI環境構築をメインで担当しています。 Certified CloudBees Jenkins Engineer (CCJE)