压箱底薅羊毛教程!用 GitHub Actions + S3 实现零成本运行 Serverless MySQL 数据库

来源:这里教程网 时间:2026-03-01 18:29:25 作者:

使用数据库做开发、测试、演示或者执行一些短期的工作负载时,通常伴随着高昂的成本和复杂的配置问题。传统的数据库托管方式,例如 VPS,云虚拟机或者托管服务,不仅会持续产生费用,还会产生存储成本和配置开销。甚至在数据库闲置时,仍需要为资源付费。

但是否可以仅在需要时启动数据库,利用廉价(甚至免费的)对象存储保存数据,工作完成后销毁环境,同时几乎零成本且不丢失数据呢?一种可行的实现方法是将 GitHub Actions 作为临时计算环境,同时使用 S3(或兼容 S3 的服务)作为持久化存储,再通过安全隧道实现临时公网访问。

重要提示

此方法仅适用于短期集成测试、临时演示或快速开发任务。 请勿滥用 GitHub Actions,请勿持续运行数据库或当作长期服务平台。GitHub Actions 设计初衷是 CI/CD,而非为持久化服务提供免费的计算资源。如果需要持续或长期运行的数据库托管,请考虑其他服务,或在受控环境中设置自托管的 GitHub Runner,并确保遵守 GitHub 使用协议。

核心思路

核心思路是:

  1. 使用 GitHub Actions 执行临时计算:按需启动兼容 MySQL 的数据库,作为 CI/CD 或测试工作流的一部分。
  2. 兼容 S3 的对象存储持久化:将数据库的数据存储在对象存储(如 AWS S3 或 Cloudflare R2)中。确保临时环境销毁后,数据仍能安全存储在外部存储系统中。
  3. 可公开访问的隧道:将数据库临时暴露到互联网,用于测试或演示。
  4. 仅适合短期使用:数据库仅在工作流执行窗口内运行,工作流结束后释放临时计算资源。这一方式不适用于长期托管解决方案。

薅羊毛提示:使用兼容 S3 服务的免费额度,比如  Cloudflare R2,可零成本实现,更香了。

