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

GitHub Actions密钥无法在Docker容器中生效问题求助

环境变量无法注入Docker容器的排查与解决

问题场景

通过GitHub Actions构建Docker镜像并推送到GitHub Container Registry,随后部署到VPS服务器,但容器内无法获取到环境变量,要么为空值,要么直接报错找不到变量。

相关配置文件

GitHub Actions工作流文件

# GitHub packages build and push v2
name: Build and Push Docker Image

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.TOKEN }}
      - name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ghcr.io/${{ github.repository_owner }}/piggybot:latest

  deploy:
    needs: build
    runs-on: ubuntu-latest
    env:
      BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
      POSTGRES_DSN: ${{ secrets.POSTGRES_DSN }}
      REDIS_DSN: ${{ secrets.REDIS_DSN }}
      APP_HOST: ${{ secrets.APP_HOST }}
      APP_PORT: ${{ secrets.APP_PORT }}
      WEBHOOK_DOMAIN: ${{ secrets.WEBHOOK_DOMAIN }}
      WEBHOOK_PATH: ${{ secrets.WEBHOOK_PATH }}
      ENVIRONMENT: ${{ secrets.ENVIRONMENT }}
      SERVICE_NAME: ${{ secrets.SERVICE_NAME }}
    steps:
      - name: Deploy to VDS
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          password: ${{ secrets.SSH_PASS }}
          port: ${{ secrets.SSH_PORT }}

          script: |
            docker login -u ${{ github.repository_owner }} -p ${{ secrets.TOKEN }} ghcr.io
            docker pull ghcr.io/${{ github.repository_owner }}/piggybot:latest
            docker stop piggybot
            docker rm piggybot
            docker run -e BOT_TOKEN=$BOT_TOKEN -e POSTGRES_DSN=$POSTGRES_DSN -e REDIS_DSN=$REDIS_DSN -e APP_HOST=$APP_HOST -e APP_PORT=$APP_PORT -e WEBHOOK_DOMAIN=$WEBHOOK_DOMAIN -e WEBHOOK_PATH=$WEBHOOK_PATH -e ENVIRONMENT=$ENVIRONMENT -e SERVICE_NAME=$SERVICE_NAME -d --name piggybot ghcr.io/${{ github.repository_owner }}/piggybot:latest

Python环境变量读取代码

class Config(BaseSettings):
    bot_token: str = os.environ["BOT_TOKEN"]
    postgres_dsn: PostgresDsn = os.environ["POSTGRES_DSN"]
    redis_dsn: Optional[RedisDsn] = os.environ["REDIS_DSN"]
    app_host: Optional[str] = os.environ["APP_HOST"]
    app_port: Optional[int] = os.environ["APP_PORT"]
    webhook_domain: Optional[str] = os.environ["WEBHOOK_DOMAIN"]
    webhook_path: Optional[str] = os.environ["WEBHOOK_PATH"]
    environment: Optional[str] = os.environ["ENVIRONMENT"]
    service_name: Optional[str] = os.environ["SERVICE_NAME"]

Dockerfile

