OneDev Docker Compose 部署指南

在 Docker 化的 Ubuntu 22.04 服务器上用 Docker Compose 部署 OneDev 16.9.3:镜像选型、持久化、免交互初始化、JVM 配置、备份与版本升级全流程实测。

OneDevOneDevDockerComposeCICD2026/10/17

OneDev Docker Compose 部署指南

‍‍​​‌​> 目标:在装有 Docker 的 Ubuntu 22.04 服务器上,用 Docker Compose 一键部署 OneDev 16.9.3,完成数据持久化、首启初始化、日常运维与版本升级。全文命令与回显均在 Docker 29.8.1 + Compose v5.5.1 环境实测通过。

一、环境信息

本文实测环境:

  • 操作系统:Ubuntu 22.04(x86_64)
  • Docker:29.8.1(Server 版本,docker version --format 'Docker {{.Server.Version}}' 实测输出)
  • Docker Compose:v5.5.1(docker compose version 实测输出)
  • OneDev 镜像:1dev/server:16.9.3(与 latest 同为 digest 镜像 bd6762b58343,体积 1.33GB,实测 docker images 输出)
  • 宿主机端口规划:HTTP 6630 → 容器 6610,SSH 6631 → 容器 6611
  • 数据目录:/opt/data/onedev-compose/data(挂载到容器 /opt/onedev)
  • 部署目录:/opt/data/onedev-compose(存放 docker-compose.yml)

二、镜像选型说明

官方镜像仓库为 Docker Hub 的 1dev/server,提供版本号 tag(如 16.9.3)与滚动 tag latest。实测两者当前指向同一镜像 ID bd6762b58343:

$ docker images 1dev/server
REPOSITORY   TAG      IMAGE ID       SIZE
1dev/server  16.9.3   bd6762b58343   1.33GB
1dev/server  latest   bd6762b58343   1.33GB

选型建议:生产固定版本号 tag(如 16.9.3),升级动作显式可控;latest 适合临时验证,随官方发版漂移(OneDev 发版频率很高,实测 2026-10-02 至 10-17 的 16 天内发布 10 个版本),用 latest 意味着每次 pull 都可能引入行为变化。

💡 说明:镜像内置 JRE 17 与 Git,宿主机不需要安装 Java;镜像首次启动会把发行包自解压到挂载的数据目录(见第四章 4.3 节实测日志),因此数据目录挂载是必需项而非可选项。

三、前置条件

  1. 服务器已安装 Docker 与 Compose 插件,实测版本确认命令:
$ docker version --format 'Docker {{.Server.Version}}'
Docker 29.8.1

$ docker compose version
Docker Compose version v5.5.1
  1. 规划好的两个宿主端口未被占用(本文用 6630/6631,避免与常见服务冲突):
ss -lntp | grep -E ':6630|:6631' || echo "端口空闲"
  1. 资源预留:官方口径 OneDev 在 2 核 2GB 机器上即可流畅运行;数据目录所在分区按「Git 仓库 + 构建日志 + 数据库」的体量预留,起步 20GB。

  2. 镜像拉取(约 1.33GB,国内网络慢时可为 Docker 守护进程配置镜像加速或代理):

docker pull 1dev/server:16.9.3

四、部署步骤

4.1 编写 docker-compose.yml

创建部署目录并写入编排文件(实测使用的原文):

mkdir -p /opt/data/onedev-compose
vi /opt/data/onedev-compose/docker-compose.yml
services:
  onedev:
    image: 1dev/server:16.9.3
    container_name: onedev-compose
    restart: unless-stopped
    ports:
      - "6630:6610"
      - "6631:6611"
    volumes:
      - /opt/data/onedev-compose/data:/opt/onedev

逐项解释:

  • image:固定版本号 tag,生产不追 latest;
  • container_name:固定容器名,便于 docker logs/exec 定位;
  • restart: unless-stopped:宿主机重启后自动拉起(手动 docker stop 除外);
  • ports:宿主 6630 映射容器 HTTP 6610,宿主 6631 映射容器 SSH 6611(Git over SSH);端口可按需调整宿主侧数字;
  • volumes:把宿主目录挂载为容器内 /opt/onedev,全部运行数据(数据库、Git 仓库、日志、构建工作区)落在宿主文件系统。

