Зачем нужна автоматическая сборка проекта никому объяснять не надо.
В случае со сборкой проектов под Unity это особенно актуально, так как средненький проект, например, под WebGL собирается на рабочей машине 5-7 минут, полностью её завешивая.
Не так давно вышла версия Unity под Linux, что дало принципиальную возможность настроить автоматическую сборку при помощи Gitlab CI (которая основана на docker образах).
Я хочу поделиться своим опытом такой настройки.
Часть первая — собираем докер образ с Unity
Нам понадобится докер-образ, содержащий Unity.
Ниже я приложу готовый докер файл.
Но сначала несколько комментариев, из которых должно стать понятно, зачем в докерфайле такая экзотика, как gnome или tightvncserver.
Итак, основная проблема при использовании докер-образа с юнити «в лоб»: юнити после установки требует ручной активации. Причем работает активация только в графическом режиме. К счастью, делать это нужно только один раз.
Поэтому план такой:
- Собираем образ с Unity, содержащий графическую среду и VNC-сервер
- Запускаем из него контейнер
- Подключаемся к VNC серверу
- Запускаем Unity вручную и активируем ее
- Сохраняем контейнер в новый образ, в котором будет содержаться активированная копия unity
Ниже мой докер файл. Он собирает образ для unity5.6
Я не меняю версию Unity на более новую, потому что сам я всё проверял именно с этой версией.
Но вы можете попробовать заменить
beta.unity3d.com/download/6a86e542cf5c/unity-editor_amd64-5.6.1xf1Linux.deb
на другую версию.
Актуальный список можно найти тут:
FROM ubuntu:16.04
RUN apt-get update -qq
RUN env DEBIAN_FRONTEND=noninteractive apt-get -qq install -y ubuntu-desktop gnome-panel gnome-settings-daemon metacity nautilus gnome-terminal --no-install-recommends curl gconf-service lib32gcc1 lib32stdc++6 libasound2 libc6 libc6-i386 libcairo2 libcap2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libfreetype6 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libgl1-mesa-glx libglib2.0-0 libglu1-mesa libgtk2.0-0 libnspr4 libnss3 libpango1.0-0 libstdc++6 libx11-6 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxtst6 zlib1g debconf npm xdg-utils lsb-release libpq5 xvfb git vim xrdp tightvncserver
&& rm -rf /var/lib/apt/lists/* && apt-get purge
RUN echo "Downloading Unity3D installer...."
&& mkdir /app
&& curl -o /app/unity_editor.deb "http://beta.unity3d.com/download/6a86e542cf5c/unity-editor_amd64-5.6.1xf1Linux.deb"
&& echo "Unity3D installer downloaded."
# To make a "min" version of this image build, omit this dpkg line. It saves a lot of space, but you'll need to dpkg it yourself when you use the image.
&& dpkg -i /app/unity_editor.deb && ln -s /opt/Unity/Editor/Unity /usr/local/bin/unity && rm -rf /app
RUN mkdir -p .vnc .cache/unity3d .local/share/unity3d
ENV USER root
ADD xstartup /root/.vnc/xstartup
COPY runUnity.sh /root
RUN chmod 755 /root/.vnc/xstartup && chmod 755 /root/runUnity.sh && sed -i -e 's/r//g' /root/.vnc/xstartup && sed -i -e 's/r//g' /root/runUnity.sh
# VNC
EXPOSE 5901
ENTRYPOINT ["bash"]
А вот два скрипта, которые используются этим докерфайлом:
#!/bin/sh
export XKL_XMODMAP_DISABLE=1
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &
gnome-panel &
gnome-settings-daemon &
metacity &
nautilus &
gnome-terminal &
#!/bin/sh
xvfb-run --server-args="-screen 0 1024x768x24" /opt/Unity/Editor/Unity -batchmode -logfile -force-opengl -quit -projectPath /project -executeMethod WebGLBuilder.build
Шаг 1
Складываем эти три файла в одну директорию.
Шаг 2
Собираем докером образ (он будет содержать неактивированную копию Unity)
Я делал так:
docker build -t softaria/unity3d
Шаг 3
Запускаем контейнер из этого образа:
docker run --privileged --cap-add=SYS_ADMIN -ti -p "5901:5901" --entrypoint=bash softaria/unity3d
Порт нам нужен, чтобы достучаться до VNC сервера.
Зачем нужны привилегии я уже не помню, но без них оно не работает.
В качестве entrypoint указываем bash чтобы сразу зайти в запущенный контейнер.
Шаг 4
Теперь внутри контейнера нужно запустить vnc сервер:
vncserver :1
Оно попросит придумать пароль. Ок — придумываем.
Как видно на скриншоте, сервер пишет путь до своего лог файла.
Можно заглянуть в этот лог, чтобы убедиться, что стартовал gnome (впрочем, можно и не заглядывать).
Шаг 5
Теперь нам нужен VNC клиент. Любой.
Если вы используете Windows, то можно взять вот этот
Заходим на свой сервер (надо указывать IP + port) например:
123.123.133.123:5901
Порт будет именно 5901. А вот IP – ваше.
Шаг 6
Запускаеи через gnome меню Unity
Логинимся, и активируем лицензию.
Выходим
Шаг 7
Останавливаем vncserver (естественно, внутри докер контейнера — там же, где его запускали)
vncserver -kill :1
Это стоит сделать, чтобы не засорять наш будущий образ с активированной Unity всяким ненужным барахлом.
Шаг 8
Теперь на машине, где запущен докер контейнер открываем другой терминал. Нам нужно сохранить новый докер-образ из работающего контейнера.
Для этого не выходя из контейнера, в другом терминале находим этот контейнер, просто запустив docker ps и копируем себе ид этого контейнера.
Далее сохраняем контейнер в новый образ:
docker commit {ид-конейнера} softaria/unity3d:licensed
Теперь у нас есть докер образ с активированной Unity.
Можно залить его в registry.
Проверяем образ
После этого шага стоит проверить работоспособность образа вне gitlab.
Сделать это можно так:
Пусть в /root/myProject лежат исходники нашего проекта, которые надо собрать.
Мы знаем (или сейчас узнаем), что для сборки из командной строки в исходники проекта нужно поместить специальный класс, конфигурирующий сборку.
Поместить его надо в Assets/Editor
И называться класс и его метод должны именно так, как в моем примере ниже (поскольку эти имена упоминались в нашем скрипте runUnity.sh. Помните :“-executeMethod WebGLBuilder.build” ?)
public class WebGLBuilder {
static void build()
{
//Здесь нужно указать все пути к вашим сценам
string[] scenes = { "Assets/main.unity" };
//Второй аргумент — название папки в которую будет помещена сборка, Третий — тип сборки (в нашем случае WebGL, четвертый обычно None)
BuildPipeline.BuildPlayer(scenes, "WebGL-Dist", BuildTarget.WebGL, BuildOptions.None);
}
}
Далее запускаем конейнер из нашего образа так:
docker run --privileged --cap-add=SYS_ADMIN -v "/root/myProject:/project" softaria/unity3d:licensed /root/runUnity.sh
И убеждаемся, что сборка работает.
Если сборка заработала, переходим к следующему пункту:
Часть вторая. Сборка проекта в Gitlab.CI
Ниже я приведу свой .gitlab-ci.yml
Но сначала снова несколько комментариев — почему он такой безобразный нетривиальный.
Попытка сделать сборку на основе только что собранного образа (softaria/unity3d:licenced)
провалилась — возникала ошибка "/usr/bin/sh: /usr/bin/sh: cannot execute binary file gitlab"
Точных ее причин я уже не помню, но простым и работающим решением оказалось использовать стандартный image – docker, а свой образ запускать уже внутри него.
Второй проблемой оказалась невозможность передать свои исходники внутрь контейнера с Unity при помощи volume. Внутри гитлаба volumes просто не заработали. Возможно, тут есть какой-то workaround, но мне было лень разбираться проще скопировать исходники внутрь контейнера с юнити, а потом забрать результат обратно.
Не претендую на элегантность этих решений, но вот вам
stages:
- build
build:
image: docker
stage: build
before_script:
#логинимся в локальный докер регистри
- docker login -u $CI_REGISTRY_USER -p $CI_BUILD_TOKEN $CI_REGISTRY
script:
#забираем оттуда образ с юнити
- docker pull docker.softaria.com/games/unity:licensed5.6r6
#создаем из образа контейнер, но не запускаем его пока
- docker create --name ${CI_BUILD_REF}_lines --privileged --cap-add=SYS_ADMIN --entrypoint=bash docker.softaria.com/games/unity:licensed5.6r6 /root/runUnity.sh
# копируем исходники в контейнер
- docker cp $(pwd) ${CI_BUILD_REF}_lines:/project
#запускаем контейнер
- docker start -a -i ${CI_BUILD_REF}_lines
#на всякий случай чистим локальную директорию
- rm -rf nginx/client
#копируем собранный проект в почищенную локальную директорию
- docker cp ${CI_BUILD_REF}_lines:/project/WebGL-Dist/ nginx/client/
#две следующие строки специфичны для моего проекта — они создают новый докер образ на основе образа nginx, который содержит только что созданную сборку и складывают этот образ в локальный регистри. Вы можете их просто убрать (тогда результатом сборки будет только артифакт) или заменить на что-то свое.
- docker build -t $CI_REGISTRY_IMAGE --build-arg build_name=$CI_PIPELINE_ID nginx
- docker push $CI_REGISTRY_IMAGE
after_script:
- docker rm ${CI_BUILD_REF}_lines
- docker logout $CI_REGISTRY
tags:
- docker
artifacts:
name: "${CI_BUILD_REF_NAME}_${CI_BUILD_REF}"
expire_in: 2 weeks
paths:
- nginx/client
only:
- master
На этом все. Если возникнут вопросы, постараюсь ответить в комментариях.
Автор: softaria