使用 Docker 搭建 Unity 引擎开发环境
Unity 开发环境虽然不是最典型的 Docker 应用场景,但对于持续集成、自动化构建和多平台测试来说,Docker 化 Unity 环境有着显著优势。以下是详细的实现方法:
1. Unity 容器化挑战与解决方案
主要挑战
Unity 容器化面临几个关键挑战:
- Unity 需要图形界面,而 Docker 容器通常是无头的
- Unity 授权和许可验证复杂
- 资源需求较高(GPU 访问、大量内存)
- 跨平台构建复杂
解决方案概述
我们将主要聚焦于以下场景的 Docker 化:
- Unity 项目的自动构建
- 持续集成与测试
- 服务器端构建与部署
- 无头模式下的游戏服务器
2. 基础 Unity 构建容器
Dockerfile 创建
创建一个基础的 Unity 构建环境 Dockerfile:
FROM ubuntu:22.04
# 避免交互式提示
ARG DEBIAN_FRONTEND=noninteractive
# 安装依赖
RUN apt-get update && apt-get install -y \
curl \
wget \
zip \
unzip \
xvfb \
libglu1-mesa \
libglib2.0-0 \
libxcursor1 \
libxrandr2 \
libasound2 \
libnss3 \
libpci3 \
libxcomposite1 \
libxdamage1 \
libgl1-mesa-glx \
libcanberra-gtk-module \
gnupg \
software-properties-common \
&& rm -rf /var/lib/apt/lists/*
# 创建Unity安装目录和工作目录
RUN mkdir -p /opt/unity /unity_project
# 设置工作目录
WORKDIR /unity_project
# 安装特定版本的Unity
# 注意:这里使用Unity Hub命令行安装特定版本
ARG UNITY_VERSION=2022.3.12f1
ARG UNITY_CHANGESET=a7ad3FC73a2F
RUN wget -qO - https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg \
&& mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg \
&& sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-$(lsb_release -cs)-prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list' \
&& apt-get update \
&& apt-get install -y dotnet-sdk-7.0 \
&& wget -O UnitySetup https://beta.unity3d.com/download/${UNITY_CHANGESET}/UnitySetup-${UNITY_VERSION} \
&& chmod +x UnitySetup \
&& ./UnitySetup --unattended --install-location=/opt/unity --components=Unity \
&& rm UnitySetup
# 设置环境变量
ENV PATH="/opt/unity/Editor:${PATH}"
ENV UNITY_PATH="/opt/unity/Editor/Unity"
# 设置一个卷,用于挂载Unity项目
VOLUME ["/unity_project"]
# 默认命令,显示Unity版本
CMD ["bash"]
3. 高级 Unity CI/CD 容器
针对持续集成的更完善配置:
FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
ARG UNITY_VERSION=2022.3.12f1
ARG UNITY_CHANGESET=a7ad3FC73a2F
ARG UNITY_LICENSE_FILE=Unity_v2022.x.ulf
# 安装基础依赖
RUN apt-get update && apt-get install -y \
curl wget gzip ca-certificates xvfb \
libglu1 libxcursor1 libxrandr2 libnss3 libasound2 libpci3 \
libxcomposite1 libxdamage1 libasound2 libgtk-3-0 \
&& rm -rf /var/lib/apt/lists/*
# 安装Unity
WORKDIR /tmp
RUN wget -q https://beta.unity3d.com/download/${UNITY_CHANGESET}/UnitySetup-${UNITY_VERSION} -O UnitySetup && \
chmod +x UnitySetup && \
./UnitySetup --unattended --install-location=/opt/unity --components=Unity,Windows-Mono,Mac-Mono,Linux-Mono && \
rm UnitySetup
# 设置环境变量
ENV PATH="/opt/unity/Editor:${PATH}"
ENV UNITY_PATH="/opt/unity/Editor/Unity"
# 添加激活和构建脚本
COPY scripts/activate_unity.sh /usr/local/bin/activate_unity
COPY scripts/build_unity.sh /usr/local/bin/build_unity
RUN chmod +x /usr/local/bin/activate_unity /usr/local/bin/build_unity
# 设置工作目录
WORKDIR /unity_project
VOLUME ["/unity_project"]
# 默认入口点
ENTRYPOINT ["/usr/local/bin/build_unity"]
激活脚本 (activate_unity.sh)
#!/bin/bash
set -e
# 检查环境变量
if [ -z "$UNITY_USERNAME" ] || [ -z "$UNITY_PASSWORD" ]; then
echo "请设置 UNITY_USERNAME 和 UNITY_PASSWORD 环境变量"
exit 1
fi
# 使用 xvfb 创建虚拟显示
Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99
# 使用Unity命令行登录
echo "正在登录 Unity 账户..."
"$UNITY_PATH" -batchmode -nographics -logFile - -quit -username "$UNITY_USERNAME" -password "$UNITY_PASSWORD"
echo "Unity 激活完成"
构建脚本 (build_unity.sh)
#!/bin/bash
set -e
# 默认参数
BUILD_TARGET=${1:-"StandaloneLinux64"}
BUILD_PATH=${2:-"./Build"}
UNITY_PROJECT_PATH=${3:-"."}
# 使用 xvfb 创建虚拟显示
Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99
echo "开始构建 Unity 项目,目标平台:$BUILD_TARGET"
echo "构建路径:$BUILD_PATH"
echo "项目路径:$UNITY_PROJECT_PATH"
# 执行Unity构建
"$UNITY_PATH" \
-batchmode \
-nographics \
-logFile /dev/stdout \
-projectPath "$UNITY_PROJECT_PATH" \
-buildTarget "$BUILD_TARGET" \
-executeMethod BuildScript.PerformBuild \
-buildPath "$BUILD_PATH" \
-quit
echo "Unity 构建完成!"
4. Docker Compose 集成
创建一个 docker-compose.yml
文件以整合 Unity 构建环境:
version: '3.8'
services:
unity-builder:
build:
context: .
dockerfile: Dockerfile
args:
UNITY_VERSION: 2022.3.12f1
UNITY_CHANGESET: a7ad3FC73a2F
container_name: unity-builder
volumes:
- ./:/unity_project
- unity_cache:/root/.cache/unity3d
environment:
- UNITY_USERNAME=${UNITY_USERNAME}
- UNITY_PASSWORD=${UNITY_PASSWORD}
- UNITY_SERIAL=${UNITY_SERIAL}
- BUILD_TARGET=StandaloneLinux64
- BUILD_PATH=./Builds/Linux
command: ["StandaloneLinux64", "./Builds/Linux", "."]
unity-builder-windows:
build:
context: .
dockerfile: Dockerfile
container_name: unity-builder-windows
volumes:
- ./:/unity_project
- unity_cache:/root/.cache/unity3d
environment:
- UNITY_USERNAME=${UNITY_USERNAME}
- UNITY_PASSWORD=${UNITY_PASSWORD}
- UNITY_SERIAL=${UNITY_SERIAL}
- BUILD_TARGET=StandaloneWindows64
- BUILD_PATH=./Builds/Windows
command: ["StandaloneWindows64", "./Builds/Windows", "."]
profiles: ["windows"]
unity-builder-android:
build:
context: .
dockerfile: Dockerfile.android
container_name: unity-builder-android
volumes:
- ./:/unity_project
- unity_cache:/root/.cache/unity3d
- android_sdk:/opt/android-sdk
environment:
- UNITY_USERNAME=${UNITY_USERNAME}
- UNITY_PASSWORD=${UNITY_PASSWORD}
- UNITY_SERIAL=${UNITY_SERIAL}
- BUILD_TARGET=Android
- BUILD_PATH=./Builds/Android
command: ["Android", "./Builds/Android", "."]
profiles: ["android"]
unity-test:
build:
context: .
dockerfile: Dockerfile
container_name: unity-test
volumes:
- ./:/unity_project
- unity_cache:/root/.cache/unity3d
environment:
- UNITY_USERNAME=${UNITY_USERNAME}
- UNITY_PASSWORD=${UNITY_PASSWORD}
- UNITY_SERIAL=${UNITY_SERIAL}
command: ["/usr/local/bin/run_tests.sh"]
profiles: ["test"]
volumes:
unity_cache:
android_sdk:
5. Android 构建支持
创建一个额外的 Dockerfile 以支持 Android 平台:
FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
ARG UNITY_VERSION=2022.3.12f1
ARG UNITY_CHANGESET=a7ad3FC73a2F
ARG ANDROID_SDK_VERSION=commandlinetools-linux-9477386_latest.zip
# 安装基础依赖
RUN apt-get update && apt-get install -y \
curl wget gzip openjdk-11-jdk ca-certificates xvfb \
libglu1 libxcursor1 libxrandr2 libnss3 libasound2 libpci3 \
libxcomposite1 libxdamage1 libasound2 libgtk-3-0 \
&& rm -rf /var/lib/apt/lists/*
# 安装Android SDK
RUN mkdir -p /opt/android-sdk/cmdline-tools && \
wget -q https://dl.google.com/android/repository/${ANDROID_SDK_VERSION} -O android-sdk.zip && \
unzip -q android-sdk.zip -d /opt/android-sdk/cmdline-tools && \
mv /opt/android-sdk/cmdline-tools/cmdline-tools /opt/android-sdk/cmdline-tools/latest && \
rm android-sdk.zip
# 设置Android环境变量
ENV ANDROID_HOME=/opt/android-sdk
ENV PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools
# 安装Android组件
RUN yes | sdkmanager --licenses && \
sdkmanager "platform-tools" "platforms;android-33" "build-tools;33.0.2" "ndk;25.2.9519653"
# 安装Unity
WORKDIR /tmp
RUN wget -q https://beta.unity3d.com/download/${UNITY_CHANGESET}/UnitySetup-${UNITY_VERSION} -O UnitySetup && \
chmod +x UnitySetup && \
./UnitySetup --unattended --install-location=/opt/unity --components=Unity,Android && \
rm UnitySetup
# 设置环境变量
ENV PATH="/opt/unity/Editor:${PATH}"
ENV UNITY_PATH="/opt/unity/Editor/Unity"
# 添加激活和构建脚本
COPY scripts/activate_unity.sh /usr/local/bin/activate_unity
COPY scripts/build_unity.sh /usr/local/bin/build_unity
RUN chmod +x /usr/local/bin/activate_unity /usr/local/bin/build_unity
# 设置工作目录
WORKDIR /unity_project
VOLUME ["/unity_project", "/opt/android-sdk"]
# 默认入口点
ENTRYPOINT ["/usr/local/bin/build_unity"]
6. Unity 测试运行器
创建 Unity 测试脚本 (run_tests.sh):
#!/bin/bash
set -e
# 使用 xvfb 创建虚拟显示
Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99
echo "开始运行 Unity 测试..."
# 执行Unity测试
"$UNITY_PATH" \
-batchmode \
-nographics \
-logFile /dev/stdout \
-projectPath "." \
-runTests \
-testPlatform PlayMode \
-testResults /unity_project/test-results.xml \
-quit
echo "Unity 测试完成!"
7. Unity 项目准备
为了让 Docker 构建正常工作,需要在 Unity 项目中添加构建脚本。创建 Assets/Editor/BuildScript.cs
:
using UnityEditor;
using UnityEngine;
using System;
public class BuildScript
{
[MenuItem("Build/Build All")]
public static void PerformBuild()
{
// 获取命令行参数
string buildTarget = GetArgument("-buildTarget");
string buildPath = GetArgument("-buildPath");
// 设置默认值
if (string.IsNullOrEmpty(buildTarget))
buildTarget = "StandaloneLinux64";
if (string.IsNullOrEmpty(buildPath))
buildPath = "Builds/" + buildTarget;
// 确定构建目标
BuildTarget target = BuildTarget.StandaloneLinux64;
switch(buildTarget)
{
case "StandaloneWindows":
target = BuildTarget.StandaloneWindows;
break;
case "StandaloneWindows64":
target = BuildTarget.StandaloneWindows64;
break;
case "StandaloneLinux64":
target = BuildTarget.StandaloneLinux64;
break;
case "Android":
target = BuildTarget.Android;
break;
case "iOS":
target = BuildTarget.iOS;
break;
case "WebGL":
target = BuildTarget.WebGL;
break;
// 如有需要,可添加更多平台支持
}
// 获取场景列表
string[] scenes = new string[EditorBuildSettings.scenes.Length];
for (int i = 0; i < scenes.Length; i++)
{
scenes[i] = EditorBuildSettings.scenes[i].path;
}
// 执行构建
Debug.Log("开始构建 " + buildTarget + " 到路径: " + buildPath);
BuildPipeline.BuildPlayer(scenes, buildPath, target, BuildOptions.None);
Debug.Log("构建完成!");
}
private static string GetArgument(string name)
{
string[] args = Environment.GetCommandLineArgs();
for (int i = 0; i < args.Length; i++)
{
if (args[i] == name && i < args.Length - 1)
{
return args[i + 1];
}
}
return null;
}
}
8. GitLab CI/CD 集成
创建 .gitlab-ci.yml
文件实现自动化构建:
stages:
- test
- build
- deploy
variables:
UNITY_VERSION: "2022.3.12f1"
DOCKER_DRIVER: overlay2
GIT_STRATEGY: fetch
.unity_before_script: &unity_before_script
before_script:
- chmod +x ./ci/activate_unity.sh
- ./ci/activate_unity.sh
unity_test:
stage: test
image:
name: $CI_REGISTRY_IMAGE/unity-builder:$UNITY_VERSION
entrypoint: [""]
<<: *unity_before_script
script:
- /usr/local/bin/run_tests.sh
artifacts:
paths:
- test-results.xml
reports:
junit: test-results.xml
build_linux:
stage: build
image:
name: $CI_REGISTRY_IMAGE/unity-builder:$UNITY_VERSION
entrypoint: [""]
<<: *unity_before_script
script:
- /usr/local/bin/build_unity StandaloneLinux64 ./Builds/Linux .
artifacts:
paths:
- Builds/Linux
expire_in: 1 week
build_windows:
stage: build
image:
name: $CI_REGISTRY_IMAGE/unity-builder:$UNITY_VERSION
entrypoint: [""]
<<: *unity_before_script
script:
- /usr/local/bin/build_unity StandaloneWindows64 ./Builds/Windows .
artifacts:
paths:
- Builds/Windows
expire_in: 1 week
build_android:
stage: build
image:
name: $CI_REGISTRY_IMAGE/unity-builder-android:$UNITY_VERSION
entrypoint: [""]
<<: *unity_before_script
script:
- /usr/local/bin/build_unity Android ./Builds/Android .
artifacts:
paths:
- Builds/Android/*.apk
expire_in: 1 week
deploy_dev:
stage: deploy
image: alpine:latest
script:
- apk add --no-cache curl
- echo "上传构建结果到开发服务器"
# 这里添加上传或部署脚本
environment:
name: development
only:
- develop
9. 优化和最佳实践
缓存优化
为了加速构建过程,可以实现多级缓存:
-
Unity 缓存
使用命名卷保存 Unity 缓存:volumes: - unity_cache:/root/.cache/unity3d
-
项目库缓存
volumes: - unity_library:/unity_project/Library
-
Gradle 缓存 (Android 构建)
volumes: - gradle_cache:/root/.gradle
多阶段构建
使用多阶段构建减小最终镜像大小:
# 构建阶段
FROM ubuntu:22.04 AS builder
# ... Unity安装和构建过程 ...
# 运行阶段(用于游戏服务器)
FROM ubuntu:22.04
COPY --from=builder /opt/unity/Editor/Data/PlaybackEngines/LinuxStandaloneSupport /opt/unity/linux
COPY --from=builder /unity_project/Builds/Linux /app
WORKDIR /app
ENTRYPOINT ["./GameServer.x86_64"]
10. 配置 Unity Hub (可选)
如果需要在容器中使用 Unity Hub:
# 安装Unity Hub
RUN wget -qO - https://hub.unity3d.com/linux/keys/public | gpg --dearmor > /etc/apt/trusted.gpg.d/unity-hub.gpg \
&& sh -c 'echo "deb [arch=amd64] https://hub.unity3d.com/linux/repos/deb stable main" > /etc/apt/sources.list.d/unity-hub.list' \
&& apt-get update \
&& apt-get install -y unity-hub \
&& rm -rf /var/lib/apt/lists/*
# 安装特定Unity版本
RUN unity-hub install --version ${UNITY_VERSION} --changeset ${UNITY_CHANGESET} --module "windows-mono" "linux-mono" "android"
11. Unity 专用工具集成
Unity Cloud Build 替代方案
设置一个带有 Web UI 的构建服务器:
services:
unity-build-server:
build:
context: .
dockerfile: Dockerfile.build-server
ports:
- "8080:8080"
volumes:
- unity_projects:/projects
- unity_builds:/builds
- unity_cache:/root/.cache/unity3d
environment:
- UNITY_USERNAME=${UNITY_USERNAME}
- UNITY_PASSWORD=${UNITY_PASSWORD}
- UNITY_SERIAL=${UNITY_SERIAL}
unity-build-agent:
build:
context: .
dockerfile: Dockerfile
depends_on:
- unity-build-server
volumes:
- unity_projects:/unity_project
- unity_builds:/builds
- unity_cache:/root/.cache/unity3d
environment:
- UNITY_USERNAME=${UNITY_USERNAME}
- UNITY_PASSWORD=${UNITY_PASSWORD}
- UNITY_SERIAL=${UNITY_SERIAL}
- BUILD_SERVER_URL=http://unity-build-server:8080
volumes:
unity_projects:
unity_builds:
unity_cache:
12. GPU 支持 (高级)
在支持 NVIDIA GPU 的主机上,使用 NVIDIA Docker 运行时:
services:
unity-gpu:
build:
context: .
dockerfile: Dockerfile.gpu
container_name: unity-gpu
volumes:
- ./:/unity_project
environment:
- UNITY_USERNAME=${UNITY_USERNAME}
- UNITY_PASSWORD=${UNITY_PASSWORD}
- UNITY_SERIAL=${UNITY_SERIAL}
- DISPLAY=${DISPLAY}
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
Dockerfile.gpu
:
FROM nvidia/cuda:11.8.0-devel-ubuntu22.04
# ... Unity安装过程 ...
# 安装 NVIDIA 图形驱动
RUN apt-get update && apt-get install -y \
mesa-utils \
libgl1-mesa-glx \
libvulkan1 \
nvidia-opencl-dev \
&& rm -rf /var/lib/apt/lists/*
# ... 其余安装过程 ...
13. 实际使用场景示例
场景1: 持续集成工作流
# 准备环境变量
echo "UNITY_USERNAME=your_email@example.com" > .env
echo "UNITY_PASSWORD=your_password" >> .env
echo "UNITY_SERIAL=your_serial_key" >> .env
# 运行测试
docker-compose --env-file .env run --rm unity-test
# 构建Linux版本
docker-compose --env-file .env run --rm unity-builder
# 构建Windows版本
docker-compose --env-file .env --profile windows run --rm unity-builder-windows
# 构建Android版本
docker-compose --env-file .env --profile android run --rm unity-builder-android
场景2: 游戏服务器部署
# 构建服务器镜像
docker build -t my-game-server -f Dockerfile.server .
# 运行游戏服务器容器
docker run -d -p 7777:7777 --name game-server my-game-server
14. 疑难解答与常见问题
许可证问题
Unity 需要有效的许可证。使用环境变量或授权文件:
# 使用授权文件
COPY Unity_v2022.x.ulf /root/.local/share/unity3d/Unity/Unity_lic.ulf
# 或者使用账户登录
export UNITY_USERNAME=your_email@example.com
export UNITY_PASSWORD=your_password
export UNITY_SERIAL=your_serial_key
构建失败问题
常见错误包括权限问题和缺少依赖:
# 检查Unity日志
docker-compose logs unity-builder
# 进入容器调试
docker-compose run --rm unity-builder bash
总结
虽然 Docker 化 Unity 开发环境有一定挑战,但它为自动化构建、测试和 CI/CD 流程提供了强大基础。这种方法特别适合:
- 持续集成系统中自动构建游戏项目
- 在多个平台上进行自动化测试
- 部署游戏服务器
- 标准化团队构建环境
通过上述配置,您可以创建一个完全自动化的 Unity 构建管道,显著提高开发效率,确保构建质量和一致性。特别是对于大型团队和需要频繁构建的项目,这种方法可以节省大量时间和资源。