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

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。