该渲染由 Shiro API 生成,可能存在排版问题,最佳体验请前往:https://innei.in/posts/Z-Turn/drone-self-host-ci-cd-with-github
群友说的我站点访问太慢。
因为部署在 Vercel 上,API 接口又在国内,通过 Zero 又套了一层,两层下来在国内的访问确实不是很好。
打算做一个在国内的镜像站。
原本 Kami 是通过 GitHub Actions 做的,通过发版然后把产物发布到 Release,SSH 连接到服务器之后再去拉取 GitHub Release,但是因为国内服务器现在访问 GitHub 真的太慢了,各大国内加速站也陆续挂壁了。
所以打算利用家用小主机完成本地部署,最后产物推送到云服务器。
问了群友之后,Drone CI 应该是是个不错的选择,Go 写的比较快也很轻量,可以非常简单和 GitHub 绑定。
总体的流程大概如下:
graph LR
A[GitHub Push Event] -->|Triggers| B(Drone Pipeline)
B --> C[Build Step]
C -->|Build Next.js Project| D[Zip Distribution]
D --> E[Deploy Step]
E -->|SCP Transfer| F[SSH Execute Deploy Script]
流程比较简单,接下来看看如何从零开始自建 Drone 和编写这个流程。
全程使用:Arch Linux + Docker 环境,其他环境仅供参考。
官方文档写的比较散,这里我踩了很多坑。但是最后的配置的也没有什么特别的,我就直接贴这里了。
name: drone
services:
drone-runner:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_RPC_PROTO=https
- DRONE_RPC_HOST=drone.innei.in
- DRONE_RUNNER_CAPACITY=2
- DRONE_RUNNER_NAME=runner
- DRONE_GITHUB_CLIENT_ID=
- DRONE_GITHUB_CLIENT_SECRET=
- DRONE_RPC_SECRET=
- DRONE_SERVER_HOST=
- DRONE_SERVER_PROTO=https
ports:
- 3000:3000
restart: always
container_name: runner
image: drone/drone-runner-docker:1
drone:
volumes:
- ./data:/data
environment:
- DRONE_GITHUB_CLIENT_ID=
- DRONE_GITHUB_CLIENT_SECRET=
- DRONE_RPC_SECRET=
- DRONE_SERVER_HOST=drone.innei.in
- DRONE_SERVER_PROTO=https
- DRONE_TLS_AUTOCERT=true
- DRONE_USER_CREATE=username:innei,machine:false,admin:true
ports:
- 80:80
- 443:443
restart: always
container_name: drone
image: drone/drone:2
networks:
mvlan:
ipv4_address: 10.0.0.47
networks:
mvlan:
external: true
上面配置缺失的环境变量需要去阅读文档,期间还需要创建一个自己的 GitHub App。
参考:
Runner 别忘了,我就是因为忘了配置 Runner,倒是 CI 一直都在 Loading 状态。
Drone 和 GitHub 连接是需要一个域名的(如果你没有域名可以试试用内网 IP 的方式),因为 oauth 的方式,验证成功之后会跳转回你设定的地址。我这里是 drone.innei.in。后续都按这个进行。
上面配置之后,在内网 10.0.0.47 去登录是无法登陆的,通过 GitHub oauth 之后会跳回配置的 drone.innei.in,但是这个地址我没还配。
我使用 Cloudflare Zero Trust 进行打洞。非常方便。
这样就好了。
进去之后,面板是空空的。这个没有关系。到此 Drone 就搞定了。
来到需要跑 CI 的 GitHub 仓库,建立一个 .drone.yml
文件在根目录,然后 push 到 GitHub,此时 drone 应该会出现这个 Repo,进入之后激活他。
kind: pipeline
name: build-and-package
platform:
os: linux
arch: amd64
steps:
- name: build
image: node:20-alpine
commands:
- 'npm i -g pnpm'
- 'pnpm install --no-frozen-lockfile'
- 'npm run build'
这步成功之后接下来就就是疯狂调 pipeline 了。
由于 NextJS build 时候需要 .env
但是我又不想一个一个传到 secrets,他不支持批量导入(能不能学学隔壁 Vercel),所以我想如何另一种方式传入 env。这里也花了很多时间。
首先想过用 http-server 托管 .env
,在 build 去下载它,因为在内网监听,相对还是安全。后来发现 Drone 的 volume 映射可行,如果现在就用这个方案了。
[!NOTE] 要使用 Volume 映射,你需要开启 Trusted 选项。
在做这一步你需要先开启管理员权限。如果是 docker 部署的,需要添加 ENV 到 Drone Server 中。
DRONE_USER_CREATE=username:innei,machine:false,admin:true
username
替换为 GitHub 用户名。重启容器后,再次进入 Drone 的 Repo Settings,会看到 Project Settings - Trusted 然后打开它。
我这里选择的是,Drone 在每个步骤都是 Docker 运行时。
在每个 step 都可以映射一个 volume 到宿主机文件路径。
我把项目需要的 .env
存放在 /home/innei/docker-compose/drone/public/shiro/.env
,在 build 的 step 添加 volume 映射。
volumes:
- name: shiro-env
host:
path: /home/innei/docker-compose/drone/public/shiro/.env
steps:
- name: build
image: node:20-alpine
commands:
- 'npm i -g pnpm'
- 'pnpm install --no-frozen-lockfile'
- 'npm run build'
volumes:
- name: shiro-env
path: /drone/src/.env
volumes 需要写两次,顶层的 volume 定义宿主机的绝对路径和 volume 名称,在 step 处则是 docker 重启的绝对路径。
我们可以把 build 和 deploy 拆分成两个 pipeline。但是前后依赖。
然后 build 完成之后,需要产物临时存储。我选择用 volume 方式,临时放在 /tmp 下,供 deploy 获取产物以推送到云服务器。
volumes:
- name: shiro-dist
host:
path: /tmp/shiro-dist
steps:
- name: build
image: node:20-alpine
commands:
- 'npm i -g pnpm'
- 'pnpm install --no-frozen-lockfile'
- 'npm run build'
volumes:
- name: shiro-env
path: /drone/src/.env
- name: dns
path: /etc/resolv.conf
- name: package
image: node:20-alpine
commands:
- 'pwd'
- 'ls -a'
- 'ls .next'
- 'apk add zip'
- 'sh ./standalone-bundle.sh'
volumes:
- name: shiro-dist # 这里映射
path: /drone/src/assets
depends_on:
- build
然后在 deploy 使用 scp 和 ssh 。
ind: pipeline
name: deploy
platform:
os: linux
arch: amd64
volumes:
- name: shiro-dist
host:
path: /tmp/shiro-dist
steps:
- name: transfer file
image: appleboy/drone-scp
settings:
host:
from_secret: ssh_host
username:
from_secret: ssh_username
key:
from_secret: ssh_key
port: 22
target: /home/deploy/shiro
source:
- assets/release.zip
rm_target: true
strip_components: 1
debug: true
volumes:
- name: shiro-dist # 这里 volume 可以获取到 build pipeline 的产物
path: /drone/src/assets
- name: deploy
image: appleboy/drone-ssh
settings:
host:
from_secret: ssh_host
username:
from_secret: ssh_username
key:
from_secret: ssh_key
port: 22
script:
- '\npm install --os=linux --cpu=x64 sharp --registry=https://registry.npmmirror.com'
- cd ~/shiro
- unzip -o release.zip
- rm release.zip
- ls
- cd standalone
- cp -r ~/node_modules/sharp ./node_modules
- ~/.n/bin/pm2 restart ecosystem.config.js
debug: true
depends_on:
- transfer file
depends_on:
- build-and-package # 这里依赖
ssh_
相关的则从 secrets 中获取。
至此结束,我也就尝试了四十几周目😂。