IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    自建 Drone 绑定 GitHub 实现 CI/CD

    静かな森发表于 2023-12-05 08:14:18
    love 0
    该渲染由 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 和编写这个流程。

    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。

    参考:

    • https://docs.drone.io/server/provider/github/
    • https://docs.drone.io/runner/docker/installation/linux/

    Runner 别忘了,我就是因为忘了配置 Runner,倒是 CI 一直都在 Loading 状态。

    Drone 和 GitHub 连接是需要一个域名的(如果你没有域名可以试试用内网 IP 的方式),因为 oauth 的方式,验证成功之后会跳转回你设定的地址。我这里是 drone.innei.in。后续都按这个进行。

    公网打洞

    上面配置之后,在内网 10.0.0.47 去登录是无法登陆的,通过 GitHub oauth 之后会跳回配置的 drone.innei.in,但是这个地址我没还配。

    我使用 Cloudflare Zero Trust 进行打洞。非常方便。

    这样就好了。

    进去之后,面板是空空的。这个没有关系。到此 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 然后打开它。

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

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

    成品配置

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

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

    看完了?说点什么呢



沪ICP备19023445号-2号
友情链接