You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从GitHub Actions向Docker Compose传递多行环境变量

解决GitHub Actions中多行数据库证书环境变量的传递问题

我存储在GitHub Secrets中的DATABASE_CA环境变量是代表数据库证书的多行文件,需要导出至VPS供Docker Compose使用。当前使用的GitHub Actions部署脚本存在多行环境变量传递错误的问题,以下是修复方案:

原部署脚本

name: 部署生产环境至DigitalOcean

on:
  create:
    branches:
      - release
  push:
    branches:
      - release
  pull_request:
    branches:
      - release

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 拉取代码仓库
        uses: actions/checkout@v3

      - name: 复制docker-compose.prod.yml到服务器
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.PRIVATE_KEY }}
          passphrase: ${{ secrets.PASSPHRASE }}
          source: "docker-compose.prod.yml"
          target: /home/${{ secrets.USERNAME }}

      - name: 启动Docker Compose服务栈
        uses: appleboy/ssh-action@v0.1.6
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.PRIVATE_KEY }}
          passphrase: ${{ secrets.PASSPHRASE }}
          script: |
            echo ${{ secrets.CR_PAT }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
            export DATABASE_HOST=${{ secrets.DATABASE_HOST }}
            export DATABASE_PORT=${{ secrets.DATABASE_PORT }}
            export DATABASE_NAME=${{ secrets.DATABASE_NAME }}
            export DATABASE_USERNAME=${{ secrets.DATABASE_USERNAME }}
            export DATABASE_PASSWORD=${{ secrets.DATABASE_PASSWORD }}
            export DATABASE_CA=${{ secrets.DATABASE_CA }}
            export APP_KEYS=${{ secrets.APP_KEYS }}
            export API_TOKEN_SALT=${{ secrets.API_TOKEN_SALT }}
            export ADMIN_JWT_SECRET=${{ secrets.ADMIN_JWT_SECRET }}
            export JWT_SECRET=${{ secrets.JWT_SECRET }}
            export R2_ACCESS_KEY_ID=${{ secrets.R2_ACCESS_KEY_ID }}
            export R2_ACCESS_SECRET=${{ secrets.R2_ACCESS_SECRET }}
            export R2_ENDPOINT=${{ secrets.R2_ENDPOINT }}
            export R2_BUCKET=${{ secrets.R2_BUCKET }}
            export R2_PUBLIC_ACCESS_URL=${{ secrets.R2_PUBLIC_ACCESS_URL }}
            export APP_URL=${{ secrets.APP_URL }}
            docker compose -f docker-compose.prod.yml down
            docker compose -f docker-compose.prod.yml pull
            docker compose -f docker-compose.prod.yml up -d

问题分析

直接用export DATABASE_CA=${{ secrets.DATABASE_CA }}传递多行证书时,证书中的换行符会被SSH脚本解析为新的命令行指令,导致语法错误,无法正确传递完整的证书内容。

修复方案:将多行证书写入文件(推荐)

最可靠的方式是将多行证书内容写入VPS上的文件,再让Docker Compose通过挂载文件的方式读取证书,而非直接传递环境变量。

修改后的SSH脚本部分

将原脚本中export DATABASE_CA=${{ secrets.DATABASE_CA }}替换为以下内容:

# 将多行证书写入/tmp/ca.crt文件
cat > /tmp/ca.crt << 'EOF'
${{ secrets.DATABASE_CA }}
EOF

同步修改docker-compose.prod.yml

在数据库服务配置中,添加证书文件的挂载路径,并指定证书环境变量:

services:
  # 你的数据库服务名称,比如postgres
  postgres:
    environment:
      # 以PostgreSQL为例,指定根证书路径
      - PGSSLROOTCERT=/etc/postgresql/ca.crt
      - PGSSLMODE=verify-full
    volumes:
      # 将VPS上的/tmp/ca.crt挂载到容器内指定路径
      - /tmp/ca.crt:/etc/postgresql/ca.crt

完整修改后的部署脚本

name: 部署生产环境至DigitalOcean

on:
  create:
    branches:
      - release
  push:
    branches:
      - release
  pull_request:
    branches:
      - release

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 拉取代码仓库
        uses: actions/checkout@v3

      - name: 复制docker-compose.prod.yml到服务器
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.PRIVATE_KEY }}
          passphrase: ${{ secrets.PASSPHRASE }}
          source: "docker-compose.prod.yml"
          target: /home/${{ secrets.USERNAME }}

      - name: 启动Docker Compose服务栈
        uses: appleboy/ssh-action@v0.1.6
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.PRIVATE_KEY }}
          passphrase: ${{ secrets.PASSPHRASE }}
          script: |
            echo ${{ secrets.CR_PAT }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
            export DATABASE_HOST=${{ secrets.DATABASE_HOST }}
            export DATABASE_PORT=${{ secrets.DATABASE_PORT }}
            export DATABASE_NAME=${{ secrets.DATABASE_NAME }}
            export DATABASE_USERNAME=${{ secrets.DATABASE_USERNAME }}
            export DATABASE_PASSWORD=${{ secrets.DATABASE_PASSWORD }}
            # 写入数据库证书文件
            cat > /tmp/ca.crt << 'EOF'
            ${{ secrets.DATABASE_CA }}
            EOF
            export APP_KEYS=${{ secrets.APP_KEYS }}
            export API_TOKEN_SALT=${{ secrets.API_TOKEN_SALT }}
            export ADMIN_JWT_SECRET=${{ secrets.ADMIN_JWT_SECRET }}
            export JWT_SECRET=${{ secrets.JWT_SECRET }}
            export R2_ACCESS_KEY_ID=${{ secrets.R2_ACCESS_KEY_ID }}
            export R2_ACCESS_SECRET=${{ secrets.R2_ACCESS_SECRET }}
            export R2_ENDPOINT=${{ secrets.R2_ENDPOINT }}
            export R2_BUCKET=${{ secrets.R2_BUCKET }}
            export R2_PUBLIC_ACCESS_URL=${{ secrets.R2_PUBLIC_ACCESS_URL }}
            export APP_URL=${{ secrets.APP_URL }}
            docker compose -f docker-compose.prod.yml down
            docker compose -f docker-compose.prod.yml pull
            docker compose -f docker-compose.prod.yml up -d

备选方案:转义换行符传递环境变量

如果必须通过环境变量传递,可将证书中的换行符转义为\n,再用双引号包裹:

export DATABASE_CA="$(echo '${{ secrets.DATABASE_CA }}' | sed -z 's/\n/\\n/g')"

但此方法可能因证书中的特殊字符(如引号、反斜杠)导致解析错误,因此优先推荐写入文件的方式。

内容的提问来源于stack exchange,提问作者user9132502

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 21:14:55