51代プログラミング研究会のしくがわです。Web班長をしてます。 弊サークルでは、ゲーム開発において主にUnityが用いられております。DevOps的な観点からUnity開発を見るならば、特に課題として炙り出されるのはCI/CDを活用したオートメーションビルドでしょう。殊、Unityのリモートビルドに関してはUnity公式から以下のようなツールが提供されており、導入は容易です。
しかし、これは基本有料なので、趣味やサークルの開発において気軽に用いられるものではありません。私達のサークルにおいてもそれは例外ではありませんでした。そこで、自宅サーバーでUnityのリモートビルド環境を作成してみました。
必要なもの
- Macサーバー
- Jenkins
- minio
- Slack (通知用。あると便利)
まず、私がリモートビルドを導入したプロジェクトはWindows向けのみにビルドされるVRゲームでした。UnityでWindows向けにビルド出来るのはMacのみです。Linux向けのUnityは存在しておりますが、Windows向けの実行可能ファイルを生成出来ません。
JenkinsはDevOpsに関わったことがある人ならおそらくほとんどの人が使ったことのあるであろうオープンソースのタスクスケジューラーです。CIツールだと有名なものにはCircle CIなんかがありますが、これらは基本的にUnityのビルド機能を持たないため、Jenkinsを用いて一からビルド環境を構築する必要があります。
minioはオープンソースのクラウドストレージです。Amazon S3互換のAPIが使用可能であるため、プライベートでS3 Bucketのようなものが構築可能です。ビルド済みファイルを外からダウンロードすることができるようにするために必要となります。
余談ですが、minioを使用するフェイズをパイプラインに組み込むならばCI(継続的インテグレーション)ではなく、CD(継続的デリバリー)になります。
手順
- Jenkins をサーバーにインストールして起動する
Macの場合ならばHomebrewを使って導入出来ます。jenkins --daemon
で簡単に起動できます。
- Webサーバーの設定
8080番ポートで起動します。外からjenkinsにアクセス出来るように、お使いのWebサーバーに合わせて設定してください。
- ビルド用のスクリプトを作成する
UnityはEditor Scriptを使用してエディタを拡張することが出来ます。Editor Scriptとしてビルド手順を定義し、コマンドからUnityの機能を呼び出すことが出来るようにします。スクリプトは以下のような感じになります。自分の環境に合わせて適宜書き換えてください。
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; using UnityEditor; using UnityEditor.Build.Reporting; struct Target { public BuildTarget target{ get; set; } public string extension{ get; set; } public Target(BuildTarget t, string e){ target = t; extension = e; } }; public class CLIBuild : MonoBehaviour { private static Target targetWindows; public static void execute() { var sceneList = CLIBuild.getSceneList(); CLIBuild.targetWindows = new Target(BuildTarget.StandaloneWindows64, ".exe"); CLIBuild.buildExecute(sceneList, targetWindows); } private static List<string> getSceneList(){ var sceneList = new List<string>(); sceneList = EditorBuildSettings.scenes .Where(scene => scene.enabled) .Select(scene => scene.path) .ToList(); return sceneList; } private static void buildExecute(List<string> sceneList, Target t){ var currentDateTime = DateTime.Now; var errorMessage = BuildPipeline.BuildPlayer( sceneList.ToArray(), "path/to/project/" + ToUnixTime(currentDateTime) + "/projectname.exe", t.target, BuildOptions.None ); } private static long ToUnixTime(DateTime dateTime){ var UNIX_EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); double nowTicks = (dateTime.ToUniversalTime() - UNIX_EPOCH).TotalSeconds; return (long)nowTicks; } }
また、Mac上ではWindows向けのビルドにScripting BackendとしてIL2CPPを使用することが出来ないので、Monoを使ってください。
- JenkinsとGithubのIntegrationを設定する
GithubにpushしたらGithub Webhookが発火してJenkinsが走る仕組みを作ります。Jenkinsの設定は以下のような感じ。リポジトリの設定如何ではGithub側でアクセストークンを作成し、Jenkins側にそれを預ける必要があります。
Github Webhook側の設定においては、Jenkins側でBasic認証情報を作成し、それをGithubに預ける必要があります。Jenkins側のアクセストークンは認証情報から作成可能です。作成後、Github Webhook側のPayload URL欄に以下のように設定します。
https://<JENKINS_USERNAME>:<JENKINS_TOKEN>@<JENKINS_URL>/job/<PROJECT_NAME>/build
- Unity3dBuild Pluginの導入
JenkinsにUnity3dBuild Pluginを導入します。
Unity3dBuilder Plugin - Jenkins - Jenkins Wiki
これは入れなくても構わないのですが、入れたほうが便利なので入れました。JenkinsのGlobal Tool ConfigrationからUnityのInstall Pathを設定します。
- Trigger時に走らせるコマンドの設定
とりあえず最適限、こんな感じに設定すればいいです。ログを外部に出力した場合は--logFile
オプションをつけてください。
- minioの導入
これもHomebrewで導入できます。MINIO_ACCESS_KEY/MINIO_ACCESS_SECRETを適当に設定してください。
~ $ export MINIO_ACCESS_KEY=<ACCESS_KEY> ~ $ export MINIO_ACCESS_SECRET=<ACCESS_SECRET>
でいいです。以下のコマンドで実行します。
~ $ minio server --address localhost:9001 /path/to/project
デフォルトでは9000番ポートで起動するのですが、私の環境ではすでに9000番ポートが使用されていたので--address
オプションを付けました。起動画面はこんな感じです。
終わりに
Unityのリモートビルドに関する情報がググってもあんまりなかったので少しでも貢献できればと思い、記事を作成致しました。UnityでもDevOpsしていきましょう。