容器方式下的轻量仓库与CI 使用方案:Gitea + Drone 基础篇
按照前篇文章所提,本篇将聊聊如何搭建使用 Gitea 和 Drone。因为内容过多,这个内容我计划拆为多篇来讲述,本篇先聊聊如何搭建使用。
写在前面
为了方便配置域名、证书、以及后续潜在的动态扩容,我们可以搭配 Traefik 一起使用,让 Drone 和 Gitea 都只专注于 CI 和 代码存储相关功能,将“加密证书,流量转发相关”的事务交给 Traefik 处理。
相比较前篇内容中提到的老版本的 GitLab,这个方案对于资源的要求更低,让本地运行一套完整 CI 对于机器的负担降到了非常低的水平,日常运行资源占用几乎可以忽略不计(不算 CI 执行时的容器,即使算上 Traefik ,日常使用内存占用不到 200M):
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
5295526d73f5 runner.nuc.com 0.00% 6.215MiB / 31.23GiB 0.02% 30.4kB / 24.3kB 11.8MB / 0B 17
9e810f12e2b4 drone.nuc.com 0.00% 10.56MiB / 31.23GiB 0.03% 36.5kB / 25.3kB 33.9MB / 0B 13
551b2e8683ba gitea.nuc.com 2.05% 152MiB / 31.23GiB 0.48% 104kB / 439kB 88.8MB / 459kB 18
f4606080ef23 traefik 2.40% 20.49MiB / 31.23GiB 0.06% 483kB / 282kB 58.1MB
这套方案对于资源的要求低,本质是因为软件数量/功能相比较 GitLab 少了至少一个数量级,而且软件编写语言单一,相比较非编译优化执行的 Ruby ,编译执行的 Go 语言程序性能上有非常变态的提升,之前我在一篇《重定向的九种方案及性能比较》的文章中也有提过。
如果你好奇完整的 GitLab CI 相关的功能和发展历程,可以翻阅这篇文章《聊聊 GitLab 的CI / CD 功能发展历程》。
搭建基础环境
接下来先聊聊如何搭建。
系统环境准备
本文采用容器方式部署,简单来说,只要你的机器环境可以运行 Docker 就可以,所以笔记本也好、NUC也罢都是可以的、更何况是标准的 Linux 系统环境。
如果你对 Linux 不甚熟悉,我推荐使用容器友好的 Ubuntu 系统,如果你希望补充、了解一些基础操作,可以翻阅以往的文章。
当然,如果你使用 MacOS ,那么只需要安装 Docker Desktop 即可。
Traefik 前置相关安装配置
Traefik 的搭建和使用,我的老读者都熟悉了,这里不就过多赘述了,不熟悉的同学可以从《更简单的 Traefik 2 使用方式》进行了解,如果你还想了解更多相关内容,可以翻阅这个标签合集。
代码仓库 Gitea 安装配置
去年年初《使用 Docker 和 Traefik v2 搭建轻量代码仓库(Gitea)》一文中,我有提到过如何安装,当时选择了使用 Traefik 转发 Git Server 的 SSH 端口,本次我们换一种方式来进行端口暴露,减少应用之间的耦合,以及进一步提升效率。
为了方便后续维护,我们需要先定义一个 .env
文件,在里面配置好后续可能会有变化,以及需要我们自定义的内容:
# 应用名称
SERVICE_NAME=Gitea
# 服务域名
SERVICE_DOMAIN=gitea.nuc.com
# 使用的应用镜像
DOCKER_IMAGE=gitea/gitea:1.13.2
# 允许公网,跨主机访问 Git SSH Server
#SSH_PORT_EXPOSE=22
# 仅允许内部 CI ,本地机器使用 SSH 访问服务
SSH_PORT_EXPOSE=127.0.0.1:22
接着来定义服务编排配置文件,一般情况下你只需要复制粘贴即可,而不需要调整:
version: '3.6'
services:
gitea:
image: ${DOCKER_IMAGE}
container_name: ${SERVICE_DOMAIN}
ports:
- ${SSH_PORT_EXPOSE}:22
environment:
- USER_UID=1000
- USER_GID=1000
- APP_NAME=${SERVICE_NAME}
- RUN_MODE=prod
- RUN_USER=git
- SSH_DOMAIN=${SERVICE_DOMAIN}
- SSH_PORT=22
- SSH_LISTEN_PORT=22
- HTTP_PORT=80
- ROOT_URL=https://${SERVICE_DOMAIN}
- LFS_START_SERVER=true
- REQUIRE_SIGNIN_VIEW=true
- DB_TYPE=sqlite3
- INSTALL_LOCK=false
- DISABLE_GRAVATAR=true
networks:
- traefik
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.giteaweb.middlewares=https-redirect@file"
- "traefik.http.routers.giteaweb.entrypoints=http"
- "traefik.http.routers.giteaweb.rule=Host(`${SERVICE_DOMAIN}`)"
- "traefik.http.routers.giteassl.middlewares=content-compress@file"
- "traefik.http.routers.giteassl.entrypoints=https"
- "traefik.http.routers.giteassl.tls=true"
- "traefik.http.routers.giteassl.rule=Host(`${SERVICE_DOMAIN}`)"
- "traefik.http.services.giteabackend.loadbalancer.server.scheme=http"
- "traefik.http.services.giteabackend.loadbalancer.server.port=80"
volumes:
# 标准 Linux 系统下使用
# - /etc/localtime:/etc/localtime:ro
# - /etc/timezone:/etc/timezone:ro
- ./repositories:/data/git/repositories
- ./data:/data/gitea/
logging:
driver: "json-file"
options:
max-size: "10m"
extra_hosts:
- "${SERVICE_DOMAIN}:127.0.0.1"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy off localhost || exit 1"]
interval: 5s
networks:
traefik:
external: true
将上面的内容保存为 docker-compose.yml
后,使用 docker-compose up -d
来启动服务。
使用 docker-compose logs -f
来观察日志:
gitea.nuc.com | Generating /data/ssh/ssh_host_ed25519_key...
gitea.nuc.com | Generating /data/ssh/ssh_host_rsa_key...
gitea.nuc.com | Generating /data/ssh/ssh_host_dsa_key...
gitea.nuc.com | Generating /data/ssh/ssh_host_ecdsa_key...
gitea.nuc.com | Could not load host certificate "/data/ssh/ssh_host_ed25519_cert": No such file or directory
gitea.nuc.com | Could not load host certificate "/data/ssh/ssh_host_rsa_cert": No such file or directory
gitea.nuc.com | Could not load host certificate "/data/ssh/ssh_host_ecdsa_cert": No such file or directory
gitea.nuc.com | Could not load host certificate "/data/ssh/ssh_host_dsa_cert": No such file or directory
gitea.nuc.com | Server listening on :: port 22.
gitea.nuc.com | Server listening on 0.0.0.0 port 22.
gitea.nuc.com | 2021/02/25 16:31:51 cmd/web.go:108:runWeb() [I] Starting Gitea on PID: 15
gitea.nuc.com | 2021/02/25 16:31:51 ...dules/setting/git.go:91:newGit() [I] Git Version: 2.26.2, Wire Protocol Version 2 Enabled
gitea.nuc.com | 2021/02/25 16:31:51 routers/init.go:132:GlobalInit() [T] AppPath: /app/gitea/gitea
gitea.nuc.com | 2021/02/25 16:31:51 routers/init.go:133:GlobalInit() [T] AppWorkPath: /app/gitea
gitea.nuc.com | 2021/02/25 16:31:51 routers/init.go:134:GlobalInit() [T] Custom path: /data/gitea
gitea.nuc.com | 2021/02/25 16:31:51 routers/init.go:135:GlobalInit() [T] Log path: /data/gitea/log
gitea.nuc.com | 2021/02/25 16:31:51 ...dules/setting/log.go:297:newLogService() [I] Gitea v1.13.2 built with GNU Make 4.3, go1.15.7 : bindata, timetzdata, sqlite, sqlite_unlock_notify
gitea.nuc.com | 2021/02/25 16:31:51 ...dules/setting/log.go:343:newLogService() [I] Gitea Log Mode: Console(Console:info)
gitea.nuc.com | 2021/02/25 16:31:51 ...dules/setting/log.go:249:generateNamedLogger() [I] Macaron Log: Console(console:info)
gitea.nuc.com | 2021/02/25 16:31:51 ...dules/setting/log.go:249:generateNamedLogger() [I] Router Log: Console(console:info)
gitea.nuc.com | 2021/02/25 16:31:51 ...les/setting/cache.go:70:newCacheService() [I] Cache Service Enabled
gitea.nuc.com | 2021/02/25 16:31:51 ...les/setting/cache.go:81:newCacheService() [I] Last Commit Cache Service Enabled
gitea.nuc.com | 2021/02/25 16:31:51 ...s/setting/session.go:63:newSessionService() [I] Session Service Enabled
gitea.nuc.com | 2021/02/25 16:31:51 ...s/storage/storage.go:151:initAttachments() [I] Initialising Attachment storage with type:
gitea.nuc.com | 2021/02/25 16:31:51 ...les/storage/local.go:43:NewLocalStorage() [I] Creating new Local Storage at /data/gitea/attachments
gitea.nuc.com | 2021/02/25 16:31:51 ...s/storage/storage.go:145:initAvatars() [I] Initialising Avatar storage with type:
gitea.nuc.com | 2021/02/25 16:31:51 ...les/storage/local.go:43:NewLocalStorage() [I] Creating new Local Storage at /data/gitea/avatars
gitea.nuc.com | 2021/02/25 16:31:51 ...s/storage/storage.go:163:initRepoAvatars() [I] Initialising Repository Avatar storage with type:
gitea.nuc.com | 2021/02/25 16:31:51 ...les/storage/local.go:43:NewLocalStorage() [I] Creating new Local Storage at /data/gitea/repo-avatars
gitea.nuc.com | 2021/02/25 16:31:51 ...s/storage/storage.go:157:initLFS() [I] Initialising LFS storage with type:
gitea.nuc.com | 2021/02/25 16:31:51 ...les/storage/local.go:43:NewLocalStorage() [I] Creating new Local Storage at /data/git/lfs
gitea.nuc.com | 2021/02/25 16:31:51 routers/init.go:176:GlobalInit() [I] SQLite3 Supported
gitea.nuc.com | 2021/02/25 16:31:51 routers/init.go:56:checkRunMode() [I] Run Mode: Production
gitea.nuc.com | 2021/02/25 16:31:51 cmd/web.go:163:runWeb() [I] Listen: http://0.0.0.0:80
gitea.nuc.com | 2021/02/25 16:31:51 cmd/web.go:166:runWeb() [I] LFS server enabled
gitea.nuc.com | 2021/02/25 16:31:51 ...s/graceful/server.go:55:NewServer() [I] Starting new server: tcp:0.0.0.0:80 on PID: 15
gitea.nuc.com | 2021/02/25 16:31:56 Started GET / for 127.0.0.1
gitea.nuc.com | 2021/02/25 16:31:56 Completed GET / 200 OK in 3.875698ms
gitea.nuc.com | 2021/02/25 16:32:01 Started GET / for 127.0.0.1
gitea.nuc.com | 2021/02/25 16:32:01 Completed GET / 200 OK in 1.131553ms
等待服务日志出现 Starting new server: tcp:0.0.0.0:80 后,打开浏览器访问我们绑定的域名 “gitea.nuc.com” 可以看到服务已经启动就绪了。
不过,应用目前还需要等待我们进一步配置,才能够正常提供服务,我等待 Drone CI 配置完毕,再进行下一步。
Drone 的服务端(Server)配置
同样的,先创建 .env
配置文件,这里有一部分内容,我们需要配置完 Gitea 后才能获取,所以你也可以选择在配置完 Gitea 后,再来完成下面的内容:
# 服务域名
SERVICE_DOMAIN=drone.nuc.com
# 使用的应用镜像
DOCKER_IMAGE=drone/drone:1.10.1
# Drone 服务端和 Runner 之间通讯秘钥
DRONE_RPC_SECRET=YOUR_RANDOM_KEY
# Drone 超级管理员账号,根据自己需求修改
DRONE_ADMIN_USERNAME=soulteary
# Gitea 域名配置
GITEA_DOMAIN=gitea.nuc.com
# Gitea OAuth ClientID / Secret
# 稍后配置 Gitea 后替换即可
DRONE_GITEA_CLIENT_ID=a0da8a47-e89e-48ea-8ea3-08f2554511b1
DRONE_GITEA_CLIENT_SECRET=nrdSbAX_4AXexpUG_ZDw9iF640M8uC79h1raJxnX74I=
服务编排配置文件也比较简单,不需要做修改,直接复制粘贴到你的配置即可:
version: '3.6'
services:
drone:
image: ${DOCKER_IMAGE}
container_name: ${SERVICE_DOMAIN}
environment:
- DRONE_GITEA_SERVER=http://${GITEA_DOMAIN}
- DRONE_GITEA_CLIENT_ID=${DRONE_GITEA_CLIENT_ID}
- DRONE_GITEA_CLIENT_SECRET=${DRONE_GITEA_CLIENT_SECRET}
- DRONE_LOGS_TRACE=true
- DRONE_AGENTS_ENABLED=true
- DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
- DRONE_SERVER_HOST=${SERVICE_DOMAIN}
- DRONE_SERVER_PROTO=http
- DRONE_CLEANUP_INTERVAL=60m
- DRONE_CLEANUP_DISABLED=false
- DRONE_CLEANUP_DEADLINE_RUNNING=1h
- DRONE_CLEANUP_DEADLINE_PENDING=2h
- DRONE_USER_CREATE=username:${DRONE_ADMIN_USERNAME},admin:true
networks:
- traefik
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.drone-web.middlewares=https-redirect@file"
- "traefik.http.routers.drone-web.entrypoints=http"
- "traefik.http.routers.drone-web.rule=Host(`${SERVICE_DOMAIN}`)"
- "traefik.http.routers.drone-ssl.middlewares=content-compress@file"
- "traefik.http.routers.drone-ssl.entrypoints=https"
- "traefik.http.routers.drone-ssl.tls=true"
- "traefik.http.routers.drone-ssl.rule=Host(`${SERVICE_DOMAIN}`)"
- "traefik.http.services.drone-backend.loadbalancer.server.scheme=http"
- "traefik.http.services.drone-backend.loadbalancer.server.port=80"
volumes:
# 标准 Linux 系统下使用
# - /etc/localtime:/etc/localtime:ro
# - /etc/timezone:/etc/timezone:ro
- ./data:/data
logging:
driver: "json-file"
options:
max-size: "10m"
extra_hosts:
- "${SERVICE_DOMAIN}:127.0.0.1"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:80/healthz || exit 1"]
interval: 5s
networks:
traefik:
external: true
因为我们尚未配置好 Gitea ,所以先不着急启动服务。
Drone 的客户端(Runner)配置
我们接着来配置 Drone Runner ,还是先创建一套 .env
文件:
# 服务域名
SERVICE_DOMAIN=runner.nuc.com
# 使用的应用镜像
DOCKER_IMAGE=drone/drone-runner-docker:1.6.3
# Drone 服务端和 Runner 之间通讯秘钥
DRONE_RPC_SECRET=YOUR_RANDOM_KEY
# Runner 最大并发数量,根据自己需求来
DRONE_RUNNER_CAPACITY=2
# Drone 服务配置域名
DRONE_SERVER_DOMAIN=drone.nuc.com
然后是定义容器编排配置文件:
version: '3.6'
services:
drone-runner:
image: drone/drone-runner-docker:1.6.3
container_name: ${SERVICE_DOMAIN}
expose:
- 3000
environment:
- DRONE_RPC_PROTO=http
- DRONE_RPC_HOST=${DRONE_SERVER_DOMAIN}
- DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
- DRONE_RUNNER_CAPACITY=${DRONE_RUNNER_CAPACITY}
- DRONE_RUNNER_NAME=${SERVICE_DOMAIN}
- DRONE_RUNNER_NETWORKS=traefik
networks:
- traefik
restart: always
volumes:
# 标准 Linux 系统下使用
# - /etc/localtime:/etc/localtime:ro
# - /etc/timezone:/etc/timezone:ro
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
logging:
driver: "json-file"
options:
max-size: "10m"
extra_hosts:
- "${SERVICE_DOMAIN}:127.0.0.1"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:3000/healthz || exit 1"]
interval: 5s
networks:
traefik:
external: true
将上面的配置保存为 docker-compose.yml
。和 Drone Server 一样,因为依赖 Gitea 配置,所以这里我们先不着急启动服务。
代码仓库 Gitea 的进一步配置
访问安装后的 Gitea,不论是点击“登陆”亦或者“注册”,界面都将会来到“初始配置”页面:https://gitea.nuc.com/install
。
直到我们配置完毕后,应用才能够真正的开始提供服务。
初始化应用配置
那么来简单讲讲如何进行配置,以及配置过程中的一些细节。
数据库可以根据自己实际情况切换为更为可靠的 PostgreSQL
,如果你是个人或者小团队使用,使用 SQLite 问题也不大。
“一般设置”默认已经根据前文中的内容,进行了的自动化填充,这里如果还是想修改,仅建议修改 “站点名称”, 其余内容不建议进行修改。
“可选设置”包含三类配置项目:
- “可选设置”中的“电子邮箱设置”可以根据你的实际情况完成配置,如果是个人使用,或者现在不想配置,可以先跳过,后续我们将配置更好用的推送通知,不依赖这个配置。
- “可选设置”中的“服务器和三方设置”,我个人建议勾选“启用本地模式”,其余内容根据自己喜好来勾选即可,如果是个人使用,可以将各种注册方式都去掉。
- “可选设置”中的“管理员账号设置”是必须完成配置填写的,填写方式可以参考下面的模式,建议全部使用小写英文,避免后续应用升级后出现预期之外的功能问题。
一切就绪后,点击安装按钮,完成安装,页面会自动跳转到新页面。
配置 Drone 跨应用自动授权(OAuth授权)
还记得前文中我们迟迟没有启动的 Drone Server 和 Drone Runner 吗?前文中我们在 Drone Server 中设置了一套 OAuth ClientID / Secret 变量,当我们正确设置了 OAuth 变量后,Drone 便能够根据 Gitea 进行自动的仓库、用户的创建和管理,而无需我们再进行手动配置。
某种程度来看,Drone 可以看作一套无状态的服务,这方便了后续我们扩容或者同类服务切换的可能性。
下面来就来讲讲如何配置跨应用授权。
点击右上角的个人用户头像,选择下拉菜单中的“设置”,在新页面中选择“应用”选项。
在名称处填写“DroneCI”,重定向 URI 填写之前的配置的域名,并带上 /login
路径:
http://drone.nuc.com/login
点击提交,可以看到我们需要的 OAuth ClientID / Secret 信息已经生成完毕。
将内容更新到我们上文中的 Drone Server 的配置中,我们开始对 Drone 进行配置。
完成 Drone 的最后配置
对 Drone Server 的 .env
配置中的信息进行更新,将上面的 OAuth 信息填入配置中:
DRONE_GITEA_CLIENT_ID=ed292553-9dca-4f76-856f-4172c8ee4186
DRONE_GITEA_CLIENT_SECRET=3FxbTuNomJ4fUiUnZuA2NXcX083v1oK76ntsOxIuy6U=
然后使用 docker-compose up -d
启动服务,顺便进入 Drone Runner 目录,将 Runner 也使用 docker-compose up -d
一并启动,等待大概五秒钟,浏览器访问我们配置的 CI 服务域名:drone.nuc.com
,会看到浏览器自动跳转到了 OAuth 配置授权页面:
点击授权按钮后,我们会以当前用户身份自动登录 Drone 。
至此,基础安装和配置部分便完成啦。
最后
虽然安装配置结束,但是距离我们使用 Drone 进行 CI 来提升开发效率还早,关于 CI 过程的各种实践也还没有涉及到。
譬如“仓库和CI系统的进一步安全认证策略”、“细粒度的配置任务过程提醒”、“根据需求完成节点扩容”、“仓库构建内容持久化”、“CI和仓库之间更安全的数据交互”,以及“如何使用我们本地的机器来服务公网诸如 GitHub 等自动化过程”等话题都还没有聊到。
下一篇内容,我们将聊聊 Drone 的一些实战,将上述内容逐步涉及,以及针对本篇内容中的一些配置进行详细展开。
–EOF
本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2021年02月25日
统计字数: 12872字
阅读时间: 26分钟阅读
本文链接: https://soulteary.com/2021/02/25/lightweight-code-warehouse-and-ci-usage-plan-in-docker-with-gitea-and-drone-part-1.html