使用GitHub Actions+Pulumi部署GCP Artifact Registry遇非TTY登录错误
解决GitHub Actions中Pulumi部署Docker镜像到GCP Artifact Registry时的"Cannot perform an interactive login from a non TTY device"错误
Cannot perform an interactive login from a non TTY device
背景说明
我正在GitHub Actions中使用Pulumi将两个Docker容器部署到GCP的Artifact Registry,但反复遇到上述错误。Stack Overflow上已有大量相关问答,我尝试了所有公开解决方案仍无法解决。
GitHub Actions配置YAML
name: Deploy to Staging on: push: branches: - main permissions: actions: read contents: read id-token: write jobs: ci: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - uses: pnpm/action-setup@v4 with: version: 9 - uses: actions/setup-node@v4 with: node-version: 22 cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build affected apps run: pnpm exec nx affected -t build deploy: runs-on: ubuntu-latest environment: staging needs: [ci] steps: - uses: actions/checkout@v4 - name: Create .env file run: | cat << EOF > libs/infrastructure/src/pulumi/.env PULUMI_MAIN_SERVICE_ACCOUNT_STAGING="${{ secrets.PULUMI_MAIN_SERVICE_ACCOUNT_STAGING }}" PULUMI_WORKLOAD_IDENTITY_PROVIDER_ID_STAGING="${{ secrets.PULUMI_WORKLOAD_IDENTITY_PROVIDER_ID_STAGING }}" PULUMI_DOPPLER_REMIX_PROJECT="remix-app" PULUMI_DOPPLER_REMIX_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_REMIX_STAGING_TOKEN }}" PULUMI_DOPPLER_REMIX_STAGING_BRANCH_NAME="stg" PULUMI_DOPPLER_TEMPORAL_PROJECT="temporal-worker" PULUMI_DOPPLER_TEMPORAL_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_TEMPORAL_STAGING_TOKEN }}" PULUMI_DOPPLER_TEMPORAL_STAGING_BRANCH_NAME="stg" PULUMI_DOPPLER_CLOUD_RUN_REMIX_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_CLOUD_RUN_REMIX_STAGING_TOKEN }}" PULUMI_DOPPLER_CLOUD_RUN_TEMPORAL_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_CLOUD_RUN_TEMPORAL_STAGING_TOKEN }}" EOF - name: Configure Workload Identity Federation id: auth uses: google-github-actions/auth@v2 with: workload_identity_provider: ${{ secrets.GCP_STAGING_WORKLOAD_IDENTITY_PROVIDER_ID }} project_id: ${{ secrets.GCP_STAGING_PROJECT_ID }} service_account: github-actions-sa-stg@alertdown-staging.iam.gserviceaccount.com token_format: 'access_token' - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@v2 - name: Configure Docker for Artifact Registry run: | gcloud auth configure-docker us-east1-docker.pkg.dev - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Artifact Registry uses: docker/login-action@v3 with: registry: us-east1-docker.pkg.dev username: oauth2accesstoken password: ${{ steps.auth.outputs.access_token }} - name: Run Pulumi uses: pulumi/actions@v6 with: work-dir: 'libs/infrastructure/src/pulumi' command: 'up' stack-name: 'alertdown/alertdown-infra/dev' comment-on-pr: true env: PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
基础设施代码(Go)
package cloudrun import ( "errors" "fmt" "os" "path/filepath" "github.com/pulumi/pulumi-docker/sdk/v3/go/docker" "github.com/pulumi/pulumi-gcp/sdk/v8/go/gcp" "github.com/pulumi/pulumi-gcp/sdk/v8/go/gcp/artifactregistry" "github.com/pulumi/pulumi-gcp/sdk/v8/go/gcp/projects" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) type createArtifactRegistryNewRepositoryInput struct { ctx *pulumi.Context artifactRegistryRepoName string artifactRegistryRepoLocation string artifactRegistryService *projects.Service `pulumi:"artifactRegistryService"` provider *gcp.Provider } func createArtifactRegistryNewRepository(input *createArtifactRegistryNewRepositoryInput) (*artifactregistry.Repository, error) { if input.artifactRegistryService == nil { return nil, errors.New("artifactRegistryService cannot be nil") } dependingResources := []pulumi.Resource{ input.artifactRegistryService, } repo, err := artifactregistry.NewRepository(input.ctx, input.artifactRegistryRepoName, &artifactregistry.RepositoryArgs{ Location: pulumi.String(input.artifactRegistryRepoLocation), RepositoryId: pulumi.String(input.artifactRegistryRepoName), Format: pulumi.String("DOCKER"), Description: pulumi.String("The repository that will hold social-log Docker images."), }, pulumi.DependsOn(dependingResources), pulumi.Provider(input.provider)) if err != nil { return nil, err } return repo, nil } type buildAndPushToArtifactRegistryInput struct { ctx *pulumi.Context artifactRegistryRepo *artifactregistry.Repository dockerImageName string dockerImagePath string dockerfileName string provider *gcp.Provider } func buildAndPushToArtifactRegistry(input *buildAndPushToArtifactRegistryInput) (*docker.Image, error) { if input.artifactRegistryRepo == nil { return nil, errors.New("artifactRegistryRepo cannot be nil") } dependingSources := []pulumi.Resource{ input.artifactRegistryRepo, } // Get the absolute path to the project root workingDir, err := os.Getwd() if err != nil { return nil, fmt.Errorf("failed to get working directory: %w", err) } // Go up to the project root (from /libs/infrastructure/src/pulumi) projectRoot := filepath.Join(workingDir, "../../../../") projectRoot, err = filepath.Abs(projectRoot) if err != nil { return nil, fmt.Errorf("failed to get absolute path: %w", err) } // Construct the absolute path to the Dockerfile dockerfilePath := filepath.Join(projectRoot, "apps", input.dockerImagePath) // Verify the Dockerfile exists if _, err := os.Stat(dockerfilePath); os.IsNotExist(err) { return nil, fmt.Errorf("dockerfile not found at path: %s", dockerfilePath) } // Create Docker build args using absolute paths buildArgs := &docker.DockerBuildArgs{ Context: pulumi.String(dockerfilePath), ExtraOptions: pulumi.StringArray{ pulumi.String("--platform=linux/amd64"), pulumi.String("--build-context"), pulumi.String(fmt.Sprintf("root=%v", projectRoot)), }, Target: pulumi.String("production"), } // Construct the full image name with registry URL // Format: LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE registryUrl := pulumi.Sprintf("%s-docker.pkg.dev/%s/%s/%s", input.artifactRegistryRepo.Location, input.artifactRegistryRepo.Project, input.artifactRegistryRepo.RepositoryId, input.dockerImageName, ) accessToken := os.Getenv("GOOGLE_ACCESS_TOKEN_FROM_CLI") image, err := docker.NewImage(input.ctx, input.dockerImageName, &docker.ImageArgs{ Build: buildArgs, ImageName: registryUrl, // Use the full registry URL instead of just the image name Registry: &docker.ImageRegistryArgs{ Server: pulumi.Sprintf("%s-docker.pkg.dev", input.artifactRegistryRepo.Location), Username: pulumi.String("oauth2accesstoken"), Password: pulumi.String(accessToken), // Replace with a valid access token }, }, pulumi.DependsOn(dependingSources), pulumi.Provider(input.provider)) if err != nil { return nil, fmt.Errorf("failed to create docker image: %w", err) } return image, nil }
已知信息
- 代码在本地环境运行正常
- 已确认服务账号具备正确的权限与角色
- 使用Workload Identity Federation认证方式
请问有什么解决思路吗?
内容的提问来源于stack exchange,提问作者Jose A
相关产品推荐
相关产品推荐

