如何为Python选择Docker基础镜像

对于容器化的应用程序,选择正确的容器基础映像(即在其上构建新的定制容器映像的基础映像)是成功的一半。您选择的基本映像在应用程序的安全性、性能、可维护性等方面起着核心作用。

为了说明这一点,本文介绍了几种为用Python(当今最流行的编程语言之一)开发的应用程序选择基本映像的方法。正如我们将看到的,尽管Python应用程序几乎与任何类型的容器基本映像兼容,但根据您的需求和优先级,一个基本映像可能比另一个更有意义。

为什么选择正确的基础图像是至关重要的

在深入了解Python的基本映像选项之前,让我们先讨论一下选择正确的基本映像如此重要的众多原因:

  • 性能:基本映像的总体大小会影响映像的下载速度。此外,容器启动时映像运行的代码量会影响应用程序启动和运行所需的时间。这两个因素都是影响容器整体性能的关键因素。
  • 依赖关系:许多应用程序都有依赖关系,即它们需要运行的库或其他代码。如果这些依赖关系被嵌入到基本镜像中,你就不需要做太多的工作来配置容器或定制它的内容来适应你的应用。
  • 更新:您需要确保您的基本映像是最新的。如果您的基本映像基于由第三方开发人员积极维护和定期修补的软件平台或发行版,则更容易做到这一点。
  • 安全性:基本映像中的代码越多,容器的攻击面就越大。出于这个原因,只包含运行应用程序严格必需的代码的基本映像更安全。

正如您所看到的,这些优先级之间存在一些冲突。例如,包含大量库的基本映像更有可能满足应用程序的依赖关系。另一方面,从安全性的角度来看,它们也可能更危险,因为它们可能包含您实际上并不需要的库,因此增加了潜在安全漏洞的风险。

考虑到在选择基础图像时要权衡的竞争因素,很少有明显理想的选择。相反,在使用特定的基本映像之前,您需要从战略上考虑应用程序和托管环境的特定需求。

Python的三个基本图像选项

作为如何在基本映像选择中考虑不同优先级的示例,假设您有一个希望在容器中运行的Python应用程序。例如,我们将使用一个非常简单的Hello World应用程序,其源代码仅由以下一行Python源代码组成:

打印(“Hello world !”)

我们将应用程序命名为hello.py。如果你愿意,你可以在命令行上运行它:

python hello.py

当然,输出应该是:

你好世界!

但是我们不想直接从命令行运行应用程序。我们想把它作为一个容器来运行。为此,我们需要创建一个码头工人形象来运行应用程序。

由于Python是一种几乎可以在任何地方运行的跨平台语言,因此您可以使用几乎任何基本映像创建容器化的Python应用程序。尽管如此,你选择的基本映像将影响你的应用程序的运行方式,维护和安全的难易程度等等。

因此,让我们来研究Python基础映像的三种不同方法:轻量级Linux发行版、标准Linux发行版和从头构建的最小基础映像。

1.用于Python的轻量级Linux基础映像

对于依赖关系很少或没有依赖关系的简单Python应用程序,可以使用使用轻量级Linux发行版创建的基本映像。这种类型的基本映像为您的容器提供了一个简单的Linux环境。这使得它比包含更多潜在漏洞的“重量级”环境更安全。

使用极简基本映像的缺点是,如果你的应用程序确实有依赖项,而这些依赖项并没有内置到基本映像中(如果它是极简图像,它们很可能不是),那么在创建映像时,你需要编写更多的代码行。

但现在,让我们假设你的应用没有依赖项。它可以使用轻量级Linux基本映像运行,比如高山,你可以免费使用码头工人中心。在这种情况下,我们唯一需要在基本映像上添加的是Python解释器,因为默认情况下Python没有安装Alpine。

所以,让我们创建一个Dockerfile,它使用Alpine作为基本镜像,安装Python,然后运行我们的应用程序。它看起来像这样:

从高山
WORKDIR工作
ENV PYTHONUNBUFFERED = 1
运行apk add -update -no-cache python3 && ln -sf python3 /usr/bin/python
COPY hello.py /usr/bin/hello
CMD python /usr/bin/hello

