透過 GitLab CI + K6 進行小規模 Load Testing

在先前的文章,已分享過使用 GitLab 搭配 JMeter 與 Drill 實施 Load Testing,這次讓我們改用 K6 這個已被 Grafana Labs 買下的新興工具,看看它是否有比前兩個工具更好用。

在先前的文章,已分享過使用 JMeterdrill 進行小規模 Load Testing,今天延續同樣的主題,這次要使用另一個新興熱門的 Load Testing 工具 K6,試一試「如何透過 GitLab CI + K6 進行小規模 Load Testing」。

操作步驟

首先,K6 在 2021 年已經被 Grafana Labs 買下來了,但目前(2022/02/03)看來,K6 官網依然還維持原貌,沒有太大的變化,只是多掛上了 Grafana Labs 的 Logo。K6 有提供 Open SourceK6 Cloud 兩種方案,而本文將採用的是 Open Source 方案。

準備 GitLab Runner

老樣子,第一步我們要先預備合適的 GitLab CI 環境,應該不用再多做解釋,請先準備好能夠操控 Container 的 GitLab Runner,如果你不知該如何準備 Runner,又想要快速試一下本文的內容,那最簡單的做法是註冊一個 gitlab.com 帳號,然後建立新 Project 並使用官方提供的 Shared Runners。

準備 Docker image - K6

第二步,預備一個能夠運行 K6 的 Docker image。

這次很幸運,已經有現成的 Image 可以使用 loadimpact/k6

建立 CI Pipeline

第三步,開一個全新的 GitLab Project(Repository),並撰寫 .gitlab-ci.yml 建立我們所需的 Pipeline。

# .gitlab-ci.yml

# Job name 叫做 k6
k6:
  # 指定能操控 docker 的 Runner
  tags:
    - "docker"
  
  image: 
    name: loadimpact/k6
    # entrypoint 很重要,沒設定這項,會出現找不到 load-testing.js 的錯誤。
    entrypoint: ['']
  
  # 要執行的動作只有一項,就是根據 load-testing.js 去跑 Load Testing
  script:
    - k6 run load-testing.js

撰寫 load-testing.js

K6 接受的 load testing 測試腳本格式是 .js,如果是熟習 JS 的人可能會感到親切,但對於只會 .yml 的 YAML 工程師可能就需要多一點學習了,好在 K6 官網的文件內容詳盡,因此要快速寫出可用的測試腳本並不困難,下面就直接做一個簡單的示範。

// 引用必要套件
import { check } from 'k6';
import http from 'k6/http';

export default function () {

  // 可以定義變數供後續使用
  const url = 'https://chengweichen.com';
  const check_keyword = 'Cheng Wei Chen';
  
  // 直接就對目標 url 發動測試
  const result = http.get(url);

  // 同時要驗證 Response 是否吻合期待,以及是否含有特定的文字
  check(result, {
    'http code = 200': (r) => r.status === 200,
    'verify homepage text': (r) => r.body.includes(check_keyword),
  });

}

// 設定要實行多大規模的 Load testing
export const options = {
  //
  duration: '1m', // 測試總共要跑多久時間
  vus: 10, // 同時要模擬的人數
  
  // 更進階的測試成功與失敗條件,這比較複雜,請參閱官網文件。
  thresholds: {
    // 這裡直接引用官方教學的範例。
    // 95 percent of response times must be below 500ms
    http_req_duration: ['p(95)<500'], 
  },
};

將 Output 儲存為 Artifacts

上面的測試腳本順利執行後,就能在 CI Job Log 看到類似下面兩張圖片的結果。

(在大大的 K6 圖案之下,開始條列各項測試結果。)

checks 皆有成功通過,因此是 100.00%。)

最後,我們再對 .gitlab-ci.yml 做一點微調,讓 Output 的資訊儲存進 GitLab Artifacts 中。

# .gitlab-ci.yml
k6:
  tags:
    - "docker"
  image: 
    name: loadimpact/k6
    entrypoint: ['']
  script:
    - k6 run load-testing.js --out json=result.json
  artifacts:
    paths:
      - result.json

【補充】直接使用 --out json=result.json 會得到完整的 Output 資訊,以上面的示範為例,最終產生的 .json 容量高達 73.9MB,因此建議大家務必要詳細參閱 K6 的文件,只需保留你所需的 Output 資訊。另外就是 K6 支援將 Output 輸出至其他的第三方服務,因此實務上你可以直接將 Output 餵給你的 Prometheus、AWS 的 CloudWatch 或其他服務,並不一定要如上面的示範儲存在 GitLab Artifacts 中。

