GitHub Actions,臥槽!牛批!

進擊的Coder發表於2022-12-06


前段時間我更新了我的分散式爬蟲管理框架—— Gerapy

現在 DevOps 的理念可謂是相當火,其中 CI/CD(持續整合、持續部署)是必不可少的環節。有了它們,我們開發完軟體之後,一些測試、構建、部署的環節就可以自動化完成了。

我開發的的這款分散式爬蟲管理框架—— Gerapy,程式碼也是放在了 GitHub 上面,但在之前 GitHub 上面是缺少原生的 CI/CD 功能支援的,可能需要根據第三工具或者 Webhook 等來配合實現專案的自動測試、構建和部署。

比如我可能有這麼一些需求:

每次合併程式碼到 master 分支時,想測試這個專案能否在各個版本的 Python 環境下正常安裝和執行。我為 Gerapy 新建了一個獨立的 Repo,叫做 Gerapy/Gerapy,在 docs 資料夾下存放文件說明,但我還另外新建了一個 Repo 專門用來存放文件,叫做 Gerapy/Docs,希望能把 Gerapy/Gerapy 的 docs 子資料夾下的內容整個自動同步到 Gerapy/Docs 這個 Repo 的根目錄。每次 Gerapy 釋出新版本的時候,自動構建 Docker 映象,並上傳到 Docker Hub,打上 latest 標籤和版本號標籤。每次 master 分支提交程式碼的時候,自動構建 Docker 映象,並上傳到 Docker Hub,打上 master 標籤,代表當前 master 分支版本。

上面的功能之前有一部分工作是手工操作的,有一部分是藉助於第三方工具來自動操作的,感覺並不是一個很好的解決方案

在最近一段時間,GitHub 上面上線了 Actions 功能,它就是為 CI/CD 而生的,和 GitHub 專案原生緊密結合。然而幾個月以來一直處於內測階段。就在 11 月 13 日,GitHub Actions 功能正式上線了。

上線之後,我就開始正式使用這個功能了,是真的香!

上面的四個需求,我用 GitHub Actions 已經完全實現了自動化,非常簡單方便。

接下來簡單介紹下我的一些實現方式。

GitHub Actions,臥槽!牛批!

GitHub Actions

首先簡單介紹下 GitHub Actions,其官方介紹頁面為:,介紹語如下:

Automate your workflow from idea to production. GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.

簡而言之就是提供了一個高效易用的 CI/CD 工作流,幫助我們自動構建、測試、部署我們的程式碼。


GitHub Actions,臥槽!牛批!另外它支援三大平臺—— Linux、MacOS、Windows,支援任何程式語言,而且官方提供了許許多多的 Actions 庫供我們直接使用,幫助我們更快地搭建工作流。

GitHub Actions 的官方文件可以見:,如果大家想好好研究下的話,一定要好好看看。

下面我就介紹我使用 GitHub Actions 實現上文所述的四個需求的方法。

自動測試

