Docker 容器化技术完全指南
·
写给算法工程师的话:在日常工作中,你可能会经常遇到这样的情况——拿到一个项目,里面有
Dockerfile,知道要运行docker build和docker run,但看到Dockerfile里的指令就头疼,出错时更是无从下手。本指南专为你而写,不讲底层原理,只讲怎么用、怎么写、怎么排查问题。
目录
-
- 1.1 镜像、容器、仓库是什么
- 1.2 为什么算法工程师需要 Docker
- 1.3 Docker vs 虚拟机 vs Conda
-
- 2.1 镜像操作命令
- 2.2 容器操作命令
- 2.3 常用参数详解
-
- 3.1 核心指令一览表
- 3.2 常用 Dockerfile 模板
- 3.3 编写最佳实践
-
- 4.1 阅读顺序与方法
- 4.2 逐行解读示例
-
- 5.1 网络问题(拉取慢/超时)
- 5.2 GPG 密钥错误
- 5.3 权限问题
- 5.4 磁盘空间不足
- 5.5 GPU 不可用
一、Docker 核心概念(5分钟速通)
1.1 镜像、容器、仓库是什么
用租房来类比,你就能轻松理解 Docker 的核心概念:
| 概念 | 技术术语 | 通俗理解 | 算法场景类比 |
|---|---|---|---|
| 镜像 | Image | 房子的设计图纸 | 一个包含 Ubuntu + CUDA + PyTorch 的压缩包文件 |
| 容器 | Container | 按照图纸建出来的房子 | 镜像运行起来后的隔离环境,可以同时启动多个 |
| 仓库 | Registry | 存放图纸的档案馆 | Docker Hub,类似 GitHub 但存的是镜像 |
| Dockerfile | Dockerfile | 如何制作图纸的说明书 | 描述环境搭建步骤的文本文件 |
一句话总结:
- 从 Dockerfile 出发 → 构建出 镜像(静态的文件)
- 运行 镜像 → 得到 容器(动态的进程)
1.2 为什么算法工程师需要 Docker?
看看这些场景你是否遇到过:
痛点 1 - 环境不一致:
- 你说:"在我电脑上能跑啊"
- 同事说:"我这边报错了"
- 服务器说:"缺少 libxxx.so"
→ Docker 解决:保证环境一模一样
痛点 2 - 环境配置麻烦:
- 要装:CUDA 11.7、cuDNN 8、PyTorch 2.0、OpenCV 4.5、MMCV...
- 还要:编译一些 C++ 库
→ Dockerfile 解决:写一次配置,所有人都能用
痛点 3 - 实验环境冲突:
- 项目 A 需要 PyTorch 1.8
- 项目 B 需要 PyTorch 2.0
→ 容器隔离解决:每个项目有自己的独立环境
痛点 4 - 复现困难:
- 论文代码发布了,但环境配置没写清楚
→ Docker 镜像解决:直接拉镜像就能跑
1.3 Docker vs 虚拟机 vs Conda
| 特性 | Docker | 虚拟机 (VM) | Conda 环境 |
|---|---|---|---|
| 启动速度 | 秒级 | 分钟级 | 毫秒级 |
| 磁盘占用 | MB~GB | GB~几十 GB | 依赖共享 |
| 系统隔离 | 共享宿主机内核 | 完全隔离 | 仅隔离 Python 包 |
| GPU 支持 | ✅ 原生支持 | 需要 GPU 虚拟化 | ✅ 原生支持 |
| 系统级依赖 | ✅ 可以装任何系统库 | ✅ 完整系统 | ❌ 只有 Python 包 |
| 学习成本 | 中等 | 较低 | 很低 |
选择建议:
- 只用 Python 包 → Conda 环境就够了
- 需要系统库(如 OpenCV、CUDA、Boost)→ 用 Docker
- 需要完整复现论文环境 → 用 Docker
- 需要部署到云服务器 → 用 Docker
二、Docker 常用命令速查表
2.1 镜像操作
# 查看本地所有镜像
docker images
docker image ls
# 搜索镜像(在 Docker Hub 上)
docker search pytorch
# 拉取镜像
docker pull ubuntu:20.04
docker pull pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime
# 删除镜像
docker rmi <镜像ID或名称>
docker rmi -f <镜像名> # 强制删除
# 查看镜像详细信息
docker inspect <镜像名>
# 导出/导入镜像(用于离线传输)
docker save -o myimage.tar myimage:tag
docker load -i myimage.tar
# 查看镜像构建历史(看镜像每层做了什么)
docker history myimage:tag
2.2 容器操作
# ========== 运行容器 ==========
# 交互式运行(最常用,进入容器内部操作)
docker run -it ubuntu:20.04 /bin/bash
# 后台运行
docker run -d --name myapp nginx
# 运行后自动删除(适合临时测试)
docker run -it --rm python:3.9 python -c "print('hello')"
# 带 GPU 支持运行
docker run -it --gpus all pytorch/pytorch:2.0.0-cuda11.7 /bin/bash
# ========== 查看容器 ==========
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器(包括已停止的)
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" # 自定义格式
# ========== 进入运行中的容器 ==========
docker exec -it <容器名> /bin/bash # 最常用,新开一个 shell
docker attach <容器名> # 附加到主进程
# ========== 容器的生命周期 ==========
docker stop <容器名> # 停止容器
docker start <容器名> # 启动已停止的容器
docker restart <容器名> # 重启容器
docker rm <容器名> # 删除容器(需要先停止)
docker rm -f <容器名> # 强制删除(不需要停止)
# ========== 查看容器信息 ==========
docker logs <容器名> # 查看日志
docker logs -f <容器名> # 实时跟踪日志
docker inspect <容器名> # 查看容器详细信息
docker stats # 查看所有容器资源占用
2.3 常用参数详解
docker run 命令有很多参数,记住这几个就够了:
docker run [参数] 镜像名 [命令]
参数 # 说明
-it # 交互式运行(一定要加,否则进不去)
-d # 后台运行(守护模式)
--rm # 容器退出时自动删除(强烈推荐:避免一堆僵尸容器)
--name <名字> # 给容器起个名字,方便管理
-p 8080:80 # 端口映射:主机:容器
-v /host/path:/container/path # 挂载目录:让宿主机和容器共享文件
--gpus all # 使用所有 GPU(需要 nvidia-docker)
-w /workspace # 设置工作目录(进入容器默认在这个目录)
-e KEY=value # 设置环境变量
--network host # 使用宿主机网络(网络性能更好)
--privileged # 特权模式(访问宿主机设备)
--shm-size 2G # 设置共享内存大小(PyTorch DataLoader 需要)
实战示例:
# 算法工程师最常用的运行命令
docker run -it --rm \
--gpus all \
--name my_exp \
-v $PWD:/workspace \
-w /workspace \
--shm-size 4G \
my-pytorch-image:latest \
/bin/bash
三、Dockerfile 编写指南
3.1 核心指令一览表
| 指令 | 用途 | 示例 |
|---|---|---|
FROM | 指定基础镜像(第一行必须是它) | FROM ubuntu:20.04 |
RUN | 构建时执行命令(每行会创建一层) | RUN apt-get install -y python3 |
COPY | 复制文件到镜像 | COPY ./requirements.txt /app/ |
ADD | 增强版 COPY(支持 URL 和自动解压) | ADD https://xxx.tar.gz /tmp/ |
WORKDIR | 设置工作目录(后面的命令都在此目录执行) | WORKDIR /app |
ENV | 设置环境变量(运行时也存在) | ENV CUDA_VISIBLE_DEVICES=0 |
ARG | 构建参数(只在构建时存在) | ARG VERSION=1.0 |
CMD | 容器启动默认命令(可被覆盖) | CMD ["python", "train.py"] |
ENTRYPOINT | 容器启动固定命令(不可被覆盖) | ENTRYPOINT ["python"] |
EXPOSE | 声明容器监听的端口(文档作用) | EXPOSE 8080 |
VOLUME | 声明挂载点 | VOLUME /data |
USER | 切换用户(安全起见不要用 root) | USER appuser |
RUN、CMD、ENTRYPOINT 的区别(最容易混淆):
| 指令 | 执行时机 | 能否被 docker run 覆盖 |
|---|---|---|
RUN | docker build 时 | 否 |
CMD | docker run 时 | ✅ 可以 |
ENTRYPOINT | docker run 时 | ❌ 不能 |
# 示例理解
CMD ["python", "train.py"]
# docker run myimage → 执行 python train.py
# docker run myimage python app.py → 执行 python app.py(覆盖 CMD)
ENTRYPOINT ["python"]
CMD ["train.py"]
# docker run myimage → 执行 python train.py
# docker run myimage app.py → 执行 python app.py(覆盖 CMD)
3.2 算法工程化典型 Dockerfile 模板
模板1:PyTorch 训练环境
# 1. 选择基础镜像(官方 PyTorch 已包含 CUDA + cuDNN)
FROM pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime
# 2. 设置环境变量(避免交互式询问)
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai
# 3. 更换 apt 源为国内源(加速下载)
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# 4. 安装系统依赖
RUN apt-get update && apt-get install -y \
libgl1-mesa-glx \ # OpenCV 需要
libglib2.0-0 \ # OpenCV 需要
ffmpeg \ # 视频处理
git \
vim \
&& rm -rf /var/lib/apt/lists/* # 清理缓存,减小镜像体积
# 5. 复制依赖文件并安装 Python 包
COPY requirements.txt /tmp/
RUN pip install --no-cache-dir -r /tmp/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 6. 复制项目代码
COPY . /workspace/
# 7. 设置工作目录
WORKDIR /workspace
# 8. 设置容器启动命令
CMD ["python", "train.py"]
模板2:Ubuntu + CUDA 最小环境
FROM nvidia/cuda:11.7.1-devel-ubuntu20.04
ENV DEBIAN_FRONTEND=noninteractive
# 换源
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# 安装基础工具
RUN apt-get update && apt-get install -y \
python3.9 \
python3-pip \
git \
cmake \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# 创建软链接
RUN ln -s /usr/bin/python3.9 /usr/bin/python
# 安装 Python 包
RUN pip3 install --upgrade pip && \
pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cu117
# 设置工作目录
WORKDIR /workspace
CMD ["/bin/bash"]
模板3:多阶段构建(减小镜像体积)
# 阶段1:编译阶段(大体积,包含编译工具)
FROM ubuntu:20.04 AS builder
RUN apt-get update && apt-get install -y build-essential cmake
COPY . /src
RUN cd /src && mkdir build && cd build && cmake .. && make
# 阶段2:运行阶段(小体积,只复制编译好的文件)
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y libstdc++6
COPY --from=builder /src/build/myapp /usr/local/bin/
CMD ["myapp"]
3.3 编写最佳实践
最佳实践清单:
✅ 1. 合并 RUN 命令:
# 错误(产生多层)
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get clean
# 正确(只有一层)
RUN apt-get update && \
apt-get install -y python3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
✅ 2. 清理缓存:
- 每执行 apt-get install 后都要 rm -rf /var/lib/apt/lists/*
- pip install 加 --no-cache-dir
✅ 3. 利用 Docker 缓存:
- 把不容易变化的命令放前面(安装依赖)
- 把容易变化的命令放后面(复制代码)
✅ 4. 指定版本号:
- 不要写 FROM ubuntu:latest(可能不稳定)
- 写 FROM ubuntu:20.04
✅ 5. 使用 .dockerignore:
- 和 .gitignore 类似,排除不需要的文件
- 排除 .git、__pycache__、.idea 等
✅ 6. 非 root 用户运行:
RUN useradd -m appuser && \
chown -R appuser:appuser /workspace
USER appuser
四、如何看懂现有 Dockerfile
4.1 阅读顺序与方法
Dockerfile 是从上往下执行的,阅读时按顺序看每一行:
- 第一行看
FROM:知道基于什么系统 - 看
ENV:了解环境变量 - 看
RUN:知道装了什么东西 - 看
COPY/ADD:知道复制了什么文件 - 看
WORKDIR:知道工作目录 - 看
CMD/ENTRYPOINT:知道容器启动做什么
4.2 逐行解读示例
以一个常见的问题 Dockerfile 为例(就是你在构建中遇到的那个):
# 第1行:基础镜像
FROM osrf/ros:melodic-desktop-full
# 解读:基于 ROS Melodic 完整版(Ubuntu 18.04)
# 第2-3行:环境变量
ENV DEBIAN_FRONTEND=noninteractive
# 解读:防止 apt-get 弹出交互式对话框
# 第4-5行:换源(加速下载)
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# 解读:把 Ubuntu 官方源换成阿里云镜像
# 第6-8行:系统依赖安装
RUN apt-get update && apt-get install -y \
wget cmake build-essential git \
&& rm -rf /var/lib/apt/lists/*
# 解读:安装基础编译工具
# 第9-11行:ceres-solver 安装
WORKDIR /home/thirdParty
RUN wget https://github.com/ceres-solver/ceres-solver/archive/1.14.0.tar.gz
# 解读:下载并编译安装 ceres-solver(非线性优化库)
# 第12-14行:用户配置
RUN useradd -m cidi && echo 'cidi:1' | chpasswd
USER cidi
# 解读:创建普通用户,切换到该用户(安全考虑)
4.3 怎么看镜像里有什么?
# 方法1:查看镜像历史(每层做了什么)
docker history myimage:tag --no-trunc
# 方法2:运行容器进去看
docker run -it myimage:tag /bin/bash
ls -la
pip list
# 或者把文件拷贝出来看
docker cp container:/path/to/file ./
# 方法3:查看镜像元数据
docker inspect myimage:tag | grep -A 10 "Cmd"
五、常见问题排查指南
5.1 网络问题(拉取慢/超时)
现象:
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
解决方案:
# 方案1:配置国内镜像源
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
sudo systemctl restart docker
# 方案2:构建时使用 host 网络
docker build --network=host -t myimage .
# 方案3:手动拉取后重命名(如果 Docker Hub 拉不下来)
docker pull docker.mirrors.ustc.edu.cn/library/ubuntu:20.04
docker tag docker.mirrors.ustc.edu.cn/library/ubuntu:20.04 ubuntu:20.04
5.2 GPG 密钥错误
现象:
W: GPG error: http://snapshots.ros.org ... InRelease: The following signatures were invalid: EXPKEYSIG
E: The repository '...' is not signed.
解决方案:
# 方案1:删除有问题的源
RUN rm -f /etc/apt/sources.list.d/ros1-snapshots.list 2>/dev/null || true
# 方案2:更新密钥
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys AD19BAB3CBF125EA
# 方案3:忽略 GPG 检查(临时方案)
RUN apt-get update --allow-insecure-repositories || true && \
apt-get install -y --allow-unauthenticated <包名>
5.3 权限问题
现象:
Permission denied
cannot create directory: Permission denied
解决方案:
# 方案1:切回 root 用户(构建时)
USER root
# 方案2:创建目录后修改权限
RUN mkdir -p /workspace && chmod 777 /workspace
# 方案3:使用正确的用户(推荐)
RUN useradd -m -s /bin/bash appuser
USER appuser
5.4 磁盘空间不足
现象:
no space left on device
解决方案:
# 查看 Docker 占用
docker system df
# 清理空间
docker system prune -a # 删除所有未使用的
docker container prune # 删除停止的容器
docker image prune -a # 删除未使用的镜像
docker volume prune # 删除未使用的卷
# 迁移 Docker 数据目录(如果 /var 分区小)
sudo systemctl stop docker
sudo mv /var/lib/docker /home/docker_data
sudo ln -s /home/docker_data /var/lib/docker
sudo systemctl start docker
5.5 GPU 不可用
现象:
CUDA error: no CUDA-capable device is detected
torch.cuda.is_available() 返回 False
解决方案:
# 方案1:安装 nvidia-container-toolkit
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker
# 方案2:运行容器时加 --gpus all
docker run -it --gpus all pytorch/pytorch /bin/bash
# 方案3:指定使用哪些 GPU
docker run -it --gpus '"device=0,1"' pytorch/pytorch /bin/bash
5.6 容器启动就退出
现象:
容器启动后立刻退出
原因:
容器没有前台进程在运行
解决方案:
# 方案1:交互式运行(加 -it)
docker run -it myimage /bin/bash
# 方案2:后台运行一个长期进程
docker run -d myimage tail -f /dev/null
# 方案3:在 Dockerfile 中确保 CMD 是前台进程
CMD ["python", "train.py"] # ⭕ 前台运行
# CMD ["service", "start"] # ❌ 后台启动会退出
5.7 常用调试技巧
# 技巧1:临时运行一个容器调试
docker run -it --rm ubuntu:20.04 /bin/bash
# 然后在容器里手动执行命令,看哪一步出错
# 技巧2:查看构建失败的层
docker build --no-cache -t myimage .
# 报错会显示是哪一层,可以用这个 ID 进入
docker run -it <上一层镜像ID> /bin/bash
# 技巧3:查看构建历史
docker history myimage:tag --no-trunc
# 技巧4:保存构建日志
docker build --network=host -t myimage . 2>&1 | tee build.log
六、实战:从零写一个算法环境 Dockerfile
场景需求
你要训练一个点云分割模型,需要:
- Ubuntu 20.04 + CUDA 11.7 + PyTorch 2.0
- Open3D、numpy、scipy
- 系统库:libgl1(Open3D 需要)
步骤1:确定基础镜像
去 Docker Hub 搜索 pytorch,找到官方镜像:
pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime
这个镜像已经包含了 CUDA、cuDNN、PyTorch。
步骤2:编写 Dockerfile
# 1. 基础镜像
FROM pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime
# 2. 设置环境变量(避免交互)
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai
# 3. 换源(加速)
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# 4. 安装系统依赖
RUN apt-get update && apt-get install -y \
libgl1-mesa-glx \
libglib2.0-0 \
git \
vim \
&& rm -rf /var/lib/apt/lists/*
# 5. 安装 Python 包
COPY requirements.txt /tmp/
RUN pip install --no-cache-dir -r /tmp/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 6. 复制代码
COPY . /workspace/
# 7. 设置工作目录
WORKDIR /workspace
# 8. 默认命令
CMD ["python", "train.py"]
步骤3:创建 requirements.txt
numpy
open3d
scipy
tqdm
步骤4:构建镜像
docker build --network=host -t pointcloud-seg:latest .
步骤5:运行容器
docker run -it --rm \
--gpus all \
-v $PWD:/workspace \
pointcloud-seg:latest \
/bin/bash
七、总结:快速自查清单
构建失败时(docker build)
□ 1. 网络问题?→ 加 --network=host 或配置国内镜像
□ 2. GPG 错误?→ 删除有问题的源或更新密钥
□ 3. 找不到文件?→ 检查 COPY 路径是否正确
□ 4. 权限问题?→ 加 USER root 或修改权限
□ 5. 磁盘不足?→ docker system prune -a
运行失败时(docker run)
□ 1. 容器秒退?→ 加 -it 交互式运行
□ 2. GPU 不可用?→ 加 --gpus all
□ 3. 端口冲突?→ 换一个主机端口 -p 8081:80
□ 4. 挂载不生效?→ 检查路径是绝对路径
□ 5. 进不去容器?→ 用 docker exec -it 进入
Dockerfile 编写规范
□ 1. FROM 指定具体版本(不用 latest)
□ 2. 多个 RUN 合并成一个
□ 3. 安装后清理缓存
□ 4. 利用 .dockerignore 排除不需要的文件
□ 5. 考虑使用非 root 用户运行
记住这 5 个最常用的命令
# 1. 构建镜像
docker build -t myimage:tag .
# 2. 运行容器(算法工程师最常用)
docker run -it --rm --gpus all -v $PWD:/workspace myimage:tag /bin/bash
# 3. 进入运行中的容器
docker exec -it <容器名> /bin/bash
# 4. 查看所有容器
docker ps -a
# 5. 清理空间
docker system prune -a
最后的话:Docker 并不难,关键是理解"镜像=静态文件,容器=运行进程"这个概念。遇到问题时,记住:先看报错信息,然后用
docker run -it --rm交互式调试,最后用docker exec进入容器排查。熟练之后,你会发现 Docker 是算法工程化的最佳伙伴。
更多推荐

所有评论(0)