使用Drone+docker配置本地轻量化CI/CD

  前几天完成了nuxt /server的迁移工作,以后本站的部署不再仅限于vercel,而是可以用任何工具sticker(见nitro deploy)。   发现一个比较轻量的CI/CD工具:Drone,成功给本站安排上了,但是只安排了一点sticker(下面会说明),地址是https://blog-drone-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

附:定期备份图片

  Drone的cronjob可以做定期任务,我目前使用第三方免费图床smms.app存储本站图片,但第三方图床没有办法保证稳定性,所以定期备份是很有必要的。   vercel也支持cronjob,但我没做,原因是没地方缓存已下载的图片,而且需要找一个支持api的网盘,不太方便。   本站已经有两个脚本,可以手动备份图片,分别是npm run genimgnpm run downimggenerate-img-map.ts搜索全站所有图片url,并输出到img.jsondownload-img.ts读取img.json,下载图片到/imgs文件夹。   npm run genimg需要输入密码和正则表达式,因为本站的内容是可以加密的,必须解密,才能获取全部图片的url,而正则表达式用来匹配图片,例如smms的图片格式是https?://[\w-]+\.loli\.net/\d{4}/\d{2}/\d{2}/[a-zA-Z0-9]+\.(jpg|jpeg|webp|gif|png)

新增环境变量与cronjob

  新增两个环境变量,NB_PASSWDNB_IMG_REGEX,分别代表密码和正则表达式(可选变量:FILE_USERFILE_GROUP,分别代表下载的图片的owner id和group id)。新增一个名为backup_img的cronjob,每周执行: Drone server配置Drone server配置

修改pipeline

# ...... # .drone.yml 新增如下内容 --- kind: pipeline type: docker name: backup_img trigger: # 由cronjob触发 event: - cron cron: - backup_img platform: os: linux arch: amd64 steps: - name: backup_img image: node:18 volumes: - name: cache path: /drone/src/node_modules - name: imgs path: /drone/src/imgs environment: FILE_USER: from_secret: FILE_USER FILE_GROUP: from_secret: FILE_GROUP NB_PASSWD: from_secret: NB_PASSWD NB_IMG_REGEX: from_secret: NB_IMG_REGEX commands: - npm i -g pnpm - pnpm genimg # 生成img.json - pnpm downimg # 读取img.json,下载 volumes: - name: cache host: path: /var/cache/drone-nuxt3-blog - name: imgs host: # 图片将被保存在宿主机的如下路径,脚本不会下载已有的图片 path: /data/nuxt3-blog-imgs

运行效果运行效果

标签:运维
1年前
0