有没有办法将Docker镜像组合成1个容器?

Dav*_*vid 59 docker dockerfile docker-image

我现在有几个Dockerfiles.

一个是Cassandra 3.5,它是 FROM cassandra:3.5

我也有一个用于Kafka的Dockerfile,但是t要复杂得多.它FROM java:openjdk-8-fre运行了很长的命令来安装Kafka和Zookeeper.

最后,我有一个用Scala编写的应用程序,它使用SBT.

对于那个Dockerfile,它是FROM broadinstitute/scala-baseimage我的Java 8,Scala 2.11.7和STB 0.13.9,这是我需要的.

也许,我不明白Docker是如何工作的,但是我的Scala程序将Cassandra和Kafka作为依赖项并用于开发目的,我希望其他人能够简单地克隆我的repo Dockerfile然后能够用Cassandra,Kafka构建它,Scala,Java和SBT都融入其中,以便他们可以编译源代码.我虽然遇到了很多问题.

如何组合这些Dockerfiles?我如何简单地制作出烘焙过的环境?

Moh*_*din 70

您可以使用Docker 1.17中引入的多阶段构建功能

看看这个:

FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  
Run Code Online (Sandbox Code Playgroud)

然后正常构建图像:

docker build -t alexellis2/href-counter:latest
Run Code Online (Sandbox Code Playgroud)

来自:https://docs.docker.com/develop/develop-images/multistage-build/

最终结果是与以前相同的微小生产图像,复杂性显着降低.您不需要创建任何中间图像,也不需要将任何工件提取到本地系统.

它是如何工作的?第二个FROM指令以alpine:最新图像为基础开始一个新的构建阶段.COPY --from = 0行仅将前一阶段的构建工件复制到此新阶段.Go SDK和任何中间工件都被遗忘,而不是保存在最终图像中.

  • 该死的东西对我不起作用。就像第一个“ FROM”被完全忽略了一样。 (3认同)
  • 假设我想合并两个基本映像,这些映像正在运行并且不是由我维护的。例如,如果我要运行具有GPU加速功能的Rust应用,我希望我的图像是nvidia-docker和rustlang / rust:nightly的合并。这些图像又位于其他图像之上。为了使用多层构建来执行此操作,我必须知道并指定要复制到另一个图像的一个图像中的所有文件-似乎是不可能的,尤其是当上游图像更改时,该集可能会更改。我读对了吗? (2认同)
  • @masonk我已经成功完成了:`FROM a / a:latest FROM b / b:latest COPY --from = 0 / /`可能很糟糕的做法,但是确实有效。这主要是出于我自己的好奇心,而不是我在生产中使用的东西。 (2认同)
  • 同样在这里:我想做`FROM image1; CMD image1命令;来自图像2;CMD image2command;`根本不起作用。始终只是第二个命令 (2认同)
  • @LuizFelipe,不,为什么要这么做呢?这减少了代码重复。 (2认同)

Hin*_*han 21

由于可能发生冲突,您无法组合dockerfiles.您要做的是创建一个新的dockerfile或构建一个自定义图像.

TL; DR; 如果您当前的开发容器包含您需要和工作的所有工具,则将其保存为图像并将其保存到存储库并创建一个dockerfile以从该存储库中提取该图像.

细节:构建自定义图像比使用公共图像创建dockerfile要容易得多,因为您可以将任何hacks和mod存储到图像中.为此,启动一个带有基本Linux映像(或broadinstitute/scala-baseimage)的空容器,安装所需的任何工具并配置它们直到一切正常,然后将其(容器)保存为图像.在此图像上创建一个新容器,然后测试是否可以通过docker-compose在其上构建代码(或者您想要构建/构建它).如果它有效,那么你可以将工作基础图像上传到一个仓库,以便其他人可以将其拉出来.

要使用公共映像构建dockerfile,您需要在dockerfile本身上放置所有hack,mods和setup.也就是说,您需要将您使用的每个命令行放入文本文件中,并将任何hacks,mods和setup设置为命令行.最后,您的dockerfile将自动创建一个图像,您不需要将此图像存储到仓库中,您只需要为其他人提供dockerfile,他们就可以在自己的docker上旋转图像.

请注意,一旦你有一个工作的dockerfile,你可以轻松地调整它,因为它会在你每次使用dockerfile时创建一个新的图像.使用自定义映像时,您可能会遇到因冲突而需要重建映像的问题.例如,您的所有工具都可以使用openjdk,直到您安装一个不起作用的工具.修复程序可能涉及卸载openjdk并使用oracle one,但是您为所有已安装的工具所做的所有配置都已破坏.

  • 自从引入多阶段构建以来,这个答案已经过时了。 (7认同)

