上一篇 《Docker 入门:为什么容器化是 AI 时代的必备技能》 我们讲了 Docker 解决了什么问题。这一篇我们把 Docker 世界的四个核心概念拆开看清楚,并完成你人生中的第一次镜像构建。
一、Docker 的四大核心概念
1.1 镜像(Image)
- 定义:镜像是一个只读的模板,包含运行应用程序所需的一切:代码、运行时、库、环境变量、配置文件。
- 类比:如果你熟悉 OOP,可以把镜像理解为一个类(Class)。它定义了应用应该长什么样,但它本身是静态的、不可运行的。
- 特性:分层结构(Layered Filesystem)。Docker 镜像是通过一系列「层」构建的,每一层对应
Dockerfile中的一条指令。这种设计让构建、存储、分发非常高效——多个镜像可以共享相同的基础层(base layer),拉取时只下载差异部分。
1.2 容器(Container)
- 定义:容器是镜像的一个可运行实例。它在镜像的只读层之上增加了一个可写层,用于存储运行时产生的数据与状态变更。
- 类比:容器就是类(Image)创建出来的对象(Object)。同一个镜像可以创建出无数个相互隔离的容器。
- 特性:
- 轻量级:与虚拟机(VM)不同,容器与宿主机共享 OS 内核,启动是秒级,资源占用极小。
- 隔离性:每个容器都有自己独立的文件系统、进程空间、网络栈,相互隔离。
1.3 仓库(Registry)
- 定义:仓库是集中存放和分发镜像的服务。
- 类比:可以把它理解为代码世界的 GitHub 或 Java 世界的 Maven Central。
- 分类:
- 公共仓库:最著名的就是 Docker Hub,托管了海量官方和第三方镜像。
- 私有仓库:企业可以搭建自己的私有仓库(如 Harbor、阿里云 ACR、AWS ECR)存储内部镜像。
1.4 Dockerfile
- 定义:
Dockerfile是一个文本文件,包含一系列指令,告诉 Docker 如何自动构建一个镜像。 - 类比:
Dockerfile是构建镜像的「食谱」或「说明书」。 - 常用指令概览:
FROM:指定基础镜像,所有构建都始于一个基础镜像。WORKDIR:设置工作目录,后续指令都在此目录下执行。COPY:将本地文件或目录复制到镜像中。RUN:在镜像构建过程中执行命令(如pip install)。CMD:指定容器启动时默认执行的命令。ENTRYPOINT:与CMD类似,但更常用于把容器配置为可执行程序。EXPOSE:声明容器运行时监听的端口(仅声明,不会自动发布)。
二、环境准备与安装
2.1 安装 Docker
根据操作系统访问官方文档:
- Windows:Install Docker Desktop on Windows
- Mac:Install Docker Desktop on Mac
- Linux (Ubuntu):Install Docker Engine on Ubuntu
安装完成后打开终端验证:
docker --version
# 输出类似 Docker version 28.5.1, build 4debf41
2.2 配置镜像加速(大陆网络必需)
Docker Hub 在大陆访问较慢,需要配置镜像加速器。在 /etc/docker/daemon.json 中加入:
{
"registry-mirrors": [
"https://8vn26jg9.mirror.aliyuncs.com",
"https://fy707np5.mirror.aliyuncs.com"
]
}
然后重启 Docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
2.3 在容器里装常用工具
刚装好的官方镜像通常很精简,连 vim 都没有。容器内安装命令:
# Debian/Ubuntu 系
apt-get update && apt-get install -y vim curl
# Alpine 系
apk add vim curl
如果出现 Unable to locate package xxx,先 apt-get update 再装。
三、常用命令实战
3.1 镜像相关
docker pull nginx # 拉取镜像
docker images # 列出本地所有镜像
docker rmi nginx # 删除镜像
docker save -o nginx.tgz nginx # 导出镜像到本地文件
docker load < nginx.tgz # 从本地文件导入镜像
docker history nginx # 查看镜像的层信息
docker search mysql # 在仓库搜索镜像
3.2 容器相关
# 创建并启动
docker run -d -p 8080:80 --name my-nginx nginx
# -d detach,后台运行
# -p 8080:80 宿主机 8080 -> 容器 80
# --name 容器名
docker ps # 正在运行的容器
docker ps -a # 所有容器(含已停止)
docker ps -aq # 只显示容器 ID
docker stop my-nginx # 停止
docker start my-nginx # 启动已停止的
docker rm my-nginx # 删除已停止的
docker rm -f my-nginx # 强制删除运行中的
docker logs -f my-nginx # 查看日志(-f 持续跟踪)
docker exec -it my-nginx bash # 进入容器内的 bash 终端
3.3 容器与镜像的转换
docker commit <container> my-image:1.0 # 把容器的当前状态提交成新镜像
docker build -t my-image:1.0 . # 从 Dockerfile 构建镜像
3.4 组合命令
# 一键删除所有容器
docker rm -f $(docker ps -aq)
# 一键删除所有「已退出」的容器
docker rm $(docker ps -qf "status=exited")
四、动手构建第一个应用镜像
我们用 FastAPI 写一个最简单的 /ping 服务,然后把它打包成 Docker 镜像。
4.1 准备项目
poetry new docker-test
cd docker-test
poetry install
source .venv/bin/activate
poetry add fastapi
poetry add uvicorn
4.2 写主程序
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/ping")
def ping():
return {"message": "pong"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
4.3 写 Dockerfile
在 docker-test 根目录创建 Dockerfile(无后缀):
# 1. 选一个轻量且带 Python 环境的基础镜像
FROM python:3.12-slim
# 2. 设置工作目录
WORKDIR /app
# 3. 安装 poetry
ENV POETRY_HOME=/opt/poetry
ENV PATH="$POETRY_HOME/bin:$PATH"
RUN apt-get update && apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/* \
&& curl -sSL https://install.python-poetry.org | python3 -
# 4. 让 poetry 不要在项目目录内创建虚拟环境
RUN poetry config virtualenvs.create false
# 5. 先只复制依赖定义文件,利用 Docker 层缓存
COPY pyproject.toml poetry.lock ./
# 6. 安装项目依赖(不安装本地项目本身)
RUN poetry install --no-interaction --no-ansi --only main --no-root
# 7. 复制应用代码
COPY ./src/docker_test/main.py .
# 8. 声明端口
EXPOSE 8000
# 9. 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
4.4 构建与运行
# 构建镜像
docker build -t docker-test .
# 第一次构建会下载基础镜像和所有依赖,可能需要几分钟
# 看到 "Successfully built xxx" + "Successfully tagged docker-test:latest" 就成功了
# 查看镜像
docker images
# 会看到名字为 docker-test 的镜像
# 启动容器
docker run -d -p 8000:8000 --name docker-test docker-test
# 看启动日志
docker logs docker-test
# 测试接口
curl localhost:8000/ping
# {"message":"pong"}
恭喜!你已经成功将一个 AI 应用容器化了。
五、镜像优化与安全
5.1 使用 .dockerignore
类似 .gitignore,可以避免把不需要的文件复制进镜像:
# .dockerignore
.git
.gitignore
__pycache__/
*.py[cod]
venv/
.venv/
.env
.DS_Store
*.log
.pytest_cache/
README.md
5.2 选更小的基础镜像
python:3.12-slim比python:3.12小很多alpine更小但可能缺一些工具链,部分 AI 框架未必兼容- 对于 GPU 推理,使用 NVIDIA 官方基础镜像(带 CUDA + cuDNN)
5.3 多阶段构建(Multi-stage Builds)
把构建过程和最终运行环境分开——一个阶段编译代码,另一个阶段只把产物复制到干净轻量的最终镜像中。对编译型语言效果显著,对 Python 也能用来分离构建依赖和运行依赖。
5.4 不要以 root 运行容器
RUN useradd -m myuser
USER myuser
5.5 扫描镜像漏洞
docker scan my-image:1.0 # 集成 Snyk
# 或使用 Trivy
trivy image my-image:1.0
六、小结
这一篇你掌握了:
- Docker 的四大核心概念:镜像 / 容器 / 仓库 / Dockerfile
- 完成了 Docker 安装、镜像加速配置
- 跑通了容器生命周期全部命令
- 写出了第一个
Dockerfile并成功构建 + 启动 FastAPI 服务 - 了解了镜像优化与安全的基础原则
下一篇 《Docker 数据持久化与网络:Volume 与容器间通信》 我们会讲容器「短暂的生命」和「隔离的边界」带来的两个新问题——数据怎么不丢、容器之间怎么对话。