YAMADA TAISHI’s diary

ゲームについてとか私の日記とか

UnityでCI Build。GitLabRunner触ってみた!

こんにちは、やまだたいし( やまだ たいし (@OrotiYamatano) / Twitter )です。
CIに手を出したいのですが色々考えた結果GitLabCI+Runnerが良さそうだと思ったので今回触ってみました。
今回はその時の知見を共有したいと思い記事化しました。

目次


そもそもCIとは


CI(継続的インテグレーション)の略。
本記事で言うCIはCI環境のこと。

CI環境とはビルド・テスト・デプロイという一連のソフトウェアの開発サイクルを短いスパンで行う環境のことです。
その環境を提供してくれるツールをCIツールと言います。

その数多くあるツールのうちの一つのGitLabCI+Runnerの組み合わせが今回良かったように思えたので紹介です。

CIを使うメリット


Unityなどでビルドした方は分かると思いますが、 ビルドには結構な時間がかかります。
その上、ビルドしたらビルドしなかったときとは違うエラーが出てしまうことも少なくありません。
バグを出さないためには高頻度にビルドを走らせ、エラーが出ないかチェックしたほうが良いのですが、
その間ビルドでPCを占拠してしまうのは勿体ないです。
かと言ってビルドせず最後まで放っておくと修正が大変になってしまいます。

そこで登場するのがCIです。

CIツールを使ってサーバー上や別PCでビルドを走らせることで、早くエラーに気づけるようにしようという試みが行えます。

なぜGitLabCI+Runnerなのか


UnityでのCI環境はいくつかあります。
私が知っているものがいくつかあります。

・Unity Cloud Build
Github Actions
・Jenkins
・GitLabCI
・CircleCI
・codemagic
・GitLabCI+Runner

この中でGitLabCI+Runnerを選んだ理由は一番使い勝手が良さそうだったからです。
具体的に他CIを選ばなかった理由も含めて説明を書いて行こうと思います。

Unity Cloud Buildが適さない理由


小規模プロジェクトであればUnity Cloud Buildが有効だと思います。
unity.com

しかし、Windowsでのbuildが$0.02Build minと有料です。 できれば無料でやりたいし、有料なら他ツールでも良さそうです。
後最近は大分良くなってきているようですがカスタイズ性に優れていない感じあります。

Github Actionsが適さない理由


Github Actionsを使ったCIには有名所の設定はGameCIというものがあります。
こちら企業でも使われているものなんですが、 Github Actions無料枠の場合2000分/月の無料枠&スペックそんな良くないので時間かかりがちのため
適さないと考えています。
(有料枠ならありだと思います)

Jenkinsが適さない理由


コチラはカスタマイズ性に優れていますが、こちらはサーバーの機能はないため別途ビルド用のPCをセットアップする必要があります。
過去にセットアップする記事も私が上げているのですが、設定時に2つのPCを頻繁に行き来する必要があるのと、設定が意外と面倒だったので、今回は除外です。
しかしながら、カスタマイズ性が高いため、企業では今もよく使われます。

GitLabCIが適さない理由


コチラは5GB storageとチョット容量が少なめです。
また、1 か月あたりの転送量も10 GBと少なめで大量にアセットを使うゲームでは適しません。
また、オンプレ版でないとLicence認証あたりで躓いてしまいます。

CircleCIが適さない理由


CircleCIはコレまで候補に入れていなかったのですが、
2022年に入ってから、CircleCIが無料枠を大幅拡大し、1カ月あたり6000分のビルド時間が得られるようになりました。
候補に入れるのはありだと思いました。

これまでは無料枠は1ヶ月あたり1000分のビルド時間まででGithubActionsより少なく問題だったのですが、
GithubActionsより大幅にビルド可能時間が伸びたのは嬉しいですね!

Macでの無料buildはRAMが8GB、DiskSizeが200 GBですがストレージがデフォルト2GBで
30,000 クレジット無料で使えますが正直ソチラを利用してもストレージがデフォルト2GBの関係上、残念な価格になりそうです。
バイナリをたくさん使っているプロジェクトだと余裕で超えてしまいます。

www.publickey1.jp

codemagic


codemagicを使う。
FREE版ではmacOS M1 Standard VMが使えるらしい。
サイズはなんとDisk 322GB (Free Space: 122GB)!でかい!
色々入ってない状態での話でXCodeなどが入るともう少し容量は小さくなってはしまうらしいが……。
XCodeがプリインストールされたものはディスク294GB (Free Space: 31GB)ほどらしい。(それでも十分)
月当たり500minのbuildが出来るらしい……。
buildのタイムアウトは120min。

がしかし、Unity Plusもしくは Unity Pro Licenceじゃないと使えないという欠点がある。
稼げるようになったら使いたい……。

GitLabCI+Runner


ということで、GitLabCI+Runnerの組み合わせで使うことにした。
ところでRunnerとは何かというとGitLab Runnerのことで、通常GitLabCIではGitLabが構築されたサーバーなどでのbuildが行われますが、Runnerはジョブをセルフホストで行えるものです。

