前几天完成了nuxt /server的迁移工作,以后本站的部署不再仅限于vercel,而是可以用任何工具
(见nitro deploy)。
发现一个比较轻量的CI/CD工具:Drone,成功给本站安排上了,但是只安排了一点
(下面会说明),地址是https://blog-cf.yunyuyuan.net/,运行在我家里的linux服务器上,使用cloudflared tunnel做内网穿透,关于cloudflared tunnel详见之前的文章。
之前我写过一篇jenkins+github配置CI/CD的文章,主要是入门Jenkins,当时觉得Jeninks太吃资源,而且各种配置混杂,管理页也很丑,所以后面没有学下去了。
安装drone
准备
- 一台linux服务器
- 已安装docker
- 已安装docker-compose
安装drone server
drone server用于接受webhook通知,然后调度drone-runner。由于drone server没有依赖,我选择安装进docker。drone提供多种集成方式,我这里使用的是github。首先按照官方教程创建一个Github OAuth应用,然后再安装drone server。 下面是我的drone/docker-compose.yml:
version: '3.5'
services:
app:
image: drone/drone:2
restart: always
user: 1000:1001
volumes:
- /var/lib/drone:/data
environment:
# Github OAuth app 信息
- DRONE_GITHUB_CLIENT_ID=your_github_oauth_client_id
- DRONE_GITHUB_CLIENT_SECRET=your_github_oauth_client_secret
# 用来和drone runner通信
- DRONE_RPC_SECRET=your_custom_secret
- DRONE_SERVER_HOST=drone.yourdomain.com
- DRONE_SERVER_PROTO=https
# 只允许特定github账号使用drone server
- DRONE_USER_FILTER=your_primary_github_account,your_another_github_account
# 指定一个账号为管理员
- DRONE_USER_CREATE=username:your_primary_github_account,admin:true,machine:false
# mysql数据库
- DRONE_DATABASE_DRIVER=mysql
- DRONE_DATABASE_DATASOURCE=drone:your_mysql_passwd@tcp(mariadb-app:3306)/drone?parseTime=true
ports:
- 9323:80
networks:
- mariadb-net
networks:
mariadb-net:
external: true我有一个已经在运行的mariadb(即mysql)容器,并且已经接入到了我创建的docker network bridge,名为mariadb-net,所以上面直接使用就行。
启动前,先在mysql里新建一个名为drone的用户,并新建一个名为drone的database,授权给用户drone。
drone server提供了一个控制面板,docker-compose up -d启动后,打开ip:9323就可以看到控制面板的欢迎页了。然后授权Github登录,授权后可以看到所有仓库都显示出来了,点击nuxt3-blog进行配置(请确保已经fork nuxt3-blog),首次进入会提示仓库未激活,点击激活。激活后,进入设置,打开这两个选项:
设置
然后,配置环境变量(MONGODB_URI是秘密内容,不能写在config.ts里,因为MOGODB_URI只会在服务端使用,浏览器无法看到。而另外三个是浏览器使用的,可以公开写在config.ts里):
环境变量
关于drone server的配置只有如上两步。
安装drone-runner
drone-runner用于执行pipeline,drone提供了多种runner。我目前配置的pipeline需要用到docker-runner,安装docker-runner比较简单,另写一个新的drone-runner/docker-compose.yml:
version: '3.5'
services:
app:
image: drone/drone-runner-docker:1
restart: always
volumes:
# 使用宿主机的docker管理
- /var/run/docker.sock:/var/run/docker.sock
environment:
# 与drone server的DRONE_RPC_SECRET保持一致
- DRONE_RPC_SECRET=your_custom_secret
- DRONE_RPC_HOST=drone.yourdomain.com
- DRONE_RPC_PROTO=https
- DRONE_RUNNER_CAPACITY=2
- DRONE_RUNNER_NAME=my-runner
ports:
- 9324:3000直接docker-compose up -d启动就好了,不需要做其他配置。
流程介绍
以下是比较通用的drone工作流程:
通用流程
以下是我的简陋版工作流程:
简陋流程
与通用流程相比,我没有上传到image registry,也没有另外的production server(一般是k8s)拉取image并部署,而是直接部署在安装drone的机器上,All in one!
drone server配置完毕,推送代码到github,应该就能触发drone的runner,编译完成后,docker打包image,然后重新运行新的image,网站更新。
自动化编译部署
此时可以看到有三个运行的容器:
容器
Pipeline
这是nuxt3-blog的pipeline:
kind: pipeline
type: docker
name: build
trigger:
event:
- push
branch:
- master
platform:
os: linux
arch: amd64
steps:
# 使用node编译nuxt3-blog
- name: build_project
image: node:18
volumes:
- name: cache
path: /drone/src/node_modules
environment:
MONGODB_URI:
from_secret: MONGODB_URI
# 也可以不写下面三个,转而写在config.ts
CommentRepoId:
from_secret: CommentRepoId
CommentDiscussionCategoryId:
from_secret: CommentDiscussionCategoryId
CloudflareAnalyze:
from_secret: CloudflareAnalyze
commands:
- npm i -g pnpm
- pnpm i
- pnpm build
# 使用docker打包.output, docker in docker!
- name: build_docker
image: docker:latest
volumes:
- name: docker
path: /var/run/docker.sock
environment:
APP_NAME: nuxt3-blog-app
IMAGE_NAME: nuxt3-blog:latest
MONGODB_URI:
from_secret: MONGODB_URI
commands:
# 先停止并删除已有的容器/镜像
- docker ps -q --filter "name=$APP_NAME" | xargs -r docker stop
- docker ps -aq --filter "name=$APP_NAME" | xargs -r docker rm
- docker images --filter "reference=$IMAGE_NAME" -q | xargs -r docker rmi
# 打包镜像
- docker build -t $IMAGE_NAME .
# 部署
- >
docker run -d
--name=$APP_NAME
--restart=always
-e MONGODB_URI=$MONGODB_URI
-p 127.0.0.1:8451:3000
$IMAGE_NAME
volumes:
- name: cache
host:
path: /var/cache/drone-nuxt3-blog
# 把drone runner的docker.sock传进来,而drone runner使用宿主机的docker.sock,所以这里相当于直接操作宿主机
- name: docker
host:
path: /var/run/docker.sock
