Docker 常用命令使用说明¶
按"从拿到镜像到排查容器问题"的实际流程组织,覆盖镜像、容器、网络、数据卷、Compose、日志与排障。带
< >的部分需替换为实际值,[ ]表示可选参数。示例基于 Docker Engine 20.10+ 与 Docker Compose V2(docker compose子命令形式)。
一、安装状态与基本信息¶
docker version # 客户端与服务端版本(服务未起会报连接错误)
docker info # 总览:镜像/容器数、存储驱动、内核、代理配置
systemctl status docker # daemon 运行状态
systemctl enable docker # 开机自启
docker context ls # 当前连接的 Docker 端点(本机/远程)
echo $DOCKER_HOST # 远程端点环境变量(如 tcp:// 或 ssh://)
docker --help # 全部子命令
docker <命令> --help # 单个命令的完整参数,例:docker run --help
免 sudo 使用 docker:
sudo usermod -aG docker $USER(必须带-a,否则会把该用户的其他附加组清空),执行后需重新登录或newgrp docker生效。这等于给用户 root 级权限,共享机器上谨慎开放。
二、镜像管理¶
查找与拉取¶
docker search nginx # 查 Docker Hub(推荐去官网看官方镜像)
docker pull nginx # 拉最新标签(等同 nginx:latest)
docker pull nginx:1.27-alpine # ⚠️ 生产环境务必指定明确标签
docker pull mysql:8.0.36 # 指定版本
docker pull registry.cn-xxx.aliyuncs.com/ns/app:v1.2 # 私有仓库镜像
查看、标记、删除¶
docker images # 本机镜像列表
docker images -q # 只输出镜像 ID(脚本用)
docker image ls --filter "dangling=true" # 列出无标签的悬空镜像
docker inspect nginx:1.27-alpine # 详细信息:层、环境变量、默认启动命令
docker history nginx:1.27-alpine # 逐层构建过程(排查镜像体积很有用)
docker tag myapp:latest registry/ns/myapp:v1.0 # 打标签
docker rmi nginx:1.27-alpine # 删除标签(被容器占用会失败)
docker rmi -f <镜像ID> # 强制删除
docker image prune -a # 清理所有未被容器使用的镜像(⚠️ 交互确认)
docker image prune # 只清理悬空镜像,更安全
导出与导入¶
docker save -o nginx.tar nginx:1.27-alpine # 打包镜像为 tar(离线分发)
docker load -i nginx.tar # 从 tar 载入本机
docker export <容器ID> > rootfs.tar # 导出容器文件系统(丢失分层与元数据)
docker import rootfs.tar myapp:base # 从文件系统 tar 创建镜像
save/load保留镜像完整结构与默认启动命令;export/import只是文件系统快照,导入时必须自己指定启动命令,两者不要混用。
三、容器生命周期¶
创建并启动(run)¶
docker run -d --name web -p 8080:80 nginx:1.27-alpine
# -d 后台运行 --name 命名 -p 主机端口:容器端口
docker run -it ubuntu:22.04 bash # 交互式进入(一次性调试用)
docker run -d --restart=unless-stopped --name redis redis:7-alpine # 开机/崩溃自动重启
docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=StrongPass123 \
-e MYSQL_DATABASE=appdb \
-v /data/mysql:/var/lib/mysql \
--name mysql mysql:8.0.36 # 环境变量 + 数据持久化
docker run -it --rm alpine sh # --rm 退出即删除,适合临时任务
docker run -d --network mynet --add-host api.local:10.0.0.5 app # 指定网络与自定义 hosts
docker run -d -m 512m --cpus 1.5 app # 限制内存与 CPU
docker run -d -v /host/certs:/etc/certs:ro app # 只读挂载
docker run -d --privileged app # ⚠️ 特权模式,容器等同宿主机 root,仅调试用
查看与运行中管理¶
docker ps # 运行中的容器
docker ps -a # 全部(含已退出,重点看 STATUS 与退出码)
docker ps --format '{{.Names}}\t{{.Status}}\t{{.Ports}}' # 自定义输出
docker stats # 实时 CPU/内存/网络(--no-stream 只取一次)
docker top <容器> # 容器内进程
docker inspect <容器> # JSON 全量信息
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <容器> # 取 IP
docker port <容器> # 端口映射关系
docker diff <容器> # 相对镜像被改动了哪些文件
启停、进入、执行¶
docker stop web # 优雅停止(发 SIGTERM,默认等 10s)
docker stop -t 30 web # 自定义优雅等待秒数
docker kill web # 立即 SIGKILL(不给清理机会)
docker start web # 启动已存在的容器
docker restart web # 重启
docker pause / unpause web # 冻结/恢复进程(调试用,少见)
docker rename old new # 改名
docker exec -it web bash # 进入运行中容器(镜像无 bash 时用 sh)
docker exec -u root -it web bash # 以指定用户进入
docker exec web ls /app # 不进入直接执行命令
docker wait web # 阻塞直到容器退出,返回退出码(脚本编排用)
文件复制与删除¶
docker cp web:/app/config.yaml ./ # 容器 → 主机
docker cp ./app.jar web:/app/ # 主机 → 容器
docker rm web # 删除已停止的容器
docker rm -f web # 强制删除运行中的容器
docker container prune # 清理所有已停止容器(⚠️ 先 docker ps -a 确认清单)
docker logs web # 查看日志
docker logs -f --tail 100 web # 跟踪最近 100 行起
docker logs --since 30m web # 最近 30 分钟
docker logs -t web # 加时间戳
⚠️
docker rm会删除容器可写层,容器内直接写下的数据(未挂载卷的部分)会永久丢失。生产数据一律放数据卷或宿主机目录。
四、数据卷与备份¶
docker volume create appdata # 命名卷(推荐,由 Docker 管理路径)
docker volume ls # 列表
docker volume inspect appdata # 查看实际挂载点(一般在 /var/lib/docker/volumes/)
docker run -d -v appdata:/var/lib/mysql mysql:8.0.36 # 使用命名卷
docker run -d -v /data/pg:/var/lib/postgresql/data pg # 绑定挂载宿主机目录
docker run -d --volumes-from mysql0 app # 复用其他容器已挂载的卷(参数是容器名)
docker volume rm appdata # 删除卷(⚠️ 数据不可恢复)
docker volume prune # 清理未被使用的卷
# 卷备份与恢复(标准套路)
docker run --rm -v appdata:/from -v "$(pwd)":/to alpine tar czf /to/appdata.tar.gz -C /from .
docker run --rm -v appdata:/to -v "$(pwd)":/from alpine tar xzf /from/appdata.tar.gz -C /to
五、网络¶
docker network ls # 网络列表(bridge/host/none + 自定义)
docker network create --driver bridge mynet # 自定义网络(容器间可用容器名互访)
docker network inspect mynet # 成员、IP、驱动详情
docker network connect mynet web # 把容器接入网络
docker network disconnect mynet web
docker network rm mynet
docker run -d --network mynet --name api app # 加入网络
# 同一自定义网络内直接用 http://api:8080 访问;默认 bridge 网络需 --link(已废弃)
# 容器内测试连通性
docker exec -it api sh -c "getent hosts db" # DNS 解析
docker exec -it api sh -c "nc -zv db 5432" # 端口可达
| 驱动 | 用途 |
|---|---|
| bridge | 默认,单机容器互联 |
| host | 直接用宿主机网络栈,性能最好但端口会冲突 |
| none | 无网络,隔离任务 |
| overlay | Swarm 多机通信 |
六、镜像构建¶
docker build -t myapp:1.0 . # 用当前目录 Dockerfile 构建
docker build -t myapp:1.0 -f Dockerfile.prod . # 指定文件
docker build --no-cache -t myapp:1.0 . # 忽略缓存(怀疑缓存污染时)
docker build -t myapp:1.0 --build-arg ENV=prod . # 传入构建参数
docker build -t myapp:1.0 --target builder . # 多阶段构建指定目标阶段
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:1.0 . # 跨架构构建
docker images -f "reference=myapp:1.0" # 查构建结果与体积
最小 Dockerfile 骨架¶
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
关键习惯:基础镜像固定版本;先
COPY依赖清单再COPY源码(否则改一行代码就重装全部依赖,缓存失效);构建上下文中无关大文件写进.dockerignore;latest不要用于生产。
七、Docker Compose(多容器编排)¶
docker compose config # 校验并输出最终合并后的配置(排错第一步)
docker compose up -d # 按 compose.yml 创建并后台启动
docker compose up -d --build # 启动前重新构建镜像
docker compose up -d web # 只启动某个服务
docker compose ps # 本项目容器状态
docker compose logs -f --tail 100 # 全部服务日志
docker compose logs -f web # 单个服务日志
docker compose exec web bash # 进入某服务容器
docker compose stop # 停止(保留容器)
docker compose start
docker compose restart web
docker compose down # 停止并删除容器与网络(卷保留)
docker compose down -v # ⚠️ 同时删除数据卷,数据库数据会丢
docker compose pull # 拉取最新基础镜像
docker compose build --no-cache web
docker compose top
# compose.yml 最小示例
services:
web:
build: .
ports: ["8080:80"]
environment:
- DB_HOST=db
depends_on: [db]
restart: unless-stopped
db:
image: mysql:8.0.36
environment:
MYSQL_ROOT_PASSWORD: StrongPass123
volumes:
- dbdata:/var/lib/mysql
restart: unless-stopped
volumes:
dbdata:
老版
docker-compose(带连字符、Python 实现)与新版docker compose命令不通用,但配置文件基本兼容;新装系统一律用docker compose。
八、清理与磁盘治理¶
docker system df # 各类资源占用(镜像/容器/卷/构建缓存)
docker system df -v # 展开到每项明细,定位大对象
docker system prune # 清停止容器 + 悬空镜像 + 未用网络 + 构建缓存
docker system prune -a # ⚠️ 追加删除所有未被使用镜像
docker system prune -a --volumes # ⚠️ 连未使用卷一起删,务必确认无状态服务在跑
docker builder prune # 只清构建缓存(构建机磁盘满常因它)
docker image inspect --format '{{.Size}}' <镜像> # 单个镜像字节数
磁盘突然变满的排查顺序:
df -h→docker system df→ 若是 overlay2 目录大则docker builder prune与docker image prune;若是容器日志,检查/var/lib/docker/containers/*/*-json.log体积并配置日志轮转(见第十节)。
九、私有仓库与推送¶
docker login registry.example.com # 登录(私有仓库需带域名)
docker tag myapp:1.0 registry.example.com/ns/myapp:1.0
docker push registry.example.com/ns/myapp:1.0
docker logout registry.example.com
docker manifest inspect registry.example.com/ns/myapp:1.0 # 查多架构清单
凭据保存在
~/.docker/config.json(明文 base64)。共享机器上建议改用docker-credential-*助手,或每次操作后docker logout。
十、常见故障对照¶
| 现象 | 起手排查 |
|---|---|
| 容器不断重启 | docker ps -a 看退出码 → docker logs --tail 100 <容器> → docker inspect -f '{{.State.ExitCode}} {{.State.OOMKilled}}' <容器> |
docker: Cannot connect to the Docker daemon |
systemctl status docker、journalctl -u docker --since "10 min";再确认当前用户是否在 docker 组 |
| 端口映射不生效 | docker port <容器> 确认映射存在 → ss -tlnp \| grep <端口> 看宿主机是否被其他进程占用 → 云安全组是否放行 |
| 容器内访问不到宿主机服务 | 用 host.docker.internal(Docker Desktop)或宿主机局域网 IP;Linux 上可 --network host 或 ip route 取网关地址 |
| 容器时间/时区不对 | docker exec <容器> date → 加 -e TZ=Asia/Shanghai 或挂载 /etc/localtime |
| 改配置后行为没变 | 镜像未重建:docker compose up -d --build;或 docker build --no-cache |
| 构建卡在拉取基础镜像 | docker info 看 Registry Mirrors;配置 /etc/docker/daemon.json 后 systemctl restart docker |
| 内存超限被杀(OOMKilled=true) | 加 -m 限制前先确认应用真实用量;docker stats 观察,必要时调大或分库拆分 |
| 磁盘被日志写满 | 见第八节;长期方案在 daemon.json 配 "log-driver":"json-file","log-opts":{"max-size":"50m","max-file":"3"} |
| 卷挂载后权限报错 | 容器内用户 uid 与宿主机目录属主不一致:ls -n 对比 uid,用 chown 或 --user 对齐 |
docker rm 提示卷仍被占用 |
先删卷:docker volume rm <卷名>;或 docker rm -v <容器> 一并删除该容器的匿名卷 |
| 无法进入容器(镜像无 bash) | 用 docker exec -it <容器> sh;极简镜像(distroless)无 shell,需另起一个带工具的容器挂载同一文件系统的卷来排查 |
十一、高频场景速查¶
| 场景 | 命令 |
|---|---|
| 起一个临时 MySQL 试数据 | docker run -d --name t-mysql -e MYSQL_ROOT_PASSWORD=root123 -p 3307:3306 mysql:8.0.36 |
| 快速跑一个命令即退出 | docker run --rm alpine date |
| 看某容器占用多少资源 | docker stats --no-stream <容器> |
| 进容器改文件后重新打包 | docker exec 修改 → docker commit <容器> myapp:debug(仅临时救急,正式改动应回写 Dockerfile) |
| 查某镜像的默认启动命令 | docker inspect -f '{{.Config.Cmd}} {{.Config.Entrypoint}}' <镜像> |
| 列出所有容器及其端口 | docker ps -a --format '{{.Names}}: {{.Ports}}' |
| 一次性清理停止的容器 | docker container prune |
| 挂载本地代码热调试 | docker run -d -v "$(pwd)":/app -w /app node:20 npm run dev |
| 把 Compose 项目迁移到新机 | 复制 compose.yml + 镜像(docker save)+ 卷备份(第四节 tar 命令) |
| 检查容器健康状态 | docker inspect -f '{{.State.Health.Status}}' <容器>;docker events 实时看事件 |
| 看 Docker 版本与存储驱动 | docker info --format '{{.ServerVersion}} / {{.Driver}}' |
十二、使用建议¶
- 永远指定明确标签:
nginx:1.27-alpine而不是nginx;latest会在某次重建后悄悄换版本,是"昨天还好好的"最常见原因。 - 数据一律出容器:命名卷或宿主机目录挂载,并定期按第四节做卷备份;删容器前先确认数据不在可写层。
- restart 策略选对:一般服务用
unless-stopped;always会覆盖你手动docker stop的意图;调试期先不设。 - 资源限制与日志轮转提前配:单机多容器时
--cpus/-m与log-opts一次性写进daemon.json,比事后救火省事。 - 别在生产用
--privileged:需要设备访问时优先精确的--device或cap_add,最小权限原则。 - 改完配置记得
config校验:docker compose config能在启动前抓出缩进、服务名拼错、变量未定义等绝大多数低级问题。 - 镜像瘦身靠多阶段与 alpine/slim 基础镜像:
docker history <镜像>逐层找体积元凶,常见是构建工具链和缓存没清(npm ci后删缓存、apt-get install -y --no-install-recommends+rm -rf /var/lib/apt/lists/*)。