Elasticsearch: GitHub Actions 與 GitLab CI

直接從您的 GitHub Actions 或 GitLab CI pipeline 啟動一個真實的 Elasticsearch 服務,執行測試,並自動銷毀服務

👋 歡迎來到 Stackhero 文件!

Stackhero 提供即用型的 Elasticsearch cloud 解決方案,帶來多項優勢,包括:

  • 專用私有 VM提供的最佳性能和強大的安全性
  • 支援 HTTPS 加密的可自訂域名

節省時間簡化您的生活:只需 5 分鐘即可嘗試 Stackhero 的 Elasticsearch cloud hosting 解決方案!

本指南將帶您一步步在 CI pipeline 中運行一個真實、專屬的 Elasticsearch 服務,可選擇 GitHub ActionsGitLab CI。依照這些步驟,您可以在接近正式環境的條件下,針對實際的 Elasticsearch 實例測試您的程式碼,無需再依賴 mock 或模擬器。Elasticsearch is a distributed search and analytics engine that turns large volumes of data into fast, relevant answers.

每次 pipeline 執行時,您都會獲得一個全新的 Elasticsearch 實例。這代表您的測試將與正式環境中用戶所見的服務完全一致。此流程會自動建立一個臨時 stack,新增 Elasticsearch,等待服務就緒,取得產生的認證資訊,利用 curl 執行 smoke test,最後在流程結束時自動清理所有資源。

您將會使用 Stackhero CLI,這是一個獨立的命令列工具,可讓您快速且簡單地啟動與管理 Stackhero 服務。

為了讓 CLI 能以非互動方式運作,您需要一組 access token(格式:usr-xxxxxx:tokenId)。這個 token 只需建立一次,然後將其加入您的 CI pipeline,作為安全加密的機密變數。

  1. 建立 token: 在您的 Stackhero 控制台,點擊右上角的大頭貼,進入 您的帳戶,選擇 Access tokens,然後點擊 Create token
  2. GitHub Actions: 在您的 repository,前往 Settings > Secrets and variables > Actions > New repository secret,將 token 輸入為 STACKHERO_TOKEN
  3. GitLab CI: 在您的專案,前往 Settings > CI/CD > Variables > Add variable,將 key 設為 STACKHERO_TOKEN,並勾選 Masked(如果您的 CI 僅在受保護分支執行,也可勾選 Protected)。

請勿將 access token 直接寫在 pipeline 的 YAML 檔案中。如果 token 出現在 YAML 內,任何有 repository 存取權的人都可能看到,甚至可能出現在建置日誌中。將其儲存為 CI 機密可確保加密與遮蔽,讓您的 token 保持安全。

以下是一個完整的腳本範例,涵蓋服務的全生命週期。您會發現設定非常簡單,只需幾個指令即可。您可以直接從下方各平台區段複製對應的 YAML 配置。

#!/bin/bash
set -euo pipefail

# STACKHERO_TOKEN 由 CI 機密提供,CLI 會自動讀取。

stackName="ci-elasticsearch-$$"          # 每次執行唯一的 stack 名稱
serviceStore="elasticsearch"             # Elasticsearch 服務 store
instance="20G"        # 如有需要可調整(見步驟 3)
region="europe"                         # 區域名稱(可用 stackhero regions-list 查詢)

# 1. 在 runner 上安裝 CLI
curl -fsSL https://www.stackhero.io/install.sh | sh

# 2. 安裝 smoke test 所需的 client(jq + curl 為基本需求)
apt-get update && apt-get install -y --no-install-recommends jq curl

# 3. 為本次執行建立專屬 stack
stackId=$(stackhero --format=script stack-create --name="$stackName")
echo "Stack created: $stackId"

# 4. 新增 Elasticsearch 並取得其 service id
serviceId=$(stackhero --format=script service-add \
  --stack="$stackId" \
  --service-store="$serviceStore" \
  --instance="$instance" \
  --region="$region")
echo "Service added: $serviceId"

# 5. 等待服務啟動(可能需數分鐘)
stackhero service-wait-for --service="$serviceId"

# 6. 讀取設定(包含產生的認證資訊)
config=$(stackhero service-configuration-get --service="$serviceId" --format=json)

# 7. 取得所需認證資訊
host=$(echo "$config" | jq -r '.configuration.domain')
user=$(echo "$config" | jq -r '.configuration.credentials.login')
password=$(echo "$config" | jq -r '.configuration.credentials.password')

# 8. Smoke test:Call the cluster health endpoint.
curl -fsS -u "$user:$password" "https://$host:9200/_cluster/health" | grep -q '"status"'

echo "✅ Elasticsearch 已可從 CI 存取。"

資源清理(刪除服務、等待刪除完成、再刪除 stack)會在下方各平台專屬區段說明。這種做法可確保即使 smoke test 失敗也會進行完整清理。

Stack 必須為空才能刪除。請務必先刪除服務並等待其移除,再刪除 stack。service-wait-for 指令可確保服務已啟動或已刪除,是等待刪除的最佳工具。

下方範例預設使用 Elasticsearch 的入門實例 20G。這對大多數工作負載來說已相當合適,您也可依需求調整。若要查詢 Elasticsearch 所有可用實例類型,可執行:

# NAME 欄位即為 --instance 參數值
stackhero instances-store-list --service-store=elasticsearch

請將下列內容儲存為 .github/workflows/ci.yml。從此之後,每次 push 或 pull request 都會針對真實的 Elasticsearch 實例執行測試。

