Elasticsearch: GitHub Actions 与 GitLab CI

通过您的 GitHub Actions 或 GitLab CI pipeline 启动一个真实的 Elasticsearch 服务,运行测试并自动销毁

👋 欢迎来到 Stackhero 文档!

Stackhero 提供现成的 Elasticsearch 云 解决方案,具有多种优势,包括:

  • 专用私有 VM提供的最佳性能和强大的安全性
  • 支持 HTTPS 加密的可定制域名

节省时间简化您的生活:只需 5 分钟即可试用 Stackhero 的 Elasticsearch 云托管 解决方案!

本指南将引导您在 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 能以非交互方式运行,您需要一个访问令牌(格式:usr-xxxxxx:tokenId)。该令牌只需创建一次,然后作为安全加密的 CI 密钥添加到您的 pipeline。

  1. 创建令牌: 在您的 Stackhero 控制台,点击右上角的头像,进入 Your account,选择 Access tokens,点击 Create token
  2. GitHub Actions: 在您的代码仓库,进入 Settings > Secrets and variables > Actions > New repository secret,将令牌填入 STACKHERO_TOKEN
  3. GitLab CI: 在您的项目中,进入 Settings > CI/CD > Variables > Add variable,设置 key 为 STACKHERO_TOKEN,勾选 Masked(如您的 CI 仅在受保护分支运行,也可勾选 Protected)。

请勿将访问令牌直接写入 pipeline 的 YAML 文件。如果令牌出现在 YAML 中,任何有仓库访问权限的人都可能看到,并且可能会出现在构建日志中。将其作为 CI 密钥存储可确保加密和隐藏,保障您的令牌安全。

以下是一个完整的服务生命周期管理脚本示例。只需几条命令即可完成全部配置。您可以直接复制下方各平台的 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: CI with Elasticsearch

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 实现。该部分无论作业是否失败都会执行,确保您的 Elasticsearch 资源被及时移除,避免产生不必要的费用。

在 GitLab 中,after_script 会在一个全新 shell中运行。为此,脚本会在作业期间将服务和 stack 的 ID 写入 deploy.env,清理前再重新加载。这样即使作业中途失败,也能确保资源被正确清理。

这就是 Elasticsearch 的完整 CI 生命周期:创建 stack、添加服务、等待、获取凭证、smoke test,并始终进行资源清理。每次 pipeline 运行都能获得一个真实、隔离的服务,流程结束后不会有任何资源遗留。如需了解更多可用命令及非交互式 STACKHERO_TOKEN 认证方式,欢迎查阅 完整 CLI 文档