【CICID】GitHub-Actions語法

Leovany發表於2024-06-16

目錄
  • 【CICID】GitHub-Actions語法
  • 1 場景
  • 2 CI/CD
    • 2.1 什麼是CI/CD
    • 2.2 持續整合(CI)
    • 2.3 持續部署(CD)
  • 3 介紹
    • 3.1 優點
  • 4 工作流常用語法
    • 4.1 name : 工作流名稱
    • 4.2 on : 觸發工作流時機
    • 4.3 jobs : 作業
  • 5 環境變數
    • 5.1 自定義變數
      • 5.1.1 在env中定義變數
      • 5.1.2 Run透過寫入到github變數
    • 5.2 預設環境變數
  • 6 常用示例
  • 7 參考資料
  • 遇到問題

【CICID】GitHub-Actions語法

1 場景

​ 當我們開發過程中,經常需要提交程式碼,打包,部署新程式碼到對應的環境,整個過程都是人工手動操作,佔據開發人員大量時間,並且很繁瑣容易出錯。所以需要藉助一些CI/CD工具讓這整個流程自動化,節約生命。

​ 一般公司都有自己的CICD工具或平臺,但如何搭建一個屬於自己的一套CICD工作流呢?

​ 常見的CI/CD工具有Jenkins、GitLab、GitHub Actions等,各有優缺點,自行百度吧~

​ 考慮程式碼都在GitHub託管,也不用額外購買伺服器,最終選定GitHub Actions方式

附:推薦參考

  • 如果公司已有完整的程式碼託管平臺,希望儘量少改動已有的工作流程,選 Jenkins
  • 如果是公司使用+新專案,選GitLab,自帶程式碼託管和CICD
  • 如果是個人專案,希望可以使用免費資源,選Github Actions
  • 如果是個人專案+有自己伺服器,也可以選GitLab

2 CI/CD

2.1 什麼是CI/CD

  • CI/CD 屬於DevOps,代表持續整合、持續部署

  • CI/CD自動化上將新程式碼從提交到生產,配置基礎設施所需的大部分或全部手動人工干預流程

  • 藉助CI/CD,開發人員可以對程式碼進行更改,然後自動測試並推出,以進行持續部署

  • 以實現停機時間最小化,程式碼釋出速度更快

2.2 持續整合(CI)

​ 持續整合是在提交或合併程式碼時,自動測試每個更改,並自動啟動構建。可以大大減少開發和運維人員的重複工作,可以在軟體開發生命週期的更早階段更輕鬆的發現並修復錯誤和安全問題。

2.3 持續部署(CD)

​ 持續交付是一種軟體開發實踐,一般與持續整合結合使用,以自動化基礎設定供應和應用程式釋出過程。

​ 一旦程式碼作為 CI 流程的一部分進行了測試和構建,持續交付將在最後階段接管,以確保可以隨時部署並將部署所需要的環境打包在一起。

​ 透過持續交付,可以隨時將構建的軟體部署到生產環境。可以手動觸發部署,也可以進行自動化部署。

3 介紹

​ GitHub Actions 是一種持續整合和持續交付 (CI/CD) 平臺,可用於自動執行生成、測試和部署管道。 您可以建立工作流程來構建和測試儲存庫的每個拉取請求,或將合併的拉取請求部署到生產環境。

3.1 優點

  • GitHub直接託管程式碼

  • Actions直接依賴於Github,不需額外安裝任何東西

  • 整合部署常用依賴庫

  • 支援Docker

  • 不需要額外購買伺服器搭建服務(重點!)

4 工作流常用語法

官網文件:https://docs.github.com/zh/actions/using-workflows/workflow-syntax-for-github-actions

​ 工作流檔案使用 YAML 語法,並且必須具有 .yml.yaml 副檔名。

4.1 name : 工作流名稱

name: 這是工作流名稱		

4.2 on : 觸發工作流時機

  • on.<event_name>.types

    定義將觸發工作流執行的事件活動型別

    # 程式碼push 或者 fork等時觸發
    on:
      # 當向分支進行git push時觸發該工作流
      push:
        branches:
          - "main"
      # 當向分支合併分支時觸發該工作流
      pull_request:
        branches:
          - "main"
    
    • 事件型別:https://docs.github.com/zh/actions/using-workflows/events-that-trigger-workflows
  • on.<push|pull_request>.<branches|tags>

    定義事件篩選器,可讓你更好地控制工作流的執行時間,可以指定分支和分支版本

    name: MYCI
    on:
    	push:
    		branches:
    			- master
    
  • on.<push|pull_request>.paths

    使用 pushpull_request 事件時,指定檔案路徑生效

    • 指定路徑
    on:
      push:
        paths:
          - '**.js'
    
    • 排除路徑

      on:
        push:
          paths-ignore:
            - 'docs/**'
      
  • on.schedule

    定義觸發事件,使用 cron

    on:
      schedule:
      	# 每天 5:30 和 17:30 UTC 觸發工作流程
    	  - cron: '30 5,17 * * *'
    	  # 每週一至週四 5:30
        - cron: '30 5 * * 1,3'
        - cron: '30 5 * * 2,4'
    

