如何快速构建Slim Docker映像

简介:   您还记得那些日子,当您编写出色的软件,但无法将其安装在其他人的计算机上,或刚安装就崩溃? 虽然这从来都不是很好的体验,但我们总是可以说  如今,由于容器化,这已不再是借口。  简而言之,通过容器化,您可以将应用程序和所有必要的依赖项打包到镜像中。 执行时,您将该镜像作为容器运行。 这样一来,您就不必为弄乱他人的系统而运行您的软件。 如果容器在您的计算机上运行,则您的软件应随即运行。 这对于数据科学家在部署依赖于不同软件包和版本的模型时也很有用。 对我来说,数据科学家必须知道如何创建镜像和容器。  众所周知,Docker是该领域的主要参与者,并且Docker镜像无处不在。 这很棒

  您还记得那些日子,当您编写出色的软件,但无法将其安装在其他人的计算机上,或刚安装就崩溃? 虽然这从来都不是很好的体验,但我们总是可以说

  如今,由于容器化,这已不再是借口。

  简而言之,通过容器化,您可以将应用程序和所有必要的依赖项打包到镜像中。 执行时,您将该镜像作为容器运行。 这样一来,您就不必为弄乱他人的系统而运行您的软件。 如果容器在您的计算机上运行,则您的软件应随即运行。 这对于数据科学家在部署依赖于不同软件包和版本的模型时也很有用。 对我来说,数据科学家必须知道如何创建镜像和容器。

  众所周知,Docker是该领域的主要参与者,并且Docker镜像无处不在。 这很棒,因为您可以轻松地并排启动不同版本的数据库。 将您的应用程序镜像合并在一起也非常简单。 这是由于大量的基本镜像和简单的定义语言所致。 但是,当您在不知道自己在做什么的情况下将镜像混合在一起时,就会遇到两个问题。

  · 由于镜像不必要地发胖,您浪费了磁盘空间。· 您等待太长时间的构建会浪费时间。

  在本文中,我想向您展示如何缓解这两个问题。 幸运的是,这仅需要您了解Docker提供的一些技巧和技术。 为了使本教程有趣且有用,我向您展示了如何将Python App打包到Docker映像中。

  你准备好了吗? 让我们继续。

  教程

  假设我们所有的代码都位于一个Python文件main.py中。 因为我们很酷,所以我们使用最新最好的Python版本,在撰写本文时为3.8。 我们的应用程序只是一个简单的Web服务器,它依赖于Pandas,fastapi和uvicorn。 我们将依赖项存储在requirements.txt文件中。 在本地,我们在虚拟环境中开发应用程序。 该环境位于与代码位于同一文件夹中的名为.venv的文件夹中(这很快变得很重要)。 现在,我们决定将所有内容打包到Docker映像中。 为此,我们要做的就是

  · 使用可用于Python 3.8的基本映像。· 复制代码和需求文件。· 在映像中安装需求和依赖项。· 公开运行我们的应用程序的命令

  我们的Docker映像的第一个版本看起来像

  FROM python:3.8.0-slim

  COPY . /app

  RUN apt-get update \

  && apt-get install gcc -y \

  && apt-get clean

  WORKDIR app

  RUN pip install --user -r requirements.txt

  ENTRYPOINT uvicorn main:app --reload --host 0.0.0.0 --port 8080

  除了我们的代码和要求之外,我们还需要安装GCC,因为FastApi在安装时需要这样做。 我们通过以下方式建立我们的形象

  docker build -t my-app:v1 .

  该映像的大小约为683 MB,需要大约一分钟的时间来构建(不下载基础映像)。 让我们看看这种情况如何减少时间。

  基本镜像

  关于基本镜像,我已经使用Python slim做出了明智的选择。 我为什么要选择那个呢?

  例如,我可以使用完整的Ubuntu或CentOS映像,这将导致映像大小> 1GB。 但是,由于我只需要Python,因此无需安装所有组件。

  在图像大小的低端,我们可以使用python:3.8.0-alpine。 但是,我的代码依赖于Pandas,这在高山上安装很麻烦。 高山也有关于稳定性和安全性的问题。 此外,slim仅比alpine大80MB,这还是可以的。 有关如何选择最佳Python图像的更多信息,请向有兴趣的读者介绍该文章。

  构建上下文

  构建镜像时,打印到控制台的第一行显示:将构建上下文发送到Docker守护程序。 在我的计算机上,这花费了大约5秒钟,并且发送了154 MB。 这是怎么回事 Docker将构建上下文中的所有文件和文件夹复制到守护程序。 在这里,构建上下文是存储Dockerfile的目录。由于我们只需要两个文本文件,所以154 MB听起来很多,不是吗? 这样做的原因是Docker复制了所有内容,例如包含虚拟环境的.venv文件夹或.git文件夹。

  要解决此问题,您只需在Dockerfile旁边添加一个名为.dockerignore的文件。 在此文件中,逐行列出了Docker不应该复制的内容。 就像git对.gitignore文件所做的一样。 举一个小例子,假设我们的文件夹中有几个Excel文件和PNG,我们不想复制它们。 .dockerignore文件看起来像

  *.xlsx

  *.png

  venv

  .venv

  .git

  在我们的示例中,添加此文件后,"将构建上下文发送到docker"仅花费几毫秒,并且仅发送了7.2 kb。 我将映像大小从683 Mb减小到了529 Mb,这大约是以前构建上下文的大小。 真好! 添加.dockerignore文件有助于加快构建速度并减小图像大小。

  层缓存

  如前所述,在我的计算机上构建此映像大约需要60秒钟。 我估计大多数时候,大约有99.98%的时间用于安装需求和依赖项。 您可能会认为现在这里没有太多的改进空间。 但是有些时候您必须经常构建映像! 为什么? Docker可以利用层缓存。

  Docker文件中的每一行都代表一个层。 通过添加/删除行中的内容,或更改其引用的文件或文件夹,可以更改图层。 发生这种情况时,将重建此层以及其下的所有层。 否则,Docker将使用该层的缓存版本。 要利用该漏洞,您应该对Dockerfile进行结构化,以便经常不变的层应该出现在Dockerfile的开头附近。 在这里安装编译器是一个很好的例子。经常变化的层应该出现在Dockerfile的结尾附近。 复制源代码是古董的完美示例。

  酷。 理论足够,让我们回到我们的例子。

  假设您没有更改要求,而只更新了代码。 开发软件时,这很常见。 现在,每次构建映像时,都会重新安装这些讨厌的依赖项。 建立镜像始终需要相同的时间。 烦人! 我们还没有使用缓存。

  神奇的新Dockerfile来解决您的问题

  FROM python:3.8.0-slim

  RUN apt-get update \

  && apt-get install gcc -y \

  && apt-get clean

  COPY requirements.txt /app/requirements.txt

  WORKDIR app

  RUN pip install --user -r requirements.txt

  COPY . /app

  ENTRYPOINT uvicorn main:app --reload --host 0.0.0.0 --port 1234

  看起来并没有什么魔力和不同,对吧? 我们要做的唯一一件事就是首先安装GCC,然后分别复制需求和复制源代码。

  GCC和依赖项更改很少。 这就是为什么此层现在显示得很早的原因。 需求变更也比GCC缓慢但频繁。 这就是为什么该层位于GCC之后。 我们的源代码经常更改。 因此,将其复制会发生得较晚。 现在,当我们减肥源代码并重建映像时,由于Docker使用缓存的层,因此不会重新安装依赖项。 现在,重建几乎不需要时间。 太好了,因为我们可以花更多的时间来测试和执行我们的应用程序!

  多阶段构建

  在示例图像中,我们必须安装GCC才能安装FastApi和uvicorn。 但是,对于运行该应用程序,我们不需要编译器。 现在想象您不仅需要GCC,还需要其他程序,例如Git,CMake,NPM或…。 您的生产形象越来越胖。

  多阶段构建,助我们一臂之力!

  使用多阶段构建,您可以在同一Dockerfile中定义各种镜像。 每个镜像执行不同的步骤。 您可以将从一个镜像生成的文件和工件复制到另一个镜像。 最常见的情况是,您有一个用于构建应用程序的镜像,另一个是用于运行应用程序的镜像。 您需要做的就是将构建工件和依赖项从构建镜像复制到应用程序映像。

  对于我们的示例,这看起来像

  # Here is the build image

  FROM python:3.8.0-slim as builder

  RUN apt-get update \

  && apt-get install gcc -y \

  && apt-get clean

  COPY requirements.txt /app/requirements.txt

  WORKDIR app

  RUN pip install --user -r requirements.txt

  COPY . /app

  # Here is the production image

  FROM python:3.8.0-slim as app

  COPY --from=builder /root/.local /root/.local

  COPY --from=builder /app/main.py /app/main.py

  WORKDIR app

  ENV PATH=/root/.local/bin:$PATH

  ENTRYPOINT uvicorn main:app --reload --host 0.0.0.0 --port 1234

  构建该文件时,最终的生产映像大小为353 MB。 这大约是我们第一个版本的大小的一半。 恭喜,还不错。 请记住,您的生产镜像越小,效果越好!

  附带说明,多阶段构建还可以提高安全性。 为什么呢? 假设您需要一个密钥(例如SSH密钥)来在构建时访问某些资源。 即使您在以后的层中删除了该机密,它仍在先前的层中存在。 这意味着有权访问您的图像的人可以获取该密钥。 在多阶段构建中,您仅复制必要的运行时工件。 因此,生产镜像永远都看不到密钥,而您已经解决了该问题。

  有关多阶段构建的更多详细信息,我请读者参考本文和本文。

  总结

  在本文中,我向您展示了一些简单的技巧和窍门,说明如何创建更快构建的较小的Docker映像。 记得

  始终添加.dockerignore文件。考虑一下图层的顺序,并将其从缓慢变化的动作转变为快速变化的动作。尝试使用和利用多阶段构建。

  我希望这将为您节省一些磁盘空间和时间。

  感谢您关注这篇文章。 与往常一样,如有任何问题,意见或建议,请随时与我联系。

