构建/部署docker镜像的最佳实践

时间:2016-05-26 20:59:44

标签: angularjs jenkins docker rancher container-image

我刚刚完成了我的角度应用程序的基本管道,它在docker中的Node图像中运行。因此,该过程如下工作:推送到Gitlab> Hook to Jenkins Build>部署脚本到docker build图片并推送到Quay>发布脚本以提示Rancher服务升级容器并刷新图像>完整。

现在,我遇到的问题是基本节点图像非常大,这意味着当我推动一个简单的更改时,需要很长时间才能完成构建管道(约8分钟)。对于每一个微小的变化来说这似乎都是不合理的,对Quay的推动以及随后向Rancher平台的发布意味着我要向码头移动250mb,向Rancher移动250mb。

我有几个"微服务"计划部署,但如果每次我想将一个部署到开发环境并每次移动那么多的数据,它似乎有点反效果......我做错了什么,我错过了什么,是否有任何构建/部署/托管基于容器的服务时的最佳实践指南?

1 个答案:

答案 0 :(得分:5)

首先介绍图像,构建,注册表和客户端的信息。

图像和图层

Docker图像构建与图层一起使用。 Dockerfile中的每个步骤都会提交一个覆盖在前一个上面的图层。

FROM node                   ---- a6b9ffdcf522
RUN apt-get update -y        --- 72886b467bd2
RUN git clone whatever        -- 430615b3487a
RUN npm install                - 4f8ddac8d3b5 mynode:latest

构成图像的每个图层都由sha256校验和单独标识。 IMAGE ID中的docker images -a是一个简短的片段。

在构建主机上运行dockviz images -t可以让您更好地了解可以构建的图层树。在构建正在运行时,您可以看到分支增长,然后最终层最终被标记,但该层保留在树中并保持与其父级的链接。

构建缓存

默认情况下,每个构建步骤都会缓存Docker构建。如果泊坞窗文件中的RUN命令没有更改,或者您正在复制的COPY源文件未被更改,那么该构建步骤不需要再次运行。该层保持不变,sha256校验和ID和docker尝试构建下一层。

当docker到达需要重建的步骤时,图像"树" dockviz present将分支以创建具有新校验和的新图层。之后的任何步骤都需要再次运行并在新分支上创建一个图层。

注册管理

注册管理机构也了解这种分层。如果您只更改新标记图像中的最顶层,那么这是唯一需要上传到注册表的层(There are caveats to this, it works best with a recent docker-1.10.1+ and registry 2.3+)注册表已经拥有大部分图像的副本构成你的新图像"并且只需要发送新图层。

客户

Docker注册表客户端以相同的方式处理图层。拉动图像时,它实际上会下载构成图像的各个图层(blob)。您可以在docker pulldocker run新图片时打印的图片ID列表中看到此信息。同样,如果大多数图层都相同,那么更新只需要下载已更改的最顶层,节省宝贵的时间。

最小化构建时间

所以你想要关注的事情是

  • 保持图片尺寸小
  • 利用构建缓存
  • 利用常见的"标记"父母的形象。

保持图像尺寸小

节省时间的主要方法是首先没有任何事情要做。 图像中的数据越少越好。

如果您可以避免使用完整的操作系统,请执行此操作。当您可以在busyboxalpine图片上运行应用时,它会让Docker众神微笑。 alpine + node.js build小于50MB。 Go二进制文件也是最小化大小的一个很好的例子。它们可以静态编译,并且没有依赖关系,因此甚至可以在空白scratch图像上运行。

利用Dockers构建缓存

将最常更改的文物(很可能是您的代码)作为Dockerfile中的后期条目,这一点非常重要。如果构建必须为一个小文件更改更新完整的50MB数据,那么构建将变慢,这会使构建步骤的缓存无效。

总会有一些更改使整个缓存失效(例如更新基础node图像)。这些你只需要偶尔住一下。

不经常更新的构建中的任何其他内容都应该转到Dockerfile的顶部。

利用常见的"标记"父图像

尽管从Docker 1.10开始已经对图像校验和进行了一定程度的修复,但使用公共父图像可以保证从使用FROM的图像开始,您将从相同的共享图像ID开始。

在Docker 1.10之前,图片ID只是一个随机的uuid。如果您在多个主机上运行构建,则可以根据构建它们的主机来使图层无效和替换。即使这些层实际上是同一件事。

当您拥有多个服务且多个Dockerfile大致相同时,常用父图像也会有所帮助。每当您开始在多个Dockerfile中重复构建步骤时,请将这些步骤拉出到公共父图像中,以便在所有服务之间明确共享图层。您基本上已经使用node图片作为基础来获取此功能。

Node.js技巧

如果在代码部署每个构建之后运行npm install并且您有许多依赖项,那么npm install会导致大量重复工作,而实际上每个构建都没有多少变化。在代码更改之前建立node_modules工作流程可能是值得的。然后npm install只需在package.json更新

时运行您
FROM node
WORKDIR /app
COPY package.json /app/package.json
RUN npm install && rm -rf ~/.npm
COPY . /app/
CMD [ "node", "/app/server.js" ]

分阶段构建

如果你依赖带有本机模块的npm包,你有时需要在容器中安装一个完整的构建链来运行npm install。现在,分阶段构建可以轻松地从运行映像中分离构建映像。

FROM node:8 AS build
WORKDIR /build
RUN apt-get update \
 && apt-get install build-essential;
COPY package.json /build/package.json
RUN npm install; \
 && rm -rf ~/.npm;
# Stage 2 app image
FROM node:8-slim
WORKDIR /app
COPY --from=build /build/node_modules /app/node_modules
COPY . /app/ 
CMD [ "node", "/app/server.js" ]

其他事项

确保您的构建主机具有ssd和良好的互联网连接,因为是您必须进行完全重建的时间,因此越快越好。 AWS通常运行良好,因为您提取和推送的软件包和映像也可能托管在AWS上。 AWS还仅为存储成本提供映像注册服务(ECR)。