[spring-projects/spring-boot]允许配置 docker 镜像创建时间戳

2024-05-14 330 views
6

正如https://github.com/spring-projects/spring-boot/issues/20126#issuecomment-625323684中提到的,我正在创建一个增强请求。

出于充分的原因(据我所知,再现性),由例如 maven 插件创建的 docker 映像将其创建时间戳设置为固定时间点(1970-01-01?)。使用相同方法的其他工具有一种自定义方法,例如使用 jib,您可以将creationTime 设置为USE_CURRENT_TIMESTAMP。我希望 Spring Boot 中也有这个功能。我不知道构建包是否已经支持这一点 - 那么这可能只是通过 Maven 插件呈现的问题 - 或者是否也需要在那里实现该功能。

我的用例是我们的 docker 注册表 (Gitlab) 具有过期策略功能,该功能使用时间戳来删除旧图像。该功能目前对我们来说无法使用。

回答

6

有一个Cloud Native Buildpacks RFC提出了生命周期支持,以任何平台(例如 CLI 和 Spring Boot 构建插件)都可以使用的方式自定义图像元数据中的日期pack,但 RFC 已被关闭且未采取任何行动。

如果不支持在 CNB 生命周期中设置当前时间戳,Spring Boot 插件应该能够设置createDate生成图像的时间戳,但可能无法控制图像中所有层的时间戳。我不知道这对于那些不关心构建再现性并愿意放弃这一点以获得createDate图像最新信息的用户来说有多重要。

0

除了允许配置使用当前日期/时间之外,此增强功能还允许用户提供自己的固定日期/时间作为默认纪元createDate( 1980-01-01T00:00:01Z) 的替代。将此标记为pending-design-work以便我们可以在实施之前进一步讨论。

7

指定一个替代方案将非常有用,因为我们可以使用 git 时间戳来进行可重现的构建。

据我所知,pack 已经支持此功能:--creation-time string Desired create time in the output image config. Accepted values are Unix timestamps (e.g., '1641013200'), or 'now'. Platform API version must be at least 0.9 to use this feature.

4

指定一个替代方案将非常有用,因为我们可以使用 git 时间戳来进行可重现的构建。

据我所知,pack 已经支持此功能:--creation-time string Desired create time in the output image config. Accepted values are Unix timestamps (e.g., '1641013200'), or 'now'. Platform API version must be at least 0.9 to use this feature.

@scottfrederick Spring Boot 会跟进吗?

5

这个问题现在变得更加重要,因为许多人将使用 bootBuildImage 来使用构建包构建本机映像。

1

@quaff @plebcity 这个问题仍然悬而未决,并标记为未来版本的增强功能。与我们一直在做的其他事情相比,这并不是一个高度优先的事情。我们可以查看pack --create-time实施情况并重新确定优先级。

1

谢谢,@plebcity。不幸的是,我们尚未准备好接受有关此问题的贡献。该status: pending-design-work标签表明我们需要在编写实现之前进行一些设计工作。

2

我完全同意@plebcity。这个问题让我完全抓狂,因为我的图像已经过时,并且在清理过程中被存储库删除。由于这个功能会带来很多问题,我们可以将其推高吗?

3

@wilkinsona @scottfrederick 为什么 Spring Boot 对社区贡献如此敌视?是关于确切的实现还是功能本身,例如在哪里配置以及如何调用?

当然,您可以批评 #34511 缺少“旧默认值”和配置,但这至少是解决此问题的第一步。添加配置已经会产生“现在”和“1980”的解决方案。但在没有任何讨论的情况下关闭 PR 并不是很受欢迎。添加https://github.com/spring-projects/spring-boot/issues/28798#issuecomment-978123191中提出的确切日期可能是该 PR 或另一个 PR 中的下一步。

3

我完全同意@plebcity。这个问题让我完全抓狂,因为我的图像已经过时,并且在清理过程中被存储库删除。由于这个功能会带来很多问题,我们可以将其推高吗?

这也正是我们面临的问题。 Gitlab 默认删除最旧的镜像。

3

我认为对每个 Docker 镜像始终使用相同的时间戳是非常违反直觉的,因为默认情况下它不是这样docker build工作的。正因为如此,并且由于这种默认行为导致过期策略的问题,恕我直言,具有固定的创建时间戳应该是一个可选功能,而不是一个可选功能。