目录
相关文章
|
1月前
|
存储 运维 安全
构建高效自动化运维体系:Ansible与Docker的完美结合
【2月更文挑战第31天】 随着云计算和微服务架构的兴起,自动化运维成为保障系统稳定性和提升部署效率的关键手段。本文将详细探讨如何通过Ansible和Docker的结合来构建一个高效、可靠且易于管理的自动化运维体系。首先,介绍自动化运维的必要性及其在现代IT基础设施中的作用;然后,分别阐述Ansible和Docker的技术特点及优势;最后,提供一个基于Ansible和Docker结合使用的实践案例,以及实施过程中遇到的挑战和解决方案。
|
1月前
|
运维 Kubernetes 监控
构建高效自动化运维体系:基于Docker和Kubernetes的实践指南
【2月更文挑战第30天】 在当今快速发展的云计算时代,传统的IT运维模式已难以满足业务的敏捷性和稳定性需求。本文深入探讨了如何通过Docker容器化技术和Kubernetes集群管理工具构建一个高效、可靠的自动化运维体系。文章首先概述了容器化技术和微服务架构的基本概念,随后详细阐述了基于Docker的应用打包、部署流程,以及Kubernetes在自动化部署、扩展和管理容器化应用中的关键作用。最后,文中通过案例分析,展示了如何在实际场景中利用这些技术优化运维流程,提高系统的整体效率和可靠性。
|
1月前
|
运维 安全 网络安全
构建高效自动化运维体系:Ansible与Docker的完美融合
【2月更文挑战第30天】在当今快速迭代和持续部署的软件发展环境中,自动化运维成为确保效率和稳定性的关键。本文将探讨如何通过结合Ansible和Docker技术,构建一个高效的自动化运维体系。我们将分析Ansible的配置管理功能和Docker容器化的优势,并展示它们如何协同工作以简化部署流程,增强应用的可移植性,并提供一致性的系统环境。此外,文章还将介绍一些最佳实践,帮助读者在真实环境中实现这一整合方案。
|
8天前
|
存储 运维 监控
构建高效稳定的Docker容器监控体系
【4月更文挑战第18天】 在现代微服务架构中,Docker容器已成为部署和运行应用的标准环境。随之而来的挑战是如何有效监控这些容器的性能与健康状况,确保系统的稳定性和可靠性。本文将探讨构建一个高效稳定的Docker容器监控体系的关键技术和方法,包括日志管理、性能指标收集以及异常检测机制,旨在为运维人员提供实用的指导和建议。
13 0
|
27天前
|
运维 Kubernetes 持续交付
构建高效自动化运维体系:基于Docker和Kubernetes的最佳实践
在现代云计算环境中,自动化运维成为保障系统稳定性与提升效率的关键。本文深入探讨了如何利用Docker容器化技术和Kubernetes容器编排工具构建一个高效、可靠的自动化运维体系。文中不仅介绍了相关的技术原理,还结合具体案例分析了实施过程中的常见问题及解决方案,为读者提供了一套行之有效的最佳实践指南。
|
29天前
|
运维 监控 云计算
构建高效稳定的Docker容器监控体系
随着微服务架构的普及,Docker容器作为其核心承载单元,在系统运维中扮演着日益重要的角色。本文旨在探讨如何构建一个高效且稳定的Docker容器监控体系,以确保容器运行的可靠性和系统的高可用性。文章首先分析了容器监控的必要性,接着详细介绍了监控体系的设计理念和组件选择,最后提供了实施过程中的关键步骤与最佳实践。通过本文,读者将掌握构建和维护Docker容器监控体系的有效方法。
|
1月前
|
Kubernetes 开发者 Docker
构建高效微服务架构:Docker与Kubernetes的完美搭档
【2月更文挑战第29天】在当今快速发展的软件开发领域,微服务架构已成为提高系统可维护性、扩展性和敏捷性的关键解决方案。本文将深入探讨如何利用Docker容器化技术和Kubernetes集群管理工具,共同构建一个既高效又可靠的微服务环境。我们将分析Docker和Kubernetes的核心功能,并展示它们如何协同工作以简化部署流程、增强服务发现机制以及实现无缝的服务伸缩。通过实际案例分析,本文旨在为开发者提供一套实用的微服务架构设计和实施指南。
|
2月前
|
消息中间件 运维 应用服务中间件
容器化运维:构建高可用RabbitMQ集群的Docker Compose指南
容器化运维:构建高可用RabbitMQ集群的Docker Compose指南
178 0
|
2月前
|
消息中间件 Docker 容器
docker构建rabbitmq并配置延迟队列插件
docker构建rabbitmq并配置延迟队列插件
35 0
|
2月前
|
关系型数据库 MySQL Linux
docker构建mysql以及多实例
docker构建mysql以及多实例
26 0