3. Docker容器管理:容器的创建与启动、容器的停止与重启、容器的进入与退出、容器的日志查看、容器的删除与资源限制

容器管理,说白了就是Docker日常操作的核心。你想想看,我们学Docker最终是为了什么?不就是把应用跑在容器里,然后管好这些容器吗?这一章,我带你把这些基础操作全部过一遍。嗯,都是实战中每天都要用的东西。

3.1 容器的创建与启动

创建容器,最常用的命令就是 docker run。这个命令其实做了两件事:先创建容器,再启动它。我个人习惯把它拆开理解,这样排查问题的时候思路更清晰。

核心命令:

# 创建并启动一个nginx容器
docker run -d --name my-nginx -p 8080:80 nginx:latest

# 只创建不启动
docker create --name my-nginx -p 8080:80 nginx:latest

# 启动已创建的容器
docker start my-nginx

我在项目中遇到过一个问题:有同事直接用 docker run 跑了一个数据库容器,结果容器一停数据全丢了。为什么?因为他没挂载数据卷。这里我提醒你一句:生产环境跑有状态服务,一定要用 -v--mount 挂载数据卷

小技巧: docker run 后面加 --rm 参数,容器停止后会自动删除。适合临时测试用,省得手动清理。

3.2 容器的停止与重启

停止容器,大家第一反应肯定是 docker stop。这个命令会给容器内的主进程发送 SIGTERM 信号,给它一个优雅退出的机会。如果10秒后还没停,Docker 就会发 SIGKILL 强制杀掉。

# 优雅停止
docker stop my-nginx

# 强制停止(直接发SIGKILL)
docker kill my-nginx

# 重启容器
docker restart my-nginx

我曾经踩过一个坑:线上有个Java应用,docker stop 之后它总是要等很久才退出。后来发现是JVM没有注册关闭钩子。解决方案是在启动命令里加上 exec,让Java进程直接接管PID 1,这样信号就能正确传递了。

注意: 不要用 docker kill 代替 docker stop 作为常规操作。强制停止可能导致数据损坏或文件系统不一致。

3.3 容器的进入与退出

调试容器的时候,我们经常需要进到容器里面看看。最常用的就是 docker exec 命令。

# 进入容器并启动bash
docker exec -it my-nginx /bin/bash

# 在容器内执行单条命令
docker exec my-nginx ls /etc/nginx

# 以root用户进入容器
docker exec -u root -it my-nginx /bin/bash

这里有个细节:-it 参数是什么意思?-i 是交互模式,-t 是分配伪终端。说白了,不加 -t 的话,你敲命令可能看不到提示符,甚至ls的输出格式都不对。我刚开始学的时候经常忘加 -t,然后纳闷怎么界面这么奇怪。

退出容器很简单,直接敲 exit 或者按 Ctrl+D。但要注意:如果你是用 docker attach 进入的容器,退出时容器也会停止。所以日常调试我推荐用 docker exec,而不是 docker attach

3.4 容器的日志查看

日志是排查问题的第一手资料。Docker 提供了 docker logs 命令来查看容器的标准输出和标准错误流。

# 查看所有日志
docker logs my-nginx

# 实时跟踪日志(类似tail -f)
docker logs -f my-nginx

# 查看最近100行日志
docker logs --tail 100 my-nginx

# 查看指定时间后的日志
docker logs --since 2024-01-01T00:00:00 my-nginx

避坑指南: 我曾经遇到一个容器,跑了三天日志文件把磁盘撑爆了。原因是默认的日志驱动是 json-file,而且没有限制日志文件大小。后来我在启动容器时加了这些参数:

docker run -d \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  --name my-app my-image

这样每个日志文件最大10MB,保留3个文件,循环覆盖。生产环境一定要配这个,不然等着磁盘报警吧。

3.5 容器的删除与资源限制

删除容器用 docker rm,但要注意:正在运行的容器不能直接删除,得先停掉或者加 -f 强制删除。

# 删除已停止的容器
docker rm my-nginx

# 强制删除运行中的容器
docker rm -f my-nginx

# 清理所有已停止的容器
docker container prune

# 删除所有容器(包括运行中的)
docker rm -f $(docker ps -aq)

资源限制这块,我觉得是很多初学者容易忽略的。默认情况下,容器可以使用宿主机的全部资源。你想想看,如果有个容器内存泄漏了,是不是整个机器都得跟着遭殃?

参数 作用 示例
--memory 限制最大内存 --memory=512m
--memory-swap 限制内存+交换分区 --memory-swap=1g
--cpus 限制CPU核心数 --cpus=1.5
--cpu-shares 设置CPU权重 --cpu-shares=512
--blkio-weight 限制磁盘IO权重 --blkio-weight=100

实战建议: 我一般会给每个容器都加上内存限制,至少设一个 --memory。CPU限制看情况,如果是CPU密集型的服务,建议用 --cpus 精确控制。至于磁盘IO,除非你跑数据库或者日志采集服务,否则一般不用管。

# 一个完整的资源限制示例
docker run -d \
  --name my-app \
  --memory=512m \
  --memory-swap=1g \
  --cpus=1.5 \
  --cpu-shares=512 \
  --blkio-weight=100 \
  my-image:latest

重要提醒: 资源限制不是越高越好。比如你把 --memory-swap 设得很大,容器可能会大量使用交换分区,导致性能急剧下降。我见过有人把内存限制设成 --memory=100m --memory-swap=10g,结果容器频繁触发OOM,应用响应慢得像蜗牛。

好了,这一章的内容就这些。容器管理说白了就是这几个命令的组合使用。你只要多练几遍,形成肌肉记忆,以后操作起来就顺手了。下一章我们会聊Docker网络,那才是真正有意思的部分。