如何使Python Docker镜像安全、快速、小巧

一、说明

        在微服务领域,拥有安全、高效和紧凑的 Docker 映像对于成功部署至关重要。本博客将探讨有助于构建此类映像的关键因素,包括不以 root 用户身份运行映像的重要性、在构建映像时更新和升级包、在编写 Dockerfile 指令时考虑 Docker 的层架构,以及利用多阶段构建来减小映像大小。本博客的部分内容受到我最近来自Matthijs Brouns的精彩演讲的启发,您可以在此处查看。

        我将使用 CLI 工具潜水来分析图像及其图层。Docker镜像的目的是充当机器学习应用程序的FASTAPI服务器的主机,而Poetry是其依赖项管理器。有关使用诗歌而不是pip/pipenv/pip-tools/conda的动机的更多信息,请阅读此博客和此博客。请注意,对 Docker 和 Docker 文件的基本了解是本文的先决条件。

FROM python:3.11-slim as build

        我正在使用 Python 3.11 的精简版本来最小化容器的大小并使其尽可能轻量级。它的大小为 121 MB。

        完整的Python映像(python:3.11)包括运行应用程序不需要的额外开发工具和文档,使其更大,大小为875 MB,比苗条版本😱大约7倍

        另一种选择是Alpine(python:3.11-alpine),它更小,大小为56.5 MB。但是,它缺少软件包安装程序 pip 和对安装轮子包的支持,这两者都是安装 Pandas 和 Numpy 等应用程序所必需的。若要安装这些应用程序,需要使用 G++ 等编译器包从源文件编译它们,默认情况下也不会在 Alpine 映像上安装这些包。这导致图像尺寸比苗条版本更大(和麻烦得多),所以让我们继续那个。

ENV PIP_DEFAULT_TIMEOUT=100 \
    # Allow statements and log messages to immediately appear
    PYTHONUNBUFFERED=1 \
    # disable a pip version check to reduce run-time & log-spam
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    # cache is useless in docker image, so disable to reduce image size
    PIP_NO_CACHE_DIR=1

ARG POETRY_VERSION=1.3.2

        Dockerfile 中的 ENV 变量被设置为在 Docker 容器中安装软件包期间优化 pip 和诗歌的行为。此外,我明确定义了要安装的诗歌版本。

二、Docker安全

        让我们继续讨论安全性,因为有几个方面很重要。不建议以 root 用户身份运行 Docker 容器,因为 root 用户可以完全控制主机系统,包括修改或删除文件、启动和停止服务以及访问敏感信息的能力。若要遵循最小特权原则,最好仅使用所需的最低特权运行容器。因此,为了增强安全性,我们为 Docker 容器创建了一个名为 的非 root 用户。appuser

RUN set -ex \
    # Create a non-root user
    && addgroup --system --gid 1001 appgroup \
    && adduser --system --uid 1001 --gid 1001 --no-create-home appuser \

        通过分配特定的用户和组 ID(例如 1001),可以更轻松地管理不同系统之间的用户权限和访问控制,尤其是在 Kubernetes 等平台上运行容器时。

        🤔 那么 的权限与根用户的权限有何不同呢?分配给的权限可能包括对某些文件和目录的读取、写入或执行访问的限制,具体取决于为这些资源设置的默认权限。例如,默认情况下,可能没有对容器中特定子目录的写入访问权限。如果运行 作为的应用程序需要对该目录的写入访问权限,则需要使用以下命令更改该目录的所有权,以授予所需的权限:appuserappuserappuserappuserchownappuser

RUN chown -R appuser:appuser /your-subdirectory

        否则将引发以下错误:

[Errno 13] Permission denied: 'your-subdirectory/filename'

        另一个安全最佳实践是更新和升级 Docker 容器中的包。原因是,在 Docker 环境中,用于创建容器的基础映像通常是特定版本的操作系统的快照。随着时间的推移,可能会发现安全漏洞或其他问题,并发布修补程序以使用 和 解决这些问题。该命令更新包索引(有点像可用软件包及其元数据的数据库),并从包存储库中检索最新的包信息。apt-get updateapt-get upgradeapt-get update

RUN set -ex \
    && apt-get update \
    && apt-get upgrade -y

        现在我们有了有关可用软件包的信息,我们可以使用该命令将容器中当前安装的软件包升级到其最新的可用版本。该标志用于在升级过程中自动对任何提示回答“是”。apt-get upgrade-y

        ⬆ 更新过程导致一些自动安装的包、包缓存文件和包索引文件。在运行应用程序时,不再需要这些文件,因为它们达到了帮助升级包的目的。我们可以使用以下命令安全地删除这些文件,这应该会减小 Docker 映像的大小。

