banner
innei

innei

写代码是因为爱,写到世界充满爱!
github
telegram
twitter

自建 Drone 绑定 GitHub 实现 CI/CD

群友说的我站点访问太慢。

因为部署在 Vercel 上,API 接口又在国内,通过 Zero 又套了一层,两层下来在国内的访问确实不是很好。

打算做一个在国内的镜像站。

原本 Kami 是通过 GitHub Actions 做的,通过发版然后把产物发布到 Release,SSH 连接到服务器之后再去拉取 GitHub Release,但是因为国内服务器现在访问 GitHub 真的太慢了,各大国内加速站也陆续挂壁了。

所以打算利用家用小主机完成本地部署,最后产物推送到云服务器。

问了群友之后,Drone CI 应该是是个不错的选择,Go 写的比较快也很轻量,可以非常简单和 GitHub 绑定。

总体的流程大概如下:

Mermaid Loading...

流程比较简单,接下来看看如何从零开始自建 Drone 和编写这个流程。

Drone 部署#

Docker Compose 一把梭#

全程使用: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 进行打洞。非常方便。

image

这样就好了。

image

进去之后,面板是空空的。这个没有关系。到此 Drone 就搞定了。

Pipeline 编写#

来到需要跑 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 然后打开它。

image

我这里选择的是,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 中获取。

至此结束,我也就尝试了四十几周目😂。

image

成品配置#

https://github.com/Innei/Shiro/blob/main/.drone.yml

参考:https://www.timochan.cn/posts/jc/drone_workflows#Preface

此文由 Mix Space 同步更新至 xLog
原始链接为 https://innei.in/posts/Z-Turn/drone-self-host-ci-cd-with-github


Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.