⚠️ 注意:官方 docker run 方式会额外挂载宿主 /var/run/docker.sock(用于「容器型作业执行器」调度宿主 Docker)。若不在 compose 里挂它,OneDev 照常运行,但容器型作业执行器不可用,构建请走 server-shell 执行器(在构建规范的命令步骤设 runInContainer: false)或远程 agent——这也是本指南实测采用的执行方式。

4.2 启动服务

cd /opt/data/onedev-compose
docker compose up -d

确认状态(实测输出):

$ docker compose ps
NAME             IMAGE                COMMAND                   SERVICE   CREATED       STATUS      PORTS
onedev-compose   1dev/server:16.9.3   "/root/bin/entrypoin…"   onedev    2 hours ago   Up 2 hours  0.0.0.0:6630->6610/tcp, [::]:6630->6610/tcp, 0.0.0.0:6631->6611/tcp, [::]:6631->6611/tcp

4.3 首次启动:发行包落盘与初始化

首次启动有一个数据目录填充过程:镜像内 /app 的发行包会被复制到挂载卷 /opt/onedev。实测 docker logs onedev-compose 开头 8 行:

11:19:50 INFO  - Launching application from '/app'...
11:19:50 INFO  - Starting application...
11:19:51 INFO  - Populating /opt/onedev...
11:19:52 INFO  - Successfully populated /opt/onedev
11:19:52 INFO  - Stopping application...
11:19:52 INFO  i.onedev.commons.bootstrap.Bootstrap - Launching application from '/opt/onedev'...
11:19:52 INFO  io.onedev.commons.loader.AppLoader - Starting application...
11:19:54 INFO  io.onedev.server.OneDev - Starting cluster

之后应用改为从 /opt/onedev 启动,全部数据落盘宿主目录。约半分钟后服务就绪,实测确认:

$ curl -s -o /dev/null -w '%{http_code}\n' http://localhost:6630
200

数据目录随即出现完整发行结构(实测 ls /opt/data/onedev-compose/data):

3rdparty-licenses  agent  bin  boot  conf  incompatibilities  IN_DOCKER
internaldb  lib  license.txt  logs  readme.txt  release.properties
site  temp  test

💡 说明:由于未配置免交互初始化变量(见第六章),服务就绪后日志会出现等待初始化的提示(实测原文):WARN - Please set up the server at http://localhost:6610——这是正常现象,表示等待浏览器向导。

4.4 浏览器初始化向导

浏览器访问 http://<服务器IP>:6630,按向导完成初始化:

  1. 设置管理员账号:登录名、密码、邮箱;
  2. 选择数据库:试用保持默认内嵌数据库;生产建议选 MySQL/PostgreSQL/MariaDB 并填连接信息;
  3. 确认服务器 URL:填 http://<服务器IP>:6630(保持与外部访问端口一致,否则 Git clone 地址与 Webhook 回调会指向错误端口)。

向导完成后进入主界面,即与裸机部署的 OneDev 完全同构。

五、数据持久化说明

OneDev 的全部状态都落在挂载目录 /opt/data/onedev-compose/data:

子目录/文件内容是否需要备份
internaldb/内嵌 HSQLDB 数据文件是(或改用外接库)
site/Git 裸仓、构建日志、附件是
conf/server.properties、hibernate.properties、wrapper.conf是
db-backup/backup-db.sh 生成的备份 zip建议外传
logs/server.log 等运行日志按需
temp/构建工作区(用后即清)否

迁移整站 = 拷走整个 data 目录:在新机器上用同一份 compose 文件启动(数据目录指向拷贝来的目录),所有项目、构建历史、账号原样恢复。注意容器内端口恒为 6610/6611,迁移后只需改 compose 的宿主端口映射。

数据库备份用发行包自带脚本在容器内执行,必须显式指定备份文件路径(实测无参执行会直接报错:Missing backup file parameter. Usage: backup-db.sh <path to database backup file>)。实测完整执行:

docker exec onedev-compose /opt/onedev/bin/backup-db.sh /opt/onedev/db-backup/backup-$(date +%Y%m%d%H%M%S).zip

实测输出尾部(逐表导出 XML 后打包):

13:21:57 INFO  - Exporting table 'EntityIdCounter'...
13:21:57 INFO  - Converting table rows to XML...
13:21:57 INFO  - Writing resulting XML to file 'EntityIdCounters.xml...
13:21:57 INFO  -
13:21:57 INFO  - Database is successfully backed up to /opt/onedev/db-backup/backup-20261017212150.zip
13:21:57 INFO  - Stopping application...

宿主侧即可看到产物(实测):

$ ls -la /opt/data/onedev-compose/data/db-backup/
-rw-r--r-- 1 root root 14530 10月 17 21:21 backup-20261017212150.zip

⚠️ 注意:backup-db.sh 执行完毕会自动停止应用(日志尾部 Stopping application... 是脚本行为,不是故障)。compose 场景下执行完执行 docker compose restart 拉起服务(实测重启后 curl http://localhost:6630 返回 200)。该脚本只备份数据库;Git 仓库与构建日志在 site/,完整灾备要「备份 zip + data 目录」两件套。

六、环境变量表

OneDev 镜像支持两组环境变量,均在 docker-compose.yml 的 environment: 段注入。

免交互初始化(首次启动前设置,仅初始化时生效):

变量名必填说明
initial_user是管理员登录名
initial_password二选一管理员密码(或用 initial_password_file)
initial_password_file二选一存放密码的文件路径
initial_email是管理员邮箱
initial_server_url是服务器对外根地址,需以 http:// 或 https:// 开头
initial_ssh_root_url否SSH 根地址(ssh://<host>:<port> 形式),留空则从 server_url 推导

设置后首次启动跳过浏览器向导,直接完成初始化,适合脚本化交付。

外接数据库(改用外部 MySQL/PostgreSQL/MariaDB 时设置):

变量名示例值
hibernate_dialectorg.hibernate.dialect.MySQL5InnoDBDialect(MySQL/MariaDB);PostgreSQL 必须用 OneDev 自带方言 io.onedev.server.persistence.PostgreSQLDialect
hibernate_connection_driver_classcom.mysql.cj.jdbc.Driver(MySQL)/ org.postgresql.Driver
hibernate_connection_urljdbc:mysql://数据库地址:3306/onedev?serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false
hibernate_connection_username数据库账号(需建表权限)
hibernate_connection_password数据库密码(或 hibernate_connection_password_file 指向密码文件)

⚠️ 注意:连接串不要省略端口号;外接库需预先创建空库(OneDev 自动建表)。改环境变量后需 docker compose up -d 重建容器生效。

七、配置参数说明

容器化部署后,运行期配置在挂载目录内维护,改完 docker compose restart 生效:

  • data/conf/server.properties:服务端口与集群参数。实测内容(挂载后自动生成):
http_host=0.0.0.0
http_port=6610
ssh_port=6611
cluster_port=5710

容器内端口不要改(镜像入口按 6610 探活),要改对外端口只动 compose 的 ports: 宿主侧;server_name 可留空(默认用主机名)。

  • data/conf/wrapper.conf:JVM 参数。默认堆上限为物理内存 50%(set.default.max_memory_percent=50);固定堆写法(实测有效):
wrapper.java.initmemory=256
wrapper.java.maxmemory=512

修改后在容器内验证生效值:

docker exec onedev-compose ps -ef | grep [j]ava
# 输出中应出现 -Xms256m -Xmx512m
  • data/conf/hibernate.properties:未通过环境变量指定外接库时,可直接改此文件切换数据库(注释/解注释对应段落)。

八、配置文件挂载

除整目录挂载外,也可只挂单个配置文件精细控制,例如把调优好的 JVM 配置与数据分离管理:

    volumes:
      - /opt/data/onedev-compose/data:/opt/onedev
      - /opt/data/onedev-compose/conf/wrapper.conf:/opt/onedev/conf/wrapper.conf

挂载单文件时注意:宿主文件必须先于容器启动存在(否则 Docker 会建出同名目录导致启动失败);且首次填充完成后 conf/ 已在数据目录内,单文件挂载属于可选优化,整目录挂载(本文方案)已覆盖绝大多数场景。

九、等价 docker run

与本文 compose 等价的单命令启动方式(官方推荐形态):

docker run --name onedev -d --restart always \
  -v /opt/data/onedev/data:/opt/onedev \
  -p 6610:6610 -p 6611:6611 \
  1dev/server:16.9.3

若需要容器型作业执行器,额外追加 -v /var/run/docker.sock:/var/run/docker.sock。两者的取舍:docker run 简单直接,适合单机快速验证;compose 把端口、目录、重启策略与后续扩展(外接数据库、agent 网络)声明式固化,便于长期维护与版本升级,生产建议 compose。

十、常用运维命令

以下命令均在实测环境验证可用:

# 状态查看
docker compose ps

# 实时日志(服务端启动/运行日志)
docker compose logs -f onedev

# 进入容器执行管理脚本(备份数据库,路径必填;执行完会自动停应用,需再 restart)
docker exec onedev-compose /opt/onedev/bin/backup-db.sh /opt/onedev/db-backup/backup-$(date +%Y%m%d%H%M%S).zip
docker compose restart

# 重置管理员密码(忘记密码时)
docker exec -it onedev-compose /opt/onedev/bin/reset-admin-password.sh

# 重启服务(改配置后)
docker compose restart

# 停止与启动
docker compose down    # 停止并移除容器,data 目录保留
docker compose up -d   # 重新拉起

版本升级流程(以 16.9.3 → 新版本为例,实测操作路径):

cd /opt/data/onedev-compose
docker exec onedev-compose /opt/onedev/bin/backup-db.sh /opt/onedev/db-backup/backup-$(date +%Y%m%d%H%M%S).zip   # 1. 先备份
docker compose restart                                  #    备份脚本会自动停应用,重启拉起
tar czf onedev-data-$(date +%F).tgz -C /opt/data/onedev-compose data   # 2. 整目录冷备(可选但建议)
docker pull 1dev/server:<新版本号>                        # 3. 拉新镜像
# 4. 编辑 docker-compose.yml,把 image 的 tag 改为新版本号
docker compose up -d                                      # 5. 重建容器,数据卷原样保留
docker compose logs -f onedev                             # 6. 观察启动与数据迁移日志

回滚 = 把 tag 改回旧版本号再 up -d,并视情况用第 1 步的备份包恢复数据库。

十一、常见问题

Q1:首次访问提示 "Please set up the server",是不是部署失败了? 不是。这是初始化向导等待提示(实测日志原文 WARN - Please set up the server at http://localhost:6610),按 4.4 节完成浏览器向导即可;若希望跳过向导,用第六章的 initial_* 免交互变量重建。

Q2:构建任务报无法调度到容器执行器? compose 文件未挂载宿主 Docker socket 时,容器型作业执行器不可用。两种解法:挂载 /var/run/docker.sock;或保持现状,在构建规范命令步骤设 runInContainer: false 走 server-shell 执行器(实测可用,构建正常)。

Q3:宿主端口想换成 80/22 风格怎么办? 只改 compose ports: 的宿主侧数字(如 "80:6610"),容器内侧 6610/6611 不动;同时把向导/环境变量里的服务器 URL 端口改成新的宿主端口,避免 Git clone 地址错误。

Q4:升级后打不开或数据异常? 先看 docker compose logs -f onedev 的启动与数据库迁移日志;确认升级前做过 backup-db.sh;异常时回滚镜像 tag 并用备份包在容器内 restore-db.sh 恢复。

Q5:数据目录可以放 NFS/网络盘吗? 不建议。OneDev 对 HSQLDB 与 Git 对象库有本地文件语义假设(锁文件、fsync),网络盘容易出现锁异常;跨机迁移用「整目录拷贝 + 备份包」而不是共享盘。

十二、参考链接