3. Docker容器管理:从生到死的完整掌控
容器管理,说白了就是管好你的应用进程。我刚开始用Docker时,总觉得容器就是个轻量级虚拟机,后来踩了不少坑才明白——容器就是个特殊进程,生命周期你得心里有数。
3.1 容器生命周期:五态模型
一个容器从创建到销毁,会经历五个状态。我习惯把这五个状态记成「创启运停删」,好记又实用。
| 状态 | 说明 | 对应命令 |
|---|---|---|
| Created | 已创建,未启动 | docker create |
| Running | 运行中 | docker start |
| Paused | 已暂停(进程挂起) | docker pause |
| Stopped | 已停止(进程退出) | docker stop |
| Deleted | 已删除 | docker rm |
docker run 一步到位,它相当于 docker create + docker start。但如果你需要精细控制启动参数,还是分开用更稳妥。
3.2 容器常用命令:每天都要敲的
这些命令我每天至少用几十遍。你想想看,没有它们,容器管理就是纸上谈兵。
3.2.1 创建与启动
# 创建但不启动
docker create --name myapp nginx:latest
# 创建并启动(最常用)
docker run -d --name myapp -p 8080:80 nginx:latest
# 交互式启动(调试用)
docker run -it --name debug ubuntu:22.04 bash
-d 是后台运行,-it 是交互终端。我在项目中遇到过,有人忘了加 -d,结果终端一关容器就停了——嗯,这坑我踩过。
3.2.2 查看与操作
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 停止容器
docker stop myapp
# 强制停止(慎用)
docker kill myapp
# 重启容器
docker restart myapp
docker kill 是直接发 SIGKILL 信号,容器里的进程来不及做清理工作。我曾经在生产环境手滑用过一次,数据库连接没释放,差点出事故。能用 stop 就别用 kill。
3.2.3 进入容器内部
# 进入运行中的容器
docker exec -it myapp bash
# 以 root 身份进入
docker exec -u root -it myapp bash
为什么要进容器?说白了就是排查问题。比如 nginx 配置写错了,你不想重新构建镜像,直接进去改一下配置文件,重启服务就行。
3.3 容器资源限制:别让一个容器吃光所有资源
我记得有一次,团队里有人跑了个内存泄漏的容器,直接把宿主机搞 OOM 了,其他服务全挂。从那以后,我定了个规矩:所有容器必须加资源限制。
3.3.1 CPU 限制
# 限制使用 1.5 个 CPU 核心
docker run --cpus="1.5" myapp
# 限制 CPU 份额(相对权重)
docker run --cpu-shares=512 myapp
--cpus 是绝对限制,--cpu-shares 是相对权重。我个人习惯用 --cpus,因为更直观——说用1.5核就是1.5核,不跟你玩虚的。
3.3.2 内存限制
# 限制最大内存 512MB
docker run -m 512m myapp
# 限制内存 + 交换分区
docker run -m 512m --memory-swap=1g myapp
3.3.3 磁盘 I/O 限制
# 限制读写速度
docker run --device-read-bps=/dev/sda:1mb \
--device-write-bps=/dev/sda:1mb myapp
这个用得少,但如果你在共享存储上跑多个容器,建议加上。不然一个容器疯狂写日志,其他容器都得等着。
3.4 容器日志管理:别让日志撑爆磁盘
日志这东西,平时没人管,一出事就抓瞎。我经历过一次磁盘写满,就是因为容器日志没做轮转,一个容器一天写了 50GB 日志。
3.4.1 查看日志
# 查看最近 100 行日志
docker logs --tail 100 myapp
# 实时跟踪日志
docker logs -f myapp
# 查看指定时间段的日志
docker logs --since "2024-01-01T00:00:00" myapp
-f 参数我调试时必用,相当于 tail -f。但生产环境慎用,因为会占用终端。
3.4.2 日志驱动配置
Docker 默认用 json-file 驱动,日志全堆在宿主机上。我建议改成 local 驱动,性能更好,还支持压缩。
# 启动时指定日志驱动
docker run --log-driver local \
--log-opt max-size=10m \
--log-opt max-file=3 \
myapp
| 日志驱动 | 特点 | 适用场景 |
|---|---|---|
| json-file | 默认,每个容器一个 JSON 文件 | 开发环境 |
| local | 自定义格式,支持压缩 | 生产环境(推荐) |
| syslog | 发送到系统日志 | 集中式日志收集 |
| journald | 发送到 systemd 日志 | CentOS/RHEL 系统 |
--log-opt max-size=10m --log-opt max-file=3。
3.4.3 全局日志配置
如果你不想每个容器都加参数,可以在 Docker daemon 配置文件里统一设置:
# /etc/docker/daemon.json
{
"log-driver": "local",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
改完记得重启 Docker:systemctl restart docker。嗯,这里要注意,重启会停掉所有容器,最好在维护窗口操作。
3.5 实战:一个完整的容器管理流程
说了这么多,咱们来走一遍完整流程。假设我要部署一个 Nginx 容器:
# 1. 创建并启动,加资源限制和日志配置
docker run -d \
--name web-nginx \
--cpus="1" \
-m 256m \
--log-driver local \
--log-opt max-size=10m \
--log-opt max-file=3 \
-p 8080:80 \
nginx:alpine
# 2. 查看状态
docker ps | grep web-nginx
# 3. 查看日志
docker logs --tail 50 web-nginx
# 4. 进入容器调试
docker exec -it web-nginx sh
# 5. 停止容器
docker stop web-nginx
# 6. 删除容器
docker rm web-nginx
这个流程我每天都在用。你想想看,从创建到销毁,每一步都有对应的命令和参数。说白了,容器管理就是把这些命令用好、用对。
下一章咱们聊聊 Docker 网络,这可是容器通信的核心。到时候我会分享一些我在跨主机容器通信上踩过的坑,保证让你少走弯路。