iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
DevOps

菜逼八用Github Actions系列 第 29

Day 29 - Goodbye Jenkins, and hello Github Actions

  • 分享至 

  • xImage
  •  

目錄

摘要

在上一篇我們比較了Github Actions和Jenkins

這篇我們會來試著把幾個pipeline翻成workflow,並看了如果搬到Github Actions,pipeline變成workflow能變得多簡潔

Jenkins的組成

在搬家前我們我們要先來了解一下pipeline的組成

pipeline

  • 相對於Github Actions的workflow
  • 組成如下
    ー pipeline
        ├── agent
        ├── stages
        │   └── stage
        │         ├──step
        │         └──step
        ├── stages
        │     └── stage
        │           └──step
        └── post
    

stage

  • 相對於Github Actions的job
  • 放在stages block底下

steps

  • 相對於Github Actions的step

agent

  • 相當於Github Actions的runs-on、container
  • 定義 pipeline 的執行環境,具有scope概念
  • pipeline block底下的top level一定要有,stage level則不一定需要
  • 和runs-on差在,runs-on會定義在job level,而不會在top level

post

  • Github Actions中無相對概念,因為每個runner都是獨立的,workflow結束後會自動清理暫存檔案、(docker)容器、記憶體...等
  • 定義在 pipeline 或 stage 結束後執行的後置步驟,通常會在這裡執行清理暫存檔案、(docker)容器、記憶體,或儲存log...等
  • 一定要記得在post中做清理的動作,不然pipeline之間會互相汙染,不過搬遷到Github Actions就不必自行處理了

例子

了解了pipeline的基本組成後我們先來把一個簡單的Jenkinsfile翻成yaml

pipeline {
    agent any

    stages {
        stage('greeting') {
            steps {
              echo 'Hello, tempura327'
            }
        }
    }

    // 因為這個pipe line並沒有build或者安裝package,所以post內不必多做清理
}
name: Example workflow

on:
  workflow_dispatch:

jobs:
  greeting:
    runs-on: ubuntu-latest
    steps:
      - print something
        run: echo 'Hello, tempura327'

其他語法

triggers

  • 相對於Github Actions的on
  • 觸發時機分為cron、upstream、pollSCM
    • cron為排程自動,對應Github Actions的schedule.cron
    • upstream某個pipeline跑完時自動觸發,對應Github Actions的workflow_call
    • pollSCM為固定間格時間檢查 SCM(如 Git)中的變更,若有變更就觸發,Github Actions無完全對應概念
  • 不定義triggers也可以自行透過Jenkins的網站手動觸發,或者設置webhook,或者是要檢查Github PR變更,若有變更就觸發也可以使用plugin,不過搬遷到Github Actions就不必再用plugin處理了

environment

  • 相對於Github Actions的env
  • 跟Github Actions的jobs.<job_id>.environment同名,搬遷時要小心這點

credentials()

  • 取得credential的function,而不是像Github Actions是透過context來取得secret
  • credential可以是文字、檔案、使用者名、密碼

parameters

  • 相對於Github Actions的inputs、output
  • 支援型別為字串、多行文字、布靈、choice、password
  • Github Actions則只支援字串,就算傳入布靈也會被當字串處理,搬遷時要小心這點

input

  • 接近於Github Actions的inputs,但是是傳給step的input

when

  • 相對於Github Actions的if

parallel

  • 相對於Github Actions的max-parallel
  • 使用宣告式時使用。可設定並發性(concurrency),讓stage同時執行
  • 搭配failFast使用,可達到Github Actions的fail-fast策略效果

options

  • 相對於Github Actions的strategy

matrix

  • 相對於Github Actions的matrix
  • 只能從matrix中用exclude排除組合,無法擴充,但搬到Github Actions後就可以用include擴充matrix

flow control

  • 非pipeline中的屬性,是指以Groovy expressions做條件控制、try catch

    node {
        stage('Greeting') {
              if (env.USER_NAME == 'tempura327') {
                  echo 'How is it going with your articles. I\'m look forward to it.'
              } else {
                  echo 'How are you?'
              }
          }
    }
    
  • if else可以改用Github Actions的if,也可以用shell command,try catch則只能用shell command做出類似的效果,但是可讀性會比較差,搬遷時要小心這一點

例子

pipeline {
    agent any

    triggers {
        // 每12小時檢查一次repo是否有變更
        pollSCM('H H/12 * * *')
    }

    environment {
        //  取得用於打slack API的Jenkins credential,"SLACK_BOT_TOKEN"是credential的key
        SLACK_TOKEN = credentials("SLACK_BOT_TOKEN")
        SLACK_CHANNEL_ID = "你的slack channel id"
    }

    stages {
        stage('Check for new tag') {
            steps {
                script {
                    // 確認更新的是否為新tag
                    def tagName = sh(returnStdout: true, script: 'git describe --tags --exact-match || true').trim()

                    if (tagName) {
                      env.TAG_NAME = tagName
                      echo "New tag detected: ${tagName}"
                    } else {
                      echo "There is no new tag."
                    }
                }
            }
        }
        stage("deploy to github-pages") {
            when {
              // 和 expression { TAG_NAME && TAG_NAME != '' } 一樣是在確認變數存在,且不為空字串
              expression { return env.TAG_NAME }
            }
            steps {
                // 用plugin安裝Node.js
                nodejs(nodeJSInstallationName: 'Node 20.0.0', configId: 'config file的id') {
                    sh "npm install -g gh-pages@6.1.1"
                }
                // 用withCredentials取得github token,並只在這個block內使用
                withCredentials([string(credentialsId: 'github-pat', variable: 'GITHUB_TOKEN')]) {
                    sh "git config --global user.email '你的email' && git config --global user.name '你的使用者名'"

                    // 設置遠端url,讓 git 使用取到的token 進行身份驗證
                    sh "git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/你的repo名.git"
                    sh "gh-pages --message '[skip ci] Updates' --dist ./dist"
                }
            }
        }
    }
    stage('send-message') {
      when {
          expression { return env.TAG_NAME }
      }
      steps {
          // slackSend是一個可以發布訊息到特定Slack頻道的plugin
          slackSend(
              teamDomain: "你的slack team domain",
              token: "${env.SLACK_TOKEN}",
              channel: "${env.SLACK_CHANNEL_ID}",
              message: "New version ${env.TAG_NAME} is deployed."
          )
      }
    }


    post {
      always {
        // 因為有安裝node package,所以要清理
        cleanWs()
      }
    }
}

name: Deploy to github page and send Slack message

on:
  push:
    tags:        
      - 'trial@\d+.\d+.\d+'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./src
          name: github-pages
     
  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: github-pages
      url: https://tempura327.github.io/try-github-actions/
    permissions:
      pages: write
      id-token: write
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
     
  send-message:
    name: send message
    runs-on: ubuntu-latest
    steps:
      - name: Get the latest version
        # 用--abbrev=0取代replace function
        run: echo "latestTag=$(git describe --abbrev=0 --tags)" >> $GITHUB_ENV
      - name: Post a message to Slack channel
        if: env.latestTag != ''
        uses: slackapi/slack-github-action@v1.27.0
        with:
          channel-id: '你的slack channel id'
          slack-message: "New version ${{ env.latestTag }} is deployed."
        env:
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

我把註解都刪掉後讓大家看一下兩者差距


上一篇
Day 28 - 比較Github Actions 與 Jenkins
系列文
菜逼八用Github Actions29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言