4

容器方式下的轻量仓库与CI 使用方案:Gitea + Drone 基础篇

 3 years ago
source link: https://soulteary.com/2021/02/25/lightweight-code-warehouse-and-ci-usage-plan-in-docker-with-gitea-and-drone-part-1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

容器方式下的轻量仓库与CI 使用方案:Gitea + Drone 基础篇

2021年02月25日阅读Markdown格式12872字26分钟阅读

按照前篇文章所提,本篇将聊聊如何搭建使用 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” 可以看到服务已经启动就绪了。

完成安装等待配置的 Gitea

完成安装等待配置的 Gitea

不过,应用目前还需要等待我们进一步配置,才能够正常提供服务,我等待 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

配置 Gitea 应用

配置 Gitea 应用

直到我们配置完毕后,应用才能够真正的开始提供服务。

初始化应用配置

那么来简单讲讲如何进行配置,以及配置过程中的一些细节。

数据库可以根据自己实际情况切换为更为可靠的 PostgreSQL,如果你是个人或者小团队使用,使用 SQLite 问题也不大。

“一般设置”默认已经根据前文中的内容,进行了的自动化填充,这里如果还是想修改,仅建议修改 “站点名称”, 其余内容不建议进行修改。

“可选设置”包含三类配置项目:

  • “可选设置”中的“电子邮箱设置”可以根据你的实际情况完成配置,如果是个人使用,或者现在不想配置,可以先跳过,后续我们将配置更好用的推送通知,不依赖这个配置。
  • “可选设置”中的“服务器和三方设置”,我个人建议勾选“启用本地模式”,其余内容根据自己喜好来勾选即可,如果是个人使用,可以将各种注册方式都去掉。
  • “可选设置”中的“管理员账号设置”是必须完成配置填写的,填写方式可以参考下面的模式,建议全部使用小写英文,避免后续应用升级后出现预期之外的功能问题。

配置管理员账号示例

配置管理员账号示例

一切就绪后,点击安装按钮,完成安装,页面会自动跳转到新页面。

完成基础安装配置的 Gitea

完成基础安装配置的 Gitea

配置 Drone 跨应用自动授权(OAuth授权)

还记得前文中我们迟迟没有启动的 Drone Server 和 Drone Runner 吗?前文中我们在 Drone Server 中设置了一套 OAuth ClientID / Secret 变量,当我们正确设置了 OAuth 变量后,Drone 便能够根据 Gitea 进行自动的仓库、用户的创建和管理,而无需我们再进行手动配置。

某种程度来看,Drone 可以看作一套无状态的服务,这方便了后续我们扩容或者同类服务切换的可能性。

下面来就来讲讲如何配置跨应用授权。

点击右上角的个人用户头像,选择下拉菜单中的“设置”,在新页面中选择“应用”选项。

配置 Gitea 的 OAuth 应用

配置 Gitea 的 OAuth 应用

在名称处填写“DroneCI”,重定向 URI 填写之前的配置的域名,并带上 /login 路径:

http://drone.nuc.com/login

点击提交,可以看到我们需要的 OAuth ClientID / Secret 信息已经生成完毕。

获取创建好的 OAuth Key

获取创建好的 OAuth Key

将内容更新到我们上文中的 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 配置授权页面:

配置成功后,将能够看到 OAuth 授权提示

配置成功后,将能够看到 OAuth 授权提示

点击授权按钮后,我们会以当前用户身份自动登录 Drone 。

至此,基础安装和配置部分便完成啦。

以 Gitea 身份自动登录 Drone

以 Gitea 身份自动登录 Drone

虽然安装配置结束,但是距离我们使用 Drone 进行 CI 来提升开发效率还早,关于 CI 过程的各种实践也还没有涉及到。

譬如“仓库和CI系统的进一步安全认证策略”、“细粒度的配置任务过程提醒”、“根据需求完成节点扩容”、“仓库构建内容持久化”、“CI和仓库之间更安全的数据交互”,以及“如何使用我们本地的机器来服务公网诸如 GitHub 等自动化过程”等话题都还没有聊到。

下一篇内容,我们将聊聊 Drone 的一些实战,将上述内容逐步涉及,以及针对本篇内容中的一些配置进行详细展开。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK