Docker的组合优于继承 - frankel

19-11-19 banq
              

Docker和容器化技术仅存在了一段时间。要了解如何充分利用自己的情况,可能需要花费一些时间以及一些反复试验。这篇文章介绍了许多可用选项之一。

Docker容器的主要优点是它们是独立的。对于开发人员来说,这意味着只需要从包含所需必需依赖项的所需Docker镜像继承即可,并且可以构建自己的应用程序将其交付生产。在大多数情况下,该过程非常简单。容器化允许前所未有的规模扩展。

但是,这种自包含的缺点是更新父镜像会成为噩梦。该过程如下:

  1. 使用新的父镜像更新Dockerfile
  2. 生成新镜像
  3. 生成的镜像可在Docker注册表中使用
  4. 最后,将其从生产计算机上的注册表中提取出来,然后启动

虽然偶尔为单个映像接受可能会出现这种情况,但是随着更新频率的增加以及涉及的容器化应用程序数量的增加,这绝对是不可行的。

现在,让我们考虑一下自包含性与灵活性之间的权衡,并放宽约束。与其从镜像继承,不如公开包含所需依赖项的文件夹:与继承完全相同,这是偏爱组成的OOP原理!通过这种设计,只需替换合成的镜像即可更新所需的二进制文件。

作为示例,我将创建一个包含此设计的简单Java应用程序。我假设一个生成可执行JAR的Maven项目。这是相关的Dockerfile:

Docker文件

FROM maven:3.6.0-alpine as build

COPY src src
COPY pom.xml .

RUN mvn package

FROM alpine:3.8

COPY --from=build target/composition-example-1.0-SNAPSHOT.jar .

ENTRYPOINT ["sh", "-c", "/usr/bin/java -jar composition-example-1.0-SNAPSHOT.jar"]

这是一个多阶段构建,首先构建Maven项目,然后运行/usr/bin/java。

请注意,标准Dockerfiles将继承自基本JRE镜像,例如openjdk:8-jre-alpine。在这里,第二阶段从基础alpine镜像继承,因为没有发现可执行文件java,因此,运行构建的Docker镜像将失败:

$ docker build -t compose-this .

$ docker run compose-this

-jar: line 1: java: not found

为了解决这个问题,让我们创建一个在镜像中公开其java可执行文件的Docker镜像:

FROM openjdk:8-jre-alpine

VOLUME /usr/bin
VOLUME /usr/lib

虽然java位于/usr/bin,它只是指向一个符号链接/usr/lib/jvm/default-jvm/jre/bin/java。因此,该/usr/lib文件夹也需要公开。

生成并运行该映像:

docker build -t myjava:8 .

docker run --name java myjava:8

此时,可以将java容器中的卷绑定到运行该compose-this镜像的新容器:

docker run -it --volumes-from java compose-this

现在不仅可以更轻松地更新从属JRE,而且还有一个好处是,与独立镜像相比,应用程序镜像已大大减少:它仅包含JAR。

可能会出现一个问题:在文件系统上使用纯JAR和共享JRE的情况下,此设置与未容器化的设置之间会有什么区别?

允许编排,即 Kubernetes。虽然可以使用配置管理工具(例如 Puppet或Chef)来实现相同的目的,但Kubernetes正在成为事实上的部署平台。