制作docker镜像
制作一个基于ubuntu的python3.11.15镜像
需先安装docker desktop,并拉取镜像
C:\Users\thbyt>docker pull ubuntu:24.04
24.04: Pulling from library/ubuntu
4029a2d69959: Download complete
966c395d29cb: Pull complete
Digest: sha256:561618e2c15bf2397621dd04f96926663a3b5616c189cf7e38db7e82f5c538ea
Status: Downloaded newer image for ubuntu:24.04
docker.io/library/ubuntu:24.04
1. 项目目录结构
在 Windows 上创建项目目录(例如 D:\python-sandbox):
D:\python-sandbox\
├── Dockerfile
├── requirements.in # 直接依赖,不写版本
└── requirements.txt # 本地生成的锁定文件
└── tmp # 临时目录
2. 准备依赖清单并生成锁定文件(本地执行)
2.1 编写 requirements.in
这里只是举例,具体需要什么以实际情况为准。
numpy
pandas
requests
2.2 在本地环境生成 requirements.txt
这里为了保证一致,使用本地已有的ubuntu。毕竟做镜像肯定是先拿已有环境做了实验的。
pip install pip-tools --index-url https://pypi.tuna.tsinghua.edu.cn/simple
然后执行:
pip-compile requirements.in
生成的 requirements.txt 会固定所有依赖及传递依赖的版本,例如:
(envXYJ) thbytwo@thbytwopower:~$ cd tmpdownload/
(envXYJ) thbytwo@thbytwopower:~/tmpdownload$ ls
(envXYJ) thbytwo@thbytwopower:~/tmpdownload$ touch requirements.in
(envXYJ) thbytwo@thbytwopower:~/tmpdownload$ vim requirements.in
(envXYJ) thbytwo@thbytwopower:~/tmpdownload$ cat requirements.in
numpy
pandas
requests
(envXYJ) thbytwo@thbytwopower:~/tmpdownload$ pip-compile requirements.in
WARNING: --strip-extras is becoming the default in version 8.0.0. To silence this warning, either use --strip-extras to opt into the new default or use --no-strip-extras to retain the existing behavior.
#
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile requirements.in
#
certifi==2026.7.22
# via requests
charset-normalizer==3.5.0
# via requests
idna==3.18
# via requests
numpy==2.4.6
# via
# -r requirements.in
# pandas
pandas==3.0.5
# via -r requirements.in
python-dateutil==2.9.0.post0
# via pandas
requests==2.34.2
# via -r requirements.in
six==1.17.0
# via python-dateutil
urllib3==2.7.0
# via requests
下载文件requirements.txt到“D:\python-sandbox\”目录里。
3. 编写多阶段 Dockerfile
这个放在“D:\python-sandbox\”目录里。
# ==================== 构建阶段 ====================
FROM ubuntu:24.04 AS builder
ENV DEBIAN_FRONTEND=noninteractive
# 设置 pip 使用清华镜像源(仅在构建阶段生效)
ENV PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
ENV PIP_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn
RUN apt-get update && apt-get install -y --no-install-recommends \
software-properties-common \
ca-certificates \
curl \
&& add-apt-repository ppa:deadsnakes/ppa \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
python3.11 \
python3.11-dev \
python3.11-venv \
python3-pip \
build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN python3.11 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir -r /tmp/requirements.txt
# ==================== 最终阶段 ====================
FROM ubuntu:24.04
# 最终阶段也可以设置 pip 源,但一般用不到(因为依赖已复制)
# ENV PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
# ENV PIP_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
software-properties-common \
&& add-apt-repository ppa:deadsnakes/ppa \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
python3.11 \
python3.11-venv \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH" \
PYTHONUNBUFFERED=1 \
PYTHONPYCACHEPREFIX=/work/.pycache \
HOME=/work
#RUN useradd -m -u 1000 -s /bin/bash sandboxuser \
# && mkdir -p /work /work/.pycache \
# && chown -R 1000:1000 /work
# 使用基础镜像中已有的 UID 1000 用户(ubuntu),无需创建新用户
RUN mkdir -p /work /work/.pycache \
&& chown -R 1000:1000 /work
USER 1000:1000
WORKDIR /work
CMD ["python"]
4. 构建镜像
在项目目录下执行(PowerShell):
docker build -t pyubuntu:3.11 .
极少数情况下,Docker 缓存可能出现不一致(例如你手动删除了一些中间层,或者 Docker Desktop 异常),此时可以清理构建缓存:
# 清理所有构建缓存(保留镜像)
docker builder prune
或者更彻底地清理悬空镜像和缓存:
# 清理未使用的镜像、网络、缓存等(会删除悬空镜像和未使用的构建缓存)
docker system prune
但平时不需要这样做,除非磁盘空间紧张或遇到奇怪的缓存问题。
运行输出如下:
D:\python-sandbox>docker build -t pyubuntu:3.11 .
[+] Building 10.2s (14/14) FINISHED docker:desktop-linux
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 2.20kB 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:24.04 0.6s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [builder 1/5] FROM docker.io/library/ubuntu:24.04@sha256:561618e2c15bf2397621dd04f96926663a3b5616c18 0.0s
=> => resolve docker.io/library/ubuntu:24.04@sha256:561618e2c15bf2397621dd04f96926663a3b5616c189cf7e38d 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 38B 0.0s
=> CACHED [stage-1 2/5] RUN apt-get update && apt-get install -y --no-install-recommends ca-cer 0.0s
=> CACHED [builder 2/5] RUN apt-get update && apt-get install -y --no-install-recommends softwa 0.0s
=> CACHED [builder 3/5] RUN python3.11 -m venv /opt/venv 0.0s
=> CACHED [builder 4/5] COPY requirements.txt /tmp/requirements.txt 0.0s
=> CACHED [builder 5/5] RUN pip install --no-cache-dir --upgrade pip && pip install --no-cache-dir 0.0s
=> CACHED [stage-1 3/5] COPY --from=builder /opt/venv /opt/venv 0.0s
=> [stage-1 4/5] RUN mkdir -p /work /work/.pycache && chown -R 1000:1000 /work 0.2s
=> [stage-1 5/5] WORKDIR /work 0.0s
=> exporting to image 8.2s
=> => exporting layers 5.8s
=> => exporting manifest sha256:e1195b28099eb0ff662e9e2b7e21478c921a2faea9ee742504a1077da6e2719f 0.0s
=> => exporting config sha256:546e09254f60d9bc8ae471875e13e154a87559dbb4c7066efa020856980f8781 0.0s
=> => exporting attestation manifest sha256:653fbcd55e17439ddf677c7342a35cf3b210d386ab274ef9de06ddc66ff 0.0s
=> => exporting manifest list sha256:469d0b47c37ccaebe4ef5795a15462eab824d16628fa995da8492889bc3df9c8 0.0s
=> => naming to docker.io/library/pyubuntu:3.11 0.0s
=> => unpacking to docker.io/library/pyubuntu:3.11
5. 测试镜像
简单运行python看看是否正常
# 检查 Python 版本
docker run --rm pyubuntu:3.11 python --version
# 检查已安装的包
docker run --rm pyubuntu:3.11 python -c "import numpy; print(numpy.__version__)"
docker run --rm pyubuntu:3.11 python -c "import pandas; print(pandas.__version__)"
运行结果如下
D:\python-sandbox>docker run --rm pyubuntu:3.11 python --version
Python 3.11.15
D:\python-sandbox>docker run --rm pyubuntu:3.11 python -c "import numpy; print(numpy.__version__)"
2.4.6
D:\python-sandbox>docker run --rm pyubuntu:3.11 python -c "import pandas; print(pandas.__version__)"
3.0.5
6.相关知识点
6.1多阶段构建
多阶段构建是 Docker 的一种优化技术,它允许在一个 Dockerfile 中使用多个 FROM 指令,每个 FROM 开始一个新的构建阶段(stage)。不同阶段可以使用不同的基础镜像,安装不同的工具,最后只把需要的文件复制到最终阶段,从而得到更小、更干净的镜像。
Dockerfile里“重复”的内容其实是两个阶段,它们的作用不同:
- 第一阶段(builder):安装了完整的构建工具(如
build-essential、python3.11-dev),用于编译安装 Python 包(特别是含有 C 扩展的包,比如numpy、pandas)。这个阶段可能会产生很多编译中间文件、头文件、编译器本身等,体积很大。 - 第二阶段(最终镜像):只安装运行 Python 程序所需的少量系统库(如 Python 解释器、CA 证书等),然后通过
COPY --from=builder把第一阶段已经安装好的虚拟环境(/opt/venv)复制过来。这样最终镜像里就没有编译工具和无关的开发文件,体积显著减小。
6.2Dockerfile的结构
# 第一阶段:构建阶段,命名为 builder
FROM ubuntu:24.04 AS builder
# 安装编译工具、Python 开发头文件等
RUN apt-get install ... build-essential python3.11-dev ...
# 创建虚拟环境并安装依赖
RUN python3.11 -m venv /opt/venv
COPY requirements.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt
# 第二阶段:最终阶段,开始一个新镜像
FROM ubuntu:24.04
# 只安装运行时必要的系统库,不安装编译工具
RUN apt-get install ... python3.11 ...
# 从 builder 阶段复制虚拟环境到当前阶段
COPY --from=builder /opt/venv /opt/venv
# 配置环境变量等
...
最终生成的镜像只包含第二阶段的内容,第一阶段的所有东西(包括编译工具)都不会出现在最终镜像里,除非显式用 COPY --from 复制过来。