第2章 Docker 基础概念
聊 Docker,绕不开三个核心概念:镜像、容器、仓库。外加一个架构图。嗯,说实话,我刚接触 Docker 时最晕的就是这几个词——长得像,又不完全一样。我习惯用「菜谱、菜、菜市场」来打比方,你想想看,是不是好记很多?
2.1 镜像(Image)—— 菜谱
镜像是一个只读模板。它打包了程序运行所需的一切:
- 操作系统底层(比如 Alpine、Ubuntu)
- 运行时环境(Python 3.11、Node 18)
- 应用代码和配置文件
- 环境变量、端口声明、挂载点
我个人习惯用 docker images 查看本地已有的镜像。你在项目初期可以先从 Docker Hub 拉一个现成的:
docker pull python:3.11-slim
这条命令会从 Docker Hub 把 Python 3.11 的精简版镜像拽到本地。镜像由一层一层可叠加的只读层组成,每一层都是一个文件系统的变更记录。这个分层机制是 Docker 的精髓——复用层,节省空间,加速构建。
FROM --stage,生产环境里能省不少磁盘和带宽。
镜像的名称格式一般是:用户名/镜像名:标签。标签默认 latest,但我建议你永远用确定版本号,比如 python:3.11-slim 而不是 python:latest——为什么?因为 latest 会随着官方更新变化,今天拉的和下周拉的可能不是同一个东西。避坑啊。
2.2 容器(Container)—— 菜
容器是镜像的运行实例。你按照菜谱做好一道菜,端上桌的就是容器。每个容器都是一个隔离的进程,拥有自己的:
- 文件系统(基于镜像层 + 可写层)
- 网络栈(独立 IP 和端口映射)
- 进程空间(pid 隔离)
- 用户组(uid/gid 隔离)
启动一个容器很简单:
docker run -d --name my-app -p 8080:80 nginx:alpine
这条命令:后台运行一个容器,名字叫 my-app,把宿主机 8080 端口映射到容器内 80 端口,基于 nginx:alpine 镜像。
--rm 参数,测试容器用完不删,结果一周下来宿主机磁盘爆满。现在只要不是持久化场景,我都会加 --rm 让容器退出时自动清理。
容器和镜像的核心区别看下表:
| 维度 | 镜像 | 容器 |
|---|---|---|
| 生命周期 | 持久存储(可删除) | 临时实例(可创建/停止/删除) |
| 读写状态 | 只读 | 可写(可写层) |
| 命名 | 镜像名:标签 | 容器名(或随机ID) |
| 体积 | 较大(分层复用) | 启动后增加约几KB(可写层) |
| 使用场景 | 构建、分发 | 运行、调试 |
2.3 仓库(Registry)—— 菜市场
仓库用来存储和分发镜像。Docker Hub 是最大的公共仓库,但企业环境一般用私有仓库,比如 Harbor、GitLab Container Registry、AWS ECR。
推送一个镜像到仓库:
docker tag my-image:latest my-registry.com/library/my-image:v1.0
docker push my-registry.com/library/my-image:v1.0
拉取命令刚好相反。你想想看,整个 CI/CD 流程里,仓库就像中间件——源码编译成镜像,推送到仓库,再部署到生产节点。我在项目中就用 Harbor 搭建私有仓库,做好镜像扫描和访问控制,安全又高效。
<应用名>:<版本号>-<构建号>,比如 drug-graph:1.2.3-b20250315,一眼能看出哪个版本、哪次构建。
2.4 Docker 架构
Docker 采用 C/S(客户端/服务端)架构。三个主要角色:
- Docker Client:你敲
docker命令的终端,本质是一个 CLI 工具。 - Docker Daemon:后台守护进程,负责管理镜像、容器、网络、卷等。通常叫
dockerd。 - Docker Registry:镜像仓库,Client 和 Daemon 都能与之交互推拉镜像。
整个交互流程我用一张图表示:
底层技术主要依赖 Linux 内核的 NameSpaces(实现资源隔离)和 Cgroups(实现资源限制)。我刚开始学的时候觉得这是黑魔法,后来亲手写了几个 pid namespace 的小 demo 才真正理解。不过你现在不需要深挖内核,先用好 Docker 命令,后续有专门的章节讲安全与资源控制。
好,三个概念都讲完了。我来用一个实际的小实验帮你串联起来:
- 拉一个
hello-world镜像:docker pull hello-world - 查看本地镜像:
docker images - 启动容器:
docker run hello-world - 查看容器列表(包括刚停止的):
docker ps -a - 删除容器:
docker rm <容器ID> - 删除镜像:
docker rmi hello-world
自己去试试看。你想想看,这几条命令走完,镜像、容器、仓库的关系是不是就清晰了?后面我们就把这些基础运用到药物图谱的 Docker 部署上,嗯,那才是真正有意思的部分。