一、安装 Docker:三分钟上桌
小陈在服务器上装 Docker(以 CentOS 为例):
# 安装 Docker(CentOS 7+)
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
# 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 验证
docker --version # Docker version 24.0.x
docker run hello-world # 跑起第一个容器!
小陈看到屏幕上出现 "Hello from Docker!",兴奋地喊:"师傅!跑起来了!"
"别急,先搞懂你刚才干了什么。刚才那条 docker run hello-world 背后发生了四件事:"
docker run hello-world 发生了什么:
① Docker 发现本地没有 hello-world 镜像
② 去 Docker Hub(官方镜像仓库)下载 hello-world 镜像
③ 用镜像创建一个容器并运行
④ 容器打印 Hello,执行完毕,退出
恭喜:你已经完成了"拉镜像 + 跑容器 + 容器退出"全流程!
二、镜像(Image):只读的"图纸"
"先讲镜像(Image)。"老周说:
镜像(Image):
定义:一个只读的、不可变的"模板"——包含应用和它需要的所有东西
(代码、运行时、依赖、配置、环境变量……)
特点:
① 只读(不可变):镜像一旦构建,内容不能改
② 分层:由一层层"只读层"堆叠而成(第三章细讲)
③ 可复用:同一个镜像能创建无数个容器
④ 可共享:能上传/下载(镜像仓库,第八章)
类比:
镜像 = 做蛋糕的"模具"(固定的、不变的)
容器 = 用模具做出来的"蛋糕"(可以有很多个)
镜像 = 图纸,容器 = 按图纸盖的房子
# 镜像相关命令
docker images # 查看本地有哪些镜像
docker pull nginx:1.25 # 拉取镜像(从仓库)
docker rmi nginx:1.25 # 删除镜像
docker tag nginx:1.25 yunjian/nginx:v1 # 给镜像打标签
"记住:镜像是不变的图纸,你永远不会'修改'镜像,只会'基于它'创建新镜像。"
三、容器(Container):可变的"实物"
"容器(Container)是镜像运行起来之后的实例——就是那个'按图纸盖出来的房子'。"老周说:
容器(Container):
定义:镜像的"运行实例"——一个隔离的、可运行的进程环境
特点:
① 可写:容器内可以改文件(但改的是容器自己的可写层)
② 隔离:有自己的文件系统、进程、网络(namespace 隔离)
③ 有生命周期:创建 → 运行 → 停止 → 删除
④ 可移植:同一镜像在任何机器上跑出的容器行为一致
镜像 vs 容器:
镜像 = 类(Class) 容器 = 对象(实例)
镜像 = 图纸 容器 = 房子
一个镜像 → 可以创建 N 个容器
# 容器相关命令
docker run -d --name web01 nginx # 后台运行一个 nginx 容器
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器(含已停止)
docker stop web01 # 停止容器
docker start web01 # 启动容器
docker rm web01 # 删除容器
"镜像负责'不变'(标准),容器负责'多变'(运行)。 这就是容器世界的第一个哲学:标准化的图纸 + 可复制的实例。"
四、容器是怎么"隔离"出来的:Namespace 与 Cgroup
"你可能好奇:容器没有自己的内核,凭什么能'互不干扰'?"老周说,"靠两个 Linux 内核机制:"
① Namespace(命名空间):"看不见别人"
把系统资源"分区"——每个容器只能看到自己的那部分:
- PID namespace:容器只能看到自己的进程(看不到别的容器进程)
- Network namespace:容器有自己的网络栈(自己的 IP、端口)
- Mount namespace:容器有自己的文件系统视图
- User namespace:容器里的 root 不是真 root(权限隔离)
效果:容器 A 和容器 B 互相"看不见"对方
② Cgroup(控制组):"抢不过别人"
限制每个容器能用的资源:
- CPU 上限:这个容器最多用 2 核
- 内存上限:最多 512MB(超了?杀进程!)
- IO 带宽、网络带宽限制
效果:容器 A 吃爆 CPU,也抢不走容器 B 的份额
# 给容器设置资源限制(Cgroup 的用法)
docker run -d --name web01 \
--cpus=1.5 \ # 最多用 1.5 核
--memory=512m \ # 最多 512MB 内存
nginx
# 进入容器看 namespace 隔离
docker exec -it web01 bash # 进入容器
ps aux # 只能看到容器自己的进程!
"Namespace 负责'看不见'(隔离视角),Cgroup 负责'抢不过'(限制资源)。 这两个内核机制,就是容器'轻量隔离'的底层秘密——不需要完整操作系统,靠内核自带的功能就够了。"
五、镜像/容器/仓库:Docker 世界的"三件套"
"Docker 最核心的三个概念,你现在都见过了:镜像(Image)、容器(Container)、仓库(Registry)。"老周画:
┌─────────┐ pull(下载) ┌──────────┐
│ 仓库 │ ◀──────────────── │ 镜像 │
│ Registry │ │ Image │
│ (Docker │ push(上传) │ (图纸) │
│ Hub/私服)│ ─────────────────▶ │ │
└─────────┘ └────┬─────┘
│ run(创建)
▼
┌──────────┐
│ 容器 │
│ Container │
│ (实例) │
└──────────┘
工作流:
写 Dockerfile → 构建镜像(build)→ 推送到仓库(push)
→ 别的机器拉镜像(pull)→ 跑容器(run)
Docker Hub:官方的公共镜像仓库(就像"应用商店")
私有仓库:企业内部自建(Harbor 等,第八章讲)
"记一个动作链:build → push → pull → run。 这就是容器应用从开发到上线的完整路径。你以后看任何容器相关的工作流,都是这四步的变形。"
六、章末:老周的第一层总结
第一层:容器基础
├── 镜像(Image):只读图纸,不变、分层、可复用
├── 容器(Container):镜像的运行实例,可写、隔离、有生命周期
├── 仓库(Registry):镜像的"应用商店"(Docker Hub/私有仓库)
├── Namespace:隔离"看不见"(进程/网络/文件系统/用户)
├── Cgroup:限制"抢不过"(CPU/内存/IO 上限)
└── 三件套工作流:build → push → pull → run
"小陈,你现在能跑起别人的镜像了(nginx、hello-world)。但那些都是现成的——你还没做过自己的'图纸'。 下一章,我们写你的第一个 Dockerfile,把云间书店的 AI 荐书服务'装进集装箱'。记住那句话:容器不是用来跑 hello world 的,是用来打包你的业务的。"