122

我现在有一些 Dockerfile。

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

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

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

对于那个 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 都内置了,因此它们可以只编译源代码。不过,我对此有很多问题。

如何组合这些 Dockerfile?我如何简单地制作一个包含这些东西的环境?

4

8 回答 8

116

您可以使用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:latest 映像为基础开始一个新的构建阶段。COPY --from=0 行仅将构建的工件从前一个阶段复制到这个新阶段。Go SDK 和任何中间工件都被留下,不会保存在最终图像中。

于 2018-01-06T12:55:44.110 回答
26

您不能合并 dockerfile,因为可能会发生冲突。您要做的是创建一个新的 dockerfile 或构建一个自定义映像。

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

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

要使用公共映像构建 dockerfile,您需要将所有 hack、mod 和设置放在 dockerfile 本身上。也就是说,您需要将您使用的每个命令行放入一个文本文件中,并将任何黑客、模组和设置减少到命令行中。最后,您的 dockerfile 将自动创建一个图像,您无需将此图像存储到 repo 中,您所需要做的就是将 dockerfile 提供给其他人,他们可以在自己的 docker 上旋转图像。

请注意,一旦您有了一个工作的 dockerfile,您就可以轻松地对其进行调整,因为每次使用该 dockerfile 时它都会创建一个新图像。使用自定义映像,您可能会遇到由于冲突而需要重建映像的问题。例如,您的所有工具都可以与 openjdk 一起使用,直到您安装了一个不起作用的工具。该修复可能涉及卸载 openjdk 并使用 oracle 之一,但是您为已安装的所有工具所做的所有配置都损坏了。

于 2016-09-21T22:14:37.287 回答
15

以下答案适用于 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=frontend . /
COPY --from=backend ./backend .
CMD ["./app"]

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

于 2019-03-23T01:51:30.557 回答
8

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

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

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

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

Docker 不会合并图像,但没有任何东西可以阻止您组合 dockerfile(如果可用),并将它们滚动到您需要构建的胖图像中。然而,有时这是有道理的,至于在容器中运行多个进程,大多数 Docker 教条会指出这一点不太理想,尤其是在微服务架构中(但是规则会被打破,对吧?)

于 2016-09-22T19:41:47.103 回答
2

您无法将 docker 图像合并到 1 个容器中。请参阅 Moby 问题中的详细讨论,如何通过 Dockerfile 将多个图像合并为一个

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

于 2017-10-13T20:59:04.087 回答
2

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

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

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

Docker 和组合

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

Docker 缺乏的是一种组合图像的好方法。您可以使用COPY --from=<image> <from-path> <to-path>. 没有将环境变量从另一个图像复制到您自己的图像的内置方法。

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

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.docker工具

如果您想要真正可组合的 Docker 构建,我建议您查看nixpkgs中的dockerTools。这也将导致更可重现(通常非常小)的图像。请参阅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 ];
}
于 2021-06-16T16:17:01.203 回答
-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推送前别忘了

希望能帮助到你

于 2020-03-14T21:05:33.467 回答