7.1 镜像、容器与运行边界
前置知识:第2章终端基础、第6章错误与日志
预计时间:15 分钟
练习环境:Bash、curl 7.71+、Docker Engine 28+,使用默认 bridge/NAT 网络;首次使用示例镜像时需要访问 registry
完成标志:能区分镜像、容器和仓库,并安全运行、观察、清理一个容器
“在我电脑上能跑”通常只证明你的电脑很配合。操作系统、CPU 架构、运行时、系统库、依赖和配置都可能不同。容器不会让差异消失,但能把一组运行条件做成可重复交付的镜像。
四个概念先分开
| 概念 | 含义 |
|---|---|
| Registry | 存放、分发镜像的服务;Docker Hub 是一个例子 |
| Image | 只读镜像层、配置和元数据组成的模板 |
| Container | 镜像配置启动出的进程,加上自己的可写层和运行时设置 |
| Layer | 镜像中可复用、内容寻址的只读文件系统变化 |
镜像是不变的输入,容器是由它启动的一次运行实例。同一镜像可以启动多个容器,每个容器有独立的可写层和运行时配置。它的核心仍是主机上的进程,不是一台完整虚拟机。
容器没有打包什么
- Linux 容器共享运行它的 Linux 内核;它没有自带一套独立内核。
- Windows 和 macOS 上的 Docker Desktop 通常通过 Linux 虚拟机运行 Linux 容器。
- 镜像仍受 CPU 架构和目标平台约束,不能承诺在任何机器上原样运行。
- 密码、部署地址和环境差异配置通常应在运行时注入,不能全烤进镜像。
- 容器隔离依赖 namespace、cgroup、capability、seccomp 等机制;它不是无条件的安全边界。
先做只读检查
docker version
docker compose version
docker image ls
docker container ls --alldocker version 同时检查客户端和服务端。只有客户端版本而服务端报错,通常表示 Docker daemon 或 Docker Desktop 尚未可用。
运行第一个 Web 容器
下面用本机随机空闲端口,并只绑定回环地址,避免把练习服务暴露给局域网:
(
set -e
container_id=$(docker run --detach --rm \
--publish 127.0.0.1::80 nginx:latest)
trap 'docker stop "$container_id" >/dev/null 2>&1 || true' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
published=$(docker port "$container_id" 80/tcp)
printf 'published=%s\n' "$published"
host_port=${published##*:}
curl --fail --silent --show-error --retry 10 --retry-all-errors \
--retry-delay 1 --max-time 2 "http://127.0.0.1:$host_port/"
docker logs "$container_id"
)圆括号创建子 Shell,成功启动后只记录本次返回的容器 ID;退出时清理该容器,避免固定名字与其他练习冲突。curl 使用有上限的重试等待 Nginx 启动。docker port 的输出才是本机实际端口,脚本没有猜固定值。--rm 表示容器停止后自动删除;镜像不会随之删除。
本例要求 Engine 28+;更早版本存在同一二层网络可访问 localhost 发布端口的历史问题,不能套用本页的回环访问结论。--publish 127.0.0.1::80 才负责端口发布。Dockerfile 的 EXPOSE 80 只是元数据说明,不会自动开放主机端口。省略主机 IP 的 -p 8080:80 默认可能监听所有主机地址,练习时不必扩大暴露面。
容器与虚拟机的边界
Linux 容器通常不需要为每个实例启动完整 guest kernel,因此常见场景下启动更快、额外开销更小。但镜像大小可以从几 MB 到数 GB,启动也受应用初始化、存储和网络影响,不能写成固定“毫秒级”或“只有几 MB”。
虚拟机提供独立 guest kernel,隔离模型不同。实际系统也常把容器运行在虚拟机里,两者并非互斥方案。
离开这一页前
- 能解释 registry、image、container、layer 的区别;
- 能说明 Linux 容器共享内核,以及 Docker Desktop 的虚拟机边界;
- 能找出随机发布端口、读取日志,并只停止自己创建的容器;
- 知道
EXPOSE不等于--publish。
你已经安全运行并清理了现成镜像。下一步是用 Dockerfile 定义自己的文件、运行时和启动命令。端口发布的安全边界可继续核对 Docker 官方文档。