Docker镜像的构build/部署的最佳实践

我刚刚完成了我的angular度应用程序的基本pipe道,它在泊坞窗中的节点图像中运行。 所以,这个过程如下:push to Gitlab> Hook to Jenkins Build>部署脚本到docker build映像并推送到Quay>发布脚本来提示Rancher服务升级容器并刷新镜像>完成。

现在,我遇到的问题是基节点图像相当大,这意味着当我推动一个简单的更改时,完成构buildpipe道(〜8分钟)需要很长时间。 这对于每一个微小的变化似乎都是不合理的,推到docker,然后发布到牧场主平台意味着我将移动250MB到docker,250MB到Rancher。

我有几个计划部署的“微服务”,但是如果每次我想部署一个到开发环境并在每次移动这么多数据时,似乎有些反作用……我做错了什么,什么是错误的我是否错过了,在构build/部署/托pipe基于容器的服务时,是否有最佳实践指南?

首先关于图像,构build,registry和客户的一些信息。

图像和图层

Docker镜像构build与图层一起工作。 Dockerfile每一步Dockerfile提交一个覆盖在前面的图层。

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

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

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

构buildcaching

在每个构build步骤默认情况下,Docker构build被caching。 如果docker文件中的RUN命令没有改变,或者COPY源文件没有改变,那么这个构build步骤就不需要再次运行。 层保持不变,sha256校验和ID和docker试图构build下一层。

当docker到达一个需要重build的步骤时,dockviz所呈现的图像“树”将分支出来,创build一个新的校验和。 之后的任何步骤都需要再次运行,在新分支上创build一个图层。

登记

注册pipe理机构也了解这种分层。 如果您只更改新标记的图像中最上面的图层,那么这是唯一需要上传到registry的图层( 有一些注意事项,最近使用最新的docker-1.10.1 +和registry 2.3+ )registry已经有了大部分构成新“图像”的图像ID的副本,只有新图层需要发送。

客户端

Dockerregistry客户端以相同的方式处理图层。 当拉图像时,它实际下载组成图像的各个图层。 您可以从docker pulldocker run新图像时打印的图像ID列表中看到此项。 同样,如果大多数图层是相同的,那么更新将只需要下载那些已经改变的最顶层,节省宝贵的时间。

最小化构build时间

所以你想要关注的东西是

  • 保持图像尺寸小
  • 利用构buildcaching
  • 利用常见的“标记”父图像。

保持图像尺寸小

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

如果你可以避免使用完整的操作系统,那就去做吧。 当你可以在busyboxalpine图片上运行应用程序时,它会让Docker的神灵微笑。 高山+节点构build小于50MB。 去二进制文件也是最小化尺寸的一个很好的例子。 它们可以静态编译,并且没有依赖关系,所以甚至可以在blank图像上运行。

利用构buildcaching

把最经常变化的文物(很可能是你的代码)作为Dockerfile的最后一个条目是Dockerfile 。 正如你所提到的,你不想为一个小文件更新50MB的数据。

总是会有一些变化使整个caching失效(比如更新基本node映像)。 这些你只需要忍受。

其他不经常更新的应该到达Dockerfile的顶部。

利用常见的“标记”父图像

尽pipe从Docker 1.10开始,图像校验和已经得到了一些修正,但是使用一个共同的父图像可以保证您将从相同的共享图像ID开始,您可以随时使用该图像。

在Docker 1.10之前,Image ID只是一个随机的uuid。 如果你的版本是在多台主机上运行的,那么这些图层可能全部失效并被取代,具体取决于哪个主机构build它们。 即使这些图层实际上是一样的东西。

当您有多个服务和多个Dockerfile时,常见的父图像也有帮助。 无论何时开始在多个Dockerfile重复构build步骤,将这些步骤拉出到一个共同的父图像中,以便在所有服务之间共享层。 你基本上已经通过使用node图像作为你的基础。

Node.js技巧

如果您在代码部署每个构build之后运行npm install ,并且您拥有大量的依赖关系,则npm install会导致大量重复的工作,而实际上并没有多less改变每个构build。 有一个工作stream可以分开build立你的node_modules并且有一个压缩的artefact来部署是值得的。 然后,只有在更新package.json的依赖项时才需要更新这个artefact,并且可以在代码之前部署,这有助于该层保留caching。

有了这个node_modules artefact还允许你从一个图像运行你的应用程序没有GCC和生成工具安装,可以节省大量的空间。

其他事情

确保你的编译主机具有ssd和一个很好的互联网连接,因为有时你必须做一个完整的重build,所以它越快越好。 AWS通常运行良好,因为您推送的提供商也可能在AWS上。 AWS还提供一个registry服务,仅用于存储成本。