本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2020年02月04日 统计字数: 12336字 阅读时间: 25分钟阅读 本文链接: soulteary.com/2020/02/04/…
本文成文于 2019年9月,将介绍如何使用 Traefik v1 搭建易于维护管理的 Gogs 。
原计划是替换家中 HomeLab 的代码仓库,但由于 GitLab CI 的良好体验,家里的 HomeLab 最终还是选择继续使用 GitLab。
这篇文章也就沉入了草稿箱,最近在折腾 Traefik 升级和测试服务器,遇到了一些相关的小需求,故将内容更新了一些后发布出来,希望能帮到有需要的同学。
一直以来,都在使用 GitLab 作为团队/个人的仓库工具,随着版本的不断升级,GitLab 的界面功能越来越强大,消耗的服务器资源也越来越多。
最近将 GitLab Community Edition 升级到了 12.3+ ,服务器上依旧是丝般顺滑,但是家里 UPS 显示服务器待机功率默默上去了 10w。
这 10w 消耗的电费是小,但是原本静音的服务器,开始了轻微的风扇转动,这就有些不能忍了,于是有了使用更轻量应用替换 GitLab 的想法。
Gogs 自身支持 HTTPS、支持挂在 SSL 证书,但是考虑到可维护性,这个事情交托给 Traefik 来处理。
Gogs 默认数据库使用的是 SQLite,轻量有余,但是作为重要数据的数据后端却不是那么安全,从官方网站的“如何修复数据库”可以看到挂掉的可能性还是不少的,所以我们要将其替换。
Gogs 默认的缓存方案是应用本身的内存,一般来说足够应付个人/小团队使用,但是为了进一步提高性能和健壮性,我们将缓存功能从应用主体解耦,交托于 Redis 进行处理。
那么开始配置 Gogs 依赖的软件和环境吧。
使用 compose 配置数据库非常简单,二十行以内解决战斗:
version: '3.6' services: db: image: mysql:5.7.16 restart: always expose: - 3306 volumes: # 标准 Linux 系统下使用 # - /etc/localtime:/etc/localtime:ro # - /etc/timezone:/etc/timezone:ro - ./mysql:/var/lib/mysql command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci environment: MYSQL_ROOT_PASSWORD: gogs MYSQL_DATABASE: gogs MYSQL_USER: gogs MYSQL_PASSWORD: gogs TZ: Asia/Shanghai 复制代码
使用 compose 搞定 Redis 更为简单,因为我们不需要将缓存持久化,所以不到二十行就完事了:
cache: image: redis:5.0-alpine restart: always expose: - 6379 environment: TZ: Asia/Shanghai # volumes: # 标准 Linux 系统下使用 # - /etc/localtime:/etc/localtime:ro # - /etc/timezone:/etc/timezone:ro 复制代码
不需要 Traefik 、MySQL、Redis 的 Gogs 编排文件显得十分简单:
version: '3.6' services: app: image: gogs/gogs:0.11.91 restart: always ports: - 22:22 - 80:3000 volumes: # 标准 Linux 系统下使用 # - /etc/localtime:/etc/localtime:ro # - /etc/timezone:/etc/timezone:ro - ./data/:/data/ labels: - "traefik.enable=true" - "traefik.port=3000" - "traefik.frontend.rule=Host:${GOGS_DOMIAN}" - "traefik.frontend.entryPoints=http,https" - "traefik.frontend.headers.SSLRedirect=true" - "traefik.frontend.headers.SSLProxyHeaders=X-Forwarded-Proto:https" - "traefik.frontend.headers.STSSeconds=315360000" - "traefik.frontend.headers.frameDeny=true" networks: traefik: external: true 复制代码
但是这样配置的应用,显然少了“应用健康检查”、“仓库数据安全存储”、“页面高性能响应”的能力。
想让 Gogs 、Redis、MySQL 作为一个整体一起正常工作,又不受到其他应用干扰,需要做几件事:
想要达到这个效果,需要修改 docker-compose.yml
文件,定义 networks
:
version: '3.6' services: app: networks: - traefik - gogs db: networks: - gogs cache: networks: - gogs networks: gogs: internal: true traefik: external: true 复制代码
上面的示例代码中,我们声明了两个网络环境,分别为私有网络 gogs
,用于 Gogs 和 MySQL、Redis 互通;外部的网络 traefik
,用于暴露 Web 服务、Git SSH 服务给用户。
应用网路互通后,Gogs 可以通过 Docker 赋予的容器名称访问 MySQL、Redis,或者使用 gogs
随机分配的内网地址进行数据交互。
然而这两种方案都不是特别利于维护,一旦容器扩展/重建后,容器名称会发生变化、分配的 IP 地址也会发生变化。
所以这里可以使用 compose 组网声明 MySQL、Redis 的内网域名。
version: '3.6' services: app: links: - db:mysql.gogs.lab.com - cache:cache.gogs.lab.com 复制代码
然后在 Gogs 容器中访问上面的域名就能够直接访问到 MySQL、Redis 啦。
如果你直接启动包含三个应用的编排文件,可能会遇到 Gogs 报错,所以可以配合给三个应用都添加健康检查,以及启动依赖关系来解决问题:
version: '3.6' services: app: depends_on: - db - cache healthcheck: test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:3000 || exit 1"] db: healthcheck: test: ["CMD-SHELL", "/etc/init.d/mysql status"] interval: 30s cache: healthcheck: test: ["CMD", "redis-cli", "ping"] 复制代码
现在,你可能会发现一贯很灵敏的 Traefik 出现了偶尔不工作的问题,原因是 Traefik 有时将端口暴露到了 gogs
私有网络网卡上,解决方案很简单,声明 Traefik 工作使用的网卡就成:
version: '3.6' services: app: labels: - "traefik.docker.network=traefik" 复制代码
根据之前的经验,反代的应用有可能会向公网 DNS 寻求帮助,查找服务域名,比如 gogs.lab.com ,为了避免这种情况发生,应用出现转半天转不开的情况,我们可以选择让 Gogs 容器的服务域名的解析地址映射为本地:
version: '3.6' services: app: extra_hosts: - "${GOGS_DOMIAN}:127.0.0.1" 复制代码
相比较“默认方案”直接映射 /data
整个大目录,如果将子目录单独映射,则可以更好的控制应用数据迁移、配置更新。
version: '3.6' services: app: volumes: - ./app.ini:/data/gogs/conf/app.ini:ro - ./logs:/data/gogs/data/log - ./data/avatars:/data/gogs/data/avatars - ./data/ssh:/data/ssh - ./data/git:/data/git 复制代码
官方文档中提到我们可以修改 custom/templates/inject/
和 public/css
下的文件,来定制页面展示。
但是容器中,这块实际的目录却有一些变化,如果你有定制模版的需求,可以参考下面的配置解决问题。
version: '3.6' services: app: volumes: - ./data/custom/template/head.tmpl:/app/gogs/templates/inject/head.tmpl - ./data/custom/template/footer.tmpl:/app/gogs/templates/inject/footer.tmpl - ./data/custom/inject-assets/:/app/gogs/public/inject-assets/ 复制代码
加上了健康检查的 Gogs ,日志会随着时间慢慢变大,而这里日志对于我们解决问题没有丝毫帮助,因该被丢弃:
app_1 | [Macaron] 2019-09-28 07:07:04: Started GET / for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:07:04: Completed GET / 302 Found in 7.6542ms app_1 | [Macaron] 2019-09-28 07:07:04: Started GET /user/login for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:07:04: Completed GET /user/login 200 OK in 16.5518ms app_1 | [Macaron] 2019-09-28 07:07:34: Started GET / for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:07:34: Completed GET / 302 Found in 2.892ms app_1 | [Macaron] 2019-09-28 07:07:34: Started GET /user/login for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:07:34: Completed GET /user/login 200 OK in 10.2743ms 复制代码
配置 Gogs 应用日志输出选项,给出一个“最大尺寸”限制即可:
version: '3.6' services: app: logging: driver: "json-file" options: max-size: "10m" 复制代码
将上述所有内容合并,完整的 docker-compose.yml
配置文件如下:
version: '3.6' services: app: image: ${DOCKER_GOGS_IMAGE} restart: always networks: - traefik - gogs expose: - 3000 ports: - 22:22 links: - db:${MYSQL_HOST} - cache:${REDIS_HOST} depends_on: - db - cache labels: - "traefik.enable=true" - "traefik.port=3000" - "traefik.frontend.rule=Host:${GOGS_DOMIAN}" - "traefik.frontend.entryPoints=http,https" - "traefik.frontend.headers.SSLRedirect=true" - "traefik.frontend.headers.SSLProxyHeaders=X-Forwarded-Proto:https" - "traefik.frontend.headers.STSSeconds=315360000" - "traefik.frontend.headers.frameDeny=true" - "traefik.docker.network=traefik" logging: driver: "json-file" options: max-size: "10m" extra_hosts: - "${GOGS_DOMIAN}:127.0.0.1" volumes: # 标准 Linux 系统下使用 # - /etc/localtime:/etc/localtime:ro # - /etc/timezone:/etc/timezone:ro - ./app.ini:/data/gogs/conf/app.ini:ro - ./logs:/data/gogs/data/log - ./data/avatars:/data/gogs/data/avatars - ./data/ssh:/data/ssh - ./data/git:/data/git # 根据自己需求使用 # - ./data/custom/template/head.tmpl:/app/gogs/templates/inject/head.tmpl # - ./data/custom/template/footer.tmpl:/app/gogs/templates/inject/footer.tmpl # - ./data/custom/inject-assets/:/app/gogs/public/inject-assets/ healthcheck: test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:3000 || exit 1"] interval: 5s db: image: ${DOCKE_MYSQL_IMAGE} restart: always networks: - gogs expose: - 3306 command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci environment: MYSQL_ROOT_PASSWORD: gogs MYSQL_DATABASE: gogs MYSQL_USER: gogs MYSQL_PASSWORD: gogs TZ: Asia/Shanghai volumes: # 标准 Linux 系统下使用 # - /etc/localtime:/etc/localtime:ro # - /etc/timezone:/etc/timezone:ro - ./mysql:/var/lib/mysql healthcheck: test: ["CMD-SHELL", "/etc/init.d/mysql status"] interval: 30s cache: image: ${DOCKER_REDIS_IMAGE} restart: always networks: - gogs expose: - 6379 healthcheck: test: ["CMD", "redis-cli", "ping"] environment: TZ: Asia/Shanghai # volumes: # 标准 Linux 系统下使用 # - /etc/localtime:/etc/localtime:ro # - /etc/timezone:/etc/timezone:ro networks: gogs: internal: true traefik: external: true 复制代码
和配置文件搭配使用的 .env
环境变量文件内容如下:
DOCKER_GOGS_IMAGE=gogs/gogs:0.11.91 GOGS_DOMIAN=gogs.lab.com DOCKE_MYSQL_IMAGE=mysql:5.7.16 MYSQL_HOST=mysql.gogs.lab.com DOCKER_REDIS_IMAGE=redis:5.0-alpine REDIS_HOST=cache.gogs.lab.com 复制代码
Gogs 使用的 app.ini
配置文件内容:
APP_NAME = Private Repo RUN_USER = git RUN_MODE = prod [database] DB_TYPE = mysql HOST = mysql.gogs.lab.com:3306 NAME = gogs USER = gogs PASSWD = gogs SSL_MODE = disable PATH = data/gogs.db [cache] ADAPTER=redis INTERVAL=60 HOST=network=tcp,addr=cache.gogs.lab.com:6379,password=,db=0,pool_size=100,idle_timeout=180 [repository] ROOT = /data/git/gogs-repositories FORCE_PRIVATE=true MAX_CREATION_LIMIT=-1 DISABLE_HTTP_GIT=true [server] DOMAIN = gogs.lab.com HTTP_PORT = 3000 ROOT_URL = https://gogs.lab.com/ DISABLE_SSH = false SSH_PORT = 22 SSH_LISTEN_HOST = 0.0.0.0 SSH_LISTEN_PORT = 22 START_SSH_SERVER = false OFFLINE_MODE = true [mailer] ENABLED = false [service] REGISTER_EMAIL_CONFIRM = false ENABLE_NOTIFY_MAIL = false DISABLE_REGISTRATION = false ENABLE_CAPTCHA = false REQUIRE_SIGNIN_VIEW = true [picture] DISABLE_GRAVATAR = true ENABLE_FEDERATED_AVATAR = false [session] PROVIDER=redis PROVIDER_CONFIG=network=tcp,addr=cache.gogs.lab.com:6379,password=,db=0,pool_size=100,idle_timeout=180 [log] MODE = console, file LEVEL = Info ROOT_PATH = /app/gogs/log [admin] DISABLE_REGULAR_ORG_CREATION=true [security] INSTALL_LOCK = true LOGIN_REMEMBER_DAYS=true SECRET_KEY = pLdr79uA4YnwDab [other] SHOW_FOOTER_BRANDING=false 复制代码
使用 docker-compose up
启动应用,稍等片刻可以看到日志类似下面:
Network traefik is external, skipping Creating network "gogs_gogs" with the default driver Creating gogs_db_1 ... done Creating gogs_cache_1 ... done Creating gogs_app_1 ... done Attaching to gogs_cache_1, gogs_db_1, gogs_app_1 cache_1 | 1:C 28 Sep 2019 15:38:57.955 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo cache_1 | 1:C 28 Sep 2019 15:38:57.955 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started cache_1 | 1:C 28 Sep 2019 15:38:57.955 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf db_1 | Initializing database db_1 | 2019-09-28T07:38:58.172565Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). db_1 | 2019-09-28T07:38:59.117064Z 0 [Warning] InnoDB: New log files created, LSN=45790 db_1 | 2019-09-28T07:38:59.264592Z 0 [Warning] InnoDB: Creating foreign key constraint system tables. db_1 | 2019-09-28T07:38:59.281117Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 08ba4fc7-e1c3-11e9-a436-0242c0a89003. app_1 | usermod: no changes cache_1 | 1:M 28 Sep 2019 15:38:57.956 * Running mode=standalone, port=6379. cache_1 | 1:M 28 Sep 2019 15:38:57.956 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. cache_1 | 1:M 28 Sep 2019 15:38:57.956 # Server initialized cache_1 | 1:M 28 Sep 2019 15:38:57.956 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. cache_1 | 1:M 28 Sep 2019 15:38:57.956 * Ready to accept connections db_1 | 2019-09-28T07:38:59.284542Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened. db_1 | 2019-09-28T07:38:59.287236Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option. app_1 | Sep 28 07:38:59 syslogd started: BusyBox v1.30.1 ... ... ... ... db_1 | 2019-09-28T07:39:11.612027Z 0 [Note] Event Scheduler: Loaded 0 events db_1 | 2019-09-28T07:39:11.612400Z 0 [Note] mysqld: ready for connections. db_1 | Version: '5.7.16' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL) app_1 | 2019/09/28 07:39:11 [TRACE] Custom path: /data/gogs app_1 | 2019/09/28 07:39:11 [TRACE] Log path: /app/gogs/log app_1 | 2019/09/28 07:39:11 [TRACE] Build Time: 2019-08-12 02:30:12 UTC app_1 | 2019/09/28 07:39:11 [TRACE] Build Git Hash: c154721f4a8f3e24d2f6fb61e74b4b64529255c2 app_1 | 2019/09/28 07:39:11 [ INFO] Private Repo 0.11.91.0811 app_1 | 2019/09/28 07:39:11 [ INFO] Cache Service Enabled app_1 | 2019/09/28 07:39:11 [ INFO] Session Service Enabled app_1 | 2019/09/28 07:39:14 [ INFO] Git Version: 2.22.0 app_1 | 2019/09/28 07:39:14 [ INFO] Git config user.name set to Gogs app_1 | 2019/09/28 07:39:14 [ INFO] Git config user.email set to gogs@fake.local app_1 | 2019/09/28 07:39:14 [ INFO] SQLite3 Supported app_1 | 2019/09/28 07:39:14 [ INFO] Run Mode: Production app_1 | 2019/09/28 07:39:14 [ INFO] Listen: http://0.0.0.0:3000 app_1 | [Macaron] 2019-09-28 07:39:14: Started GET / for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:39:14: Completed GET / 302 Found in 2.4563ms app_1 | [Macaron] 2019-09-28 07:39:14: Started GET /user/login for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:39:14: Completed GET /user/login 200 OK in 13.0259ms app_1 | [Macaron] 2019-09-28 07:39:20: Started GET / for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:39:20: Completed GET / 302 Found in 1.4996ms app_1 | [Macaron] 2019-09-28 07:39:20: Started GET /user/login for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:39:20: Completed GET /user/login 200 OK in 11.8768ms app_1 | [Macaron] 2019-09-28 07:39:25: Started GET / for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:39:25: Completed GET / 302 Found in 1.9598ms app_1 | [Macaron] 2019-09-28 07:39:25: Started GET /user/login for 127.0.0.1 app_1 | [Macaron] 2019-09-28 07:39:25: Completed GET /user/login 200 OK in 10.8364ms app_1 | [Macaron] 2019-09-28 07:39:30: Started GET / for 127.0.0.1 复制代码
访问 gogs.lab.com
打开页面,就可以开始使用啦。
备份数据需要使用 gogs backup
,不论是在 容器内执行,还是在容器外使用 docker exec
都是可以的。
chown -R /backup su git -c "/app/gogs/gogs backup -v --target /backup/" 2019/09/28 17:12:36 [ INFO] Backup succeed! Archive is located at: /app/gogs/backup/gogs-backup-20190928171236.zip 复制代码
比较巧合的是,去年九月开始,gogs 的更新开始了休眠模式,随后它的 fork 版本 Gitea 开始了茁壮成长。
下一篇聊聊,怎么使用 Traefik v2 TCP 模式搭建 Gitea 。
--EOF
我现在有一个小小的折腾群,里面聚集了一些喜欢折腾的小伙伴。
在不发广告的情况下,我们在里面会一起聊聊软件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术沙龙的资料。
喜欢折腾的小伙伴欢迎扫码添加好友。(请注明来源和目的,否则不会通过审核)