自建三节点 K3s 集群搭建 Drone CI/CD 流水线
本文记录如何在家庭网络环境中,使用 Gitee、Drone CI、自建 Docker Registry、GitOps 和 Argo CD,搭建完整的持续集成与持续交付流程。
一、最终架构
text
Gitee Push
-> Gitee WebHook
-> Drone Server / Runner(node2)
-> 测试代码
-> 构建 Docker 镜像
-> 推送 Registry(node1)
-> 更新 GitOps 仓库
-> Argo CD 自动同步
-> K3s 应用节点滚动更新
三台主机职责:
- master:K3s control-plane、Argo CD
- node1:RustFS、外接硬盘、自建 Docker Registry
- node2:Drone Server、Drone Docker Runner
Ingress、RustFS 和本地磁盘属于基础设施,不应在应用发布流水线中修改。
二、在 node2 启动 Drone
项目配置位于:
text
deploy/drone/docker-compose.yaml
deploy/drone/.env.example
deploy/drone/.gitignore
在 node2 执行:
bash
cd deploy/drone
cp .env.example .env
vim .env
sudo docker compose up -d
sudo docker compose ps
环境变量包括 Gitee OAuth Client ID、Client Secret、Server 和 Runner 共用的 RPC Secret、Drone 对外地址以及管理员用户名。RPC Secret 可用以下命令生成:
bash
openssl rand -hex 32
Server 与 Runner 的 RPC Secret 必须完全一致。
三、配置 Gitee OAuth 和 WebHook
家庭宽带封禁 80 和 443 时,可以使用高位端口,例如公网 18444 转发到 node2 的 18444。
Gitee OAuth 回调地址:
text
http://公网域名或IP:18444/login
Gitee WebHook 地址:
text
http://公网域名或IP:18444/hook
只选择 Push 事件即可。地址必须能被 Gitee 公网访问,不能使用 localhost 或集群内部地址。
四、在 K3s 中部署自建 Registry
node1 的外接分区已经挂载到:
text
/dev/sdb1 -> /data/sdb
不要格式化或卸载 RustFS 正在使用的磁盘。为 Registry 使用独立目录:
bash
sudo mkdir -p /data/sdb/registry
项目中的 K3s Registry 清单位于:
text
deploy/registry/k3s/
├── namespace.yaml
├── pv.yaml
├── secret.yaml.example
├── deployment.yaml
├── service.yaml
└── kustomization.yaml
Registry Pod 固定在 node1,PV 使用 /data/sdb/registry,Service 使用 NodePort 30500。部署前创建认证 Secret:
bash
read -r -p "Registry username: " REGISTRY_USER
read -r -s -p "Registry password: " REGISTRY_PASSWORD
printf '\n'
sudo docker run --rm httpd:2.4-alpine \
htpasswd -Bbn "$REGISTRY_USER" "$REGISTRY_PASSWORD" \
> /tmp/registry-htpasswd
kubectl apply -f deploy/registry/k3s/namespace.yaml
kubectl create secret generic movie-registry-auth \
-n registry \
--from-file=htpasswd=/tmp/registry-htpasswd \
--dry-run=client -o yaml | kubectl apply -f -
rm -f /tmp/registry-htpasswd
部署 Registry:
bash
kubectl apply -f deploy/registry/k3s/pv.yaml
kubectl apply -f deploy/registry/k3s/deployment.yaml
kubectl apply -f deploy/registry/k3s/service.yaml
kubectl -n registry rollout status deployment/movie-registry
Registry v2 没有网页管理界面,使用 API 测试:
bash
curl -i -u '用户名:密码' http://节点1内网IP:30500/v2/
返回 HTTP 200 和空 JSON 对象即表示正常。
五、配置 K3s 和 Drone 访问 Registry
在 node1、node2 创建 K3s 配置文件:
text
/etc/rancher/k3s/registries.yaml
内容如下,替换节点 IP、用户名和密码:
yaml
mirrors:
"节点1内网IP:30500":
endpoint:
- "http://节点1内网IP:30500"
configs:
"节点1内网IP:30500":
auth:
username: registry-user
password: registry-password
保存后执行:
bash
sudo chmod 600 /etc/rancher/k3s/registries.yaml
sudo systemctl restart k3s-agent
node2 的 Docker daemon 还需要允许 HTTP Registry。编辑 /etc/docker/daemon.json:
json
{
"insecure-registries": ["节点1内网IP:30500"]
}
然后重启并测试:
bash
sudo systemctl restart docker
docker login 节点1内网IP:30500
六、配置 Drone Secrets
在 Drone 仓库 Settings -> Secrets 中添加:
text
image_repository=节点1内网IP:30500/movie-web
registry_username=Registry用户名
registry_password=Registry密码
gitops_repo=GitOps仓库地址
gitops_username=Gitee用户名
gitops_token=Gitee私人令牌
gitops_branch=main
gitops_file=apps/movie-web/deployment.yaml
不要把密码和 Token 写入 .drone.yml 或提交到 Git。image_repository 不要带 latest,流水线使用提交 SHA 作为不可变 Tag。
七、Drone 到 Argo CD
源码仓库的 .drone.yml 依次执行:测试、构建镜像、推送 Registry、更新 GitOps 仓库。
Drone 不直接执行 kubectl apply。Argo CD 监听 GitOps 仓库提交,并通过自动同步将新版本发布到 K3s。
建议 Application 开启:
yaml
syncPolicy:
automated:
prune: true
selfHeal: true
八、常见问题
- 401 Unauthorized:检查 Registry Secret 中的 htpasswd 和账号密码。
- HTTP response to HTTPS client:Docker 未配置 insecure-registries,或应改用 HTTPS。
- ImagePullBackOff:检查 node1、node2 的 registries.yaml 和镜像地址。
- Registry 浏览器空白:registry:2 没有 Web UI,使用 /v2/ API 验证。
- Runner 离线:检查 Server 与 Runner 的 RPC Secret 是否一致。
九、安全建议
- 不要提交 .env、Registry 密码、Gitee Token 和 RPC Secret。
- 不要将 Docker 2375 端口暴露到公网。
- HTTP Registry 只用于可信内网,正式环境建议使用 HTTPS。
- node1 是 Local PV 单点存储,应定期备份 Registry 数据。