3、Docker容器管理:容器的创建与启动(run)、查看(ps)、停止与启动(stop/start)、进入容器(exec/attach)、日志查看(logs)、删除(rm)

好,咱们进入容器管理的核心环节。说实话,容器管理是Docker日常操作中最频繁的部分,也是我当年从传统运维转向容器化时,最先啃透的一块。你想想看,容器说白了就是一个轻量级的“小虚拟机”,但它的生命周期管理比虚拟机灵活得多。今天我就带你把这些命令一个一个捋清楚。

3.1 容器的创建与启动:docker run

docker run 是Docker里最常用的命令,没有之一。它的作用是从一个镜像创建并启动一个容器。我个人习惯把它拆成两步理解:先“创建”,再“启动”。但Docker把这两步合并成了一个命令,用起来更爽快。

最基本的用法是这样的:

docker run nginx

这条命令会从Docker Hub拉取nginx镜像(如果本地没有的话),然后启动一个容器。但你会发现,容器启动后终端就被“粘”住了,按Ctrl+C容器就停了。嗯,这里要注意——默认情况下,docker run 是在前台运行的。

那怎么让它在后台跑呢?加个 -d 参数:

docker run -d nginx

这样容器就在后台默默运行了,终端会返回一个容器ID。我在项目中遇到过不少新手,启动容器后找不到容器了,其实就是忘了加 -d

再来看几个常用参数:

  • --name:给容器起个名字,方便管理。比如 docker run --name my-nginx -d nginx
  • -p:端口映射。把宿主机的端口映射到容器端口,比如 docker run -d -p 8080:80 nginx
  • -v:挂载卷。把宿主机的目录挂载到容器里,实现数据持久化
  • -e:设置环境变量。比如 docker run -e MY_ENV=hello -d nginx

举个例子,启动一个带端口映射和名字的Nginx:

docker run --name web-server -d -p 8080:80 nginx

这时候你打开浏览器访问 http://localhost:8080,就能看到Nginx的欢迎页了。

小技巧: 我习惯在启动容器时总是加上 --name 参数。为什么呢?因为容器ID是一串乱码,记不住。有了名字,后续操作直接按名字来,省心多了。

3.2 查看容器:docker ps

容器启动后,怎么知道它跑没跑?用 docker ps。这个命令会列出当前正在运行的容器。

docker ps

输出大概长这样:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp web-server

这里有几个关键字段:

  • CONTAINER ID:容器ID,唯一标识
  • IMAGE:基于哪个镜像启动的
  • STATUS:运行状态,Up 表示正在运行,Exited 表示已停止
  • PORTS:端口映射情况
  • NAMES:容器名字

如果想看所有容器(包括已经停止的),加个 -a 参数:

docker ps -a

我曾经排查过一个线上问题,发现有个容器“消失”了,用 docker ps -a 一看,原来它早就退出了,状态是 Exited (0)。所以,-a 这个参数在排查问题时特别有用。

3.3 停止与启动:docker stop / docker start

容器运行久了,总得停下来维护吧?用 docker stop

docker stop web-server

这个命令会向容器发送一个SIGTERM信号,让容器优雅地退出。如果容器在10秒内没反应,Docker会强制发送SIGKILL。嗯,这里有个细节——stop 是优雅关闭,不是暴力断电。

启动一个已经停止的容器,用 docker start

docker start web-server

注意,startrun 的区别:run 是创建+启动,start 是启动一个已经存在的容器。说白了,run 是“生”,start 是“唤醒”。

还有一个 docker restart,相当于先 stopstart

docker restart web-server
注意: 我曾经在生产环境上犯过一个错——直接 docker stop 了一个正在处理请求的容器,导致部分请求中断。后来我养成了习惯:先检查容器是否还有活跃连接,再决定是否停止。你可以用 docker logs 先看看最近的请求情况。

3.4 进入容器:docker exec / docker attach

有时候我们需要“钻进”容器里看看,比如检查配置文件、调试程序。这时候有两个命令可以用:docker execdocker attach

docker exec 是我最常用的。它可以在运行中的容器里执行命令:

docker exec -it web-server /bin/bash

解释一下参数:

  • -i:交互模式,保持标准输入打开
  • -t:分配一个伪终端,让命令看起来像在终端里执行
  • web-server:容器名字
  • /bin/bash:要执行的命令,通常是bash或sh

执行后,你就进入了容器的shell,可以像操作普通Linux一样操作它。退出时输入 exit,容器会继续运行。

docker attach 就不太一样了。它会把当前终端连接到容器的标准输入输出上:

docker attach web-server

但这里有个坑——如果你用 attach 进入容器,然后按Ctrl+C退出,容器也会跟着停止。为什么呢?因为 attach 连接的是容器的主进程,你退出时相当于给主进程发了信号。

我个人建议:日常调试用 docker exec,别碰 attach,除非你很清楚自己在做什么。我在项目中见过有人用 attach 不小心把生产容器给停了,那叫一个尴尬。

3.5 日志查看:docker logs

容器跑起来了,但程序报错了怎么办?看日志。用 docker logs

docker logs web-server

这会输出容器从启动到现在的所有标准输出和标准错误日志。如果日志太多,可以加几个参数:

  • --tail N:只看最后N行。比如 docker logs --tail 100 web-server
  • -f:实时跟踪日志,类似 tail -f。比如 docker logs -f web-server
  • --since:只看某个时间点之后的日志。比如 docker logs --since 2024-01-01 web-server

举个例子,实时查看最近50行日志:

docker logs --tail 50 -f web-server

我记得有一次排查线上问题,容器启动后立刻退出了,根本来不及看日志。后来我用 docker logs 一看,原来是配置文件里写错了数据库连接地址。所以,logs 命令是排查问题的第一把钥匙。

小技巧: 如果容器日志太多,可以配合 grep 过滤。比如 docker logs web-server 2>&1 | grep ERROR,只显示错误信息。注意 2>&1 是把标准错误也重定向到标准输出,不然你可能会漏掉一些错误日志。

3.6 删除容器:docker rm

容器不用了,就得清理掉。用 docker rm

docker rm web-server

注意,只能删除已经停止的容器。如果容器还在运行,会报错。这时候可以加 -f 参数强制删除:

docker rm -f web-server

-f 相当于先 stoprm,不太优雅。我建议先 stoprm,这样容器有机会做清理工作。

如果想一次删除多个容器,可以这样:

docker rm container1 container2 container3

或者删除所有已停止的容器:

docker container prune

这个 prune 命令会清理所有处于停止状态的容器,释放磁盘空间。我每周都会跑一次,防止磁盘被废弃容器占满。

注意: 删除容器前,一定要确认容器里的数据已经持久化到宿主机或卷里了。否则容器一删,数据就没了。我曾经有个同事,删了一个数据库容器,结果数据全丢了——因为他没挂载卷。嗯,血的教训。

3.7 实战小总结

好了,咱们把今天的内容串起来。假设你要部署一个Nginx服务:

  1. 启动容器:docker run --name my-nginx -d -p 8080:80 nginx
  2. 查看状态:docker ps
  3. 查看日志:docker logs --tail 20 -f my-nginx
  4. 进入容器调试:docker exec -it my-nginx /bin/bash
  5. 停止容器:docker stop my-nginx
  6. 启动容器:docker start my-nginx
  7. 删除容器:docker rm my-nginx

这一套流程,说白了就是容器的“生老病死”。你多练几遍,肌肉记忆就形成了。下一节咱们聊聊镜像管理,到时候你会发现,容器和镜像就像“鸡蛋”和“鸡”的关系——镜像生容器,容器又能提交成新镜像。有意思吧?