更彈性的進行 Load Testing

最後還是老樣子,我們希望能更彈性的進行 Load Testing,如果想要動態的變更 Load Testing 的目標及強度,該怎麼做呢?好在 K6 也提供了許多彈性,因此我們一樣能用老方法,運用 GitLab CI 的 Variables 加上 Run Pipeline 可動態變更 Variables 的方式處理。

修改 .gitlab-ci.yml,調整 Run K6 的 Command,並且定義變數的預設值。

# .gitlab-ci.yml

# 定義所需的變數預設值
variables:
  K6_VUS: 10
  K6_DURATION: 1m
  TESTING_URL: https://chengweichen.com
  TESTING_KEYWORD: "Cheng Wei Chen"

k6:
  tags:
    - "docker"
  image: 
    name: loadimpact/k6
    entrypoint: ['']
  script:
    # 加上參數 --include-system-env-vars
    - k6 run load-testing.js --out json=result.json --include-system-env-vars
  artifacts:
    paths:
      - result.json

由於 K6 接受 Environment variables,因此在上面我們可以直接用 K6_VUSK6_DURATION 來取代原本設置在 load-testing.js 中的 vusduration。至於要施測的網址與該檢查的字串,也同樣設置在 ENV 中,並透過 --include-system-env-vars 傳遞給 K6 使用。

修改 load-testing.js,將變數放在正確的位置。

import { check } from 'k6';
import http from 'k6/http';

export default function () {
  // 從 ENV 中取得變數值
  const url = `${__ENV.TESTING_URL}`;
  const check_keyword = `${__ENV.TESTING_KEYWORD}`;

  const result = http.get(url);
  check(result, {
    'http code = 200': (r) => r.status === 200,
    'verify homepage text': (r) => r.body.includes(check_keyword),
  });
}

export const options = {
// duration 與 vus 改由 ENV 取得,因此將下面兩行註解
//   duration: '1m',
//   vus: 10,
  thresholds: {
    http_req_duration: ['p(95)<500'], 
  },
};

透過上面的修改,在沒有輸入變數的狀況下,就會用預設值來執行 K6。如果想要動態修改測試內容,就能透過 GitLab 的 Run pipeline 來進行指定的 Load Testing。

(在 Run pipeline 的介面中,輸入這一次的 Pipeline 要使用哪些 Variables。)

Pipeline 順利執行,並取得結果。

(上面我故意填寫錯誤的 TESTING_KEYWORD,果然在 verify homepage text 這邊出現 0% 的結果。)

結語

延續前兩次運用 GitLab CI 來進行小規模 Load Testing 的文章,這次我們又換了一個工具,變成以 GitLab CI + K6 來實施測試。

這次撰寫文章,也順利試用了 K6 這項新興的 Load Testing 工具,K6 使用起來容易,可以快速上手,又具備可輕易與其他服務整合的特性,不愧是被大廠看上的新工具。

最後還是要小提醒一下,本文僅是一個簡單的 DEMO,只靠單一 GitLab Runner 我們能模擬的最大負載量是有限的,如果你需要進行的是切切實實的大流量及高負載 Load Testing,那你還需要更多的前置作業,又或者不妨考慮直接採購 K6 Cloud。

針對本文我依然有建立一個 DEMO Project,公開放在 gitlab.com,有興趣者可自行 Fork 參考,同樣的為了避免 Public Project 的 CI/CD 被人亂按,Pipeline 已關閉權限避免被人隨意誤觸。

參考資料

工商服務

如果你覺得艦長的文章對你有產生幫助,歡迎抖內(Donate),讓我可以將養家活口的力氣分一些在社群分享。歡迎支持我的著作《和艦長一起 30 天玩轉 GitLab》,不只能抖內艦長,還能一併支持出版社與圖書通路商,一次抖內一舉數得!謝謝大家。

【補充】《和艦長一起 30 天玩轉 GitLab》除了介紹 GitLab 功能及入門使用,也包含純粹的 CI/CD/DevOps 觀念,由於近一年 GitLab 版本更新大爆發,導致書中部分功能介面截圖已失準,但本書仍內含值得讀者參考的內容。

更多文章