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

时间:2016-09-21 21:04:34

标签: 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作为依赖项并用于开发目的,我希望其他人能够使用Dockerfile简单地克隆我的repo然后是能够用Cassandra,Kafka,Scala,Java和SBT构建它们,所有这些都可以编译源代码。我虽然遇到了很多问题。

如何组合这些Dockerfiles?我如何简单地制作一个带有烘焙内容的环境?

8 个答案:

答案 0 :(得分:41)

您可以使用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"]  

然后正常构建图像:

docker build -t alexellis2/href-counter:latest

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

  

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

     

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

答案 1 :(得分:19)

由于可能发生冲突,您无法组合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,但是你为所有已安装的工具所做的所有配置都破坏了。

答案 2 :(得分:4)

是的,你可以将大量软件整合到一个Docker镜像中(GitLab执行此操作,其中一个图像包含Postgres和其他所有内容),但是{{3} }是对的 - 这不是使用Docker的典型方式。

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

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

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

答案 3 :(得分:1)

Docker不会对图像进行合并,但是如果可用的话,没有什么能阻止你将dockerfiles组合在一起,并将它们转换成你需要构建的胖图像。然而,有时这是有道理的,因为在容器中运行多个进程,大多数Docker教条都会指出这一点,特别是对于微服务架构而言,这是不太理想的(但是规则是否会被破坏?)

答案 4 :(得分:1)

您无法将泊坞窗图像合并到1个容器中。请参阅Moby问题中的详细讨论How do I combine several images into one via Dockerfile

对于您的情况,最好不要包含整个Cassandra和Kafka图像。该应用程序只需要Cassandra Scala驱动程序和Kafka Scala驱动程序。容器应仅包含驱动程序。

答案 5 :(得分:1)

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

我更愿意使用import { Button } from 'react-bootstrap/Button' --from=NAME 为什么? 您可以使用from image as NAME及更高版本,但是当dockerfile中有许多Docker阶段时,这可能很难管理。

示例示例:

--from=0

注意:正确管理dockerfile将有助于更快地构建docker映像。如果必须重建映像,则在内部docker使用docker层缓存来帮助完成此过程。

答案 6 :(得分:1)

我需要Gitlab CI的docker:latest和python:latest图像。这是我想出的:

FROM ubuntu:latest
RUN apt update
RUN apt install -y sudo
RUN sudo apt install -y docker.io
RUN sudo apt install -y python3-pip
RUN sudo apt install -y python3
RUN docker --version
RUN pip3 --version
RUN python3 --version

在构建并将其推送到我的Docker Hub存储库后:

docker build -t docker-hub-repo/image-name:latest path/to/Dockerfile
docker push docker-hub-repo/image-name:latest

在推送之前不要忘记docker login

希望有帮助

答案 7 :(得分:0)

您什么时候想“组合”Docker 镜像?

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

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

Docker 和组合

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

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

也就是说,我个人创建了一个添加 INCLUDE <image> 关键字的 custom frontend/parser for Dockerfiles。这会将整个文件系统以及环境变量复制到您的映像中:

DOCKER_BUILDKIT=1 docker build -t myimage .
#syntax=bergkvist/includeimage
FROM alpine:3.12.0
INCLUDE rust:1.44-alpine3.12
INCLUDE python:3.8.3-alpine3.12

nixpkgs.dockerTools

如果您想要真正可组合的 Docker 构建,我建议您查看 dockerTools 中的 nixpkgs。这也将导致更多 reproducible(通常非常小)图像。见https://nix.dev/tutorials/building-and-running-docker-images

docker load < $(nix-build docker-image.nix)
# docker-image.nix
let
  pkgs = import <nixpkgs> {};
  python = pkgs.python38;
  rustc = pkgs.rustc;
in pkgs.dockerTools.buildImage {
  name = "myimage";
  tag = "latest";
  contents = [ python rustc ];
}