0

@vgropp 抱歉,我的行为似乎对社区贡献怀有敌意。我们确实欢迎贡献,正如我们从 100 多个不同贡献者合并的 1000 多个 PR 中所希望的那样。不幸的是,我们不能接受一切,当我们拒绝提案时,我们会尽力通过解释原因来尊重潜在贡献者的时间。

除了标记对贡献者特别有利的问题之外,ideal-for-contribution我们还尝试通过标记我们知道尚无法解决的问题来帮助潜在的贡献者pending-design-work。本问题属于后者。

34511 无法合并,因为对于那些依赖当前行为的人来说,这将是一个重大更改。它还会让我们与我们试图匹配的包的默认行为不一致。我们尝试将其匹配,以便人们能够尽可能顺利地从一种转移到另一种。不幸的是,这意味着如果我们接受了 PR,那么在发布下一个里程碑之前,我们将不得不做额外的工作来解决这两个问题。不幸的是,我们目前有太多优先级更高的工作项目,无法做出时间承诺。

展望未来,我们非常确定我们需要一个配置选项,但我们还不知道我们想要它是什么以及它将如何在 Maven 和 Gradle 插件中公开。一旦我们有时间完成设计工作,我们就会知道需要完成哪些工作以及在哪里完成。我们将非常乐意接受该领域的贡献。

9

@vgropp 抱歉,我的行为似乎对社区贡献怀有敌意。我们确实欢迎贡献,正如我们从 100 多个不同贡献者合并的 1000 多个 PR 中所希望的那样。不幸的是,我们不能接受一切,当我们拒绝提案时,我们会尽力通过解释原因来尊重潜在贡献者的时间。

除了标记对贡献者特别有利的问题之外,ideal-for-contribution我们还尝试通过标记我们知道尚无法解决的问题来帮助潜在的贡献者pending-design-work。本问题属于后者。

34511 无法合并,因为对于那些依赖当前行为的人来说,这将是一个重大更改。它还会让我们与我们试图匹配的包的默认行为不一致。我们尝试将其匹配,以便人们能够尽可能顺利地从一种转移到另一种。不幸的是,这意味着如果我们接受了 PR,那么在发布下一个里程碑之前,我们将不得不做额外的工作来解决这两个问题。不幸的是,我们目前有太多优先级更高的工作项目,无法做出时间承诺。

展望未来,我们非常确定我们需要一个配置选项,但我们还不知道我们想要它是什么以及它将如何在 Maven 和 Gradle 插件中公开。一旦我们有时间完成设计工作,我们就会知道需要完成哪些工作以及在哪里完成。我们将非常乐意接受该领域的贡献。

在解决此问题之前,我们无法使用 bootBuildImage 步骤,因为图像不断从注册表中删除。最好的解决方法是什么?使用构建器创建我们自己的 DockerFile 并运行映像,或者创建一个将 bootBuildImage 输出作为基础映像的 DockerFile?还有另一种方法可以获取具有正确创建日期的图像吗?

5

@plebcity 目前,您可以替换./gradlew bootBuildImagepack build --builder paketobuildpacks/builder:base使用--creation-time参数(请参阅pack文档)来指定您所需的创建时间。中可用的可选参数bootBuildImage可以类似地传递给pack

Cloud Native Buildpacks 的主要功能之一是可重复性,这就是为什么创建时间戳默认设置为常规日期,以便在输入不变的情况下始终获得相同的结果。

对于以可重现方式构建的映像,通常根据“上次使用时间”而不是“创建时间”在容器注册表上定义过期策略。例如,如果图像超过 6 个月没有使用,则可以删除该图像,而不是因为它自创建以来已经 6 个月了。

我希望这有帮助。

0

如果 bootBuildImage 默认使用根项目目录中最近修改的文件的最后修改时间作为创建时间,用户可以通过自定义 bootBuildImage 任务传递自己的创建时间(例如最新的 git 提交日期)来覆盖它。

9

@plebcity,@ThomasVitale 的建议正是我的建议。谢谢,托马斯。

5

如果 bootBuildImage 默认使用根项目目录中最近修改的文件的最后修改时间作为创建时间,那就有希望了