# Clean up
RUN set -ex apt-get autoremove -y \\
    && apt-get clean -y \\
    && rm -rf /var/lib/apt/lists/*

        最后的安全最佳做法是确保 docker 映像中不包含任何机密。为了帮助防止这种情况,您可以将常用机密文件和文件夹添加到 .dockerignore 文件中:

**/.env
**/.aws
**/.ssh

        您还可以使用 Trivy,例如,当您使用“root”作为图像用户时,它会警告您。以下是VSCode扩展的屏幕截图:

Trivy 的 VSCode 扩展

三、应用程序文件

        好了,现在我们已经设置了一些环境变量并提高了 docker 容器的安全性,让我们继续复制实际的应用程序文件并安装依赖项。我们希望将工作目录设置为“/app”。此目录在基本映像中尚不存在,但如果不存在,则会为我们创建它。所有后续指令都将在此位置执行,这使我们的 docker 镜像更有条理和可移植性。WORKDIR

WORKDIR /app
COPY pyproject.toml poetry.lock ./

        该命令用于将文件从主机系统复制到容器文件系统。在本例中,我们正在复制 和 ,这是 Poetry 包管理器的配置文件。COPYpyproject.tomlpoetry.lock

四、潜水

        现在我们已经完成了一些步骤,让我们构建 docker 镜像并深入研究它以检查🕵️ ♀️不同的层:

docker build -t app:latest .
dive app:latest

        👇 我们可以在每一层中看到与前一层相比进行了哪些更改。首先,我们使用命令创建了一个应用程序目录,然后复制两个文件。WORKDIR

        当前映像的大小为 139 MB。它看起来相当不错,但可以进行一些改进以减小其大小。首先要记住的是,系统中后续层删除的文件实际上仍然存在于图像中;它们只是在最后一层无法访问。

        👆因此,分别安装安全更新和删除现在不必要的文件和包的步骤不会节省任何空间。起作用的是将这两个步骤合二为一。

RUN set -ex \
    # Create a non-root user
    && addgroup --system --gid 1001 appgroup \
    && adduser --system --uid 1001 --gid 1001 --no-create-home appuser \
    # Upgrade the package index and install security upgrades
    && apt-get update \
    && apt-get upgrade -y \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

        这将图像的大小从 18 mb 减小到 总大小 121 mb 🎉 ,这与我们之前的图层完全相同。apt-get update && update-get upgrade -y

五、缓存

好的,让我们继续!安装依赖项后,我们会将我的应用程序需要的一些子目录复制到容器中。接下来是使用 Poetry 安装 python 包:

COPY ./artifacts artifacts
COPY ./api api

RUN pip install "poetry==$POETRY_VERSION" \
    && poetry install --no-root --no-ansi --no-interaction

        🤔 但是这些命令的顺序有意义吗?请记住,每个层都是与其下方层独立的增量。每次更改图层时,它都会更改其后的每个图层。如果上一层与之前完全相同,我们可以只使用缓存的值,而不是重建该步骤。

Step 12/18 : COPY ./api api
 ---> Using cache
 ---> ea3ba41d1a13

        因此,您希望将图层从最不可能更改到最有可能更改进行排序,以缩短构建时间💨。在复制程序的其余部分之前先安装依赖项是有意义的。与应用程序代码相比,更新和更改依赖项的可能性通常要小得多。👇 因此,这是一个更好的指令顺序:

RUN pip install "poetry==$POETRY_VERSION" \
    && poetry install --no-root --no-ansi --no-interaction

COPY ./artifacts artifacts
COPY ./api api

        下一步是公开一个端口供我们的应用程序侦听。 在 Dockerfile 中更多地用于文档📄目的,指示应用程序在容器中侦听哪些端口。EXPOSE

为了实际公开我们的 FASTAPI 服务器,我们运行以下命令:

CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"]

        最后,我们使用命令设置应用程序将运行的用户。这设置为我们之前创建的用户 .USERappuser

让我们再次构建 docker 镜像并检查大小:

        映像现在的总大小为 731 MB。531 mb 来自 Poetry 安装的依赖项,但 Poetry 本身也占用了一些空间。

        💡 尽管 Poetry 在开发阶段对于创建虚拟环境和管理依赖项很有用,但在运行 Docker 映像时不需要这些功能,因为映像提供了自己的隔离环境,并且我们的依赖项已经安装。因此,减小 Docker 映像的大小也可以通过确保 Poetry 包不包含在最终映像中来实现。

六、多阶段构建

        多阶段构建可用于从最终的 Docker 映像中排除 Poetry,因为它可以从单个 Dockerfile 创建多个映像。与直接使用 Poetry 安装依赖项不同,Poetry 还可以在构建阶段将必要的依赖项导出到 needs.txt 文件中。此文件可以复制到最后阶段,并由 pip 用于安装依赖项。

