This commit is contained in:
gitadmin
2026-09-12 08:27:29 +08:00
parent 8ae2256e19
commit d1661aced0
2 changed files with 280 additions and 138 deletions
+52 -138
View File
@@ -1,90 +1,58 @@
# ============================================================================ # ============================================================
# 基础镜像构建文件:RockyLinux 8 + Python 3.12.8(多阶段、精简版) # 基础镜像:RockyLinux 8 + Python 3.12.8(多阶段、精简版)
# 作者:小蚂蚁云团队 # 定位:通用 Python 运行时,预置 MySQL 客户端运行库
# 说明: # 产出:python-base:3.12.8
# 采用「builder + runtime」两阶段构建: # ============================================================
# - builder 阶段:安装编译工具链,编译 Python,并裁剪安装目录
# - runtime 阶段:只拷贝编译好的 Python,不携带任何编译工具
# 最终镜像体积约为单阶段版本的 1/3。
# ============================================================================
# ============================================================
# ============================================================================ # 阶段一:builder —— 编译 Python,产物最终丢弃
# 阶段一:builder —— 只负责编译 Python,产物最终会被丢弃 # ============================================================
# ============================================================================
FROM rockylinux:8 AS builder FROM rockylinux:8 AS builder
# ----------------------------------------------------------------------------
# 环境变量
# PYTHON_VERSION : Python 版本号,便于统一引用
# PYTHON_HOME : Python 安装前缀目录(--prefix 使用)
# LANG : 编译期语言环境,避免 make/configure 中文乱码
# ----------------------------------------------------------------------------
ENV PYTHON_VERSION=3.12.8 \ ENV PYTHON_VERSION=3.12.8 \
PYTHON_HOME=/usr/local/python3.12.8 \ PYTHON_HOME=/usr/local/python3.12.8 \
LANG=en_US.UTF-8 LANG=en_US.UTF-8
# ---------------------------------------------------------------------------- # 安装编译 CPython 所需的工具链
# 安装编译 Python 所需的工具链与依赖库 # make / gcc / gcc-c++ 构建工具
# 关键点: # openssl-devel _ssl / _hashlib 模块
# 1) 替换为阿里云镜像源,加快 dnf 安装速度 # bzip2-devel _bz2 模块
# 2) --setopt=install_weak_deps=False 不安装「弱依赖」,减少包数量 # libffi-devel _ctypes 模块
# 3) 编译完成后立即 dnf clean all,清除缓存,避免缓存进入镜像层 # zlib-devel zlib 模块(第三方包间接依赖)
# 4) 只安装编译期需要的 -devel 包,不装 kernel-devel(除非要编译内核模块) # readline-devel readline 模块
# ---------------------------------------------------------------------------- # sqlite-devel _sqlite3 模块(必须保留)
# xz / tar / findutils 解压与裁剪
# 注意:不装 cmake,CPython 不用它
RUN set -eux; \ RUN set -eux; \
# ---- 配置国内 dnf 镜像源 ----
sed -e 's|^mirrorlist=|#mirrorlist=|g' \ sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
-i.bak /etc/yum.repos.d/*.repo; \ -i.bak /etc/yum.repos.d/*.repo; \
# ---- 安装编译依赖 ----
dnf install -y --setopt=install_weak_deps=False \ dnf install -y --setopt=install_weak_deps=False \
make cmake gcc gcc-c++ \ make gcc gcc-c++ \
openssl-devel bzip2-devel libffi-devel \ openssl-devel bzip2-devel libffi-devel \
zlib-devel readline-devel sqlite-devel \ zlib-devel readline-devel sqlite-devel \
xz tar findutils; \ xz tar findutils; \
# ---- 清理 dnf 缓存,减小层体积 ----
dnf clean all; rm -rf /var/cache/dnf dnf clean all; rm -rf /var/cache/dnf
# ---------------------------------------------------------------------------- # 添加 Python 源码包(构建上下文中需有 Python-3.12.8.tar.xz)
# 把 Python 源码包 ADD 进来
# - ADD 会自动解压 .tar.xz
# - 该 tar.xz 只存在于 builder 阶段,最终镜像不会包含它
# - 前提:构建上下文里需要有 Python-3.12.8.tar.xz
# ----------------------------------------------------------------------------
ADD Python-3.12.8.tar.xz /tmp/ ADD Python-3.12.8.tar.xz /tmp/
# ---------------------------------------------------------------------------- # 编译安装 Python,并裁剪安装目录
# 编译并安装 Python # --enable-shared 生成 libpython3.12.so,便于其他程序链接
# 关键点: # --with-system-ffi 使用系统 libffi,避免自编译
# 1) 去掉 --enable-optimizations,避免 PGO 训练导致编译时间暴涨 # --with-ensurepip=install 安装 pip
# (若必须追求性能,可保留,但编译时间会从几分钟涨到 20~40 分钟) # 裁剪:删除 test/idlelib/tkinter/lib2to3 等运行时不需要的模块,
# 2) --enable-shared 生成 libpython3.12.so,方便其他程序链接 # 删除 .a/.la/__pycache__/.pyc,strip .so 调试符号
# 3) --with-system-ffi 使用系统 libffi,避免自编译 # 注意:不要删 ensurepip 和 site-packages,否则 pip 会丢失
# 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; \ RUN set -eux; \
# ---- 进入源码目录并配置 ----
cd /tmp/Python-3.12.8; \ cd /tmp/Python-3.12.8; \
./configure \ ./configure \
--prefix=${PYTHON_HOME} \ --prefix=${PYTHON_HOME} \
--enable-shared \ --enable-shared \
--with-system-ffi \ --with-system-ffi \
--with-ensurepip=install; \ --with-ensurepip=install; \
# ---- 编译并安装(-j 使用所有 CPU 核心加速)----
make -j"$(nproc)"; \ make -j"$(nproc)"; \
make install; \ make install; \
\
# ---- 裁剪 Python 安装目录,去掉运行时不需要的内容 ----
# 注意:不要删 ensurepip,也不要删 site-packages/*
# 否则 make install 阶段安装的 pip 会一起被删掉,
# 导致 runtime 阶段 "No module named 'pip'"
cd ${PYTHON_HOME}; \ cd ${PYTHON_HOME}; \
rm -rf lib/python3.12/test \ rm -rf lib/python3.12/test \
lib/python3.12/idlelib \ lib/python3.12/idlelib \
@@ -92,100 +60,63 @@ RUN set -eux; \
lib/python3.12/turtledemo \ lib/python3.12/turtledemo \
lib/python3.12/lib2to3 \ lib/python3.12/lib2to3 \
lib/python3.12/config-3.12-*; \ 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 '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true; \
find ${PYTHON_HOME} -name '*.pyc' -delete; \ find ${PYTHON_HOME} -name '*.pyc' -delete; \
# ---- 删除静态库和 libtool 文件 ----
find ${PYTHON_HOME} -name '*.a' -delete; \ find ${PYTHON_HOME} -name '*.a' -delete; \
find ${PYTHON_HOME} -name '*.la' -delete; \ find ${PYTHON_HOME} -name '*.la' -delete; \
# ---- 剥离 .so 动态库的调试符号 ----
find ${PYTHON_HOME}/bin ${PYTHON_HOME}/lib -type f -name '*.so*' \ find ${PYTHON_HOME}/bin ${PYTHON_HOME}/lib -type f -name '*.so*' \
-exec strip --strip-unneeded {} + 2>/dev/null || true; \ -exec strip --strip-unneeded {} + 2>/dev/null || true; \
\
# ---- 清理源码目录,避免残留在 builder 层 ----
cd /tmp; rm -rf /tmp/Python-3.12.8 cd /tmp; rm -rf /tmp/Python-3.12.8
# ============================================================================ # ============================================================
# 阶段二:runtime —— 最终镜像 # 阶段二:runtime —— 最终基础镜像
# 只包含:运行时依赖库 + 从 builder 拷贝过来的 Python # ============================================================
# ============================================================================
FROM rockylinux:8 AS runtime FROM rockylinux:8 AS runtime
# ---------------------------------------------------------------------------- # 镜像元数据
# 镜像元数据(LABEL 不影响镜像体积)
# ----------------------------------------------------------------------------
LABEL maintainer="小蚂蚁云团队" \ LABEL maintainer="小蚂蚁云团队" \
version="1.1" \ version="1.3" \
description="基于RockyLinux 8的Python 3.12.8精简运行环境" \ description="RockyLinux 8 + Python 3.12.8 精简运行环境(预置 MySQL 运行库)" \
python.version="3.12.8" python.version="3.12.8"
# ----------------------------------------------------------------------------
# 运行时环境变量 # 运行时环境变量
# PYTHON_HOME : 与 builder 保持一致,便于 COPY 路径引用 # PYTHON_HOME 与 builder 一致,便于 COPY 路径引用
# TZ : 时区 # PATH 把 Python bin 目录放最前,保证 python/pip 生效
# LANG : 默认语言环境
# PATH : 把 Python 的 bin 目录放到最前,保证 python/pip 生效
# ----------------------------------------------------------------------------
ENV PYTHON_VERSION=3.12.8 \ ENV PYTHON_VERSION=3.12.8 \
PYTHON_HOME=/usr/local/python3.12.8 \ PYTHON_HOME=/usr/local/python3.12.8 \
TZ=Asia/Shanghai \ TZ=Asia/Shanghai \
LANG=en_US.UTF-8 \ LANG=en_US.UTF-8 \
PATH=/usr/local/python3.12.8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PATH=/usr/local/python3.12.8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# ---------------------------------------------------------------------------- # 安装运行时库
# 安装运行时所需的系统库(注意:全部是运行时库,不是 -devel 开发包) # openssl-libs / bzip2-libs / libffi / zlib / readline / sqlite-libs
# openssl-libs : _ssl 模块依赖 # Python 各标准库模块的运行期依赖
# bzip2-libs : _bz2 模块依赖 # mariadb-connector-c
# libffi : _ctypes 模块依赖 # MySQL 客户端运行库,为 MySQL 项目预置
# zlib : zlib 模块依赖 # glibc-langpack-en / shadow-utils / tzdata
# readline : 交互式命令行 # locale、useradd/groupadd、时区数据
# sqlite-libs : sqlite3 模块依赖 # 同时完成时区和 locale 配置
# glibc-langpack-en : en_US.UTF-8 locale
# shadow-utils : useradd/groupadd 等
# tzdata : 时区数据
# 同时完成:时区、locale 配置
# ----------------------------------------------------------------------------
RUN set -eux; \ RUN set -eux; \
# ---- 配置国内 dnf 镜像源 ----
sed -e 's|^mirrorlist=|#mirrorlist=|g' \ sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
-i.bak /etc/yum.repos.d/*.repo; \ -i.bak /etc/yum.repos.d/*.repo; \
# ---- 安装运行时依赖 ----
dnf install -y --setopt=install_weak_deps=False \ dnf install -y --setopt=install_weak_deps=False \
openssl-libs \ openssl-libs bzip2-libs libffi zlib \
bzip2-libs \ readline sqlite-libs \
libffi \ mariadb-connector-c \
zlib \ glibc-langpack-en shadow-utils tzdata; \
readline \
sqlite-libs \
glibc-langpack-en \
shadow-utils \
tzdata; \
# ---- 清理缓存 ----
dnf clean all; rm -rf /var/cache/dnf; \ dnf clean all; rm -rf /var/cache/dnf; \
\
# ---- 时区配置 ----
ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime; \ ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime; \
echo ${TZ} > /etc/timezone; \ echo ${TZ} > /etc/timezone; \
# ---- 语言环境配置 ----
echo 'LANG="en_US.UTF-8"' > /etc/locale.conf; \ echo 'LANG="en_US.UTF-8"' > /etc/locale.conf; \
echo 'LC_ALL="en_US.UTF-8"' >> /etc/locale.conf echo 'LC_ALL="en_US.UTF-8"' >> /etc/locale.conf
# ---------------------------------------------------------------------------- # 从 builder 拷贝编译好的 Python,编译工具链不进入最终镜像
# 从 builder 阶段拷贝编译好的 Python
# - 只拷贝 ${PYTHON_HOME},编译工具链完全不进入最终镜像
# - 路径保持一致,避免 PATH 失效
# ----------------------------------------------------------------------------
COPY --from=builder ${PYTHON_HOME} ${PYTHON_HOME} COPY --from=builder ${PYTHON_HOME} ${PYTHON_HOME}
# ---------------------------------------------------------------------------- # 建软链、注册动态库、验证
# 建立 python/pip 软链,并注册动态链接库 # ldconfig 注册 ${PYTHON_HOME}/lib,否则运行 python 会报 libpython3.12.so 找不到
# 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; \ RUN set -eux; \
ln -sf ${PYTHON_HOME}/bin/python3.12 /usr/bin/python3; \ 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/python3.12 /usr/bin/python; \
@@ -194,35 +125,18 @@ RUN set -eux; \
ldconfig; \ ldconfig; \
python3 --version; pip --version python3 --version; pip --version
# ---------------------------------------------------------------------------- # 创建非 root 用户 esxi,工作目录 /opt/apps
# 创建非 root 用户 esxi
# 1) groupadd -r : 创建系统组
# 2) useradd -r : 创建系统用户,家目录 /opt/apps
# 3) 把工作目录和 Python 目录的属主交给 esxi
# ----------------------------------------------------------------------------
RUN set -eux; \ RUN set -eux; \
groupadd -r esxi; \ groupadd -r esxi; \
useradd -r -g esxi -d /opt/apps -s /bin/bash esxi; \ useradd -r -g esxi -d /opt/apps -s /bin/bash esxi; \
mkdir -p /opt/apps; \ mkdir -p /opt/apps; \
chown -R esxi:esxi /opt/apps ${PYTHON_HOME} chown -R esxi:esxi /opt/apps ${PYTHON_HOME}
# ----------------------------------------------------------------------------
# 工作目录 & 运行用户
# - WORKDIR 在 USER 之前设置,避免权限问题
# - USER esxi 让容器以非 root 身份运行,提升安全性
# ----------------------------------------------------------------------------
WORKDIR /opt/apps WORKDIR /opt/apps
USER esxi USER esxi
# ---------------------------------------------------------------------------- # 健康检查:每 30s 检查 python3 是否可用
# 健康检查:每 30s 检查一次 python3 是否可用
# --start-period=5s 容器启动后 5s 内不判定为不健康
# --retries=3 连续失败 3 次才标记为 unhealthy
# ----------------------------------------------------------------------------
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python3 --version > /dev/null 2>&1 || exit 1 CMD python3 --version > /dev/null 2>&1 || exit 1
# ----------------------------------------------------------------------------
# 默认启动命令(可被子镜像或 docker run 覆盖)
# ----------------------------------------------------------------------------
CMD ["python3", "--version"] CMD ["python3", "--version"]
@@ -0,0 +1,228 @@
# ============================================================================
# 基础镜像构建文件:RockyLinux 8 + Python 3.12.8(多阶段、精简版)
# 作者:小蚂蚁云团队
# 说明:
# 采用「builder + runtime」两阶段构建:
# - builder 阶段:安装编译工具链,编译 Python,并裁剪安装目录
# - runtime 阶段:只拷贝编译好的 Python,不携带任何编译工具
# 最终镜像体积约为单阶段版本的 1/3。
# ============================================================================
# ============================================================================
# 阶段一:builder —— 只负责编译 Python,产物最终会被丢弃
# ============================================================================
FROM rockylinux: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) 替换为阿里云镜像源,加快 dnf 安装速度
# 2) --setopt=install_weak_deps=False 不安装「弱依赖」,减少包数量
# 3) 编译完成后立即 dnf clean all,清除缓存,避免缓存进入镜像层
# 4) 只安装编译期需要的 -devel 包,不装 kernel-devel(除非要编译内核模块)
# ----------------------------------------------------------------------------
RUN set -eux; \
# ---- 配置国内 dnf 镜像源 ----
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
-i.bak /etc/yum.repos.d/*.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 \
xz tar findutils; \
# ---- 清理 dnf 缓存,减小层体积 ----
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; \
# ---- 编译并安装(-j 使用所有 CPU 核心加速)----
make -j"$(nproc)"; \
make install; \
\
# ---- 裁剪 Python 安装目录,去掉运行时不需要的内容 ----
# 注意:不要删 ensurepip,也不要删 site-packages/*
# 否则 make install 阶段安装的 pip 会一起被删掉,
# 导致 runtime 阶段 "No module named 'pip'"
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; \
\
# ---- 清理源码目录,避免残留在 builder 层 ----
cd /tmp; rm -rf /tmp/Python-3.12.8
# ============================================================================
# 阶段二:runtime —— 最终镜像
# 只包含:运行时依赖库 + 从 builder 拷贝过来的 Python
# ============================================================================
FROM rockylinux:8 AS runtime
# ----------------------------------------------------------------------------
# 镜像元数据(LABEL 不影响镜像体积)
# ----------------------------------------------------------------------------
LABEL maintainer="小蚂蚁云团队" \
version="1.1" \
description="基于RockyLinux 8的Python 3.12.8精简运行环境" \
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 模块依赖
# glibc-langpack-en : en_US.UTF-8 locale
# shadow-utils : useradd/groupadd 等
# tzdata : 时区数据
# 同时完成:时区、locale 配置
# ----------------------------------------------------------------------------
RUN set -eux; \
# ---- 配置国内 dnf 镜像源 ----
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
-i.bak /etc/yum.repos.d/*.repo; \
# ---- 安装运行时依赖 ----
dnf install -y --setopt=install_weak_deps=False \
openssl-libs \
bzip2-libs \
libffi \
zlib \
readline \
sqlite-libs \
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 是否可用
# --start-period=5s 容器启动后 5s 内不判定为不健康
# --retries=3 连续失败 3 次才标记为 unhealthy
# ----------------------------------------------------------------------------
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python3 --version > /dev/null 2>&1 || exit 1
# ----------------------------------------------------------------------------
# 默认启动命令(可被子镜像或 docker run 覆盖)
# ----------------------------------------------------------------------------
CMD ["python3", "--version"]