@quaff 我们更喜欢将我们的默认行为与包 CLI 的行为保持一致。

4

对于任何寻找解决方法的人,我们添加了一个 Dockerfile,其中包含 bootBuildImage 的输出映像作为基本映像(在 FROM 中)。然后我们向图像添加标签以创建新图层。在将图像发布到注册表之前,我们首先构建它(添加新层)。 bootBuildImage 的输出仍然是可重现的,就像 Spring 团队想要的那样,当我们想要发布我们的图像时,我们会添加一个新层,该层添加了正确的创建日期。

7

目前,在我们找到一个好的解决方案之前,我会回到旧的 dockerfile,它应该可以很好地工作。

0

如果 bootBuildImage 默认使用根项目目录中最近修改的文件的最后修改时间作为创建时间,那就有希望了

@quaff 我们更喜欢将我们的默认行为与包 CLI 的行为保持一致。

pack 的实现似乎是一个解决方法,因为他们无法弄清楚如何使其可以使用“现在”创建日期来重现。为什么有人会期望准备发布的“最终”图像具有 Windows 纪元的创建日期?我对具有 Windows 纪元的中间/测试图像感到满意,但不接受要发布到存储库的最终图像。

所以我认为默认行为应该是每个人都期望发生的,所以如果我们将其与任何其他构建工具进行比较,我们将得到“现在”作为默认值,而不是 Windows 纪元。可复制图像的唯一好处是能够在其他人的机器上使用相同的 id 构建完全相同的图像,这似乎是大多数人不会感兴趣的边缘情况。

您可以在这里阅读 pack 选择 windows epoch 的原因:https://medium.com/buildpacks/time-travel-with-pack-e0efd8bf05db

因此,将“现在”设置为默认值,并将 Windows 纪元设置为可配置。

0

@plebcity 目前,您可以替换./gradlew bootBuildImagepack build --builder paketobuildpacks/builder:base使用--creation-time参数(请参阅pack文档)来指定您所需的创建时间。中可用的可选参数bootBuildImage可以类似地传递给pack

Cloud Native Buildpacks 的主要功能之一是可重复性,这就是为什么创建时间戳默认设置为常规日期,以便在输入不变的情况下始终获得相同的结果。

我很欣赏这个解决方法的建议,但恕我直言,必须在本地环境和/或 CI/CD 代理中单独安装 pack-cli,这增加了一层复杂性,而使用 Gradle 和 Spring Boot 应该可以保护大多数开发人员免受这种复杂性的影响。

100% 同意上面的@plebcity,即构建图像时的默认行为应使用当前时间戳进行标记,因为这是合乎逻辑且符合预期的。 “再现性”目标在某种程度上是可以理解的,但实际上并不值得争论;应该公开一个简单的机制来覆盖created用于测试可重复纯度的标签,然后在构建实际部署到图像存储库时分配正确/逻辑值。


这可能值得它自己的票,但在调查这个问题时我发现这个插件似乎不允许LABEL在结果图像上公开任何自定义,这令人费解。一般来说,这样做至少允许用户根据需要进行设置,例如

tasks.getByName<BootBuildImage>("bootBuildImage") {
  labels = mapOf(
        "created" to SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(Date())
    )
}
5

Created我们添加了将图像元数据字段设置为用户选择的日期和时间或当前日期和时间的功能。

为了保持依赖当前行为的用户的向后兼容性,默认情况下仍将使用纪元日期来启用再现性。这还保持了与CNB 规范packCLI 和其他 CNB 平台(包括SkaffoldJib等其他工具)的默认行为的兼容性。

4

该插件似乎不允许在生成的图像上公开任何自定义标签,这令人费解。一般来说,这样做至少允许用户根据需要进行设置

@snagielCreated从技术上讲,该字段不是一个标签,可以使用Dockerfile 中的LABEL指令docker inspect image-name --format='{{json .Config.Labels}}'进行设置并使用 进行查看。它是图像元数据,由 CNB buildpack 控制。

如果您使用的是 Paketo buidpacks,则可以通过在 Spring Boot 构建插件中设置环境变量(为图像标签配置 Paketo Buildpack)来在生成的图像上设置真实标签。