适用人群:Linux 运维新手、后端开发、DevOps 初学者
1. 核心概念:区分"Docker 服务"与"容器"
在开始之前,需要明确两个概念,避免混淆:
- Docker 服务 (Daemon):指 Docker 引擎本身(
dockerd)。如果它挂了,所有容器都会停止。 - 容器 (Container):指运行在 Docker 里的具体应用(如 Nginx、MySQL、Nacos、你的业务代码)。
新手提示:通常我们说"查看 Docker 运行",既可能指查看引擎是否活着,也可能指查看里面的业务容器是否正常。下文将分开讲解。
2. 基础篇:查看 Docker 引擎状态
2.1 检查 Docker 引擎是否存活
这是最基础的命令,用于确认服务器上的 Docker 软件本身是否在运行。
# 查看详细的服务状态(推荐)sudo systemctl status docker# 快速判断(脚本常用)systemctl is-active docker
输出解读:
active (running)inactive (dead):未启动,需要执行 sudo systemctl start docker。failed:启动失败,需要查看日志排查:sudo journalctl -u docker.service -n 50。
2.2 验证 Docker 客户端连接
如果 systemctl 显示正常,但执行 docker 命令报错,可以用此命令验证。
输出解读:
- 如果输出一大堆关于 Containers、Images、Storage Driver 的信息,说明连接正常。
- 如果报错
Cannot connect to the Docker daemon,说明服务虽然启动了但 socket 文件有问题或权限不足。此时可尝试将当前用户加入 docker 用户组:sudo usermod -aG docker $USER,然后重新登录。
2.3 Docker 服务管理命令速查
| | |
|---|
| sudo systemctl start docker | |
| sudo systemctl stop docker | |
| sudo systemctl restart docker | |
| sudo systemctl enable docker | |
| sudo journalctl -u docker.service | |
3. 进阶篇:查看与管理容器(业务服务)
这是日常工作中最高频的操作区域。
3.1 查看容器运行状态(黄金命令)
不要只用 docker ps,建议养成使用格式化输出的习惯,信息更直观。
# 查看所有容器(包括已退出的),并格式化输出docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Image}}\t{{.Ports}}"
参数拆解:
-a / --all:显示所有容器,不仅仅是正在运行的。--format:自定义输出列。这里我们按顺序展示:容器ID、名字、状态、镜像、端口映射。
输出示例与解读:
状态关键字速查表:
| | |
|---|
Up x hours | | |
Up x hours (healthy) | | |
Up x seconds | | |
Exited (0) | | |
Exited (1) | | |
Restarting | | |
Created | | |
Paused | | |
Dead | | |
3.2 快速筛选特定状态的容器
当服务器上有几十个容器时,直接筛选更高效。
# 1. 只看"活着"的容器(默认等价于 docker ps)docker ps# 2. 只看"死掉"的容器(Exited)docker ps -a --filter "status=exited"# 3. 只看"反复重启"的容器(最危险)docker ps -a --filter "status=restarting"# 4. 只看"已创建未启动"的容器docker ps -a --filter "status=created"
3.3 查看容器日志(排查神器)
当发现容器状态异常时,日志是唯一的真相(“黑匣子”)。
# 查看最后 50 行日志(实时滚动)docker logs -f --tail 50 <容器名或ID># 查看特定时间段的日志docker logs --since "2023-10-27T10:00:00" <容器名>
3.3.1 容器名和 ID 从哪里来?
在使用 docker logs 之前,你需要知道目标容器的"身份证号"。
- 容器名 (NAMES)
- 来源:通常在启动容器时通过
--name 参数手动指定。例如:docker run --name my-nginx -d nginx。 - 特点:人类可读,方便记忆。如果你没指定,Docker 会自动生成一个随机的名字(如
happy_turing)。
- 容器 ID (CONTAINER ID)
- 来源:Docker 自动生成的唯一标识符,一串十六进制字符(如
a1b2c3d4e5f6...)。 - 特点:在命令行中,通常只需要输入前 3-4 位(短 ID)即可唯一识别,无需输入全称。
3.3.2 怎么找到我要查的容器名或 ID?
如果你忘记了名字,可以通过以下命令查找:
# 方法一:列出所有容器,人工查找docker ps -a# 方法二:模糊搜索(比如记得名字里带 "mysql")docker ps -a | grep mysql# 方法三:只获取 ID(适合配合其他命令使用)docker ps -aq --filter "name=mysql"# 方法四:查看某个容器的详细信息(包含完整的 ID、启动命令、挂载等)docker inspect <容器名或ID>
实战技巧:
- 如果你想找跟 “mysql” 有关的容器:
docker ps -a | grep mysql - 如果你只想获取容器 ID(用于脚本):
docker ps -q - 如果你想看某个容器的完整信息(包括启动命令、环境变量、挂载目录等):
docker inspect <容器名>
3.3.3 常用日志查看命令
假设你要排查的容器名为 my-app(或者用 ID a1b2 代替):
# 1. 基础查看:查看最后 100 行日志(最常用)docker logs --tail 100 my-app# 2. 实时跟踪:像看直播一样看日志输出(排查启动卡住时很有用)docker logs -f my-app# 按 Ctrl + C 退出实时模式# 3. 带时间戳:查看日志发生的具体时间docker logs -t --tail 50 my-app# 4. 搜索错误:结合 grep 只看报错信息docker logs my-app 2>&1 | grep -i "error"# 5. 查看特定时间之后的日志docker logs --since "2023-10-27T10:00:00" my-app# 6. 查看特定时间之前的日志docker logs --until "2023-10-27T12:00:00" my-app# 7. 同时查看多个容器的日志docker logs --tail 20 my-app1 && docker logs --tail 20 my-app2
技巧:2>&1 的意思是将"标准错误输出"合并到"标准输出"中,防止有些程序的报错信息打印在另一条流里而被 grep 漏掉。
实战排查流程(四步法):
- 抓日志:
docker logs --tail 100 <容器名> - 搜关键词:
docker logs <容器名> 2>&1 | grep -iE "error|exception|panic|fatal" - 缩小时间范围:如果故障发生在某个时间点,用
--since 参数缩小范围 - 进入容器
3.4 进入容器内部调试
有时候光看日志不够,需要进入容器内部检查配置文件、网络、文件等。
# 进入容器的 bash 终端(容器需支持 bash)docker exec -it <容器名> /bin/bash# 进入容器的 sh 终端(轻量级,多数基础镜像支持)docker exec -it <容器名> /bin/sh# 在宿主机上执行容器内的命令(不需要进入容器)docker exec <容器名> ps auxdocker exec <容器名> cat /etc/hostnamedocker exec <容器名> env # 查看容器内的环境变量
参数拆解:
-i / --interactive:保持标准输入打开。-texec
3.5 资源占用监控
当服务器变慢时,查看是哪个容器在"抢资源"。
# 实时查看 CPU、内存、网络、IO 占用(类似 top 命令)docker stats# 查看某个容器的资源占用(一次性输出,不实时刷新)docker stats <容器名> --no-stream# 查看容器的详细资源限制docker inspect <容器名> | grep -A 5 "Memory"
4. 常见问题处理(Troubleshooting)
4.1 容器处于 Restarting 状态
现象:docker ps 显示 Restarting (1) 3 seconds ago。
原因:容器启动命令执行失败,或者主进程崩溃,Docker 策略设为 always 导致无限重试。
解决步骤:
- 立即查看日志:
docker logs --tail 100 <容器ID> - 常见错误:配置文件路径错误、数据库连不上、端口被占用
- 如果确定要停止重启循环:
docker update --restart=no <容器名>docker stop <容器名>
4.2 容器处于 Exited (137)
现象:容器意外退出,退出码 137。
原因:OOM (Out Of Memory)。容器使用的内存超过了设定的 limit,被 Linux 内核杀掉了。
解决步骤:
- 验证:
docker inspect <容器ID> | grep -i oom(如果返回 true 则是内存溢出) - 查看系统内核日志确认:
dmesg | grep -i 'out of memory' | grep <容器名>
4.3 容器处于 Created 状态
现象:docker ps -a 显示 Created。
原因:容器被创建了,但没有执行 docker start,或者启动命令(Entrypoint/Cmd)为空/错误。
解决步骤:
- 检查配置:
docker inspect <容器名> | grep -A 5 "Cmd" - 如果启动后立刻变成
Exited,查看日志定位原因
4.4 容器内时间不对
现象:业务日志时间与北京时间差 8 小时。
原因:容器默认使用 UTC 时间,而宿主机是东八区。
解决:启动时挂载宿主机时间文件。
docker run -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro ...
4.5 磁盘空间满了(No space left on device)
现象:无法启动新容器,或者日志写不进去。
排查步骤:
# 1. 查看磁盘整体使用率df -h# 2. 查看 Docker 占用了多少空间docker system df# 3. 一键清理(慎用!会删除所有停止的容器、未使用的网络和悬空镜像)docker system prune# 4. 安全清理(只删除未使用的镜像,保留容器)docker image prune# 5. 彻底清理(删除所有未使用的镜像、停止的容器、构建缓存)docker system prune -a# 6. 查找大日志文件(Docker 容器日志可能占用几十 G)find /var/lib/docker/containers/ -name "*-json.log" -size +1G# 7. 清空指定日志文件(不删除文件,只清空内容)cat /dev/null > /var/lib/docker/containers/<长ID>/<长ID>-json.log
4.6 端口冲突
现象:启动容器时报错 driver failed programming external connectivity。
原因:宿主机的端口已经被其他进程占用了。
解决步骤:
# 1. 查看哪个进程占用了目标端口netstat -tlnp | grep <端口号># 或lsof -i :<端口号># 2. 杀掉占用端口的进程(谨慎操作)kill -9 <PID># 3. 或者修改容器启动时的端口映射docker run -p 新端口:容器端口 ...
4.7 容器无法联网
现象:容器内 ping 或 curl 外网超时。
排查步骤:
# 1. 检查 Docker 网络模式docker inspect <容器名> | grep -A 5 "NetworkMode"# 2. 进入容器检查 DNS 配置docker exec <容器名> cat /etc/resolv.conf# 3. 检查宿主机 DNS 是否正常cat /etc/resolv.conf# 4. 重启 Docker 网络(临时恢复)sudo systemctl restart docker
5. Nacos 专项运维与排查实战
Nacos (Naming and Configuration Service) 是微服务架构的核心组件,承载了服务注册发现和配置管理两大功能。由于它一旦出问题往往是"爆炸性"的(所有微服务失联),因此需要特别关注其运行状态。
5.1 快速检查 Nacos 健康状态
不要只看 docker ps 显示 Up,Nacos 经常会出现"假死"状态(进程在,但无法响应 HTTP 请求)。
# 1. 检查端口监听情况(默认端口 8848)# 确保状态是 LISTEN,且不是 127.0.0.1(除非你只允许本机访问)netstat -tlnp | grep 8848# 2. 使用 curl 探测控制台接口(最准确)# 如果返回 HTTP 200 或 HTML 内容,说明服务正常curl -I http://<服务器IP>:8848/nacos/# 3. 检查集群节点状态(如果是集群模式)curl http://<服务器IP>:8848/nacos/v1/ns/operator/cluster/state# 4. 查看服务注册列表(确认微服务是否注册成功)curl http://<服务器IP>:8848/nacos/v1/cs/services?serviceName=<服务名>
5.2 Nacos 常见故障排查
场景一:Nacos 启动后自动退出 (Exited)
原因:Nacos 对内存非常敏感,默认 JVM 堆内存设置过大,超过了 Docker 容器的内存限制,导致被 OOM Killer 杀掉。
排查命令:
# 查看退出码,如果是 137,大概率是内存溢出docker inspect <容器ID> --format='{{.State.ExitCode}}'# 查看系统内核日志确认 OOMdmesg | grep -i 'out of memory' | grep nacos
解决方案:启动时通过环境变量调小 JVM 内存。
# 示例:将堆内存限制为 512mdocker run -e JVM_XMS=256m -e JVM_XMX=512m ... nacos/nacos-server
场景二:微服务连不上 Nacos(注册失败)
原因:网络模式问题或 IP 漂移。Nacos 默认会注册服务器的内网 IP,如果 Docker 使用了桥接模式,微服务可能拿到的是错误的 IP。
排查命令:
# 进入容器查看 Nacos 认为自己是谁docker exec -it <nacos容器ID> cat /home/nacos/conf/application.properties# 查看 Nacos 启动日志中的 IP 绑定信息docker logs <nacos容器ID> | grep "Nacos started successfully"# 查看 Nacos 启动完整日志docker logs <nacos容器ID>
关键配置:确保 nacos.inetutils.ip-address 配置的是微服务能访问到的真实 IP。
场景三:配置中心数据丢失或不更新
原因:数据库连接断开或 Derby 模式数据未持久化。
注意:生产环境严禁使用默认的 Derby 嵌入式数据库,必须切换为 MySQL。
检查命令:
# 检查是否连接到了外部 MySQLdocker logs <nacos容器ID> | grep "DataSource"# 应该看到类似 HikariPool 初始化成功的日志,而不是 Derby
场景四:Nacos 控制台无法访问
排查步骤:
# 1. 检查容器是否在运行docker ps | grep nacos# 2. 检查端口是否正确映射docker inspect <nacos容器ID> | grep -A 10 "Ports"# 3. 检查容器内部 Nacos 进程是否正常docker exec -it <nacos容器ID> ps aux | grep nacos# 4. 检查防火墙是否放行了 8848 端口# CentOS/RHEL:sudo firewall-cmd --list-ports | grep 8848# Ubuntu/Debian:sudo ufw status | grep 8848# 5. 重启 Nacos 容器docker restart nacos
5.3 Nacos 常用运维命令速查
| | |
|---|
| docker logs -f --tail 200 nacos | |
| docker exec -it nacos bash | Nacos 脚本通常在 /home/nacos/bin/ |
| docker exec -it nacos vi /home/nacos/conf/application.properties | |
| docker restart nacos | |
| docker exec nacos cat /home/nacos/version.txt | |
| rm -rf /home/nacos/data/protocol/raft | |
5.4 Nacos 生产环境最佳实践 Checklist
- 持久化:必须挂载
/home/nacos/data 目录到宿主机,防止容器删除后配置丢失。 - 数据库:必须使用 MySQL 8.0/5.7 作为外部存储,严禁使用默认的 Derby。
- 单机模式 vs 集群
- 开发测试用单机模式(
MODE=standalone)。 - 生产环境务必使用集群模式(
MODE=cluster),至少 3 个节点。
- 鉴权:生产环境务必开启鉴权(
nacos.core.auth.enabled=true)并修改默认密钥,防止被黑客利用上传恶意配置。 - 内存限制:通过
JVM_XMS 和 JVM_XMX 环境变量合理设置堆内存,避免 OOM。 - 日志轮转:配置 Nacos 日志轮转策略,防止日志文件无限增长占满磁盘。
6. 附录:常用命令速查表
6.1 容器管理
| | |
|---|
| docker start <name> | |
| docker stop <name> | |
| docker kill <name> | |
| docker restart <name> | |
| docker rm <name> | |
| docker create <镜像> | |
| docker exec -it <name> /bin/bash | |
| docker cp ./file.txt <name>:/path/ | |
| docker cp <name>:/path/file.txt ./ | |
6.2 镜像管理
| | |
|---|
| docker images | |
| docker pull <镜像名> | |
| docker rmi <镜像名> | |
| docker build -t <名> . | |
| docker inspect <镜像名> | |
| docker tag <旧名> <新名> | |
| docker push <镜像名> | |
6.3 网络与存储
| | |
|---|
| docker network ls | |
| docker network create <名> | |
| docker volume ls | |
| docker volume create <名> | |
6.4 清理与监控
| | |
|---|
| docker stats | |
| docker info | |
| docker system df | |
| docker system prune | |
| docker system prune -a | |
7. 附录:容器名与 ID 速查
很多新手在执行 docker logs、docker exec 等命令时,不知道 <容器名或ID> 该填什么。以下是快速查找的方法汇总:
# 1. 列出所有容器,显示名字和 IDdocker ps -a# 2. 只列出容器 ID(适合脚本中使用)docker ps -q# 3. 只列出容器 ID(包括已停止的)docker ps -aq# 4. 按名称模糊搜索容器docker ps -a --filter "name=关键字"# 5. 获取某个容器的完整 IDdocker inspect -f '{{.Id}}' <容器名># 6. 获取某个容器的短 ID(前 12 位)docker inspect -f '{{.Id}}' <容器名> | cut -c1-12
命名规范建议:
- 容器名使用有意义的英文命名,如
myapp-backend、mysql-primary、nacos-cluster-1。 - 集群场景下用序号区分:
nacos-1、nacos-2、nacos-3。
8. 附录:Docker 常用启动参数速查
| | |
|---|
-d | | docker run -d nginx |
-p | | docker run -p 8080:80 nginx |
-v | | docker run -v /data:/data nginx |
-e | | docker run -e MODE=standalone nacos |
--name | | docker run --name my-nginx nginx |
--restart | | --restart=always |
-it | | docker run -it ubuntu /bin/bash |
--network | | docker run --network mynet nginx |
--memory | | docker run --memory 512m nginx |
--cpus | | docker run --cpus 1.5 nginx |
-h | | docker run -h myhost nginx |
重启策略说明:
noon-failure:容器非正常退出时才重启,可指定最大重启次数:on-failure:5。alwaysunless-stopped
核心原则:先看状态(docker ps),再看日志(docker logs),最后进容器调试(docker exec)。掌握这个顺序,你已经可以应对绝大多数 Docker 运维问题了。