142 lines
5.6 KiB
Docker
142 lines
5.6 KiB
Docker
# ============================================================
|
||
# Dockerfile:项目镜像(多阶段构建)
|
||
# 基础镜像:python-base:3.12.8(RockyLinux 8 + Python 3.12.8 + mariadb-connector-c)
|
||
#
|
||
# 设计要点
|
||
# - builder 只编译依赖,装到 /opt/deps,不碰基础镜像的 Python 目录
|
||
# - runtime 继承基础镜像的 Python,只把依赖的 site-packages COPY 过来
|
||
# - MySQL 运行库(mariadb-connector-c)由基础镜像预置,runtime 无需重复安装
|
||
# - 用 COPY --chown 指定属主,避免额外的 chown 层
|
||
# - 源码 COPY 放在依赖之后,保护依赖层缓存
|
||
#
|
||
# 构建参数
|
||
# VAR_BASE_IMAGE 基础镜像
|
||
# VAR_PYTHON_PREFIX Python 安装前缀(与基础镜像一致)
|
||
# VAR_PYTHON_SHORT_VERSION Python 主次版本号,用于 site-packages 路径
|
||
# VAR_PYFILE_PATH 项目源码目录
|
||
# VAR_PROFILES 应用 profile(dev / prod)
|
||
# VAR_PORT 应用监听端口
|
||
# VAR_PYFILE 入口文件名(不含 .py)
|
||
# ============================================================
|
||
|
||
|
||
# ------------------------------------------------------------
|
||
# 全局构建参数
|
||
# 在 FROM 之前声明,可供后续各阶段引用
|
||
# ------------------------------------------------------------
|
||
ARG VAR_BASE_IMAGE
|
||
ARG VAR_PYTHON_PREFIX=/usr/local/python3.12.8
|
||
ARG VAR_PYTHON_SHORT_VERSION=3.12
|
||
|
||
|
||
# ============================================================
|
||
# 阶段一:builder —— 编译并安装项目依赖
|
||
# ============================================================
|
||
FROM ${VAR_BASE_IMAGE} AS builder
|
||
|
||
# 阶段内重新声明,否则读不到全局 ARG
|
||
# Docker 规则:全局 ARG 只在 FROM 行可见,阶段内使用必须重新声明
|
||
ARG VAR_PYTHON_PREFIX
|
||
ARG VAR_PYTHON_SHORT_VERSION
|
||
ARG VAR_PYFILE_PATH
|
||
|
||
# 基础镜像末尾是 esxi 用户;dnf/pip 需要写系统目录和 /opt/deps,
|
||
# 所以这里仍需 root
|
||
USER root
|
||
|
||
LABEL MAINTAINER="djangoadmin@126.com"
|
||
|
||
# 编译阶段环境变量
|
||
# PYTHONUNBUFFERED=1 日志实时输出
|
||
# PYTHONDONTWRITEBYTECODE=1 不生成 .pyc
|
||
# PIP_NO_CACHE_DIR=1 不缓存 wheel
|
||
# PIP_DISABLE_PIP_VERSION_CHECK=1 关闭 pip 版本检查
|
||
ENV PYTHONUNBUFFERED=1 \
|
||
PYTHONDONTWRITEBYTECODE=1 \
|
||
PIP_NO_CACHE_DIR=1 \
|
||
PIP_DISABLE_PIP_VERSION_CHECK=1
|
||
|
||
# 安装编译工具链
|
||
# gcc / gcc-c++ / make 编译 C 扩展(mysqlclient、uwsgi 等)
|
||
# openssl-devel cryptography、_ssl 等
|
||
# bzip2-devel / libffi-devel
|
||
# mariadb-devel 编译 mysqlclient(提供 .pc 文件)
|
||
# pkgconf-pkg-config 提供 pkg-config 命令(mysqlclient 2.2.x 必需)
|
||
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 \
|
||
gcc gcc-c++ make \
|
||
openssl-devel bzip2-devel libffi-devel \
|
||
mariadb-devel pkgconf-pkg-config; \
|
||
dnf clean all; rm -rf /var/cache/dnf
|
||
|
||
# 配置 pip 国内镜像源(阿里云 PyPI)
|
||
RUN pip3 config set global.index-url http://mirrors.aliyun.com/pypi/simple && \
|
||
pip3 config set install.trusted-host mirrors.aliyun.com
|
||
|
||
# 只拷 requirements.txt
|
||
# 源码变化但依赖未变时,可复用 pip install 层缓存
|
||
WORKDIR /opt/apps
|
||
COPY ${VAR_PYFILE_PATH}/requirements.txt ./
|
||
|
||
# 依赖装到 /opt/deps,与基础镜像 Python 目录解耦
|
||
# --prefix=/opt/deps 安装到独立目录,runtime 只 COPY 这个目录的产物
|
||
# uwsgi 生产环境 WSGI 服务器,单独安装
|
||
RUN python3 -m pip install --prefix=/opt/deps -r requirements.txt && \
|
||
python3 -m pip install --prefix=/opt/deps uwsgi
|
||
|
||
|
||
# ============================================================
|
||
# 阶段二:runtime —— 最终业务镜像
|
||
# ============================================================
|
||
FROM ${VAR_BASE_IMAGE} AS runtime
|
||
|
||
# 阶段内重新声明
|
||
ARG VAR_PYTHON_PREFIX
|
||
ARG VAR_PYTHON_SHORT_VERSION
|
||
ARG VAR_PROFILES
|
||
ARG VAR_PORT
|
||
ARG VAR_PYFILE
|
||
ARG VAR_PYFILE_PATH
|
||
|
||
LABEL MAINTAINER="djangoadmin@126.com"
|
||
|
||
# 运行期环境变量
|
||
ENV PYTHONUNBUFFERED=1 \
|
||
PYTHONDONTWRITEBYTECODE=1
|
||
|
||
# ARG 转 ENV,运行期可读取
|
||
# PORT 供 EXPOSE 与 CMD 使用
|
||
# PYFILE 入口文件名
|
||
# PROFILES 应用读取的 profile
|
||
ENV PORT=${VAR_PORT} \
|
||
PYFILE=${VAR_PYFILE} \
|
||
PROFILES=${VAR_PROFILES}
|
||
|
||
# 把 builder 编译好的 site-packages 和可执行文件拷到基础镜像 Python 对应目录
|
||
# 目标路径必须与基础镜像 Python 的实际 site-packages 一致
|
||
# 用 COPY --chown 指定属主,避免额外的 chown 层
|
||
COPY --chown=esxi:esxi --from=builder \
|
||
/opt/deps/lib/python${VAR_PYTHON_SHORT_VERSION}/site-packages/ \
|
||
${VAR_PYTHON_PREFIX}/lib/python${VAR_PYTHON_SHORT_VERSION}/site-packages/
|
||
COPY --chown=esxi:esxi --from=builder /opt/deps/bin/ ${VAR_PYTHON_PREFIX}/bin/
|
||
|
||
WORKDIR /opt/apps
|
||
|
||
# 拷项目源码(放在依赖之后,保护 pip 层缓存)
|
||
# 建议配合 .dockerignore 排除 .git、__pycache__、本地虚拟环境等
|
||
COPY --chown=esxi:esxi ${VAR_PYFILE_PATH}/ ./
|
||
|
||
USER esxi
|
||
EXPOSE ${PORT}
|
||
|
||
# 启动命令
|
||
# ${PYFILE} 为入口文件名(不含 .py),如 manage
|
||
# runserver 仅适合开发/调试;生产环境建议改用 uwsgi / gunicorn,例如:
|
||
# CMD ["sh","-c","uwsgi --http 0.0.0.0:${PORT} \
|
||
# --module 你的项目名.wsgi:application \
|
||
# --processes 4 --threads 2"]
|
||
CMD ["sh", "-c", "python3 ${PYFILE}.py runserver 0.0.0.0:${PORT} --noreload"] |