由於我開發的 Gerapy 是一個 Python Package,因此我看重的是測試它是否可以在各個 Python 平臺下安裝和正常使用,於是我新建了一個 GitHub Action,它會自動在專案目錄下生成一個 .github/workflows/*.yml 檔案,內容如下:

name: build
on: 
  push:
    branches: 
    - master
    - dev
jobs:
  test:
    runs-on: 
    - ubuntu-latest
    strategy:
      max-parallel: 3
      matrix:
        python-version: [3.5, 3.6, 3.7]
    steps:
    - uses: actions/checkout@v1
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v1
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install Dependencies
      run: |
        python -m pip install --upgrade pip
        pip install .
    - name: Run Gerapy
      run: |
        gerapy -v
        gerapy init
        cd gerapy
        gerapy migrate
        gerapy initadmin

其實在這裡一個 Action 就是一個 YAML 檔案,其字尾為 yml,它規定了一系列語法規則,我們根據它的語法規則寫出一些工作流,在符合一定條件時,這些工作流會被觸發,自動執行。

比如這裡最開頭,on 就是監聽某個事件,其內容為 push,意思就是當 push 程式碼的時候,就會觸發。再進一步地,這裡定義了兩個分支 master 和 dev。這什麼意思呢?就是當我往 master 或者 dev 分支 push 程式碼的時候,我們定義的工作流就會執行。

下面的 jobs 就是工作流的定義了,包括在什麼平臺執行,具體執行什麼步驟。

比如這裡 runs-on 我就定義了在 ubuntu-latest 版本上執行,另外定義了一些並行策略和引數,比如這裡就定義了 Python 的三個版本引數,在 3.5、3.6、3.7 版本上執行。

GitHub Actions,臥槽!牛批!

下面的 steps 就是具體執行哪些步驟了。第一步和第二步,我們可以看到它都有一個 uses 引數,內容都為 actions 開頭,這就說明我們使用了 GitHub 提供的寫好的 Action,我們只需要引用它的名字就能使用了。這兩步執行完畢之後,Python 環境會被初始化,同時會從 GitHub Clone Gerapy 專案程式碼到本地。

在第三步和第四步,就是我自定義的 Task 了,這裡自持直接寫入 Shell 指令碼。在這裡我分了兩步。

第三步 Install Dependencies 就是安裝 pip 和 Gerapy 安裝包,其中一句 pip install . 就是安裝當前 Gerapy 目錄下的內容到系統中,安裝完成之後,就可以使用 gerapy 命令了。

於是第四步 Run Gerapy 就是測試了 gerapy 命令的一些初始化使用,包括初始化工作環境、資料庫遷移、初始化賬號等等,當然還有更多,比如執行某些測試,執行服務等等,這裡我只把一些必要的內容寫進去了。

好,基本內容就是這樣。

儲存這個 Action,命名為 build.yml,它會儲存為 .github/workflows/build.yml 檔案。同時在儲存的時候,我們就相當於執行了一次 Push 任務,這時候我們就可以看到這個 Action 已經啟動了,頁面如下:

GitHub Actions,臥槽!牛批!

我們所定義的每一個步驟以及對應的執行結果都會顯示在控制檯中,一目瞭然。

可以看到這裡初始化了三個版本的 Python 環境,同時都執行了其中的測試流程。如果測試成功,會打綠色的勾,如果失敗,會提示紅色的叉,並有郵件提示。

這樣以來,一些自動化的測試就完成了!!!

GitHub Actions,臥槽!牛批!

同步文件到新的 Repo

接下來我這個需求可以說稍微有點奇葩了。

寫專案免不了的要寫文件,這裡文件我是用 Sphinx 來寫的,可以藉助於 ReadTheDocs 自動構建並分發到 readthedocs.io 上面,類似這樣子:


GitHub Actions,臥槽!牛批!

但文件的原始碼我是放在了 Gerapy/Gerapy 這個 Repo 的 docs 資料夾,向 Scrapy 看齊,是這樣子的:

GitHub Actions,臥槽!牛批!

但我想著還新建一個 Repo,來單獨存放文件,比如我新建一個 Gerapy/Docs 這個 Repo,我在 Gerapy/Gerapy docs 子資料夾下的內容可以被自動同步到 Gerapy/Docs 根目錄下面,這樣我只需要往 Gerapy/Gerapy 上面提交程式碼,docs 子資料夾下面的內容變了,Gerapy/Docs 下面的內容也會跟著變。

那這個能不能做到呢?能!我問你答,快樂神仙;自問自答,法力無邊~~

這個流程可以分為四步:

下載 Gerapy/Gerapy Repo 的原始碼。利用 git 的 subtree 命令將 docs 資料夾下的內容分離到新的分支。將新分離的分支推送到 Docs 這個 Repo 下面。推送 Docs 這個 Repo 到遠端 Gerapy/Docs Repo。

這裡面就有一個關鍵地方,那就是怎樣無需密碼將內容推送到遠端 Gerapy/Docs 這個 Repo 下面,當然就是 SSH 了。(啊,超爽der)

那 SSH 的話應該怎麼設定呢?我們首先要有一對公鑰和私鑰,這個我們用 ssh-keygen 命令自己生成就好了。

那接下來 Gerapy/Docs 裡面需要存有公鑰,怎麼辦呢?我們可以藉助於 GitHub 提供的 Deploy Key 配置好公鑰即可:

GitHub Actions,臥槽!牛批!然後我們需要將私鑰上傳到 Action 所執行的虛擬機器裡面,但我們又不能明文將其放在 yml 檔案裡面,那這個怎麼做到呢?只需要將其配置到 Secrets 裡面即可,Action 是有許可權訪問到的:
GitHub Actions,臥槽!牛批!

嗯,做好這兩部分工作之後,接下來完善一下 yml 檔案就好了,內容如下:

name: sync docs
on: 
  push:
    branches: 
    - master
jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
    - name: Set SSH Environment
      env:
        DOCS_DEPLOY_KEY: ${{ secrets.DOCS_DEPLOY_KEY }}
      run: |
        mkdir -p ~/.ssh/
        echo "$DOCS_DEPLOY_KEY" > ~/.ssh/id_rsa
        chmod 600 ~/.ssh/id_rsa
        ssh-keyscan github.com > ~/.ssh/known_hosts
        chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
        git config --global user.email "cqc@cuiqingcai.com"
        git config --global user.name "Germey"
    - name: Sync Docs of Gerapy
      run: |
        cd /tmp
        git clone git@github.com:Gerapy/Docs.git docs
        cd docs
        git branch -D docs || true
        git push origin --delete docs || true
        git clone 
        cd gerapy
        git subtree split --prefix=docs --squash -b docs
        git checkout docs
        git push /tmp/docs docs:docs
        cd /tmp/docs
        git checkout docs
        git checkout -b master || git checkout master || true
        git reset --hard docs
        git push origin master --force

可以看到,這裡主要就分了兩步。

第一部分就是設定虛擬機器的 SSH 環境,這裡 secrets.DOCS_DEPLOY_KEY 就是我們剛才在 Secrets 裡面定義的私鑰,對應的執行命令就是將私鑰新增到 ~/.ssh/id_rsa 裡面。

第二部分就是分離 docs 資料夾到新的分支,然後將其上傳到新的 Repo 下了。

GitHub Actions,臥槽!牛批!

那麼這裡有兩條比較關鍵的命令:

git subtree split --prefix=docs --squash -b docs

這條命令就是將 docs 資料夾的內容分離到一個新的分支的根目錄下,新的分支的名稱為 docs。

git push /tmp/docs docs:docs

這條命令就是將本地的分支推送到另外一個本地 Repo 下,注意這裡 push 的目標不一定是遠端的 Repo 地址,也可以是本地的 Repo 地址。

最後,將新的 Repo 內容強制推送到遠端即可。

這樣我們就可以實現,Gerapy/Gerapy Repo docs 資料夾下內容的變動,會自動更新到 Gerapy/Docs Repo 了。

例如 docs 下是這樣的:

GitHub Actions,臥槽!牛批!

Gerapy/Docs Repo 下和子檔案的內容會一直維持同步,並在 master 分支上面:

GitHub Actions,臥槽!牛批!


自動構建 Docker 映象

由於 Gerapy 是一個 Web 工程,所以它非常適合於打包一個 Docker 映象。對於 Docker 的映象,我期望有三個版本:

當前 master 分支的版本,比較穩定,但未釋出版本。最新版本,latest,代表最新的釋出版本。每個歷史版本,每次釋出版本的版本號,都標記一個 tag。

最後我們自動構建的映象都自動 Push 到 Docker Hub 上面,這樣大家都可以使用了。

那這個怎麼做到呢,同樣藉助於 GitHub Action 也可以輕鬆做到。

首先 master 版本,由於沒有發版,所以前端需要自行 build,然後 Python Package 需要安裝原生程式碼。廢話不多說了,上程式碼:

name: build docker image master
on:
  push:
    branches: 
    - master
    paths:
    - .github/workflows/**
    - gerapy/**
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout Source
      uses: actions/checkout@v1
    - name: Docker Login
      run: docker login -u germey -p ${{ secrets.DOCKERHUB_LOGIN_PASSWORD }}
    - name: Setup Node.js
      uses: actions/setup-node@v1.1.0
      with:
        version: 10.x
    - name: Build Frontend Source
      run: |
        cd gerapy/client
        npm install
        npm run build
    - name: Build the Docker Image
      run: |
        docker build -t germey/gerapy:master -f ./docker/Dockerfile .
    - name: Push the Docker Image
      run: docker push germey/gerapy:master

可以看到這裡,監聽了 master 分支的變動,同時限定了路徑 workflows 資料夾和 gerapy 資料夾下變動。

流程包括了前端的構建和 Docker 的打包,Docker 打包的時候使用了 -f 命令指定了 Dockerfile 的路徑,並將打包完成之後的映象標記為 gerapy:master,推送到 Docker Hub 即可。

對於釋出新版本的時候,則直接監聽 tag 的變動即可:

name: build docker image release
on:
  push:
    tags:
      - 'v*.*.*'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout Source
      uses: actions/checkout@v1
    - name: Docker Login
      run: docker login -u germey -p ${{ secrets.DOCKERHUB_LOGIN_PASSWORD }}
    - name: Setup Node.js
      uses: actions/setup-node@v1.1.0
      with:
        version: 10.x
    - name: Build Frontend Source
      run: |
        cd gerapy/client
        npm install
        npm run build
    - name: Build and Push the Docker Image
      run: |
        tag=${GITHUB_REF:11}
        echo "Build Tag '$tag'"
        docker build -t germey/gerapy:$tag -f ./docker/Dockerfile .
        docker push germey/gerapy:$tag
        regex='^([0-9]+\.){0,2}(\*|[0-9]+)$'
        if [[ $tag =~ $regex ]]; then
          echo "Build Stable Version '$tag'"
          docker tag germey/gerapy:$tag germey/gerapy:latest
          docker push germey/gerapy:latest
        fi

可以看到這裡監聽的配置改成了 tags,tag 也變成了一個變數,可以透過 ${GITHUB_REF:11} 獲取到。

同時這裡還加了一個正則判斷是不是正式的發版,如果是 beta、rc 版本,則不構建正式 latest 的 Docker 映象。

最後我們看看我再一次發版之後,構建完成之後,Docker Hub 的效果:

GitHub Actions,臥槽!牛批!

可以看到,我釋出了 0.9.2 版本之後,它就自動構建了 0.9.2 版本的映象,同時將 latest 映象指向 0.9.2 版本。另外對應 maser 版本也構建了一個版本。

這樣,以後媽媽再也不用擔心我忘記打 Docker 映象啦。

以上便是我將 GitHub Actions 應用到我的開源專案上的記錄。

GitHub Actions,臥槽!牛批!

最後,如果大家對 Scrapy 爬蟲感興趣的話,也(非常)歡迎大家(高高興興的)瞭解一下我寫的 Gerapy 框架,利用它我們可以(無敵)更方便地管理(呀)、監控(呀)、(或者是)部署 Scrapy 爬蟲專案(什麼的)。

其 GitHub 地址為:,文件:。

掰掰!

GitHub Actions,臥槽!牛批!



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31557738/viewspace-2666560/,如需轉載,請註明出處,否則將追究法律責任。

相關文章