如何从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
相关产品推荐
相关产品推荐

