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
核心原则: 内存限制一定要设。不设的话,容器可以吃掉宿主机所有内存。我见过最夸张的一次,一个 Java 应用容器吃了 32GB 内存,把数据库容器挤到 OOM 了。

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 系统
避坑指南: 我曾经在生产环境用默认的 json-file 驱动,没设日志轮转。结果三个月后,一个容器的日志文件达到了 200GB,磁盘直接爆了。从那以后,我所有容器都加上 --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 网络,这可是容器通信的核心。到时候我会分享一些我在跨主机容器通信上踩过的坑,保证让你少走弯路。