docs.gitlab.com

GitHubActionsにも似たような機能がありGithubActions+Self-hostedRunnerで構築しても良いのですが、GitLFSを使いたいと考えた場合にGithubでは1GBまでしか無料でGitLFSを使えません。
GitLabならばRepositoryサイズトータル(LFS含めて)で10GBまで利用可能なので、ソチラを使ったほうが良いという判断です。
またGitLab+GithubActions+Self-hostedRunnerやGithub+LFSリポジトリサーバー+GithubActions+Self-hosedRunnerなどの組み合わせも存在しそうですが、やはり構成が簡単なGitLub+GitLubIC+Runnerが良いと判断しました。

環境


今回は

Unity2021.3.11f1
GitLab
Windows ローカルホスト

での利用を想定。

作業手順目次


早速、以下手順で導入をして行こうと思います。

(GitLubへの登録・初回コミットは済んでいる想定)

1.Runnerのダウンロード
2.Runnerの登録
3.実際にRunnerを使ってみる
4.Unity側のスクリプト
5.yml(ビルドパイプライン)の設定
+α 6. Slackへの通知
+α 7. deployGateとの連携(理想)

1.GitLabRunnerのダウンロード

今回はWindowsでの利用を想定しています。

Runnerを動かしたいビルドサーバー(Windows)にてRunnerのダウンロードを行います。
以下リンクよりダウンロードを行います。
docs.gitlab.com

Install on Windows を選択
私の手元のPCはWindows10の64bitなので64bitを選択

ダウンロード。

パワーシェルを管理者権限で立ち上げ、先程インストールした gitlab-runner.exe (ダウンロードした物によって名前が違います。以後は私の環境で行うので gitlab-runner-windows-amd64.exe とします)を指定してインストールする。
コマンド的にはこんな感じ

.\gitlab-runner-windows-amd64.exe install


↓のようなメッセージが出てきたらそれは管理者権限じゃないので昇格します。

FATAL: Failed to install gitlab-runner: Access is denied.
## ちなみに昇格コマンドは↓
Start-Process powershell -verb runas

 

Runtime platform arch=amd64 os=windows pid=xxxxxxx revision=xxxxxx version=15.4.0

などのようなメッセージが問題なく表示されてれば多分OK

2. GitLabRunnerの登録

GitLabRunnerが問題なく動いたのを確認したら、Runnerと実際のRepositoryを紐づけるためにGitLabにRunnerを登録します。

↓参考
docs.gitlab.com

Runnerは様々な単位で登録出来るのですが今回はプロジェクトと直接紐づけたいと思います。
(ちなみに他には共有ランナー、グループ ランナーという単位があります)

まず、GitLabのプロジェクトRepositoryをブラウザで開きます。

次に左のサイドバー→設定→CI/CDを選びます。
(CI/CDの項目がない人は 設定→一般→CI/CDのToggleをオンに切り替える)

Runnerの項目を見ます。

そうしたら 1. で開いたパワーシェル画面で、

.\gitlab-runner-windows-amd64.exe register
を実行

そうするとURLを登録する旨が出てくるので、ブラウザのRunnnerのSpecific runnersというこうもくの 2. に表示されているURLを打ち込みます。
ちなみに今回はオンプレじゃないウェブサービスのGitLab使ってるので https://gitlab.com/ を入力。

次はtokenの入力を迫られるので、ブラウザに出ているtokenをコピペします。
ランナーの説明を入力します。
これはブラウザ側でも後で変えられるそうなのでテキトーに。

タグをつけろと言われますコチラもテキトーに(私はWindowsというタグにしました)

ランナーのメンテナンスメモの追加テキトーに

どの形式で実行するかを聞かれます。
今回は直接PCで実行したいので shell と入力します。

これでようやく登録完了です。

ブラウザを再起動すると追加したランナーが表示されているはずです。

3.実際にRunnerを使ってみる


今回用意したRunnerは specific runner と呼ばれるものになるのですが、実際に使うためにはyamlに追加記述が必要になります。

といっても tags の項目を追加し、どのランナーで起動するか指定するだけです。
タグなしで実行する方法もあるにはあるのですが、今回は割愛。

Window11の場合、コマンドを実行しても以下のようなエラーが出て実行できません。

Job failed (system failure): prepare environment: failed to start process: exec: "pwsh": executable file not found in %PATH%. Check https://docs.gitlab.com/runner/shells/index.html#shell-profile-loading for more information

理由は.Net版のパワーシェルPowerShell Coreが入っていないためです。
Windowsで使われている標準のPowerShellWindows PowerShellと呼ばれるものです。

.Net版のパワーシェルをダウンロードして解決しても良いのですが、Win11にあった挙動ではない可能性もあると考え今回はPathを修正する様にします。
Runnerのデフォルトシェルは、Windows OSに作成したRunnerフォルダーの下に自動作成されているファイル config.toml を編集することで変更できます。
(.\gitlab-runner-windows-amd64.exe installした時に生成されてるはず)