4.3 jobs : 作業

工作流執行由一個或多個 jobs 組成,預設情況下並行執行。

  • jobs.<job_id>

    使用 jobs.<job_id> 為作業提供唯一識別符號,是一個字串

    jobs:
      my_first_job:
        name: My first job
      my_second_job:
        name: My second job
    
  • jobs.<job_id>.name

    設定作業名稱

  • jobs.<job_id>.needs

    此作業之前必須成功完成的所有作業

    • 要求成功的依賴項作業

      按順序執行 job1 -> job2 -> job3

    jobs:
      job1:
      job2:
      	# 依賴job1完成
        needs: job1
      job3:
      	# 依賴job1和job2完成
        needs: [job1, job2]
    
    • 無論是否成功,都要執行 always()

      按順序執行 job1 -> job2 -> job3 ,但job3 無論是否成功,都會執行

    jobs:
      job1:
      job2:
        needs: job1
      job3:
        if: ${{ always() }}
        needs: [job1, job2]
    
  • jobs.<job_id>.runs_on

    定義要執行環境

    • 指定作業系統
    runs-on: ubuntu-latest
    
    • 公共免費GitHub託管的標準執行器

      image-20240609112206015

  • jobs.<job_id>.steps

    作業包含一系列任務,稱為 steps步驟,步驟可以執行命令、執行設定任務,每個步驟在執行器環境中以其自己的程序執行,且可以訪問工作區和檔案系統,步驟之間不會保留環境變數的更改。

    • jobs.<job_id>.steps[*].uses

      選擇要作為作業中步驟的一部分執行的操作,

      jobs:
        my-jobname:
      		steps:
            # checkout出v1版本程式碼
            - uses: actions/checkout@v1
      
  • jobs.<job_id>.timeout-minutes

    工作執行超時時間,超過則取消,預設 360分鐘(6小時)

  • jobs.<job_id>.strategy

    作業使用的矩陣策略,根據定義陣列的笛卡爾積,建立作業

    jobs:
      example_matrix:
        strategy:
          matrix:
            version: [10, 12]
            os: [ubuntu-latest, windows-latest]
    

    根據上述矩陣,按順序建立作業

    • {version: 10, os: ubuntu-latest}
    • {version: 10, os: windows-latest}
    • {version: 12, os: ubuntu-latest}
    • {version: 12, os: windows-latest}
  • jobs.<job_id>.container

    注意:如果工作流使用 Docker 容器操作、作業容器或服務容器,則必須使用 Linux 執行器:

    		* 如果您要使用 GitHub 託管的執行器,則必須使用 Ubuntu 執行器。
    		* 如果您要使用自託管執行器,則必須使用 Linux 機器作為執行器,並且必須安裝 Docker。
    

    用於執行作業中尚未指定容器的任何步驟的容器

    • 在容器中執行作業

      name: CI
      on:
        push:
          branches: [ main ]
      jobs:
        container-test-job:
        	# 執行的外部環境
          runs-on: ubuntu-latest
          # 環境下執行的容器(Docker定義)
          container:
          	# 容器中使用映象
            image: node:18
            # 容器中定義環境
            env:
              NODE_ENV: development
            # 容器中定義埠
            ports:
              - 80
            # 容器中定義對映位置
            volumes:
              - my_docker_volume:/volume_mount
            options: --cpus 1
          steps:
            - name: Check for dockerenv file
              run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv)
      
      
    • 只指定容器映像時,可以忽略 image 關鍵詞

      jobs:
        container-test-job:
          runs-on: ubuntu-latest
          container: node:18
      
  • jobs.<job_id>.services

    注意:如果工作流使用 Docker 容器操作、作業容器或服務容器,則必須使用 Linux 執行器:

    • 如果您要使用 GitHub 託管的執行器,則必須使用 Ubuntu 執行器。

    • 如果您要使用自託管執行器,則必須使用 Linux 機器作為執行器,並且必須安裝 Docker。

    多個服務編排

    services:
    	# 1. nginx服務
      nginx:
        image: nginx
        # ngxin 80 對映 docker 8080埠 
        ports:
          - 8080:80
    	# 2. redis服務
      redis:
        image: redis
        # ngxin 6379 對映 docker 6379 
        ports:
          - 6379/tcp
    
  • 單個事件

    # 程式碼push
    on: push	
    
  • 多個事件

    # 程式碼push 或者 fork
    on:[push,fork]
    
  • 指定分支觸發

    name: MYCI
    on:
    	push:
    		branches:
    		- master
    

