如何将 python 库从主机共享到多个 docker 容器?

Posted

技术标签:

【中文标题】如何将 python 库从主机共享到多个 docker 容器?【英文标题】:How to share python libraries from host to multiple docker containers? 【发布时间】:2021-07-11 10:19:26 【问题描述】:

我们设置了多个运行 python 微服务的 docker 容器。问题是许多库在容器中是多余的。由于 docker 隔离,所有的库都独立安装在每个容器中,这增加了 docker 镜像的大小。

那么,有没有一种方法可以通过将所有库安装在共享文件夹或任何其他解决方案中来跨多个容器共享 python 库,保持代码仍然隔离但允许使用共享库?

Dockerfile1:

FROM python:3.8.5-slim

RUN apt-get update && \ 
        apt-get install -y \
        git openssh-server 

# Avoid cache purge by adding requirements first
RUN git clone git@github.com:some_org/some_repo_1.git
WORKDIR ./some_repo_1/

RUN pip3 install --upgrade pip
RUN pip3 install -r requirements.txt

EXPOSE 80

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

Dockerfile2:

FROM python:3.8.5-slim

RUN apt-get update && \ 
        apt-get install -y \
        git openssh-server 

# Avoid cache purge by adding requirements first
RUN git clone git@github.com:some_org/some_repo_2.git
WORKDIR ./some_repo_2/

RUN pip3 install --upgrade pip
RUN pip3 install -r requirements.txt

EXPOSE 81

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "81"]

docker-compose.yml

version: "3.9"
services:
        service_1:
                build:
                        context: './some_repo_1/'
                ports:
                        - '80:80'

        service_2:
                build:
                        context: './some_repo_2/'
                ports:
                        - '81:81'

注意:我们必须部署许多不同的微服务 docker 容器,它们的依赖关系有些相似。所以 docker 镜像大小是一个主要问题。

PS:我正在使用 docker-compose 来运行多个 docker 容器。

【问题讨论】:

这听起来你不应该首先使用 docker。但是,一个解决方案可能是将您需要的核心库放在一个文件夹中,您将通过卷选项在容器之间共享该库。 听起来您应该只创建一个包含所有依赖项的基础映像,然后在此基础上构建您的服务映像。 @Dimitar 我已经尝试过使用volumes 选项,但我无法在其他容器中获取python venv。我明白你不使用 docker 的意思,但问题陈述要求我隔离代码。 @larsks 创建基本映像后,我必须在此映像上克隆一个 git 存储库,这些存储库是所有容器上的单独存储库。所以这会产生一个大小相同的重复图像。 你能分享你正在使用的两个 Dockerfile 吗? 【参考方案1】:

假设您可以将您的需求拆分为一个“通用”集,以及一些额外的每个应用程序的依赖项。在非 Docker 环境中,您可能会运行:

python3 -m venv venv1
./venv1/bin/pip install ./requirements-common.txt
./venv1/bin/pip install ./some_repo_1/requirements.txt
./venv1/bin/uvicorn ...
# and similarly for venv2, some_repo_2

您可以构建自己的仅包含常用库的中间 Docker 映像:

FROM python:3.8.5-slim
WORKDIR /app
COPY requirements-common.txt .
RUN pip install -r requirements-common.txt
docker build -t my/app-base .

然后,当您构建每个应用程序的映像时,您可以将其作为基础映像并预先安装该库集。 Docker 分层的工作方式,底层库集将在各种派生镜像之间共享。

FROM my/app-base
# Inherits WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 81
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "81"]

Compose 对此模式没有任何特定支持。如果中间映像仅包含一组很少更改的预安装库,则根据需要手动docker build 并按原样使用问题中的docker-compose.yml 可能是最简单的。

【讨论】:

是的,我可以使用带有公共库的预构建映像,但问题仍然是使用此作为基础映像构建的所有其他映像都将具有这些公共库,因此它是多余的。它会影响图像的大小 他们应该能够共享基础镜像。即使相同的库包含在公共列表和每个服务列表中,Pip 也应该知道不要重新安装已经存在的库,因此每个服务图像应该只有特定于服务的库依赖项加上实际的服务代码. 我同意你的观点,但我的观点是我创建的基本图像,比如说“x”大小,每当我使用它来构建其他图像时,这个“x”都会添加到每个图像中其中。这意味着如果我正在构建 10 个图像,则使用的总大小将是 10 倍。这就是为什么我想提出一个解决方案,有点像所有其他容器将共享同一个库文件夹(或者说,venv)。 这个设置的重点是“x”在所有派生图像之间共享;它不会在它们之间重复。 不,它被复制到每个容器中,导致它们的大小为“x”+something。可以肯定的是,我尝试了您建议的设置并创建了 3 张图像。 1) 带有通用库的基础镜像 (size=533mb) 2) 使用基础镜像的应用镜像(在上一步中创建)只有一个额外的库 (size=534mb) 3) 另一个应用镜像使用原始 python 镜像和 1 个库大小( =120mb)。因此,该图像作为其他容器的基础图像最终会被复制到其中。

以上是关于如何将 python 库从主机共享到多个 docker 容器?的主要内容,如果未能解决你的问题,请参考以下文章

Python 共享主机

如何将文件从 docker 容器共享到主机

如何让 2 个应用程序共享同一个 Dock 磁贴

如何在 Mac 的 Dock 上对应用程序的多个窗口进行分组

如何将文件从 dockerfile 复制到主机?

使用 Serviceability Agent 检查 JVM 核心转储时如何获取共享库列表?