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

Pulumi(Go)结合Docker构建镜像报错:无法找到Dockerfile路径

使用Pulumi(Go)部署Docker镜像到GCP Artifact Registry时的Dockerfile路径问题

报错信息

ERROR: resolve : lstat apps: no such file or directory

另一种场景下的完整报错:

error: an unhandled error occurred: program failed:
waiting for RPCs: docker build -f apps/remix-app-vite/Dockerfile --target production --platform=linux/amd64 /Users/joseasilis/Documents/programming/alertdown -t remix-app-dev failed with error: exit status 1

docker:image:Image (temporal-worker-dev):
    error: ERROR: resolve : lstat apps: no such file or directory

docker:image:Image (remix-app-dev):
    error: ERROR: resolve : lstat apps: no such file or directory

目录结构

  • 这是一个TypeScript的nx monorepo,Pulumi的Go代码位于<root>/libs/infrastructure/src/pulumi目录
  • Dockerfile分别位于<root>/apps/remix-app-vite/和<root>/apps/temporal-worker/目录下

构建镜像的核心Go代码

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 current working directory
    workingDir, err := os.Getwd()
    if err != nil {
        return nil, err
    }

    // Go up to the project root (from /libs/infrastructure/src/pulumi)
    projectRoot := filepath.Join(workingDir, "../../../../")
    projectRoot = filepath.Clean(projectRoot)

    // Debug information
    fmt.Printf("Working Directory: %s\n", workingDir)
    fmt.Printf("Project Root: %s\n", projectRoot)
    fmt.Printf("Dockerfile Path: %s\n", filepath.Join("apps", input.dockerImagePath, "Dockerfile"))

    // Create Docker build args
    buildArgs := &docker.DockerBuildArgs{
        Context:    pulumi.String(projectRoot),
        Dockerfile: pulumi.String(filepath.Join("apps", input.dockerImagePath, "Dockerfile")),
        ExtraOptions: pulumi.StringArray{
            pulumi.String("--platform=linux/amd64"),
        },
        Target: pulumi.String("production"),
    }

    image, err := docker.NewImage(input.ctx, input.dockerImageName, &docker.ImageArgs{
        Build:     buildArgs,
        ImageName: pulumi.String(input.dockerImageName),
    }, pulumi.DependsOn(dependingSources), pulumi.Provider(input.provider))

    if err != nil {
        return nil, err
    }

    return image, nil
}

代码调用与常量定义

调用方式

remixDockerImage, remixDockerImageErr := buildAndPushToArtifactRegistry(&buildAndPushToArtifactRegistryInput{
    ctx:                  input.Ctx,
    artifactRegistryRepo: remixRepository,
    dockerImageName:      input.Constants.RemixAppDockerImageName,
    dockerImagePath:      input.Constants.RemixAppDockerImagePath,
    dockerfileName:       input.Constants.RemixAppDockerfileName,
    provider:             input.Provider,
})

if remixDockerImageErr != nil {
    return BuildAndPushDockerImagesOutput{}, remixDockerImageErr
}

temporalDockerImage_, temporalWorkerDockerImageErr := buildAndPushToArtifactRegistry(&buildAndPushToArtifactRegistryInput{
    ctx:                  input.Ctx,
    artifactRegistryRepo: temporalWorkerRepository,
    dockerImageName:      input.Constants.TemporalDockerImageName,
    dockerImagePath:      input.Constants.TemporalDockerImagePath,
    dockerfileName:       input.Constants.TemporalDockerfileName,
    provider:             input.Provider,
})

常量定义

var remixDockerfileLocation = "apps/remix-app-vite"
var temporalDockerfileLocation = "apps/temporal-worker"
func GetConstants(pulumiContext *pulumi.Context) *Constants {
    stackName := pulumiContext.Stack()
    
    return &Constants{
        // Others omitted 
        RemixAppDockerImageName:    fmt.Sprintf("remix-app-%s", stackName),
        RemixAppDockerImagePath:    "remix-app-vite",
        RemixAppDockerfileName:     "Dockerfile",
        RemixAppDockerfileLocation: remixDockerfileLocation,
        TemporalDockerImageName:    fmt.Sprintf("temporal-worker-%s", stackName),
        TemporalDockerImagePath:    "temporal-worker",
        TemporalDockerfileName:     "Dockerfile",
    
    }
}

调试输出路径信息

// For First app
Working Directory: /Users/joseasilis/Documents/programming/alertdown/libs/infrastructure/src/pulumi
Project Root: /Users/joseasilis/Documents/programming/alertdown
Dockerfile Path: apps/remix-app-vite/Dockerfile
Working Directory: /Users/joseasilis/Documents/programming/alertdown/libs/infrastructure/src/pulumi
Project Root: /Users/joseasilis/Documents/programming/alertdown
Dockerfile Path: apps/temporal-worker/Dockerfile

已尝试的解决方法

  • 将Dockerfile重命名为Dockerfile.remix和Dockerfile.temporal,并传入对应名称,问题未解决
  • 将应用目录作为上下文路径(不指定Dockerfile),虽然能找到Dockerfile,但因需要整个monorepo作为上下文导致镜像构建失败

可行解决方案建议

1. 提前验证Dockerfile是否存在

在构建参数前加入文件存在性检查,确认路径计算正确:

// 在计算projectRoot后添加
dockerfileFullPath := filepath.Join(projectRoot, "apps", input.dockerImagePath, input.dockerfileName)
if _, err := os.Stat(dockerfileFullPath); err != nil {
    return nil, fmt.Errorf("Dockerfile not found at %s: %w", dockerfileFullPath, err)
}

如果这里报错,说明路径计算有误,需要重新调整projectRoot的计算逻辑。

2. 使用绝对路径指定Dockerfile

尝试直接传入Dockerfile的绝对路径给DockerBuildArgs,避免相对路径的解析问题:

dockerfileAbsPath := filepath.Join(projectRoot, "apps", input.dockerImagePath, input.dockerfileName)
buildArgs := &docker.DockerBuildArgs{
    Context:    pulumi.String(projectRoot),
    Dockerfile: pulumi.String(dockerfileAbsPath),
    ExtraOptions: pulumi.StringArray{
        pulumi.String("--platform=linux/amd64"),
    },
    Target: pulumi.String("production"),
}

3. 检查.dockerignore配置

确认项目根目录的.dockerignore文件没有排除apps目录,如果存在类似apps/的规则,会导致Docker在上下文加载时跳过该目录,引发找不到文件的错误。

4. 显式指定相对路径前缀

在Dockerfile路径前添加./,明确是相对于Context的相对路径:

Dockerfile: pulumi.String(filepath.Join("./apps", input.dockerImagePath, "Dockerfile")),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:55:04