​ 時機型別:https://docs.github.com/zh/actions/using-workflows/events-that-trigger-workflows

5 環境變數

Github action 定義變數很多方式,很容易搞混,記錄下常用方式

口訣:

  • 普通使用 $xxx ,

  • 命令列或字串拼接使用 ${xxx},

  • 遇到uses則用${{xxxx}}

    使用別人寫好的Action,要用兩個花括號

5.1 自定義變數

5.1.1 在env中定義變數

定義變數

jobs:
  build:
    runs-on: ubuntu-latest
     env:
      # 埠號
      Port: 8080
      # 雲服務地址
      Host_IP: ${{secrets.REMOTE_SERVER01_IP}}  
      # 雲服務密碼
      Host_PWD: ${{secrets.REMOTE_SERVER01_PWD}}
      # 賬號
      Host_Role: root
      # 路徑
      Host_Dir: "/cicd"

變數取值

  • 普通使用,$xxx
# 測試環境變數
- name: Use variable from environment
  run: |
    echo "埠號:$Port"
    echo "伺服器地址: $Host_IP"
  • 有命令列或拼接使用,${xxxx}
 # 上傳新的docker映象
- name: upload new docker image and start-up script
  run:
    sshpass -p ${Host_PWD} scp -r -o StrictHostKeyChecking=no ./${FILE_NAME}.tar ${Host_Role}@${Host_IP}:${Host_Dir}
  • 當使用外部uses時,${{env.xxx}}

    run 裡面也要用 ${{env.xxx}}

# 載入tar檔案,載入docker映象
- name: Load new docker image
  uses: matheusvanzan/sshpass-action@v2
  with:
    host: ${{env.Host_IP}}
    user: ${{env.Host_Role}}
    pass: ${{env.Host_PWD}}
    run:
      docker load -i ${{env.Host_Dir}}/${{env.FILE_NAME}}.tar

5.1.2 Run透過寫入到github變數

在run裡面定義了變數,需要給後面step使用,一定要寫入github環境中echo "key=$xxx" >> "$GITHUB_ENV"