# Separate build image
FROM python:3.10-slim-bullseye as compile-image
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN apt-get update \
 && apt-get install -y gcc \
 && pip install --no-cache-dir --upgrade pip \
 && pip install --no-cache-dir setuptools wheel \
 && pip install --no-cache-dir -r requirements.txt \
 && rm -rf /var/lib/apt/lists/*

# Final image
FROM python:3.10-slim-bullseye
COPY --from=compile-image /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /app
COPY app /app
CMD ["python", "-m", "tgbot"]

问题排查与修复

1. SSH脚本中环境变量传递错误

核心原因:GitHub Actions runner中定义的env变量无法直接传递到SSH连接的服务器shell中,导致docker run命令里的$BOT_TOKEN等变量为空。

修复方案(二选一):

方案一:通过ssh-action的env传递变量

修改deploy步骤的ssh-action配置,将需要的Secrets直接注入到SSH会话的环境中:

- name: Deploy to VDS
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.SSH_HOST }}
    username: ${{ secrets.SSH_USER }}
    password: ${{ secrets.SSH_PASS }}
    port: ${{ secrets.SSH_PORT }}
    # 定义要传递到服务器的环境变量
    env: |
      BOT_TOKEN=${{ secrets.BOT_TOKEN }}
      POSTGRES_DSN=${{ secrets.POSTGRES_DSN }}
      REDIS_DSN=${{ secrets.REDIS_DSN }}
      APP_HOST=${{ secrets.APP_HOST }}
      APP_PORT=${{ secrets.APP_PORT }}
      WEBHOOK_DOMAIN=${{ secrets.WEBHOOK_DOMAIN }}
      WEBHOOK_PATH=${{ secrets.WEBHOOK_PATH }}
      ENVIRONMENT=${{ secrets.ENVIRONMENT }}
      SERVICE_NAME=${{ secrets.SERVICE_NAME }}
    script: |
      docker login -u ${{ github.repository_owner }} -p ${{ secrets.TOKEN }} ghcr.io
      docker pull ghcr.io/${{ github.repository_owner }}/piggybot:latest
      # 容器不存在时避免命令报错
      docker stop piggybot || true
      docker rm piggybot || true
      # 包含特殊字符的变量用双引号包裹,避免shell解析错误
      docker run -e BOT_TOKEN=$BOT_TOKEN -e POSTGRES_DSN="$POSTGRES_DSN" -e REDIS_DSN="$REDIS_DSN" -e APP_HOST=$APP_HOST -e APP_PORT=$APP_PORT -e WEBHOOK_DOMAIN=$WEBHOOK_DOMAIN -e WEBHOOK_PATH=$WEBHOOK_PATH -e ENVIRONMENT=$ENVIRONMENT -e SERVICE_NAME=$SERVICE_NAME -d --name piggybot ghcr.io/${{ github.repository_owner }}/piggybot:latest

方案二:直接在script中注入Secrets

跳过runner的env变量,直接将${{ secrets.XXX }}写入docker run命令:

script: |
  docker login -u ${{ github.repository_owner }} -p ${{ secrets.TOKEN }} ghcr.io
  docker pull ghcr.io/${{ github.repository_owner }}/piggybot:latest
  docker stop piggybot || true
  docker rm piggybot || true
  docker run -e BOT_TOKEN=${{ secrets.BOT_TOKEN }} -e POSTGRES_DSN="${{ secrets.POSTGRES_DSN }}" -e REDIS_DSN="${{ secrets.REDIS_DSN }}" -e APP_HOST=${{ secrets.APP_HOST }} -e APP_PORT=${{ secrets.APP_PORT }} -e WEBHOOK_DOMAIN=${{ secrets.WEBHOOK_DOMAIN }} -e WEBHOOK_PATH=${{ secrets.WEBHOOK_PATH }} -e ENVIRONMENT=${{ secrets.ENVIRONMENT }} -e SERVICE_NAME=${{ secrets.SERVICE_NAME }} -d --name piggybot ghcr.io/${{ github.repository_owner }}/piggybot:latest

2. Python代码中环境变量读取方式错误

核心原因:手动调用os.environ会绕过Pydantic BaseSettings的自动处理逻辑,且变量不存在时会抛出未捕获的KeyError。

修复方案:利用BaseSettings的自动读取特性,去掉手动的os.environ调用:

from pydantic import BaseSettings, PostgresDsn, RedisDsn
from typing import Optional

class Config(BaseSettings):
    # 必填字段,未设置会抛出明确错误
    bot_token: str
    postgres_dsn: PostgresDsn
    # 可选字段,未设置则为None
    redis_dsn: Optional[RedisDsn] = None
    app_host: Optional[str] = None
    app_port: Optional[int] = None
    webhook_domain: Optional[str] = None
    webhook_path: Optional[str] = None
    environment: Optional[str] = None
    service_name: Optional[str] = None

    class Config:
        # 本地开发时可加载.env文件,部署时无需此配置
        env_file = ".env"
        # 允许环境变量大写(如BOT_TOKEN)匹配小写字段(bot_token)
        case_sensitive = False

3. 验证环境变量是否注入成功

在部署脚本末尾添加验证命令,可在GitHub Actions日志中查看容器内的环境变量:

docker exec piggybot printenv | grep -E "(BOT_TOKEN|POSTGRES_DSN|REDIS_DSN)"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:20:33