首页
/ Gogs Docker 部署完全指南(Legacy 镜像):app.ini 注入、容器服务编排与自动备份系统

Gogs Docker 部署完全指南(Legacy 镜像):app.ini 注入、容器服务编排与自动备份系统

2026-09-07 16:46:38作者:何将鹤

本文基于 Gogs 仓库中的 docker/README.md,系统讲解 legacy Docker 镜像的配置注入方式(绑定挂载、命名卷)、容器内部的服务编排原理,以及由环境变量驱动的自动备份系统实现。读完本文,你将能够独立完成 Gogs 的 Docker 化部署、创建管理员账号、按需开启容器内定时任务,并理解备份任务从环境变量解析到 cron 执行的完整调用链。

1. Legacy 镜像定位与版本标签

首先需要明确一点:docker/ 目录下的镜像是 legacy(旧版)Docker 镜像,官方提示其缺乏现代安全最佳实践。从 0.16.0 开始它将以 gogs/gogs:legacy-latest 标签发布,并不晚于 0.17.0 被完全移除。如果追求下一代、安全性更强的镜像,应参考 docker-next/README.md

镜像版本遵循以下标签约定:

  • 每个正式发布的版本都有独立标签,例如 gogs/gogs:0.13.4
  • 小版本标签指向该小版本的最新补丁版本,例如 gogs/gogs:0.13
  • latest 标签是从最新 main 分支构建的镜像。

具体可用标签可在 Docker Hub 的 gogs 官方账户或 GitHub Container Registry 中查看。

2. 镜像构建与启动流程(源码级)

Dockerfile 采用多阶段构建:第一阶段用 node:24-alpine 构建前端资源(web/ 目录),第二阶段用 golang:1.26-alpine3.23pam prod 标签编译 Gogs 二进制,最终镜像基于 alpine:3.23,安装了 opensshs6socatgosu(shadow 提供)等运行时组件。关键配置如下:

  • ENV GOGS_CUSTOM=/data/gogs:声明容器的 "custom" 目录位置;
  • VOLUME ["/data", "/backup"]:数据卷与备份卷;
  • EXPOSE 22 3000:SSH 与 HTTP 端口;
  • HEALTHCHECK 通过 curl http://localhost:3000/healthcheck 探活;
  • ENTRYPOINT ["/app/gogs/docker/start.sh"]CMD 默认为 /usr/bin/s6-svscan /app/gogs/docker/s6/

入口脚本 start.sh 的职责

docker/start.sh 在启动时依次完成四件事:

  1. setids(L49-L55):将 git 用户的 UID/GID 修改为环境变量 PUID/PGID(默认均为 1000),便于宿主机文件权限管理;
  2. cleanup(L26-L31):清理上次运行遗留的 s6 事件目录与 SOCAT_* 服务目录;
  3. create_volume_subfolder(L33-L47):在 /data 下创建 gogs/datagogs/confgogs/loggitssh 五个子目录,并确保其属主为 git(仅在属主不一致时执行 chown,避免 NFS 挂载下的昂贵开销);
  4. 根据 SOCAT_LINK / RUN_CROND 环境变量决定是否为链接容器生成 socat 转发、是否启动 crond,最后 exec 用户指定的命令或默认的 s6 服务监管器。

s6 监管的三类服务

s6-svscan 监管 docker/s6/ 下的服务,各自通过 run + setup 脚本启动:

服务 启动脚本 作用
gogs docker/s6/gogs/run exec gosu "$USER" /app/gogs/gogs web,以 git 用户运行 Web 服务
openssh docker/s6/openssh/run 运行 sshd -D -f /app/gogs/docker/sshd_config,监听容器内 22 端口
crond docker/s6/crond/run 运行 crond -fS,仅在 RUN_CROND=true 时被启用(否则 start.shtouchdown 文件标记停止该服务)

几个值得注意的实现细节:

  • docker/s6/gogs/setup 在启动 Gogs 前将 /data/gogs/log/data/gogs/data 软链接到应用目录,并保留 /data/git -> /home/git 的向后兼容链接;它还向 ~git/.ssh/environment 写入 GOGS_CUSTOM 变量并设置权限——配合 docker/sshd_config 中的 PermitUserEnvironment yes(L14)与 AllowUsers git(L15),Git-over-SSH 钩子在以 git 用户执行时才能拿到正确的 GOGS_CUSTOM 路径。
  • SSH 主机密钥在首次启动时由 docker/s6/openssh/setup 自动生成(rsa/dsa/ecdsa/ed25519 四类),持久化在 /data/ssh/ 下,权限为 600,因此重建容器后密钥不变。
  • legacy 镜像内不支持 Gogs 内置 SSH 服务器,这正是配置示例中必须写 START_SSH_SERVER = false 的原因:git 流量走的是独立的 openssh 服务。

3. app.ini 配置详解