定義

 steps:
    # 定義環境變數
    - name: Define environment variables
      run: |
        # 定義全域性變數
        PROJECT_NAME=$(basename $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')
        FILE_NAME=${PROJECT_NAME}-backend
        VERSION=0.1
        # 寫入環境中
        echo "PROJECT_NAME=$PROJECT_NAME" >> "$GITHUB_ENV"
        echo "FILE_NAME=$FILE_NAME" >> "$GITHUB_ENV"
        echo "VERSION=$VERSION" >> "$GITHUB_ENV"

取值

  • 普通使用,$xxx

     # 測試環境變數
    - name: Use variable from environment
      run: |
        echo "專案名稱 (從環境變數): $PROJECT_NAME"
        echo "檔名稱 (從環境變數): $FILE_NAME"
        echo "專案版本 (從環境變數): $VERSION"
    
  • 有命令列或拼接使用,${xxxx}

     # 構建映象
    - name: Build docker image
      run: |
        docker build -t ${FILE_NAME}:${VERSION} .    # 構建docker映象,命令最後的點代表Dockerfile所在目錄
    
  • 當使用外部uses時,${{env.xxx}}

    # 刪除舊的docker映象壓縮包
    - name: Delete old docker tar
      uses: matheusvanzan/sshpass-action@v2
      with:
        host: ${{env.Host_IP}}
        user: ${{env.Host_Role}}
        pass: ${{env.Host_PWD}}
        run: |
          echo "Attempting to delete ${{env.Host_Dir}}/${{env.FILE_NAME}}.tar"
          rm -rf ${{env.Host_Dir}}/${{env.FILE_NAME}}.tar
    

5.2 預設環境變數

  • 地址:

    https://docs.github.com/zh/codespaces/developing-in-a-codespace/default-environment-variables-for-your-codespace#list-of-default-environment-variables

環境變數 說明
CODESPACE_NAME 程式碼空間的名稱 例如,octocat-literate-space-parakeet-mld5
CODESPACES 在程式碼空間中始終為 true
GIT_COMMITTER_EMAIL 未來 git 提交的“作者”欄位的電子郵件。
GIT_COMMITTER_NAME 未來 git 提交的“提交者”欄位的名稱。
GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN 返回 GitHub Codespaces 轉發埠的域。 例如 app.github.dev
GITHUB_API_URL 返回 API URL。 例如 https://api.github.com
GITHUB_GRAPHQL_URL 返回 GraphQL API URL。 例如 https://api.github.com/graphql
GITHUB_REPOSITORY 所有者和倉庫名稱。 例如,octocat/Hello-World
GITHUB_SERVER_URL 返回 GitHub 伺服器的 URL。 例如,https://github.com
GITHUB_TOKEN 代表程式碼空間中使用者的簽名身份驗證令牌。 您可以使用它對 GitHub API 進行經過身份驗證的呼叫。 有關詳細資訊,請參閱“GitHub Codespaces 中的安全性”。
GITHUB_USER 啟動程式碼空間的使用者的名稱。 例如,octocat
  • 使用方式

    • 專案名稱: ${GITHUB_REPOSITORY}

    • 分支名稱:${GITHUB_REF##*/}

      • refs/heads/main -> main

      • refs/tags/v1.0.0 -> v1.0.0

    示例

    
    - name: Print Environment
      run: | 
        echo $GITHUB_REPOSITORY   # 倉庫全名
        echo ${GITHUB_REF##*/}
    

6 常用示例

  • 定義環境變數

     - name: Define environment variables
          run: |
            # 定義全域性變數
            # 當前專案名(小寫)
            PROJECT_NAME=$(basename $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')
            # 檔名
            FILE_NAME=${PROJECT_NAME}-backend
            # 常量
            VERSION=0.1
            # 寫入環境中
            echo "PROJECT_NAME=$PROJECT_NAME" >> "$GITHUB_ENV"
            echo "FILE_NAME=$FILE_NAME" >> "$GITHUB_ENV"
            echo "VERSION=$VERSION" >> "$GITHUB_ENV"
    
  • 拉取程式碼

    # 拉取最新程式碼
    - name: Pull latest code
      uses: actions/checkout@v3       # 使用官方的checkout action,用於將倉庫中的最新程式碼檢查並拉取到工作目錄中
    
  • 連線遠端伺服器操作

    # 連線遠端伺服器操作
    - name: SSH Commonds
      uses: matheusvanzan/sshpass-action@v2
      with:
        host: "遠端主機IP"
        user: root
        pass: "遠端主機密碼"
        run: |
        	# 命令列
          pwd
          ls
    
  • 傳輸檔案

    # 上傳新的docker映象
    - name: upload new docker image and start-up script
      run:
        # sshpass -p 遠端伺服器密碼 scp -r -o StrictHostKeyChecking=no 當前檔案 賬號@遠端伺服器地址:目標目錄
        sshpass -p ${Host_PWD} scp -r -o StrictHostKeyChecking=no ./${FILE_NAME}.tar ${Host_Role}@${Host_IP}:${Host_Dir}
    

7 參考資料

  • 【CICD】github新功能actions全方位講解!!

    https://www.bilibili.com/video/BV1RE411R7Uy/?spm_id_from=333.337.search-card.all.click&vd_source=1d31e698afb74bb3222db3bb76f9b408

  • GitHub文件-Actions

    https://docs.github.com/zh/actions/learn-github-actions/understanding-github-actions

  • GitHub Actions 的工作流語法

https://docs.github.com/zh/actions/using-workflows/workflow-syntax-for-github-actions

  • Github Actions 的一份不完全指南

    https://ucaskernel.com/d/822-github-actions

遇到問題

  • run 報錯: bash: -c: line 1: syntax error: unexpected end of file

    如下圖所示:

    - name: xxxx
      with:
        run: | 
          echo "只有一條命令會報錯"
    

    image-20240615183702798

    原因:run後面的 |: 執行執行多個命令,但一條命令時會報錯

    解決方法:

    # 單條命令,去掉run後面的 `|`
    - name: xxxx
      with:
        run: 
          echo "只有一條命令會報錯"
    
    # 多條命令
    - name: xxxx
      with:
        run: | 
          echo "只有一條命令會報錯"
          echo "兩條命令就不會報語法錯誤"
    

本文由部落格一文多發平臺 OpenWrite 釋出!