РАВ*_*АВИ 12

以下答案适用于 docker 1.7 及更高版本:

我更愿意使用--from=NAMEfrom image as NAME 为什么?您可以使用--from=0及以上,但是当您在 dockerfile 中有许多 docker 阶段时,这可能会变得很难管理。

示例:

FROM golang:1.7.3 as backend
WORKDIR /backend
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN  #install some stuff, compile assets....

FROM golang:1.7.3 as assets
WORKDIR /assets
RUN ./getassets.sh

FROM nodejs:latest as frontend 
RUN npm install
WORKDIR /assets
COPY --from=assets /asets .
CMD ["./app"] 

FROM alpine:latest as mergedassets
WORKDIR /root/
COPY --from=merge ./
COPY --from=backend ./backend .
CMD ["./app"]
Run Code Online (Sandbox Code Playgroud)

注意:正确管理 dockerfile 将有助于更快地构建 docker 镜像。在内部 docker 使用 docker 层缓存来帮助完成这个过程,以防必须重建图像。


Elt*_*man 8

是的,您可以将大量软件整合到一个 Docker 映像中(GitLab这样做,一个映像包含 Postgres 和其他所有内容),但是generalhenry是对的 - 这不是使用 Docker 的典型方式。

正如您所说,Cassandra 和 Kafka 是您的 Scala 应用程序的依赖项,它们不是应用程序的一部分,因此它们并不都属于同一个映像。

必须使用 Docker Compose 编排许多容器会增加一个额外的管理层,但它为您提供了更大的灵活性:

  • 你的容器可以有不同的生命周期,所以当你有一个新版本的应用程序要部署时,你只需要运行一个新的应用程序容器,你就可以让依赖项保持运行;
  • 您可以在任何环境中使用相同的应用程序映像,为您的依赖项使用不同的配置——例如,在开发中,您可以运行一个基本的 Kafka 容器,而在生产中,将它聚集在许多节点上,您的应用程序容器是相同的;
  • 您的依赖项也可以被其他应用程序使用 - 因此多个消费者可以在不同的容器中运行,并且都可以使用相同的 Kafka 和 Cassandra 容器;
  • 加上已经提到的所有可扩展性、日志记录等。


Tob*_*ist 6

您什么时候可能想要“合并”Docker 镜像?

正如其他人在这里指出的那样,您通常不希望将数据库和应用程序放入同一个 Docker 映像中。理想情况下,您希望 Docker 映像包装“单个进程”/“运行时”。这允许每个进程单独放大/缩小和重新启动。

假设您想要使用一些共享的 C 库/可执行文件,这些库/可执行文件在您正在使用的映像的包管理器中不可用,但其他人已经创建了一个预编译的映像- 您可能不想将这些二进制文件重新编译为构建的一部分(取决于这需要多长时间)。有没有办法根据现有镜像快速创建包含所有这些可执行文件/库的 POC-Docker 镜像?

Docker 和组合

相关讨论: https: //github.com/moby/moby/issues/3378

Docker 缺少的是一种好的构建镜像的方式。您可以使用 .txt 文件将其他映像中的单个文件或整个文件系统复制到您自己的映像中COPY --from=<image> <from-path> <to-path>。没有内置方法可以将环境变量从另一个映像复制到您自己的映像中。

也就是说,我亲自为 Dockerfiles 创建了一个自定义前端/解析器,添加了INCLUDE <image>- 关键字。这会将整个文件系统以及环境变量复制到您的映像中:

DOCKER_BUILDKIT=1 docker build -t myimage .
Run Code Online (Sandbox Code Playgroud)
#syntax=bergkvist/includeimage
FROM alpine:3.12.0
INCLUDE rust:1.44-alpine3.12
INCLUDE python:3.8.3-alpine3.12
Run Code Online (Sandbox Code Playgroud)

nixpkgs.docker工具

如果您想要真正可组合的 Docker 构建,我建议您查看nixpkgs中的dockerTools。这也将产生更具可重复性(通常非常小)的图像。请参阅https://nix.dev/tutorials/building-and-running-docker-images

#syntax=bergkvist/includeimage
FROM alpine:3.12.0
INCLUDE rust:1.44-alpine3.12
INCLUDE python:3.8.3-alpine3.12
Run Code Online (Sandbox Code Playgroud)
docker load < $(nix-build docker-image.nix)
Run Code Online (Sandbox Code Playgroud)