Gogs 启动前必须存在 app.ini,它会覆盖镜像自带的默认配置,因此只需写你真正要改的键。以"通过 https://gogs.example.com 提供 Gogs、HTTP 端口映射到宿主机 10880、SSH 映射到 10022、数据库使用宿主机上的 Postgres"为例,官方给出的完整示例如下:

RUN_MODE = prod
; USE AS-IS because the image already created this user.
RUN_USER = git

[server]
EXTERNAL_URL = https://gogs.example.com/
DOMAIN       = gogs.example.com
; The port exposed by `docker run -p 10022:22`. Shown in clone URLs.
SSH_PORT     = 10022
; The builtin SSH server is not supported inside legacy Docker.
START_SSH_SERVER = false

[repository]
; USE AS-IS to match the data volume layout shipped in the image.
ROOT = /home/git/gogs-repositories

[database]
TYPE     = postgres
; Use host.docker.internal (or the host's LAN IP) to reach a DB on the host.
HOST     = host.docker.internal:5432
NAME     = gogs
USER     = gogs
PASSWORD = ${GOGS_DATABASE_PASSWORD}

[security]
SECRET_KEY = ${GOGS_SECURITY_SECRET_KEY}

各关键项说明:

  • RUN_USER = git:镜像内已创建该用户,必须原样保留;
  • EXTERNAL_URL / DOMAIN:对外访问地址,必须与反向代理实际暴露的地址一致;
  • SSH_PORT = 10022:对应 docker run -p 10022:22 暴露的宿主机端口,会显示在克隆 URL 中;
  • [repository] ROOT:保持 /home/git/gogs-repositories 不变,因为 setup 脚本 已通过 /home/git -> /data/git 软链接将其落到数据卷上;
  • 访问宿主机数据库时使用 host.docker.internal(或宿主机局域网 IP);
  • SECRET_KEY 可以是任意不可猜测的字符串(如 UUID)。Gogs 在使用不安全的默认值时会拒绝启动

环境变量展开:任何配置值中的 ${...} 引用会在容器启动时从容器环境展开,从而避免把密钥落盘写入 app.ini。通过 docker run -e GOGS_DATABASE_PASSWORD=… -e GOGS_SECURITY_SECRET_KEY=…(或 --env-file secrets.env)传入即可;直接写字面量也可以,例如 PASSWORD = hunter2

配置系统的完整工作机制,可进一步阅读仓库中的 配置入门文档,默认配置模板见 conf/app.ini

方式一:绑定挂载(Bind mount)

app.ini 写到宿主机目录,然后 docker run 时用 -v 挂进来:

$ mkdir -p /var/gogs/gogs/conf
$ vi /var/gogs/gogs/conf/app.ini   # Paste the example above and edit
$ docker run --name=gogs -p 10022:22 -p 10880:3000 -v /var/gogs:/data gogs/gogs

方式二:命名卷(Named volume)

命名卷位于 Docker 的存储内部,因此文件必须通过容器写入。由于 Gogs 缺少 app.ini 会拒绝启动,所以容器必须先创建(而非直接运行):

$ docker volume create --name gogs-data
$ docker create --name=gogs -p 10022:22 -p 10880:3000 -v gogs-data:/data gogs/gogs
$ docker cp app.ini gogs:/data/gogs/conf/app.ini
$ docker start gogs

方式三:直接编辑 "custom" 目录

Docker 环境中的 "custom" 目录可能并不直观:容器内的 /data/gogs 本身就是 custom 目录(对应 Dockerfile 中的 ENV GOGS_CUSTOM=/data/gogs)。不需要再套一层目录,直接编辑其中的文件即可。容器内目录布局为:

/data
|-- git
|   |-- gogs-repositories
|-- ssh
|   |-- # ssh public/private keys for Gogs
|-- gogs
    |-- conf
    |-- data
    |-- log

4. 首次启动与管理员创建

打开 https://gogs.example.com/ 完成注册即可——在尚无任何用户时,第一个注册的人自动成为管理员。

也可以从命令行创建管理员。该命令在容器内执行,因此通过同一份配置访问数据库:

$ docker exec -it gogs gogs admin create-user \
    --name admin \
    --password ${PASSWORD} \
    --email admin@example.com \
    --admin \
    --config /data/gogs/conf/app.ini

--config 指向容器内的 app.ini 实际路径 /data/gogs/conf/app.ini;该 admin create-user 子命令对应源码 cmd/gogs/admin.go。此后重启容器直接使用 docker start gogs / docker stop gogs

5. 容器环境选项

容器通过环境变量提供若干选择性开启的运维选项:

选项 可选值 默认值 作用
SOCAT_LINK true/false/1/0 true 使用 socat 将 Docker 链接(link)容器的导出端口转发到本容器 localhost 对应端口
RUN_CROND true/false/1/0 false 请求在容器内运行 crond。默认配置会周期性执行 /etc/periodic/${period} 下所有脚本;自定义 crontab 可放入 /var/spool/cron/crontabs/
BACKUP_INTERVAL 3h7d3M null RUN_CROND=true 配合启用备份系统
BACKUP_RETENTION 360m7d 等 m/d 表达式 7d 备份保留期,超期备份被周期性删除
BACKUP_ARG_CONFIG /app/gogs/example/custom/config null gogs backup 提供 --config 参数
BACKUP_ARG_EXCLUDE_REPOS test-repo1,test-repo2 null gogs backup 提供 --exclude-repos 参数
BACKUP_EXTRA_ARGS --verbose --exclude-mirror-repos null 追加任意额外参数到 gogs backup 命令行

SOCAT_LINK 的免责声明:该选项依赖 Docker 链接机制生成的环境变量,因此在 Rancher 或 Kubernetes 等托管环境中应关闭(设为 0false)。

从源码看,start.sh 的 create_socat_links 函数(L3-L24)通过解析环境中形如 *_PORT_<n>_TCP=tcp://<addr>:<port> 的链接变量,为每个链接容器动态生成一个 s6/SOCAT_<NAME>_<PORT> 服务目录,运行 socat -ls TCP4-LISTEN:<port>,fork,reuseaddr TCP4:<addr>:<port>;若端口与 Gogs 自身占用的 3000/22 冲突则跳过并告警。这些动态生成的目录会在每次启动/关停时由 cleanup 清除。

6. 备份系统实现剖析

备份系统提供"自动备份 + 保留策略"。环境变量语义为:

  • BACKUP_INTERVAL 控制备份频率,支持小时(h)、天(d)、月(M),如 3h7d3M,最小值为 1h
  • BACKUP_RETENTION 支持分钟(m)和天(d)表达式,如 360m2d,最小值为 60m

其底层实现由 docker/runtime/ 下三个脚本完成,全部由 crond 驱动:

  1. 初始化backup-init.shRUN_CROND=true 时由 start.sh(L72)调用。它创建 /backup 目录(权限 2770、属主 git:git),校验 BACKUP_INTERVAL(缺失则中止),将 BACKUP_RETENTION 缺省补为 7d,然后做两件事:
    • parse_generate_cron_expression(L27-L71)把 BACKUP_INTERVAL 解析成 cron 表达式——h 上限 23(生成 */N 小时字段)、d 上限 30(生成 */N 天字段)、M 上限 12(每月 1 日 + */N 月字段);
    • add_backup_cronjob/etc/crontabs/<git 用户名> 写入两条 cron 任务(L142-L144):一条是每 5 分钟执行 backup-rotator.sh 做清理,另一条按解析出的周期执行 backup-job.sh
  2. 执行备份backup-job.sh/app/gogs 下执行 ./gogs backup --target=/backup,并按需追加 --config=--exclude-repos=(来自 BACKUP_ARG_CONFIG / BACKUP_ARG_EXCLUDE_REPOS)以及 BACKUP_EXTRA_ARGS 中的原始参数。
  3. 轮换清理backup-rotator.sh 使用 find /backup -type f -name "gogs-backup-*.zip" -<retention表达式> 找出超期备份并删除(mtime +Nmmin +N,表达式由 parse_generate_retention_expression 生成,最小强制为 60m)。脚本还内置了防御:BACKUP_PATH/ 或目录不存在时直接报错退出。

需要牢记的前提:/backup 本身是 Dockerfile 声明的卷,若要备份长期保存,务必将其绑定挂载到宿主机目录;同时 crontab 文件写入容器内文件系统,容器删除后需重新初始化。

7. 升级流程

注意:升级前请确保数据卷已持久化到容器之外!

Gogs 的 Docker 升级步骤:

  1. docker pull gogs/gogs 拉取新镜像;
  2. docker stop gogs 停止容器;
  3. docker rm gogs 删除旧容器;
  4. 按首次启动的方式重新创建容器——务必保持相同的卷映射与端口映射。

由于 app.ini、仓库数据(/data/git)、SSH 主机密钥(/data/ssh)都在数据卷中,重建容器不会丢失数据。

8. 已知问题

  • 目前该镜像无法在 Raspberry Pi 1(armv6l)上构建,因为基础镜像 alpine 没有该平台可用的 go 包。

参考文件

文件 说明
docker/README.md 本文主体依据的部署文档
Dockerfile legacy 镜像的多阶段构建定义
docker/start.sh 容器入口:用户 ID 设置、卷目录初始化、socat/crond 开关
docker/s6/ s6 监管的 gogs / openssh / crond 服务脚本
docker/sshd_config 容器内 sshd 配置(仅允许 git 用户)
docker/runtime/backup-init.sh 备份 cron 任务生成逻辑
docker/runtime/backup-job.sh 备份任务执行脚本
docker/runtime/backup-rotator.sh 备份文件轮换清理脚本
docker-next/README.md 下一代安全增强镜像的文档
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388