3、Docker容器管理:容器的创建与启动、容器的生命周期管理、进入容器、容器日志与监控、容器资源限制
好,咱们直接进入正题。容器管理是Docker操作中最核心的部分,说白了就是你每天都要跟它打交道。我刚开始接触Docker那会儿,觉得容器就是个轻量级虚拟机,后来踩了不少坑才明白——它俩完全是两码事。
3.1 容器的创建与启动
创建容器,最常用的命令就是 docker run。这个命令其实做了两件事:先拉取镜像(如果本地没有),再基于镜像启动一个容器。我个人习惯把创建和启动分开来理解,这样排查问题会更清晰。
# 创建并启动一个nginx容器
docker run -d --name my-nginx -p 8080:80 nginx:latest
# 只创建不启动
docker create --name my-redis redis:7.0
# 启动已创建的容器
docker start my-redis
这里有个细节要注意:docker run 每次都会创建一个新容器。如果你只是想让停掉的容器重新跑起来,用 docker start 就行,别每次都 run。
docker run --rm 来跑临时任务。容器退出后自动删除,省得手动清理。比如做测试或者跑一次性脚本时特别好用。
3.2 容器的生命周期管理
容器的生命周期,说白了就是「生老病死」。我们来看看几个关键操作:
| 命令 | 作用 | 常用场景 |
|---|---|---|
docker start |
启动已停止的容器 | 重启之前停掉的服务 |
docker stop |
优雅停止容器(发送SIGTERM) | 正常关闭服务,给进程留清理时间 |
docker restart |
重启容器(stop + start) | 配置更新后快速重启 |
docker rm |
删除已停止的容器 | 清理不再使用的容器 |
嗯,这里要特别说一下 docker stop 和 docker kill 的区别。Stop 会给容器内的主进程发 SIGTERM 信号,给它10秒左右的时间做清理工作。Kill 则是直接发 SIGKILL,强行干掉。我曾经在生产环境遇到过一个问题:某个数据库容器用 kill 强行停止,结果数据文件损坏了。从那以后,我都是优先用 stop,除非容器卡死了才用 kill。
# 优雅停止
docker stop my-container
# 强制停止(慎用)
docker kill my-container
# 停止并删除
docker rm -f my-container
docker rm -f 会强制删除正在运行的容器。这个操作不可逆,数据卷如果没有挂载到宿主机,数据就丢了。我曾经手滑删错过,血的教训。
3.3 进入容器:exec 与 attach
进入容器有两种方式:docker exec 和 docker attach。很多人搞不清它俩的区别,我简单说说。
docker exec 是在容器里新开一个进程。比如你想在运行中的容器里执行一条命令,或者开一个交互式 shell,用 exec 就对了。
# 在容器中执行一条命令
docker exec my-nginx ls /etc/nginx
# 进入容器的交互式shell
docker exec -it my-nginx /bin/bash
# 以root身份进入
docker exec -u root -it my-nginx /bin/bash
docker attach 则是连接到容器的主进程。说白了,就是把你当前的终端「粘」到容器的主进程上。如果你用 attach 连上去,然后按 Ctrl+C,它会直接终止容器的主进程——容器就停了。
docker exec -it,别用 attach。除非你明确知道自己在做什么,否则 attach 很容易误操作把容器搞停。
3.4 容器日志与监控
日志是排查问题的第一道防线。Docker 默认把容器的标准输出和标准错误都收集起来,用 docker logs 就能查看。
# 查看最近100行日志
docker logs --tail 100 my-container
# 实时跟踪日志输出
docker logs -f my-container
# 加上时间戳
docker logs -t my-container
# 查看指定时间段的日志
docker logs --since "2024-01-01T00:00:00" --until "2024-01-02T00:00:00" my-container
监控方面,docker stats 是我最常用的命令。它能实时显示所有容器的 CPU、内存、网络 I/O 和磁盘 I/O 情况。
# 实时监控所有容器
docker stats
# 只监控指定容器
docker stats my-container1 my-container2
# 只输出一次,不持续监控
docker stats --no-stream my-container
为什么会推荐 --no-stream?因为我在写自动化脚本时,需要采集某个时间点的资源使用情况,持续输出反而会干扰脚本逻辑。
3.5 容器资源限制
这是生产环境中必须掌握的内容。如果不加限制,一个容器就可能把宿主机的 CPU 和内存吃光,影响其他容器运行。我见过最惨的一次,某个 Java 应用没设内存限制,直接 OOM 把宿主机搞挂了,上面跑的十几个容器全部遭殃。
CPU 限制
# 限制最多使用1.5个CPU核心
docker run --cpus="1.5" my-app
# 限制CPU份额(相对权重,默认1024)
docker run --cpu-shares=512 my-app
# 绑定到特定CPU核心
docker run --cpuset-cpus="0,2" my-app
--cpus 是最直观的,直接指定容器能用的 CPU 核心数。比如宿主机有 4 核,你设 --cpus="2",那这个容器最多用 2 个核的资源。
内存限制
# 限制最大内存为512MB
docker run -m 512m my-app
# 限制内存+swap总和为1GB
docker run -m 512m --memory-swap 1g my-app
# 禁止使用swap
docker run -m 512m --memory-swap 512m my-app
-m 和 --memory-swap 两个参数。
综合示例
来个实际点的例子,启动一个受资源限制的 Nginx 容器:
docker run -d \
--name web-server \
--cpus="1" \
-m 256m \
--memory-swap 512m \
--restart=always \
-p 80:80 \
nginx:alpine
这个配置的意思是:最多用 1 个 CPU 核心,内存上限 256MB,加上 swap 总共 512MB。如果容器挂了,Docker 会自动重启它。
--memory-swap 没设,默认是内存限制的两倍。结果容器用了大量 swap,性能急剧下降。所以我的习惯是:要么明确设 swap 大小,要么设成跟内存一样大(禁用 swap)。
好了,容器管理这块的内容就这些。说白了就是三板斧:创建启动、生命周期、资源限制。把这些搞明白了,日常的容器操作基本就够用了。下一章咱们聊聊 Docker 网络,那才是真正让人头疼的地方。