MySQL: GitHub Actions & GitLab CI

Inicie um serviço real de MySQL a partir do seu pipeline do GitHub Actions ou GitLab CI, execute os seus testes sobre ele e elimine-o automaticamente

👋 Bem-vindo à documentação da Stackhero!

A Stackhero oferece uma solução MySQL cloud pronta a usar que proporciona uma série de benefícios, incluindo:

  • Conexões e transferências ilimitadas.
  • Interface web phpMyAdmin incluída.
  • Atualizações fáceis com apenas um clique.
  • Desempenho ótimo e segurança robusta alimentados por uma VM privada e dedicada.

Poupe tempo e simplifique a sua vida: leva apenas 5 minutos para experimentar a solução de MySQL cloud hosting da Stackhero!

Este guia irá guiá-lo na execução de um serviço real e dedicado de MySQL dentro do seu pipeline CI, utilizando GitHub Actions ou GitLab CI. Ao seguir estes passos, poderá testar o seu código contra uma instância ativa de MySQL em condições semelhantes às de produção, deixando de depender de mocks ou simulações. MySQL is the world's most popular open source SQL database, trusted by applications of every size.

Sempre que o seu pipeline for executado, será criada uma nova instância de MySQL. Isto significa que os seus testes interagem com o mesmo tipo de serviço que os seus utilizadores verão em produção. O workflow cria automaticamente uma stack temporária, adiciona o MySQL, aguarda que esteja pronto, obtém as credenciais geradas, executa um smoke test com o the MySQL client e, no final, garante sempre a limpeza de todos os recursos.

Irá utilizar o Stackhero CLI, uma ferramenta de linha de comandos autónoma que facilita o lançamento e a gestão de serviços Stackhero de forma rápida e simples.

Para permitir que o CLI funcione de forma não interativa, irá necessitar de um access token (formato: usr-xxxxxx:tokenId). Só precisa de criar este token uma vez e adicioná-lo ao seu pipeline CI como um segredo seguro e encriptado.

  1. Criar o token: No seu dashboard Stackhero, clique na sua foto de perfil no canto superior direito, aceda a A sua conta, depois Access tokens e clique em Criar token.
  2. Para GitHub Actions: No seu repositório, vá a Settings > Secrets and variables > Actions > New repository secret e introduza o token como STACKHERO_TOKEN.
  3. Para GitLab CI: No seu projeto, vá a Settings > CI/CD > Variables > Add variable, defina a chave como STACKHERO_TOKEN e selecione Masked (e Protected se o seu CI só correr em branches protegidas).

Nunca inclua o seu access token diretamente no ficheiro YAML do pipeline. Se estiver presente no YAML, pode ser exposto a qualquer pessoa com acesso ao repositório e pode aparecer nos logs de build. Guardá-lo como segredo CI mantém-no encriptado e mascarado, garantindo a segurança do seu token.

Segue-se um exemplo completo de script que gere todo o ciclo de vida do serviço. Demonstra como a configuração é simples, bastando apenas alguns comandos. Pode copiar o YAML pronto para a sua plataforma nas secções abaixo.

#!/bin/bash
set -euo pipefail

# STACKHERO_TOKEN é fornecido pelo segredo CI, o CLI deteta-o automaticamente.

stackName="ci-mysql-$$"          # Nome único da stack para cada execução
serviceStore="mysql"             # O serviço store de MySQL
instance="10G"        # Altere se necessário (ver passo 3)
region="europe"                         # Nome da região (ver stackhero regions-list)

# 1. Instalar o CLI no runner
curl -fsSL https://www.stackhero.io/install.sh | sh

# 2. Instalar o cliente necessário para o smoke test (jq + curl são o mínimo)
apt-get update && apt-get install -y --no-install-recommends jq curl default-mysql-client

# 3. Criar uma stack dedicada para esta execução
stackId=$(stackhero --format=script stack-create --name="$stackName")
echo "Stack criada: $stackId"

# 4. Adicionar MySQL e obter o id do serviço
serviceId=$(stackhero --format=script service-add \
  --stack="$stackId" \
  --service-store="$serviceStore" \
  --instance="$instance" \
  --region="$region")
echo "Serviço adicionado: $serviceId"

# 5. Esperar até o serviço estar operacional (pode demorar alguns minutos)
stackhero service-wait-for --service="$serviceId"

# 6. Ler a configuração (contém as credenciais geradas)
config=$(stackhero service-configuration-get --service="$serviceId" --format=json)

# 7. Extrair as credenciais necessárias
host=$(echo "$config" | jq -r '.configuration.domain')
password=$(echo "$config" | jq -r '.configuration.mysqlRootPassword')

# 8. Smoke test: Run a trivial query against the database.
mysql --host="$host" --port=3306 --user=root --password="$password" --ssl-mode=REQUIRED -e "SELECT 1;"

