简体   繁体   English

在 Spring Boot Maven 插件创建的 Docker 镜像中安装包

[英]Install package in Docker image created by Spring Boot Maven plugin

My Spring Boot project contains the Spring Boot Maven Plugin which I use for building a Docker image by running mvn spring-boot:build-image .我的 Spring Boot 项目包含 Spring Boot Maven 插件,我使用它通过运行mvn spring-boot:build-image来构建 Docker mvn spring-boot:build-image

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>build-image</goal>
            </goals>
        </execution>
    </executions>
</plugin>

When deploying this image to a Docker stack I need to run a healthcheck using the curl command but unfortunately curl is not installed by the default buildpack.将此映像部署到 Docker 堆栈时,我需要使用curl命令运行运行状况检查,但不幸的是默认 buildpack 未安装curl

Is it possible to further tweak the image building process so that curl gets installed into the iamge?是否可以进一步调整图像构建过程,以便将curl安装到图像中? I couldn't find the necessary information我找不到必要的信息

TLDR; TLDR;

Install curl into the build image with:使用以下命令将curl安装到构建映像中:

docker run --user="root" --entrypoint launcher my-app:0.0.1-SNAPSHOT "apt-get update && apt-get install curl -y"

Crab container id of the stopped container with docker ps -a :使用docker ps -a已停止容器的 Crab 容器 ID:

$ docker ps -a
CONTAINER ID   IMAGE                                  COMMAND                  CREATED          STATUS                       PORTS     NAMES
2ff7db32825f   my-app:0.0.1-SNAPSHOT   "launcher 'apt-get u…"   44 minutes ago   Exited (0) 44 minutes ago              reverent_swanson

Create a new container image based on the one we installed curl into with:根据我们安装curl镜像创建一个新的容器镜像:

docker commit 2ff7db32825f my-app-with-curl

Fire up a new container defining the correct ENTRYPOINT to start Spring Boot app:启动一个定义正确ENTRYPOINT的新容器来启动 Spring Boot 应用程序:

docker run --rm -p 8080:8080 --user="cnb" --entrypoint /cnb/process/web my-app-with-curl

Now curl should be ready inside your container.现在curl应该在你的容器中准备好了。


Details of the solution:解决方案详情:

The reasoning behind Cloud Native Buildpacks (CNBs) & Paketo.io, which are basically abstracted away by the spring-boot-maven-plugin s build-image goal, is to free us from the need to write/maintain our own Dockerfiles . Cloud Native Buildpacks (CNBs) 和 Paketo.io 背后的原因,基本上被spring-boot-maven-pluginbuild-image目标抽象出来,是让我们无需编写/维护我们自己的Dockerfiles So the inversion of this is: It's easy to configure the build process, but it is not easy to change things like installed packages.所以这个倒过来是:配置构建过程很容易,但改变安装包之类的东西并不容易。

The reason is, that those packages are maintained in a so called stack , that manages the used build -time and run -time images.原因是,这些包维护在所谓的堆栈中,它管理使用的buildrun映像。 And if the stack doesn't define a Mixin for your OS-level dependency , then you can't simply add another package.如果堆栈没有为您的操作系统级依赖项定义Mixin ,那么您不能简单地添加另一个包。 It would also not suffice to create your own simple buildpack (I tried this approach). 创建自己的简单 buildpack也是不够的(我尝试过这种方法)。 And creating your own stacks, buildpacks and/or builders would also negate the huge benefits that Cloud Native Buildpacks provide!创建自己的堆栈、构建包和/或构建器也会抵消云原生构建包提供的巨大好处! Amongst other things we would be also forced to keep the images updated ourselves...除其他事项外,我们还将被迫自行更新图像......

But there's another solution.但还有另一种解决方案。 As we don't want to create our own stacks/buildpacks, we can tweak the container image which has been created by CNBs/ spring-boot-maven-plugin .由于我们不想创建自己的堆栈/构建包,我们可以调整由 CNBs/ spring-boot-maven-plugin创建的容器镜像。 Because the official docs show us how to hook into the startup process of the produced containers and run shell scripts for example.因为官方文档向我们展示了如何挂钩生成的容器的启动过程并运行 shell 脚本。 Let's assume our mvn spring-boot:build-image command produced a container image called my-app:0.0.1-SNAPSHOT .假设我们的mvn spring-boot:build-image命令生成了一个名为my-app:0.0.1-SNAPSHOT的容器镜像。

Then first we install curl into the image with:然后首先我们将curl安装到图像中:

docker run --user="root" --entrypoint launcher my-app:0.0.1-SNAPSHOT "apt-get update && apt-get install curl -y"

We need to use --user="root" here in order that the command apt-get update && apt-get install curl -y will run successfully (otherwise we would run into errors like List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied) ).我们需要在这里使用--user="root"以便命令apt-get update && apt-get install curl -y能够成功运行(否则我们会遇到像List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied) )。 This will install curl, but we shouldn't use the resulting container in production.这将安装 curl,但我们不应该在生产中使用生成的容器。 Because our Spring Boot app would run using the root user, which would introduce a variety of security problems.因为我们的 Spring Boot 应用程序将使用 root 用户运行,这会引入各种安全问题。 Also we've overwritten the ENTRYPOINT of our container, so it wouldn't be able to start our app.此外,我们已经覆盖了容器的ENTRYPOINT ,因此它无法启动我们的应用程序。

Therefore we simply start this stopped container with a new command , entrypoint & user!因此,我们只需使用新命令、入口点和用户启动这个停止的容器 Simply crab the container id of the stopped container with docker ps -a :只需使用docker ps -a获取已停止容器的容器 ID:

$ docker ps -a
CONTAINER ID   IMAGE                                  COMMAND                  CREATED          STATUS                       PORTS     NAMES
2ff7db32825f   my-app:0.0.1-SNAPSHOT   "launcher 'apt-get u…"   44 minutes ago   Exited (0) 44 minutes ago              reverent_swanson

And create a new container image based on the one we installed curl into with:并根据我们安装curl镜像创建一个新的容器镜像

docker commit 2ff7db32825f my-app-with-curl

Finally fire up a new container based on this new image, defining the correct ENTRYPOINT to start our Spring Boot app and also using the cnb user again (as defined in the Cloud Native Buildpacks):最后基于这个新镜像启动一个新容器,定义正确的ENTRYPOINT来启动我们的 Spring Boot 应用程序,并再次使用cnb用户(如 Cloud Native Buildpacks 中定义的):

docker run --rm -p 8080:8080 --user="cnb" --entrypoint /cnb/process/web my-app-with-curl

Off topic but relevant :离题但相关

There are ongoing discussions if it is desired to install curl in a production container.如果需要在生产容器中安装 curl,目前正在进行讨论。 See this post for example . 例如,请参阅此帖子

我最终使用了一个安装的卷(例如/utils )和一个静态编译的 curl( https://github.com/moparistthebest/static-curl )和配置的健康检查器,比如

/utils/curl http://localhost:8080/actuator/health

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM