Docker 常用命令全解:从容器启停到 Compose 编排(速查手册)

面向日常运维与开发的 Docker 命令速查手册。全文按「镜像 → 容器 → 排障 → 网络 → 存储 → 编排 → 清理」的顺序组织,每条命令均给出可直接复制的最小示例,并在关键处标注易踩的坑。

一、命令的分类,先建立心智模型

Docker 的命令看着多,其实只有六类。把命令挂到类别上,记忆负担会小很多:

类别 作用对象 代表命令
镜像管理 静态的、只读的模板 pull images build tag rmi save/load
容器生命周期 镜像运行起来的实例 run start stop restart kill rm ps
运行时观测 容器内部状态 logs top stats inspect exec cp
网络与端口 容器对外通信 -p port network
数据卷 数据持久化 -v volume
编排与清理 多容器 / 磁盘回收 compose system prune

一句话区分镜像与容器:镜像是类,容器是对象。 镜像不会被"启动",被启动的永远是容器。

二、镜像管理

2.1 查看与搜索

docker images                  # 查看本地镜像
docker images -a               # 含中间层镜像(构建缓存)
docker images -q               # 只输出 IMAGE ID,便于脚本处理
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
docker search nginx            # 在 Docker Hub 搜索(仅对公共仓库有效)

2.2 拉取与打标签

docker pull nginx:1.25         # 不写 tag 时默认 latest,生产环境不要依赖 latest
docker tag nginx:1.25 registry.example.com/library/nginx:1.25

docker tag 是给同一个镜像 ID 起别名,不产生新的存储占用。它是推送私有仓库前的必要一步:仓库地址必须出现在镜像名里。

2.3 构建镜像

# 基本形式:-t 指定 名称:版本,末尾是构建上下文目录(注意是目录,不是 Dockerfile 文件)
docker build -t "java75-nginx:2.1" /root/docker-75/1/

# 指定 Dockerfile 位置与额外参数
docker build -t java75-nginx:2.2 -f /root/docker-75/2/Dockerfile \
  --build-arg ENV=prod --no-cache /root/docker-75/2/

要点:

  • 构建上下文会被整体发送给 Docker daemon,目录里不要放无关的大文件,用 .dockerignore 排除。
  • 层缓存按指令顺序命中,COPY package.json 与 COPY . 的顺序会显著影响构建速度。
  • --no-cache 用于排查"明明改了代码但镜像没变"的问题。

2.4 导出与导入

docker save -o nginx-1.25.tar nginx:1.25       # 镜像 → tar 文件(保留历史层与 tag)
docker load -i nginx-1.25.tar                  # tar 文件 → 镜像

docker export -o container.tar mycontainer     # 容器快照 → tar(丢失历史与元数据)
docker import container.tar myimage:latest     # tar → 镜像(无 CMD/ENV,需重新指定)

save/load 面向镜像,export/import 面向容器文件系统,离线迁移优先用 save。

2.5 删除镜像

docker rmi nginx:1.25
docker rmi -f nginx:1.25                       # 强制删除,多个 tag 指向同一 ID 时需 -f
docker rmi $(docker images -q -f "dangling=true")   # 清理悬空镜像(<none>:<none>)

三、容器的生命周期

3.1 一张图看懂状态流转

             docker create                docker start
   (无) ───────────────────►  Created ─────────────────►  Up (running)
                                 ▲                            │
                                 │        docker stop         │
                                 └────── Exited ◄─────────────┘
                                            │
                                            │ docker start(可再次启动)
                                            ▼
                                          Up
        docker rm  ──► 彻底删除(不可恢复)

3.2 docker run:创建并启动

docker run = create + start,是最常用的命令,也是参数最多的命令。

# 交互式启动,进入容器 shell
docker run -it --name mycentos centos /bin/bash

# 后台启动,映射端口,设置开机自启
docker run -d -p 10001:80 --restart=always --name nginx-demo \
  nginx:java75 /usr/sbin/nginx -g "daemon off;"

上例的三个关键点:

片段 含义
-p 10001:80 宿主机 10001 端口映射到容器 80 端口(宿主机:容器)
--restart=always Docker 服务重启或容器异常退出后自动拉起
/usr/sbin/nginx -g "daemon off;" 覆盖镜像的启动命令,让 nginx 在前台运行;容器的主进程一旦退出,容器即结束

常用参数速查:

参数 说明
-i 保持标准输入开启
-t 分配伪终端(TTY)
-d 后台运行,返回容器 ID
--name 指定容器名,便于后续操作
-p 宿主:容器 端口映射,可重复使用多个
-P 随机映射镜像暴露的所有端口
-v 宿主路径:容器路径 挂载目录或文件
-e KEY=VALUE 注入环境变量
--network 加入指定网络
--restart 重启策略,见第九节
--rm 容器退出后自动删除,适合一次性任务
--privileged 赋予几乎全部宿主机权限,非必要不用

3.3 启动、停止、重启、杀死

docker start 容器名          # 启动已存在的容器(不重新创建)
docker stop 容器名           # 优雅停止:先发 SIGTERM,10 秒后 SIGKILL
docker restart 容器名        # 重启
docker kill 容器名           # 直接 SIGKILL,进程没有机会清理现场
docker pause 容器名          # 冻结进程(cgroup freezer)
docker unpause 容器名

run 与 start 的区别是新手最容易混淆的一点: run 用镜像创建一个新容器再启动;start 只是把已存在的、处于 Exited 状态的容器重新跑起来。想改端口、改挂载、改环境变量,start 做不到,必须 rm 后重新 run。

stop 与 kill 的区别: stop 给进程留出收尾时间(关闭连接、刷盘、提交事务);kill 直接断电式终止,数据库类容器可能产生脏数据或需要恢复。生产环境优先用 stop。

3.4 查看容器

docker ps                      # 运行中的容器
docker ps -a                   # 所有容器,含已停止
docker ps -q                   # 只输出 ID
docker ps -qa                  # 所有容器 ID(批量操作的输入源)
docker ps -s                   # 附带容器可写层占用大小
docker ps -a --filter "status=exited"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

3.5 删除容器

docker rm 容器名               # 删除已停止的容器
docker rm -f 容器名            # 强制删除运行中的容器(先 kill 再删)
docker rm -f $(docker ps -qa)  # 删除全部容器

⚠️ docker rm -f $(docker ps -qa) 会连生产容器一起清掉。执行前先用 docker ps -a 核对,或改用 --filter 精确圈定范围。数据若无持久化,删除即永久丢失。

四、进入容器:attach 与 exec 的关键差异

docker attach 容器名                    # 接入容器的主进程标准输入输出
docker exec -it 容器名 /bin/bash        # 在容器内新开一个进程与终端

两者都能"进入容器",但行为完全不同,这是必须掌握的区别:

对比项 docker attach docker exec
本质 连接到 PID 1 的标准流 在容器内 fork 一个新进程
退出方式 输入 exit 或 Ctrl+D 会使主进程结束,容器停止 exit 只结束这个 shell,容器继续运行
安全退出的快捷键 Ctrl+P 再 Ctrl+Q(detach) 无需特殊操作
适用场景 查看主进程实时输出 调试、改配置、查文件 —— 日常首选

结论:除了观察前台进程输出,一律用 exec。 若容器是精简镜像(如 alpine)没有 bash,改用 /bin/sh:

docker exec -it 容器名 sh

五、观测与排障

5.1 日志

docker logs 容器名                 # 输出全部日志
docker logs -f 容器名              # 持续跟踪(类似 tail -f)
docker logs --tail 100 容器名      # 只看最后 100 行
docker logs -f --since 10m 容器名  # 最近 10 分钟并持续跟踪
docker logs -t 容器名              # 每行附加时间戳

排查顺序建议固定为:ps -a 看状态 → logs 看报错 → inspect 看配置 → exec 进容器验证。

5.2 进程与资源

docker top 容器名                  # 容器内进程列表(对应宿主机 PID)
docker stats                       # 实时 CPU / 内存 / 网络 / 磁盘 IO
docker stats --no-stream 容器名    # 取一次快照,适合脚本采集

docker top 输出的 PID 是宿主机视角的 PID,排查"宿主机 CPU 被打满但不知道是哪个容器"时非常有用。

5.3 详情与 IP

docker inspect 容器名                                   # 完整 JSON(配置、网络、挂载、状态)
docker inspect -f '{{.State.Status}}' 容器名             # 只看运行状态
docker inspect -f '{{.NetworkSettings.IPAddress}}' 容器名  # 只看 IP
原始写法 `docker inspect 容器名 grep IPAddress 也能用,但会输出整行 JSON("IPAddress": "172.17.0.2",),后续处理不便。推荐 -f`(Go 模板)精确取值,便于写进脚本。

注意:默认 bridge 网络下容器 IP 在每次重建后会变化,不要把它写死在配置文件里。容器间通信应使用自定义网络 + 容器名解析(见第七节)。

5.4 其他排查用命令

docker port 容器名                 # 查看端口映射关系
docker diff 容器名                 # 容器可写层相对镜像的文件变化
docker events --since 1h           # 守护进程事件流(启停、OOM、健康检查)
docker history 镜像名              # 镜像分层历史,用于分析体积膨胀来源

docker diff 是排查"容器里被改了什么"的利器:输出 A(新增)、C(修改)、D(删除)。若发现该持久化的目录出现在列表里,说明数据卷没挂对。

六、宿主机与容器之间传文件

# 宿主机 → 容器
docker cp ./app.jar 容器名:/opt/app/app.jar
# 容器 → 宿主机
docker cp 容器名:/var/log/app.log ./app.log
# 容器 → 容器
docker cp 容器A:/data ./backup

路径规则:容器侧必须以"容器名:"开头,否则会被当成宿主机路径。目录拷贝默认递归,加 -a 保留权限位。

一个常被忽略的点:docker cp 是"一次性搬运",不是同步。需要双向实时同步时应使用数据卷挂载。

七、网络与端口

7.1 端口映射

docker run -d -p 8080:80 nginx          # 指定映射:宿主 8080 → 容器 80
docker run -d -p 127.0.0.1:8080:80 nginx  # 只监听本机回环,不对外暴露
docker run -d -P nginx                  # 随机映射镜像 EXPOSE 的端口
docker port 容器名                       # 反向查询映射关系

排查"端口不通"的固定三板斧:

  1. docker ps 确认 PORTS 列有映射;
  2. 容器内 curl localhost:端口 确认服务真的起来了;
  3. ss -lntp | grep 端口 确认宿主机端口没被其他进程占用(-p 8080:80 报 port is already allocated 就是此因)。

7.2 自定义网络

docker network create mynet
docker network ls
docker run -d --name api --network mynet myapp:1.0
docker run -d --name web --network mynet nginx
docker exec -it web ping api           # 同网络内可用容器名直接解析

在同一个自定义网络里,Docker 内置 DNS 会把容器名解析为 IP,这比记 IP 可靠得多,也是 Compose 服务间通信的基础。

八、数据卷:容器的"持久层"

容器可写层随容器删除而消失,需要保留的数据必须落在卷上。

8.1 绑定挂载(bind mount)

docker run -v ~/60/data:/data -it centos /bin/bash

三个部分的含义:

片段 含义
-v 声明数据卷
~/60/data 宿主机目录,不存在会自动创建(以 root 身份创建,常见权限坑)
/data 容器内目录,不存在同样会自动创建

带名字的容器与卷:

# --name 命名容器,同时把宿主机目录挂进容器
docker run -it --name=v-1 -v ~/docker-75/data:/data centos /bin/bash

8.2 命名卷(named volume)

docker run -d --name mysql -v mysql-data:/var/lib/mysql mysql:8
docker volume ls
docker volume inspect mysql-data

两种挂载的取舍:

方式 写法 适用场景
绑定挂载 -v /宿主/绝对路径:/容器路径 开发时改代码即时生效、挂配置文件
命名卷 -v 卷名:/容器路径 数据库、日志等运行数据,由 Docker 统一管理,跨平台一致

8.3 只读挂载与权限

docker run -v /etc/localtime:/etc/localtime:ro -d nginx   # 只读挂载,常用于时区同步

若容器内进程因权限写不了挂载目录,优先检查宿主机目录属主 UID 与容器内用户 UID 是否一致,而不是直接 chmod 777。

九、重启策略:让容器"活着"

docker run -d --restart=always nginx
docker update --restart=always nginx-demo        # 修改已存在容器的策略

原文中的 update --restart=always nginx-demo 缺少 docker 前缀,正确写法是上面这条。

四种策略的差异:

策略 行为
no 默认值,不自动重启
on-failure[:N] 非 0 退出码时重启,最多 N 次
always 无论退出码如何都重启;docker stop 后不再重启,但重启宿主机后会拉起
unless-stopped 同 always,但手动 stop 后即使宿主机重启也不拉起

生产环境推荐 unless-stopped:always 会让运维手动停掉的容器在机器重启后"自己复活",反而干扰故障处理。

十、清理:磁盘告警时的标准动作

docker system df                        # 先看占用分布:镜像/容器/卷/构建缓存
docker system df -v                     # 明细到单个镜像与卷

docker container prune                  # 删除所有已停止的容器
docker image prune                      # 删除悬空镜像
docker image prune -a                   # 删除所有未被容器使用的镜像
docker volume prune                     # 删除未被使用的卷
docker system prune -a --volumes        # 全家桶清理,危险

⚠️ docker system prune -a --volumes 会删除所有未使用镜像、已停止容器与所有未被引用的数据卷(含数据库数据)。执行前务必确认没有"停着但还要用"的容器。

