制作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-essentialpython3.11-dev),用于编译安装 Python 包(特别是含有 C 扩展的包,比如 numpypandas)。这个阶段可能会产生很多编译中间文件、头文件、编译器本身等,体积很大。
  • 第二阶段(最终镜像):只安装运行 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 复制过来。