name: 使用 Elasticsearch  CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      STACKHERO_TOKEN: ${{ secrets.STACKHERO_TOKEN }}
      STACK_NAME: ci-elasticsearch-${{ github.run_id }}-${{ github.run_attempt }}
      INSTANCE: "20G"   # 如有需要可調整(見步驟 3)
      REGION: europe
    steps:
      - uses: actions/checkout@v4

      - name: 安裝 Stackhero CLI  client
        run: |
          curl -fsSL https://www.stackhero.io/install.sh | sh
          apt-get update && apt-get install -y --no-install-recommends jq curl

      - name: 建立 Elasticsearch 服務
        run: |
          set -euo pipefail
          STACK_ID=$(stackhero --format=script stack-create --name="$STACK_NAME")
          echo "STACK_ID=$STACK_ID" >> "$GITHUB_ENV"
          SERVICE_ID=$(stackhero --format=script service-add \
            --stack="$STACK_ID" \
            --service-store="elasticsearch" \
            --instance="$INSTANCE" \
            --region="$REGION")
          echo "SERVICE_ID=$SERVICE_ID" >> "$GITHUB_ENV"
          stackhero service-wait-for --service="$SERVICE_ID"

      - name: 執行 Elasticsearch 測試
        run: |
          set -euo pipefail
          config=$(stackhero service-configuration-get --service="$SERVICE_ID" --format=json)
          host=$(echo "$config" | jq -r '.configuration.domain')
user=$(echo "$config" | jq -r '.configuration.credentials.login')
password=$(echo "$config" | jq -r '.configuration.credentials.password')
          # Call the cluster health endpoint.
          curl -fsS -u "$user:$password" "https://$host:9200/_cluster/health" | grep -q '"status"'
          echo "✅ Elasticsearch 已可從 CI 存取。"
          # 您也可以在此使用上述認證資訊執行自訂測試 ...

      - name: 清理資源(無論成功或失敗皆執行)
        if: always()
        run: |
          if [ -n "${SERVICE_ID:-}" ]; then
            stackhero service-delete --service="$SERVICE_ID" --confirm
            stackhero service-wait-for --service="$SERVICE_ID"
          fi
          if [ -n "${STACK_ID:-}" ]; then
            stackhero stack-delete --stack="$STACK_ID" --confirm
          fi

清理步驟設定為 if: always(),確保無論流程結果如何都會執行,讓您的 Elasticsearch 實例被刪除,避免產生不必要的資源費用。

請將下列設定儲存為 .gitlab-ci.yml。每次 pipeline 執行時都會建立一個全新的 Elasticsearch 實例供測試使用。

test:
  image: ubuntu:24.04
  variables:
    STACK_NAME: "ci-elasticsearch-$CI_PIPELINE_ID-$CI_JOB_ID"
    INSTANCE: "20G"   # 如有需要可調整(見步驟 3)
    REGION: "europe"
    SERVICE_STORE: "elasticsearch"
  # STACKHERO_TOKEN 來自您於步驟 1 建立的 CI/CD 變數。
  script:
    - set -euo pipefail
    - curl -fsSL https://www.stackhero.io/install.sh | sh
    - apt-get update && apt-get install -y --no-install-recommends jq curl
    - STACK_ID=$(stackhero --format=script stack-create --name="$STACK_NAME")
    - echo "STACK_ID=$STACK_ID" >> deploy.env
    - SERVICE_ID=$(stackhero --format=script service-add --stack="$STACK_ID" --service-store="$SERVICE_STORE" --instance="$INSTANCE" --region="$REGION")
    - echo "SERVICE_ID=$SERVICE_ID" >> deploy.env
    - stackhero service-wait-for --service="$SERVICE_ID"
    - config=$(stackhero service-configuration-get --service="$SERVICE_ID" --format=json)
    - host=$(echo "$config" | jq -r '.configuration.domain')
user=$(echo "$config" | jq -r '.configuration.credentials.login')
password=$(echo "$config" | jq -r '.configuration.credentials.password')
    # Call the cluster health endpoint.
    - curl -fsS -u "$user:$password" "https://$host:9200/_cluster/health" | grep -q '"status"'
    - echo "✅ Elasticsearch 已可從 CI 存取。"
    # 您也可以在此使用上述認證資訊執行自訂測試 ...
  after_script:
    - test -f deploy.env && . ./deploy.env || true
    - >
      if [ -n "${SERVICE_ID:-}" ]; then
        stackhero service-delete --service="$SERVICE_ID" --confirm
        stackhero service-wait-for --service="$SERVICE_ID"
      fi
    - >
      if [ -n "${STACK_ID:-}" ]; then
        stackhero stack-delete --stack="$STACK_ID" --confirm
      fi

在 GitLab 中,資源清理會寫在 after_script 區塊。這個區塊無論 job 成功或失敗都會執行,確保您的 Elasticsearch 資源被移除,避免產生不必要的費用。

在 GitLab,after_script 會在一個全新 shell中執行。為了處理這點,腳本會在 job 過程中將 service 與 stack 的 ID 寫入 deploy.env,並於清理前重新載入。如此即使 job 執行中途失敗,您的資源仍能被正確清除。

這就是 Elasticsearch 的完整 CI 生命週期:建立 stack、加入服務、等待、取得認證、smoke test,並始終進行清理。每次 pipeline 執行都會獲得一個真實、隔離的服務,流程結束後不會有任何資源殘留。如需更多可用指令與非互動式 STACKHERO_TOKEN 認證說明,歡迎參考 完整 CLI 文件