echo "✅ MySQL está acessível a partir do CI."

O passo de teardown, que elimina o serviço, aguarda a sua remoção e depois elimina a stack, é detalhado nas secções específicas de cada plataforma abaixo. Este método garante que a limpeza é sempre realizada, mesmo que um smoke test falhe.

Uma stack só pode ser eliminada quando estiver vazia. Elimine sempre o serviço primeiro e aguarde a sua remoção, depois elimine a stack. O comando service-wait-for garante que o serviço está em execução ou já foi eliminado antes de prosseguir, sendo a ferramenta adequada também para aguardar pela eliminação.

Os exemplos abaixo utilizam por defeito a instância de entrada 10G para MySQL. É uma escolha sólida para a maioria dos workloads, mas pode ajustá-la conforme necessário. Para ver todos os tipos de instância disponíveis para MySQL, execute:

# A coluna NAME mostra o valor a passar para --instance
stackhero instances-store-list --service-store=mysql

Para começar, guarde o seguinte conteúdo como .github/workflows/ci.yml. A partir de agora, cada push e pull request irá executar testes contra uma instância real de MySQL.

name: CI com MySQL

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      STACKHERO_TOKEN: ${{ secrets.STACKHERO_TOKEN }}
      STACK_NAME: ci-mysql-${{ github.run_id }}-${{ github.run_attempt }}
      INSTANCE: "10G"   # Altere se necessário (ver passo 3)
      REGION: europe
    steps:
      - uses: actions/checkout@v4

      - name: Instalar o Stackhero CLI e o cliente
        run: |
          curl -fsSL https://www.stackhero.io/install.sh | sh
          apt-get update && apt-get install -y --no-install-recommends jq curl default-mysql-client

      - name: Criar o serviço MySQL
        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="mysql" \
            --instance="$INSTANCE" \
            --region="$REGION")
          echo "SERVICE_ID=$SERVICE_ID" >> "$GITHUB_ENV"
          stackhero service-wait-for --service="$SERVICE_ID"

      - name: Executar testes sobre MySQL
        run: |
          set -euo pipefail
          config=$(stackhero service-configuration-get --service="$SERVICE_ID" --format=json)
          host=$(echo "$config" | jq -r '.configuration.domain')
password=$(echo "$config" | jq -r '.configuration.mysqlRootPassword')
          # Run a trivial query against the database.
          mysql --host="$host" --port=3306 --user=root --password="$password" --ssl-mode=REQUIRED -e "SELECT 1;"
          echo "✅ MySQL está acessível a partir do CI."
          # Pode executar a sua própria suite de testes aqui usando as credenciais acima ...

      - name: Limpeza (sempre, mesmo em caso de falha)
        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

O passo de limpeza está configurado com if: always() para garantir que é sempre executado, assegurando que a sua instância de MySQL é eliminada e que não será cobrado por recursos não utilizados.

Pode guardar esta configuração como .gitlab-ci.yml. Com esta configuração, cada execução do pipeline cria uma nova instância real de MySQL para os seus testes.

test:
  image: ubuntu:24.04
  variables:
    STACK_NAME: "ci-mysql-$CI_PIPELINE_ID-$CI_JOB_ID"
    INSTANCE: "10G"   # Altere se necessário (ver passo 3)
    REGION: "europe"
    SERVICE_STORE: "mysql"
  # STACKHERO_TOKEN vem da variável CI/CD criada no passo 1.
  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 default-mysql-client
    - 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')
password=$(echo "$config" | jq -r '.configuration.mysqlRootPassword')
    # Run a trivial query against the database.
    - mysql --host="$host" --port=3306 --user=root --password="$password" --ssl-mode=REQUIRED -e "SELECT 1;"
    - echo "✅ MySQL está acessível a partir do CI."
    # Pode executar a sua própria suite de testes aqui usando as credenciais acima ...
  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

No GitLab, a limpeza é feita na secção after_script. Esta secção é sempre executada, mesmo que o job falhe, garantindo que os recursos de MySQL são eliminados e que não será cobrado por recursos não utilizados.

No GitLab, o after_script corre numa shell nova. Para lidar com isto, o script grava os IDs do serviço e da stack em deploy.env durante o job e volta a carregá-los antes da limpeza. Assim, mesmo que algo falhe a meio do job, os seus recursos são sempre eliminados.

Este é o ciclo CI completo para MySQL: criar uma stack, adicionar o serviço, aguardar, obter credenciais, smoke-test e garantir sempre a limpeza. Cada execução do pipeline recebe um serviço real e isolado, sem nada a correr no final. Para mais informações sobre os comandos disponíveis e autenticação não interativa com STACKHERO_TOKEN, consulte a documentação completa do CLI.