FROM python:3.11-slim as build

. . . 

RUN pip install "poetry==$POETRY_VERSION" \
    && poetry install --no-root --no-ansi --no-interaction \
    && poetry export -f requirements.txt -o requirements.txt


### Final stage
FROM python:3.11-slim as final

WORKDIR /app

COPY --from=build /app/requirements.txt .

RUN pip install -r requirements.txt

        通过在最后阶段排除诗歌,Docker图像的大小减小,如从732 MB减少到538 MB 🎉🍾所示。

七、👇 我们最终得到以下文件:

FROM python:3.11-slim as build

ENV PIP_DEFAULT_TIMEOUT=100 \
    # Allow statements and log messages to immediately appear
    PYTHONUNBUFFERED=1 \
    # disable a pip version check to reduce run-time & log-spam
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    # cache is useless in docker image, so disable to reduce image size
    PIP_NO_CACHE_DIR=1 \
    POETRY_VERSION=1.3.2

WORKDIR /app
COPY pyproject.toml poetry.lock ./

RUN pip install "poetry==$POETRY_VERSION" \
    && poetry install --no-root --no-ansi --no-interaction \
    && poetry export -f requirements.txt -o requirements.txt


### Final stage
FROM python:3.11-slim as final

WORKDIR /app

COPY --from=build /app/requirements.txt .

RUN set -ex \
    # Create a non-root user
    && addgroup --system --gid 1001 appgroup \
    && adduser --system --uid 1001 --gid 1001 --no-create-home appuser \
    # Upgrade the package index and install security upgrades
    && apt-get update \
    && apt-get upgrade -y \
    # Install dependencies
    && pip install -r requirements.txt \
    # Clean up
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

COPY ./artifacts artifacts
COPY ./api api

EXPOSE 8000

CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"]

# Set the user to run the application
USER appuser

八、总结

        总之,通过在创建 Dockerfile 时遵循这些提示和最佳实践,您可以确保最终映像针对安全性、大小和性能进行了优化。

        确保选择正确的基础映像,了解 Docker 层的不变性,按正确的顺序放置说明,并遵循安全最佳实践。

     