应用场景

  • 在 CI/CD 中集成测试:在 CI/CD 中启动一个真实且兼容 MySQL 的环境进行测试,测试完成后关闭。
  • 临时演示:需要可快速创建、可共享的数据库实例进行一次性演示?完美适配。
  • 短期开发:无需维护全套服务即可在真实数据库环境中快速测试新代码。

    不推荐用于以下场景:

  • 长期数据库托管或生产用工作负载。
  • 维护长期在线的公共数据库端点。
  • 需要规避 GitHub Actions 的使用协议。

    注意:如有长期使用需求,建议使用 自托管 Runner,自行管理资源,遵循使用规则。

    GitHub Actions 工作流示例

    以下是一个  GitHub Actions 工作流示例,演示了如何在短时间内启动 WeSQL 数据库,使用对象存储持久化数据,并提供隧道实现临时访问。如需复用该工作流,可参考  README 中的步骤。

    name: Start WeSQL Clusteron:
      workflow_dispatch:jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - name: Configure AWS CLI
            run: |
              aws configure set aws_access_key_id ${{ secrets.WESQL_OBJECTSTORE_ACCESS_KEY }}
              aws configure set aws_secret_access_key ${{ secrets.WESQL_OBJECTSTORE_SECRET_KEY }}
              aws configure set default.region ${{ secrets.WESQL_OBJECTSTORE_REGION }}
          - name: Start WeSQL Server
            run: |
              export WESQL_OBJECTSTORE_BUCKET=${{ secrets.WESQL_OBJECTSTORE_BUCKET }}
              export WESQL_OBJECTSTORE_REGION=${{ secrets.WESQL_OBJECTSTORE_REGION }}
              export WESQL_OBJECTSTORE_ACCESS_KEY=${{ secrets.WESQL_OBJECTSTORE_ACCESS_KEY }}
              export WESQL_OBJECTSTORE_SECRET_KEY=${{ secrets.WESQL_OBJECTSTORE_SECRET_KEY }}
              docker run -itd --network host --name wesql-server \
                -p 3306:3306 \
                -e MYSQL_CUSTOM_CONFIG="[mysqld]\n\
                port=3306\n\
                log-bin=binlog\n\
                gtid_mode=ON\n\
                enforce_gtid_consistency=ON\n\
                log_slave_updates=ON\n\
                binlog_format=ROW\n\
                objectstore_provider='aws'\n\
                repo_objectstore_id='tutorial'\n\
                objectstore_bucket='${WESQL_OBJECTSTORE_BUCKET}'\n\
                objectstore_region='${WESQL_OBJECTSTORE_REGION}'\n\
                branch_objectstore_id='main'" \
                -v ~/wesql-local-dir:/data/mysql \
                -e WESQL_CLUSTER_MEMBER='127.0.0.1:13306' \
                -e MYSQL_ROOT_PASSWORD=${{ secrets.WESQL_ROOT_PASSWORD }} \
                -e WESQL_OBJECTSTORE_ACCESS_KEY=${WESQL_OBJECTSTORE_ACCESS_KEY} \
                -e WESQL_OBJECTSTORE_SECRET_KEY=${WESQL_OBJECTSTORE_SECRET_KEY} \
                apecloud/wesql-server:8.0.35-0.1.0_beta3.38
          - name: Wait for MySQL port
            run: |
              for i in {1..60}; do
                if nc -z localhost 3306; then
                  echo "MySQL port 3306 is ready!"
                  exit 0
                fi
                echo "Waiting for MySQL port 3306..."
                sleep 5
              done
              echo "Timeout waiting for MySQL port 3306"
              exit 1
          - name: Start and parse Serveo tunnel
            run: |
              # Just a neat trick: start a tunnel and parse out the assigned port
              nohup ssh -o StrictHostKeyChecking=no -R 0:localhost:3306 serveo.net > serveo.log 2>&1 &
              sleep 5
              TUNNEL_LINE=$(grep 'Forwarding TCP' serveo.log || true)
              if [ -z "$TUNNEL_LINE" ]; then
                echo "No forwarding line found"
                exit 1
              fi
              HOST="serveo.net"
              PORT=$(echo "$TUNNEL_LINE" | sed 's/.*Forwarding TCP connect from .*:\([0-9]*\)/\1/')
              echo "MySQL Public Access:"
              echo "Host: $HOST"
              echo "Port: $PORT"
              echo "Connect: mysql -h $HOST -P $PORT -u root -p${{ secrets.WESQL_ROOT_PASSWORD }}"
              echo "HOST=$HOST" >> $GITHUB_ENV
              echo "PORT=$PORT" >> $GITHUB_ENV
          - name: Write Connection Info to S3
            run: |
              # Just a convenience: store connection info in S3 so you can find it later
              cat << EOF > connection_info.txt
              host=$HOST
              port=$PORT
              username=root
              password=${{ secrets.WESQL_ROOT_PASSWORD }}
              mysql_cli="mysql -h $HOST -P $PORT -u root -p${{ secrets.WESQL_ROOT_PASSWORD }}"
              EOF
              aws s3 cp connection_info.txt s3://${{ secrets.WESQL_OBJECTSTORE_BUCKET }}/connection_info.txt
              echo "Connection info is now in s3://${{ secrets.WESQL_OBJECTSTORE_BUCKET }}/connection_info.txt"
          - name: Keep session running
            run: |
              # Keep the workflow alive so the database stays accessible.
              echo "Press Ctrl+C or cancel the workflow when done."
              tail -f /dev/null

    工作流详解(附赠小技巧)

  • 使用 S3 或 R2:示例中默认使用 AWS S3。但 WeSQL 支持所有兼容 S3 API 的服务,您可以轻松切换到 Cloudflare R2 的免费套餐。这样,不管使用频率如何,都能实现整套配置零成本运行。
  • 隧道服务:诀窍是用 Serveo。通过 SSH,Serveo 会将其服务器上的随机高端口映射到 GitHub Runner 的 MySQL 端口,这样互联网上的任何人都能访问这个临时数据库。如果需要,也可以替换为其他隧道服务(如 ngrok)。不过 Serveo 操作简单且免费。
  • 持久化: 数据全部存储在 S3(或 R2)中,这意味着即使数据库消失,数据也不会丢失。您可以将此解决方案视为 “Serverless MySQL”。
  • 将连接信息存储到 S3: 又一个小技巧轻松 get。此方法可以避免从日志中查找连接详情的麻烦。还可以通过编程方式从 S3 获取连接信息,用于其他自动化流程。

    连接数据库

    工作流正常运行后,可通过 Action 日志获取数据库  Host 和  Port 信息。如需本地连接,可修改以下示例中的信息后执行:

    mysql -h serveo.net -P <PORT> -u root -p<YOUR_PASSWORD>

    数据持久化与重启

    这个方法的核心优势在于:Runner 终止后,容器虽然消失,但数据仍然保存在对象存储中。下次运行 GitHub 工作流时,WeSQL 会从 S3、R2 或者其他兼容 S3 的存储服务中恢复数据。这意味着即使计算环境是短暂的,您的数据库却能长期存在。

    您可以在 S3 的存储桶中查看所有数据:

    安全注意事项

  • 由于隧道暴露在公网,建议使用强密码,或者更严格的访问限制(如果您使用的服务支持该功能),并在任务结束后更换凭证。
  • 将 AWS 和数据库凭证等敏感信息存储在 GitHub Secrets 中,而非代码中。
  • 如果您处理的是敏感数据,请考虑使用 TLS 或其他额外安全层。

    总结

    此方法颠覆了传统“租用服务器并保持其长期运行”的数据库模式。通过 GitHub Actions 提供临时计算能力,并搭配 S3 持久存储,您可以拥有按需运行、零成本且随时可用的 Serverless 数据库,非常适合快速测试或演示。

    下次需要临时数据库环境时,不妨试试这种方法,告别高成本的虚拟机或托管实例!

  • 相关推荐