安全的排查顺序是:system df → 定位大头 → 针对性地 image prune / container prune,不要一上来就全家桶。

十一、Docker Compose 常用命令

docker-compose 面向单机多容器编排,一条命令拉起整套依赖。

docker-compose up -d            # 构建并启动所有服务,后台运行
docker-compose up -d --build    # 强制重新构建镜像后再启动
docker-compose ps               # 查看各服务运行状态
docker-compose logs -f          # 跟踪所有服务日志
docker-compose logs -f myApp    # 只看某个服务

docker-compose restart          # 重启所有服务
docker-compose restart myApp    # 只重启 myApp
docker-compose start            # 启动(不重建)所有服务
docker-compose start myApp      # 只启动 myApp
docker-compose stop             # 停止所有服务(保留容器)
docker-compose stop myApp       # 只停止 myApp
docker-compose rm               # 删除已停止的服务容器
docker-compose rm myApp         # 只删除 myApp 的容器

docker-compose down             # 停止并删除容器与网络(推荐用它代替 rm)
docker-compose down -v          # 额外删除数据卷
docker-compose config           # 校验并打印合并后的配置
docker-compose exec myApp sh    # 在运行中的服务里执行命令

两个容易混淆的点:

- `stop` 与 `down`:`stop` 只停容器,容器和网络都还在;`down` 会删除容器和网络,下次 `up` 是全新创建。
- `restart` 不会重新读取 `docker-compose.yml` 的修改。**改了编排文件必须 `up -d`**,`restart` 只重启进程。

Compose V2 中命令为 `docker compose`(中间是空格,作为 Docker CLI 插件),V1 是 `docker-compose`(独立二进制)。两者参数基本一致,新环境建议用 V2。

### 一个最小可用示例

```yaml
services:
  web:
    image: nginx:1.25
    ports:
      - "10001:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped
    depends_on:
      - api

  api:
    build: ./api
    environment:
      - TZ=Asia/Shanghai
    restart: unless-stopped

若使用独立的 compose 二进制,首次还需赋予执行权限:

chmod +x docker-compose

十二、速查表

需求 命令
后台起一个容器并映射端口 docker run -d -p 8080:80 --name web nginx
交互式进入新容器 docker run -it --name c1 centos /bin/bash
进入运行中的容器 docker exec -it 容器名 bash
安全脱离 attach Ctrl+P Ctrl+Q
看日志并跟踪 docker logs -f --tail 100 容器名
看资源占用 docker stats
取容器 IP docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名
拷贝文件进容器 docker cp ./a.jar 容器名:/opt/
构建镜像 docker build -t app:1.0 .
导出 / 导入镜像 docker save -o a.tar app:1.0 / docker load -i a.tar
设开机自启 docker update --restart=always 容器名
批量删容器 docker rm -f $(docker ps -qa)
看磁盘占用 docker system df
拉起整套服务 docker compose up -d
停掉并清理整套服务 docker compose down

十三、八个高频坑

  1. run -it 启动服务类容器,一 exit 服务就停。 服务应使用 -d 后台运行,调试点用 exec 进入。
  2. 用 attach 调试后 exit,容器跟着退出。 记住 Ctrl+P Ctrl+Q,或直接改用 exec。
  3. run 之后再想改端口/挂载。 改不了,必须删掉重建,或改用 Compose 管理配置。
  4. 容器名写错但没报错。 docker rm -f 对不存在的容器会报错,但脚本里用 $(docker ps -qa) 拼参数时若结果为空,可能变成参数缺失的意外行为,加 set -e 更稳。
  5. kill 掉数据库容器后起不来。 断电式终止会留下未完成的事务或锁文件,优先 stop。
  6. 挂载目录权限报 Permission denied。 是 UID 不一致,不是"没给 777 就好"。
  7. 时区不对。 容器默认 UTC,挂载 /etc/localtime:ro 或设置 TZ=Asia/Shanghai。
  8. 数据卷忘了挂,删容器丢数据。 建容器前先想清楚:哪些目录必须在卷上。

小结

日常使用中,真正高频的命令不超过二十条:run ps logs exec cp stop rm images build inspect stats prune 以及 compose up/down。把这二十条用熟,再理解"镜像与容器分离""容器主进程退出即结束""数据必须落在卷上"这三条原则,绝大多数 Docker 操作都能自己推导出来。

排障时保持固定顺序:先看状态,再看日志,再看配置,最后进容器验证。 顺序稳定,效率就不会被情绪带偏。

posted on 2026-11-11 21:37  会是新的白昼  阅读(5)  评论(0)    收藏  举报