如果 CloudBuild 失败,则在 Cloud Build 中使用 2 个 Dockerfile 来重用中间步骤映像
Posted
技术标签:
【中文标题】如果 CloudBuild 失败,则在 Cloud Build 中使用 2 个 Dockerfile 来重用中间步骤映像【英文标题】:Using 2 Dockerfiles in Cloud Build to re-use intermediary step image if CloudBuild fails 【发布时间】:2021-10-25 22:15:40 【问题描述】:Cloud Build 因超时错误而失败(我正在尝试使用 Prophet 部署 CloudRun)。因此,我试图将 Dockerfile 一分为二(将图像保存在两者之间,以防万一失败)。我会像这样拆分 Dockerfile:
Dockerfile_one:python + 先知的依赖关系 Dockerfile_two:image_from_Dockerfile_one + 先知 + 其他依赖项cloudbuild.yaml 应该是什么样子:
-
如果有以前可用的映像跳过该步骤,否则使用 Dockerfile_one 运行该步骤并保存映像
使用步骤(1)中的镜像,添加更多依赖并保存镜像以进行部署
这是 cloudbuild.yaml 现在的样子
steps:
# create gcr source directory
- name: 'bash'
args:
- '-c'
- |
echo 'Creating gcr_source directory for $_GCR_NAME'
mkdir _gcr_source
cp -r cloudruns/$_GCR_NAME/. _gcr_source
# Build the container image
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/$_GCR_NAME', '.']
dir: '_gcr_source'
# Push the container image to Container Registry
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/$_GCR_NAME']
# Deploy container image to Cloud Run
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: gcloud
args:
- run
- deploy
- $_GCR_NAME
- --image=gcr.io/$PROJECT_ID/$_GCR_NAME
非常感谢!
【问题讨论】:
一个更好的设计是保持简单。拥有一个构建基础映像的管道,您可以在需要时运行该管道。另一个使用此基础映像并完成其工作的管道。关注点分离总是更好、更简单、更智能。 有道理。我了解如何在第一个管道中保存构建映像。如何从第二个图像中构建? 如果您的构建镜像与此名称相同(例如在容器注册表中)gcr.io/projectid/baseimage
,只需使用相同的镜像FROM gcr.io/projectid/baseimage
启动您的Dockerfile
@guillaumeblaquiere 谢谢!这就是我所需要的。我不知道我可以在 FROM 中指定 gcr.io/* 图像。我设法将构建拆分为两个 Dockerfile。在 Python 3.9 上它无论如何都不起作用。看起来 pystan 不适合 Python3.9。在 python3.8 上,即使使用 1 个 Dockerfile 也一切正常,但归根结底,这是一个很好的学习练习。
@guillaumeblaquiere 请发表您的评论作为答案,我会接受。
【参考方案1】:
不是答案,而是一种解决方法。如果有人有同样的问题,使用 Python3.8 而不是 3.9 对 Cloud Build 有效。
这就是 Dockerfile 的样子:
RUN pip install --upgrade pip wheel setuptools
# Install pystan
RUN pip install Cython>=0.22
RUN pip install numpy>=1.7
RUN pip install pystan==2.19.1.1
# Install other prophet dependencies
RUN pip install -r requirements.txt
RUN pip install prophet
虽然弄清楚如何为 CloudRun 迭代构建图像,但真的很棒。
【讨论】:
【参考方案2】:为什么您的 Cloud Build 会因超时错误而失败?
在 docker 中构建图像时,减小图像大小很重要。通常会创建多个 dockerfile 来处理图像大小限制。在您的情况下,您无法减小图像大小并仅包含所需的内容。
有什么办法可以改正?
根据这个documentation,多阶段构建,(在 Docker 17.05) 允许您在第一次“构建”中构建您的应用程序 容器并在另一个容器中使用结果,同时使用 相同的 Dockerfile。 您在 Dockerfile 中使用了多个 FROM 语句。每个 FROM 指令可以使用不同的基础,并且每个指令都开始一个新的 构建阶段。您可以选择性地从一个阶段复制工件 给另一个人,在决赛中留下你不想要的一切 图片。要展示它是如何工作的,请关注link。 您只需要一个 Dockerfile。 结果是与以前相同的微小生产图像,带有一个 显着降低复杂性。你不需要创建任何 中间图像,您不需要提取任何伪影到 您的本地系统。它是如何工作的?
您可以name your build stages。默认情况下,阶段不是 命名,并通过它们的整数来引用它们,从 0 开始 对于第一个 FROM 指令。但是,您可以通过以下方式命名您的阶段 在 FROM 指令中添加一个 AS。 构建映像时,不一定需要构建 整个 Dockerfile 包括每个阶段。您可以指定target build stage。 使用多阶段构建时,您不仅限于从 您之前在 Dockerfile 中创建的阶段。您可以使用 复制——从指令到copy from a separate image,或者 使用本地镜像名称、本地或 Docker 上可用的标签 注册表或标签 ID。 您可以通过引用pick up where a previous stage离开 使用 FROM 指令时对其进行处理。 Google documentation中有一个dockerfile的例子 它使用多阶段构建。 hello 二进制文件首先内置 容器并注入第二个容器。因为第二个容器 基于scratch,生成的图像只包含你好 二进制文件,而不是过程中所需的源文件和目标文件 构建。这里是 tutorial,用于了解多阶段构建的工作原理。FROM golang:1.10 as builder WORKDIR /tmp/go COPY hello.go ./ RUN CGO_ENABLED=0 go build -a -ldflags '-s' -o hello FROM scratch CMD [ "/hello" ] COPY --from=builder /tmp/go/hello /hello
【讨论】:
【参考方案3】:你需要有 2 个管道
-
第一个创建基本映像。像这样,您可以在每次需要重建此基础映像时触发它,其生命周期可能与您的应用程序生命周期不同。类似的东西
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/<PROJECT_ID>/base-image', '-f', 'DOCKERFILE_ONE', '.']
images: ['gcr.io/<PROJECT_ID>/base-image']
-
然后,在您的第二个 dockerfile 中,从基础映像开始,并使用第二个 Cloud Build 管道来构建、推送和部署它(就像您在问题的最后 3 个步骤中所做的那样)
FROM gcr.io/<PROJECT_ID>/base-image
COPY .....
....
...
【讨论】:
谢谢!我终于设法做到了,构建时间减少了 x5 对于任何来到这里的人来说,使用 pystan 的 CloudBuild Python3.9 似乎并不顺利。看起来 pystan==2.19.1.1 仅在使用 GCB 构建时才能与 Python3.8 一起使用以上是关于如果 CloudBuild 失败,则在 Cloud Build 中使用 2 个 Dockerfile 来重用中间步骤映像的主要内容,如果未能解决你的问题,请参考以下文章
Google Cloud Builder-构建触发器失败,并显示“未找到请求的资源”
GitHub Cloud Build 与 monorepo 中的多个 cloudbuild.yamls 集成
Google Cloud Build 不会替换 cloudbuild.yaml 的机密部分中的值
有没有办法让 cloudbuild 步骤访问 GCP 中的 Cloud SQL