# ============================================================================ # 基础镜像构建文件:CentOS 8 + Python 3.12.8(多阶段、精简版) # 作者:小蚂蚁云团队 # 说明: # 采用「builder + runtime」两阶段构建: # - builder 阶段:安装编译工具链(含 make/cmake/mariadb-devel/sqlite-devel), # 编译 Python,并裁剪安装目录 # - runtime 阶段:只拷贝编译好的 Python + 运行时库,不携带任何编译工具 # 最终镜像体积约为单阶段版本的 1/3。 # # 注:CentOS 8 已于 2021-12-31 EOL,官方源已下线。 # 本脚本把 dnf 源切换到阿里云 rockylinux 镜像(与 CentOS 8 二进制兼容), # 保证 dnf install 仍然可用。 # ============================================================================ # ============================================================================ # 阶段一:builder —— 只负责编译 Python,产物最终会被丢弃 # ============================================================================ FROM centos:8 AS builder # ---------------------------------------------------------------------------- # 环境变量 # PYTHON_VERSION : Python 版本号,便于统一引用 # PYTHON_HOME : Python 安装前缀目录(--prefix 使用) # LANG : 编译期语言环境,避免 make/configure 中文乱码 # ---------------------------------------------------------------------------- ENV PYTHON_VERSION=3.12.8 \ PYTHON_HOME=/usr/local/python3.12.8 \ LANG=en_US.UTF-8 # ---------------------------------------------------------------------------- # 安装编译 Python 所需的工具链与依赖库 # 关键点: # 1) CentOS 8 官方源已 EOL,切换到阿里云 rockylinux 镜像(二进制兼容) # 2) --setopt=install_weak_deps=False 不安装弱依赖,减少包数量 # 3) 编译完成后立即 dnf clean all,清除缓存 # 4) 加入 make / cmake / mariadb-devel / sqlite-devel: # - make : Python 自身编译必需 # - cmake : 第三方 C 扩展(如部分数据库/科学计算库)构建用 # - mariadb-devel : 提供 mysql.h / mysql_config,编译 MySQL C 扩展用 # (CentOS 8 里 mysql-devel 已被 mariadb-devel 取代) # - sqlite-devel : Python _sqlite3 模块编译必需 # 5) 不装 kernel-devel(除非要编译内核模块) # ---------------------------------------------------------------------------- RUN set -eux; \ # 禁用 mirrorlist,启用 vault 归档源 sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo; \ sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*.repo; \ dnf install -y --setopt=install_weak_deps=False \ make cmake gcc gcc-c++ \ openssl-devel bzip2-devel libffi-devel \ zlib-devel readline-devel sqlite-devel \ mariadb-devel \ xz tar findutils; \ dnf clean all; rm -rf /var/cache/dnf # ---------------------------------------------------------------------------- # 把 Python 源码包 ADD 进来 # - ADD 会自动解压 .tar.xz # - 该 tar.xz 只存在于 builder 阶段,最终镜像不会包含它 # - 前提:构建上下文里需要有 Python-3.12.8.tar.xz # ---------------------------------------------------------------------------- ADD Python-3.12.8.tar.xz /tmp/ # ---------------------------------------------------------------------------- # 编译并安装 Python # 关键点: # 1) 去掉 --enable-optimizations(PGO 训练会导致编译时间从几分钟涨到 20~40 分钟) # 2) --enable-shared 生成 libpython3.12.so,方便其他程序链接 # 3) --with-system-ffi 使用系统 libffi,避免自编译 # 4) --with-ensurepip=install 安装 pip # 5) 安装完成后对 Python 目录做「瘦身」: # - 删除 test/idlelib/tkinter/turtledemo/lib2to3 等运行时用不到的模块 # - 保留 ensurepip 与 site-packages,否则 pip 会被一并删除 # - 删除静态库 .a、libtool 文件 .la、__pycache__、.pyc # - 对 .so 执行 strip,去掉调试符号 # 6) 最后删除源码目录,避免残留在 builder 层 # ---------------------------------------------------------------------------- RUN set -eux; \ cd /tmp/Python-3.12.8; \ ./configure \ --prefix=${PYTHON_HOME} \ --enable-shared \ --with-system-ffi \ --with-ensurepip=install; \ make -j"$(nproc)"; \ make install; \ \ # ---- 裁剪 Python 安装目录,去掉运行时不需要的内容 ---- # 注意:不要删 ensurepip,也不要删 site-packages/* cd ${PYTHON_HOME}; \ rm -rf lib/python3.12/test \ lib/python3.12/idlelib \ lib/python3.12/tkinter \ lib/python3.12/turtledemo \ lib/python3.12/lib2to3 \ lib/python3.12/config-3.12-*; \ # ---- 删除 Python 缓存文件 ---- find ${PYTHON_HOME} -name '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true; \ find ${PYTHON_HOME} -name '*.pyc' -delete; \ # ---- 删除静态库和 libtool 文件 ---- find ${PYTHON_HOME} -name '*.a' -delete; \ find ${PYTHON_HOME} -name '*.la' -delete; \ # ---- 剥离 .so 动态库的调试符号 ---- find ${PYTHON_HOME}/bin ${PYTHON_HOME}/lib -type f -name '*.so*' \ -exec strip --strip-unneeded {} + 2>/dev/null || true; \ \ # ---- 清理源码目录 ---- cd /tmp; rm -rf /tmp/Python-3.12.8 # ============================================================================ # 阶段二:runtime —— 最终镜像 # 只包含:运行时依赖库 + 从 builder 拷贝过来的 Python # ============================================================================ FROM centos:8 AS runtime # ---------------------------------------------------------------------------- # 镜像元数据(LABEL 不影响镜像体积) # ---------------------------------------------------------------------------- LABEL maintainer="小蚂蚁云团队" \ version="2.1" \ description="基于CentOS 8的Python 3.12.8精简运行环境(含 MySQL/SQLite 运行时库)" \ python.version="3.12.8" # ---------------------------------------------------------------------------- # 运行时环境变量 # PYTHON_HOME : 与 builder 保持一致,便于 COPY 路径引用 # TZ : 时区 # LANG : 默认语言环境 # PATH : 把 Python 的 bin 目录放到最前,保证 python/pip 生效 # ---------------------------------------------------------------------------- ENV PYTHON_VERSION=3.12.8 \ PYTHON_HOME=/usr/local/python3.12.8 \ TZ=Asia/Shanghai \ LANG=en_US.UTF-8 \ PATH=/usr/local/python3.12.8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # ---------------------------------------------------------------------------- # 安装运行时所需的系统库(注意:全部是运行时库,不是 -devel 开发包) # openssl-libs : _ssl 模块依赖 # bzip2-libs : _bz2 模块依赖 # libffi : _ctypes 模块依赖 # zlib : zlib 模块依赖 # readline : 交互式命令行 # sqlite-libs : _sqlite3 模块依赖(对应 builder 的 sqlite-devel) # mariadb-connector-c : MySQL/MariaDB 客户端运行库 # (对应 builder 的 mariadb-devel, # 编译出的 mysqlclient 等 C 扩展运行需要) # glibc-langpack-en : en_US.UTF-8 locale # shadow-utils : useradd/groupadd 等 # tzdata : 时区数据 # 同时完成:时区、locale 配置 # ---------------------------------------------------------------------------- RUN set -eux; \ # ---- 把 CentOS 8 官方源替换为阿里云 rockylinux 镜像 ---- sed -e 's|^mirrorlist=|#mirrorlist=|g' \ -e 's|^#baseurl=http://mirror.centos.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \ -i.bak /etc/yum.repos.d/CentOS-*.repo; \ # ---- 安装运行时依赖 ---- dnf install -y --setopt=install_weak_deps=False \ openssl-libs \ bzip2-libs \ libffi \ zlib \ readline \ sqlite-libs \ mariadb-connector-c \ glibc-langpack-en \ shadow-utils \ tzdata; \ # ---- 清理缓存 ---- dnf clean all; rm -rf /var/cache/dnf; \ \ # ---- 时区配置 ---- ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime; \ echo ${TZ} > /etc/timezone; \ # ---- 语言环境配置 ---- echo 'LANG="en_US.UTF-8"' > /etc/locale.conf; \ echo 'LC_ALL="en_US.UTF-8"' >> /etc/locale.conf # ---------------------------------------------------------------------------- # 从 builder 阶段拷贝编译好的 Python # - 只拷贝 ${PYTHON_HOME},编译工具链完全不进入最终镜像 # - 路径保持一致,避免 PATH 失效 # ---------------------------------------------------------------------------- COPY --from=builder ${PYTHON_HOME} ${PYTHON_HOME} # ---------------------------------------------------------------------------- # 建立 python/pip 软链,并注册动态链接库 # 1) /usr/bin/python3、python、pip 指向 Python 安装目录 # 2) 把 ${PYTHON_HOME}/lib 写入 ld.so.conf.d 并执行 ldconfig # 否则运行 python 时会报 "libpython3.12.so not found" # 3) 最后验证 python3 / pip 是否可用 # ---------------------------------------------------------------------------- RUN set -eux; \ ln -sf ${PYTHON_HOME}/bin/python3.12 /usr/bin/python3; \ ln -sf ${PYTHON_HOME}/bin/python3.12 /usr/bin/python; \ ln -sf ${PYTHON_HOME}/bin/pip3 /usr/bin/pip; \ echo "${PYTHON_HOME}/lib" > /etc/ld.so.conf.d/python3.conf; \ ldconfig; \ python3 --version; pip --version # ---------------------------------------------------------------------------- # 创建非 root 用户 esxi # 1) groupadd -r : 创建系统组 # 2) useradd -r : 创建系统用户,家目录 /opt/apps # 3) 把工作目录和 Python 目录的属主交给 esxi # ---------------------------------------------------------------------------- RUN set -eux; \ groupadd -r esxi; \ useradd -r -g esxi -d /opt/apps -s /bin/bash esxi; \ mkdir -p /opt/apps; \ chown -R esxi:esxi /opt/apps ${PYTHON_HOME} # ---------------------------------------------------------------------------- # 工作目录 & 运行用户 # - WORKDIR 在 USER 之前设置,避免权限问题 # - USER esxi 让容器以非 root 身份运行,提升安全性 # ---------------------------------------------------------------------------- WORKDIR /opt/apps USER esxi # ---------------------------------------------------------------------------- # 健康检查:每 30s 检查一次 python3 是否可用 # ---------------------------------------------------------------------------- HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD python3 --version > /dev/null 2>&1 || exit 1 # ---------------------------------------------------------------------------- # 默认启动命令(可被子镜像或 docker run 覆盖) # ---------------------------------------------------------------------------- CMD ["python3", "--version"]