runners セクションにあるパラメーター shell を pwsh から cmd (全部小文字)に変更することで解決します。
(PowerShellでやっても良かったのですが、ymlの構文解析が一部上手く動かなかったので今回はcmdで対応)

プロセスをスタートします。

.\gitlab-runner-windows-amd64.exe start

動かしたら
今回は一旦build Testと表示させるだけのものを動かします。
リポジトリ直下に以下のようなファイルを作成。

.gitlab-ci.yml

stages:
  - build
prepare-job:
  stage: build
  tags:
    - Windows #Runnerでつけたタグ名
  script: 
    - echo "build Test"

ファイルをアップロードすると .gitlab-ci.yml が読み込まれ既に起動してあるCIが反応して実行されます。

一時停止マークが表示されて動かない場合

ランナーが上手く登録できてないかtagsの設定が間違っており、実行できるRunnerがない状態だと思われます。(もしくはジョブを待っているマシンがネットワークから切れたとか……?)

.\gitlab-runner-windows-amd64.exe restart

を行う、ウェブ側でtagの設定をし直すなどすれば直ると思います。

4.Unity側のスクリプト


コチラは通常のビルドスクリプトで大丈夫です。
以前↓の記事で紹介したJenkinsで使ったものを流用しようと思います。

orotiyamatano.hatenablog.com

今回もHTML5でのBuildのスクリプトです。

using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

    public static class BuildScript
    {
        private static void Build()
        {
            bool isSuccess;
            const string path = "/../output";
            FolderCreate(Application.dataPath+path);

            PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.WebGL, "");
            // ビルド処理
            BuildPlayerOptions buildOption = new BuildPlayerOptions
            {
                options = BuildOptions.None,
                scenes = GetAllScenePaths(),
                target = BuildTarget.WebGL,
                locationPathName = Application.dataPath+path,
            };
            UnityEditor.Build.Reporting.BuildReport reports = BuildPipeline.BuildPlayer(buildOption);
            isSuccess = (reports.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded);
            

            Debug.Log(Application.dataPath + path);
            Debug.Log("isSuccess:"+ isSuccess);
            EditorApplication.Exit(isSuccess ? 0 : 1);
            
        }

        /// <summary>
        /// 出力先フォルダ生成
        /// </summary>
        /// <param name="path"></param>
        private static void FolderCreate(string path)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }
        //GetAllScenePath
        private static string[] GetAllScenePaths()
        {
            var levels = EditorBuildSettings.scenes
                .Where(scene => scene.enabled)
                .Select(scene => scene.path)
                .ToArray();

            return levels;
        }


        [MenuItem("Build/Build Develop App")]
        private static void BuildApp()
        {
            Build();
        }
    }

↑のようなビルドスクリプトをエディターフォルダにいれてaddしてcommit・Pushします。

5.yml(ビルドパイプライン)の設定


まず、Buildを走らせるサーバーに同じバージョンのUnityをインストールしておきます。
そして、3で追加した、ymlを変更します。

.gitlab-ci.yml

stages:
  - build
prepare-job:
  stage: build
  tags:
    - Build #Runnerでつけたタグ名
  script: 
    - echo "build Test"
    - echo %UNITY_VERSION%
    - echo %CI_PROJECT_DIR%
    - chcp 65001 #そのままだとログが文字化けしてしまうので文字コード変える
    - '"C:\unity\%UNITY_VERSION%\Editor\Unity.exe" -quit -batchmode -projectPath %CI_PROJECT_DIR% -executeMethod BuildScript.Build -logFile -' #Unityのexeとプロジェクトのフォルダを選ぶ

UNITY_VERSIONは後から自由に変えられるように設定、CD/CIの変数にプロジェクトごとに変更します。

(ProjectSettingsフォルダのProjectVersion.txtの中身を見てきて自動的にUnityのダウンロードをするみたいなこともやろうと思えば出来るのですが、面倒だったので割愛)

変更し、PushするとBuildが走ります。
問題がなければエラーなく最後までBuildが行われるはずです。

+α 6. Slackへの通知


Slackから通知が受け取れるともっと楽になります。
SlackアプリとしてIncoming Webhookを追加し、ログを吐き出したいチャンネルを指定。
するとWebhook URLが出来上がるのでソレをコピーして、
GitLabのプロジェクトの設定→インテグレーション→Slack notificationsのWebhookに設定し変更を保存します。

するとログが出るようになるはずです。
また、SlackAppとしてGitLabを追加することで便利なコマンドも使えるようになるのでソチラも追加して置くと良いかも知れません。

+α 7. deployGateとの連携(理想)


暇があれば書きます。多分。知らんけど。

まとめ


以上で、GitLabRunner触ってみたを終わります。
Jenkinsより比較的設定が楽だった感じがします。
また、この仕組を利用すればUnity Test FrameworkやRoslynアナライザなどを使って詳しいテストをしてみるなど、
色々使用方法が広がりそうです。