以Dockerfile的名字保存这个文件,并确保你的Python应用和Dockerfile保存在同一个目录下。然后,使用以下命令构建容器:

Docker build -t hello。

这告诉Docker用标签“hello”来命名容器。

要运行容器,输入:

Docker运行-你好

你应该看到“Hello world!”的命令行输出。

如果你想知道你的新容器镜像有多大,运行下面的命令:

Docker镜像1

如果您使用Alpine作为基本映像,您将看到容器映像的大小相对较小——大约52兆字节:

存储库标记图像id创建的大小
你好,最新的51.7MB

2.Python的标准Linux基础映像

像Alpine这样的轻量级Linux发行版可以很好地用于一个简单的“Hello World”应用程序,它除了Python之外没有任何依赖。但是,如果您有一个更复杂的Python应用程序,并且有很多依赖项,那么Alpine可能不是一个很好的选择,因为您必须将每个模块安装在基本映像的顶部。

相反,您可能更喜欢使用标准的Linux发行版,比如Ubuntu。在这种情况下,你可以使用如下的Dockerfile为你的Python应用创建一个容器(在这个例子中,我们使用的是Ubuntu 20.04的基本镜像):

罗ubuntu: 20.04
运行apt update
运行apt install -y python3
COPY hello.py /usr/bin/hello.py
ENTRYPOINT [" python3 "]
CMD(“/ usr / bin / hello.py”)

你可以使用与Alpine基本镜像相同的命令,基于这个Dockerfile创建一个容器:

Docker build -t hello_ubuntu

在本例中,我们将映像命名为“hello_ubuntu”,以区别于基于alpine的映像。

您可以使用以下命令运行新容器:

Docker运行- hello_ubuntu

因为我们使用的是Ubuntu的基本镜像,所以在这种情况下,总的镜像大小是147mb——比我们的Alpine镜像大很多:

存储库标记图像id创建的大小
hello_ubuntu latest 0ed400ca01b4分钟前147MB

3.从零开始的极简主义基础图像

容器化Python应用程序的第三种方法是使用从头创建的基本映像。在这种方法下,您根本不需要使用第三方基础映像。相反,您可以生成自己唯一的基本映像,然后使用基本映像为应用程序创建容器映像。(从技术上讲,在这种方法中仍然有一个基础映像——Docker的“scratch”映像——但这是一个专门的、极其简约的映像,其唯一目的是为创建全新的基础映像提供一个空白的石板。)

使用从头创建的基本映像的优点是,它将产生一个尽可能小且安全的容器。主要的缺点是创建和更新容器需要更多的工作,因为您必须将Python代码编译成静态二进制文件。这是必要的,因为您需要能够在容器内部没有Python解释器可用的情况下执行应用程序。

要将Python代码编译为静态代码,首先安装cython(它将Python代码转换为C语言):

sudo -H pip3安装cython

然后,根据Python代码生成C源代码(这里,我们使用的是" hello.py "示例程序):

python hello.py -embed

最后,继续使用gcc编译代码:

c -lpython2.7 -lpython2.7 -lpthread -lm -lutil -ldl

(请注意,您可能需要根据系统上安装的Python版本修改前面的命令。)

此时,你应该有一个可执行的二进制文件,名为hello,你可以在没有Python解释器的情况下运行它:

。/你好

现在,我们可以创建一个Dockerfile来定义一个容器来运行这个二进制文件:

从头开始
添加hello /
CMD (" / hello”)

使用如下命令构建并运行容器:

Docker build -t hello_scratch
Docker运行- hello_scratch

如果你检查一下这个容器的大小,你会发现它非常非常小——只有24千字节左右,比我们使用Alpine base映像创建的容器小20000倍。

存储库标记图像id创建的大小
大约一分钟前24.1kB

因此,尽管从头开始为Python应用程序创建基本映像需要更多的努力,但您将获得一个极其高效且(由于其极简性)安全的容器。