如何使您的 Python Docker 镜像安全、快速和小巧 |作者:比约恩·范·迪克曼 |华帝人工智能 |中等 (medium.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/65315.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ZIG:理解未来编程语言的视角

文章目录 摘要:引言:性能简洁性和模块化避免常见错误和陷阱总结:参考资料📑: 摘要: 本文介绍了新兴编程语言ZIG的目标和特点,包括高性能、简洁性和模块化,并分析了这些特点是如何通过语言设计来…

关于丢失安卓秘钥的撞sha-1值的办法

实验得知,安卓sha-1和keytool生成秘钥签名文件的时间有关。 前提条件是,开发者必须知道生成秘钥的所有细节参数 以下是撞文件代码(重复生成) import time import osidx 0while True:cmdkeytool -keyalg RSA -genkeypair -alia…

中国信通院腾讯安全发布《2023数据安全治理与实践白皮书》

导读 腾讯科技(深圳)有限公司和中国信息通信研究院云计算与大数据研究所共同编制了本报告。本报告提出了覆盖组织保障、管理流程、技术体系的以风险为核心的数据安全治理体系,并选取了云场景、互娱、社交等场景,介绍相应场景下数据安全治理实践路线及主…

26 MFC序列化函数

文章目录 Serialize对于存储文件的序列化 Serialize Serialize 是一个在 MFC (Microsoft Foundation Classes) 中常用的函数或概念。它用于将对象的数据进行序列化和反序列化,便于在不同的场景中保存、传输和恢复对象的状态。 在 MFC 中,Serialize 函数…

MongoDB 入门

1.1 数据库管理系统 在了解MongoDB之前需要先了解先数据库管理系统 1.1.1 什么是数据? 数据(英语:data),是指未经过处理的原始记录。 一般而言,数据缺乏组织及分类,无法明确的表达事物代表的意…

elk开启组件监控

elk开启组件监控 效果: logstash配置 /etc/logstash/logstash.yml rootnode1:~# grep -Ev "^#|^$" /etc/logstash/logstash.yml path.data: /var/lib/logstash path.logs: /var/log/logstash xpack.monitoring.enabled: true xpack.monitoring.elasti…

AI Chat 设计模式:12. 享元模式

本文是该系列的第十二篇,采用问答式的方式展开,问题由我提出,答案由 Chat AI 作出,灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 给我介绍一下享元模式A.1Q.2 也就是说,其实共享的是对象的内部状态&…

分享21年电赛F题-智能送药小车-做题记录以及经验分享

这里写目录标题 前言一、赛题分析1、车型选择2、巡线1、OpenMv循迹2、灰度循迹 3、装载药品4、识别数字5、LED指示6、双车通信7、转向方案1、开环转向2、位置环速度环闭环串级转向3、MPU6050转向 二、调试经验分享1、循迹2、识别数字3、转向4、双车通信5、逻辑处理6、心态问题 …

RISC-V架构的演变

随着苹果基于ARM的硅和新的RISC-V CPU的推出,对于CPU开发来说,这是一个令人兴奋的时刻,尽管开发人员的旅程目前对后者来说有点坎坷。 我最喜欢的理论是,没有发生是孤独的,而只是重复了以前发生过的事情,也…

【数据结构与算法】平衡二叉树(AVL树)

平衡二叉树(AVL树) 给你一个数列{1,2,3,4,5,6},要求创建二叉排序树(BST),并分析问题所在。 BST 存在的问题分析: 左子树全部为空,从形式上看,更像一个单链表。插入速度…

Softing工业获得自动化产品安全开发流程认证

Softing工业获得了TV Sd颁发的IEC 62443-4-1产品安全开发流程认证。 (IEC 62443-4-1认证确保网络安全) 截至2023年6月,位于德国哈尔和纽伦堡的工厂以及罗马尼亚克卢日的Softing工业研发部门已获得IEC 62443-4-1:2018标准的认证。该认证流程由…

Webpack5新手入门简单配置

1.初始化项目 yarn init -y 2.安装依赖 yarn add -D webpack5.75.0 webpack-cli5.0.0 3.新建index.js 说明:写入下面的一句话 console.log("hello webpack"); 4.执行命令 说明:如果没有安装webpack脚手架就不能执行yarn webpack&#xff08…

k8sday02

第四章 实战入门 本章节将介绍如何在kubernetes集群中部署一个nginx服务,并且能够对其进行访问。 Namespace ​ Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 ​ 默认情况下&…

linux手动安装 golangci-lint-1.53.3-linux-386.rpm

首先还是 去下载对应的 rpm 包 https://github.com/golangci/golangci-lint/releases 然后上传到 服务器/usr/local 目录下 执行安装命令 sudo rpm -ivh golangci-lint-1.53.3-linux-386.rpm 查看版本 golangci-lint --version

Nginx与docker配置安装

目录: Nginx的安装配置: 1、安装依赖包: 2、下载Nginx安装包: 3、解压Nginx压缩包: 4、配置Nginx编译环境: 5、编译并安装Nginx: 6、安装完Nginx后,可以切换到Nginx的安装目录…

使用MIT Kerberos Ticket Manager在windows下浏览器访问hadoop页面

Author : Spinach | GHB Link : http://blog.csdn.net/bocai8058文章目录 前言准备配置说明安装Firefox浏览器安装MIT Kerberos Ticket Manager客户端配置krb5.ini文件配置MIT Kerberos Ticket Manager客户端配置Firefox浏览器代理参数 访问WebUI 前言 kerberos是一种计算机…

vite项目中使用@代表根路径

1.配置vite.config.ts import { defineConfig } from vite import vue from vitejs/plugin-vue import path from pathexport default defineConfig({plugins: [vue()],resolve: {alias:{: path.resolve(__dirname, src) }} })2.报错path和__dirname 找不到模块“path”或其相…

实力认证!TDengine 入选 Gartner 中国数据分析与人工智能技术成熟度曲线

近日,国际权威研究机构 Gartner 发布了《2023 年中国数据分析及人工智能技术成熟度曲线》(即《Hype Cycle for Data, Analytics and AI in China, 2023》)报告,TDengine 成功入选实时数据管理领域代表产品。 作为评估全球新技术成…

MySQL— 基础语法大全及操作演示!!

MySQL—— 基础 一、MySQL概述1.1 、数据库相关概念1.2 、MySQL 客户端连接1.3 、数据模型 二、SQL2.1、SQL通用语法2.2、SQL分类2.3、DDL2.4、DML2.5、DQL2.6、DCL 三、函数四、约束五、多表查询六、事务 一、MySQL概述 1.1 、数据库相关概念 数据库、数据库管理系统、SQL&a…

STM32自带的DSP库的滤波初体验(一)

最近在弄STM32自带的DSP库里的滤波,记录一下: arm_fir_instance_q15 instance_q15_S; #define NUM_TAPS 16 //滤波系数的个数 #define BLOCK_SIZE 32 q15_t firStateF32[BLOCK_SIZE NUM_TAPS]; q15_t Fir_Coeff[NUM_TAPS] {-79, -136, 312, 6…