Docker 高频操作手册
Docker 高频操作手册
面向日常开发与运维的 Docker 速查手册:镜像/容器/Compose/数据卷/网络/排障/备份/安全。
命令兼容 Docker Engine 20.10+(含 Docker Desktop for Windows/Mac、Linux 原生、云主机)。
Windows 下请在 Git Bash / PowerShell / CMD 中执行,docker CLI 命令本身跨平台一致;涉及 shell 语法差异处已标注。
一、核心概念一句话
| 概念 | 一句话 |
|---|---|
| 镜像 Image | 只读的打包产物(代码 + 运行环境),相当于"安装包" |
| 容器 Container | 镜像运行起来的实例,可启停、可删,数据默认不持久 |
| 数据卷 Volume | 挂载到容器里的持久化目录,容器删了数据还在 |
| 网络 Network | 容器之间的通信通道,同网络内可用服务名互访 |
| Compose | 用 YAML 声明多容器编排,一条命令起整套环境 |
最重要的一条心智模型:容器是"临时"的,数据要放卷里。 90% 的"数据丢了"事故,都是因为没挂卷或删了卷。
二、镜像操作
docker pull nginx:1.27 # 拉取镜像(:tag 指定版本,不写默认 latest)
docker images # 列出本地镜像
docker image inspect nginx:1.27 # 查看镜像详情(架构、环境变量、层信息)
docker rmi nginx:1.27 # 删除镜像(有容器在用时需先删容器或加 -f)
# 构建镜像
docker build -t myapp:1.0 . # 用当前目录 Dockerfile 构建
docker build -t myapp:1.0 --no-cache . # 跳过层缓存(构建异常/要验证依赖时用)
docker build -f deploy/Dockerfile -t myapp:1.0 . # 指定 Dockerfile 路径
# 镜像导出迁移(离线环境/跨机器)
docker save myapp:1.0 | gzip > myapp.tar.gz # 导出
docker load < myapp.tar.gz # 导入
docker save myapp:1.0 -o myapp.tar # 导出为单文件
# 推送到仓库
docker tag myapp:1.0 registry.example.com/myapp:1.0 # 打仓库 tag
docker push registry.example.com/myapp:1.0 # 推送
镜像瘦身三条铁律:
- 用多阶段构建(构建阶段装全套工具,运行阶段只拷产物,见附录)
- 写
.dockerignore(排除 node_modules/.git/dist 等,避免脏文件进镜像 + 缓存失效) - 基础镜像选小体积:
alpine/slim优先,别默认latest全量版
三、容器操作
# 运行
docker run -d --name myapp -p 8080:80 -v mydata:/data -e KEY=value myapp:1.0
# │ │ │ │ │
# 后台运行 容器名 端口映射 数据卷挂载 环境变量
# 常用参数
--restart unless-stopped # 退出自动重启(推荐,配合 docker restart 语义)
--network mynet # 加入自定义网络(容器间用服务名互访的前提)
--env-file .env # 从文件注入环境变量(密钥别写命令行/镜像里)
--read-only # 只读根文件系统(安全加固)
-v /host/path:/container # bind mount(挂宿主机目录)
-v /container # 匿名卷(很少用)
# 查看与启停
docker ps # 运行中的容器
docker ps -a # 全部(含已退出)
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker start/stop/restart myapp
docker rm -f myapp # 删除容器(-f 强删运行中的)
# 日志
docker logs myapp # 全部日志
docker logs -f --tail=200 myapp # 跟随输出,只看最近 200 行
docker logs myapp 2>&1 | grep -i error # 过滤错误
docker logs myapp | grep "traceId" # 用 traceId/请求号 grep 链路
# 进入容器
docker exec -it myapp sh # 交互式进入(alpine 用 sh,Ubuntu 用 bash)
docker exec myapp env # 看容器内环境变量(排查配置)
docker exec myapp cat /etc/hosts # 看 DNS 解析(排查容器互访)
# 拷贝文件
docker cp myapp:/app/logs/ ./logs/ # 容器 → 宿主机
docker cp ./config.yml myapp:/app/config.yml # 宿主机 → 容器
# 端口与资源
docker port myapp # 查看端口映射
docker stats # 实时 CPU/内存(排查资源占用)
docker inspect myapp | grep -i ip # 容器 IP(调试用,正常应走服务名)
四、Compose 多容器编排
# 最常用组合
docker compose up -d # 按 compose.yml 启动(不重建)
docker compose up -d --build # 改代码后重建镜像并启动(部署主命令)
docker compose up -d backend # 只操作某个服务
docker compose down # 停止并删除容器(数据卷保留!)
docker compose down -v # 停止并删除容器+数据卷(⚠️ 数据全清)
# 查看与调试
docker compose ps # 服务状态
docker compose logs -f # 全部服务日志
docker compose logs --tail=200 backend
docker compose exec mysql sh # 进入某服务容器
docker compose config # 校验并打印解析后的最终配置(改完先跑这个)
docker compose config --services # 列出服务名
# 其他常用
docker compose -p myproj up -d # 指定项目名(影响卷名/网络名前缀)
docker compose restart backend # 重启单个服务
docker compose pull # 更新镜像
依赖控制:depends_on + healthcheck。 depends_on 默认只保证"容器启动了",不保证"服务可用了"(比如 MySQL 容器起来 ≠ 能接受连接)。要等真正就绪,必须给依赖服务配健康检查:
services:
mysql:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p123456"]
interval: 10s
timeout: 5s
retries: 10
backend:
depends_on:
mysql:
condition: service_healthy # 等 MySQL 真正就绪
项目名规则: 卷名/网络名 = <项目名>_<声明名>,项目名默认取 compose 文件所在目录名(-p 可覆盖)。所以同一个 compose 文件在两个目录里跑,卷是两套——查卷名请以 docker volume ls 实际输出为准,别靠猜。
五、数据卷与挂载
命名卷(推荐,数据与容器生命周期解耦)
docker volume ls # 列卷
docker volume inspect mydata # 看挂载点(Linux 是 /var/lib/docker/volumes/...)
docker volume create mydata # 手动创建
docker volume rm mydata # 删除
- Linux:卷存在
/var/lib/docker/volumes/<卷名>/_data - Windows(Docker Desktop):存在 WSL2 的
docker-desktop-data发行版里,宿主路径\\wsl$\docker-desktop-data\data\docker\volumes\<卷名>\_data。别手动去翻改,只作查看 - macOS(Docker Desktop):在 Docker Desktop 的 Linux VM 里
卷备份与恢复(通用套路)
# 备份:把卷挂到临时 alpine 容器里打包
docker run --rm -v mydata:/data -v "$(pwd)":/backup \
alpine tar czf /backup/mydata_$(date +%Y%m%d).tar.gz -C /data .
# 恢复:先建空卷,再解包
docker volume create mydata
docker run --rm -v mydata:/data -v "$(pwd)":/backup \
alpine tar xzf /backup/mydata_xxx.tar.gz -C /data
Windows 下
$(pwd)在 Git Bash 可用;PowerShell 用$PWD或${PWD},CMD 用%cd%。
数据库备份(MySQL 示例)
docker compose exec mysql sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD dbname' > backup.sql
# 恢复
docker compose exec -T mysql sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD dbname' < backup.sql
named volume vs bind mount 怎么选
| 命名卷 | bind mount(宿主机目录) | |
|---|---|---|
| 位置 | Docker 管理,不关心具体路径 | 你指定的宿主机路径 |
| 适用 | 数据库/上传文件等纯数据 | 开发调试(改宿主机代码即生效)、nginx 配置 |
| 迁移 | 容易(卷名搬运) | 路径跟着项目走 |
| 权限 | Docker 自动处理 | 需注意 UID 权限(Linux 常见坑) |
六、网络
docker network ls # 列网络(bridge/host/none/自定义)
docker network create mynet # 创建自定义 bridge 网络
docker network inspect mynet # 看网络里的容器与 IP
要点:
- 容器间通信优先用服务名/容器名,不要用 IP(容器重建 IP 会变)。compose 内自动建网络,服务名即 DNS 名
- 自定义网络里容器名可互相解析;默认 bridge 网络只能靠 IP
- 端口映射排查:
docker port <容器>+ 宿主机netstat -ano | findstr <port>(Windows)/ss -tlnp(Linux) - 容器里连宿主机:Linux 用
host.docker.internal(Docker Desktop 已内置),Linux 原生需--add-host=host.docker.internal:host-gateway
七、故障排查清单(按症状定位)
1. 容器起不来 / 一直重启
docker ps -a # 看状态与重启次数(Restarting (1) xx秒前)
docker logs --tail=50 <容器> # 看崩溃原因,这是第一步
docker inspect <容器> | grep -A5 State # 看退出码(ExitCode 137=被杀 143=优雅停)
2. 端口冲突 address already in use
netstat -ano | findstr <port> # Windows 找占用进程
ss -tlnp | grep <port> # Linux
# 解法:停占用进程,或改映射端口后 docker compose up -d
3. 容器 A 连不上容器 B
- 确认在同一网络:
docker network inspect <网络> | grep 容器名 - 代码里连的是服务名不是 localhost/IP
- 确认依赖服务真的起来了(
docker compose ps状态 healthy) - 容器里验证:
docker exec -it <A> sh然后ping <B>/curl <B>:port
4. 容器重启后数据丢了
- 检查数据目录有没有挂卷:
docker inspect <容器> | grep -A10 Mounts - 没有挂卷 → 容器删除即数据消失。改 compose 加 volume,重建
- 挂了卷但数据"没生效" → 检查挂载目标路径是否正确(容器内应用写的目录 vs 挂载点)
5. 中文乱码 / 时区不对
- 时区:
ENV TZ=Asia/Shanghai+-e TZ=Asia/Shanghai - 中文乱码:容器内
LANG=C.UTF-8;数据库初始化脚本顶部SET NAMES utf8mb4;(MySQL 官方镜像 init 脚本默认 latin1 会话字符集)
6. healthcheck 一直 unhealthy
docker inspect --format='{{json .State.Health}}' <容器>
# 常见原因:检查命令本身失败(如 mysqladmin 缺密码参数)、间隔/超时参数不合理、服务启动慢于重试窗口
7. 镜像拉取慢 / 失败
- Docker Desktop:Settings → Docker Engine 里换镜像源(别手改 ~/.docker/daemon.json,会被 GUI 覆盖)
- 国内源参考(需实测,随时可能失效):
https://docker.1panel.live等 - 换源后
docker info | grep -A2 Registry确认生效
8. 容器内时间/日志 UTC 而非本地
- 统一在 compose/Dockerfile 设
TZ=Asia/Shanghai,日志会随之本地化
八、日志与监控
docker logs -f --tail=200 <容器> # 高频操作,够用 90% 场景
docker logs --since 1h <容器> # 最近 1 小时
docker logs --since "2026-08-06T10:00:00" <容器>
docker events --filter container=<容器> # 实时事件流(启停/异常排查)
docker stats # 实时资源占用
docker system df # 磁盘占用分布(镜像/容器/卷/缓存)
日志轮转(防止日志撑爆磁盘): compose 里给服务配:
logging:
driver: json-file
options:
max-size: "20m" # 单文件上限
max-file: "5" # 保留份数
九、清理与镜像瘦身
docker system df # 先看占用,再决定清什么
docker system prune # 清停止容器/悬空镜像/无用网络(不动数据卷)
docker system prune -a # 全清(含未使用镜像,慎用)
docker system prune --volumes # ⚠️ 连未使用数据卷一起清(数据不可恢复)
docker builder prune # 清构建缓存(build 占空间的大头)
docker rm $(docker ps -aq) # 批量删所有停止容器(慎用)
prune 区别一句话: 不带 --volumes 不删卷,带 -a 才删未用镜像。默认的 docker system prune 是相对安全的。
十、备份与恢复(完整清单)
| 要备份的东西 | 方法 |
|---|---|
| 数据卷 | 卷打包法(见第五节) |
| 数据库 | 容器内执行 dump 导出 SQL(通用、跨引擎可恢复,优先于备份数据文件) |
| 镜像 | docker save / docker load(离线迁移) |
| 容器(含配置) | 有 compose 就别 commit;docker commit 只作应急快照,不推荐日常用 |
| Compose 配置 | docker compose config > 解析后配置.yml 留档 |
备份纪律: 先停写(或选低峰),备份后验证可恢复(docker load / 导入 SQL 到临时库跑通),再算备份完成。
十一、安全红线(必读)
- 密钥/密码/token 一律环境变量注入(
--env-file或 compose environment),禁止写进镜像、配置文件、命令行。曾发生 API Key 提交进公开仓库需重写历史的真实事故 - 只暴露必要端口:DB/Redis 等仅内网的服务不要映射到宿主端口;生产用 compose 内部网络互访即可
- 容器内不用 root:
USER指令切非 root;镜像里避免RUN chmod 777 - 基础镜像用可信来源:官方镜像 / 知名组织;
docker scan或trivy扫漏洞 .dockerignore:防止本地敏感文件(.env、密钥文件)被打进镜像- 健康检查 + restart 策略:
restart: unless-stopped让故障自动恢复,减少人工介入窗口
十二、30 秒速查表
| 想做什么 | 命令 |
|---|---|
| 启动(含重建) | docker compose up -d --build |
| 查看状态 | docker compose ps / docker ps -a |
| 看日志 | docker compose logs -f / docker logs -f --tail=200 <c> |
| 进入容器 | docker compose exec <svc> sh |
| 停止(保留数据) | docker compose down |
| 重置(清数据) | docker compose down -v(⚠️) |
| 重启单个服务 | docker compose restart <svc> |
| 拉镜像/构建 | docker pull <img> / docker build -t <tag> . |
| 看卷 | docker volume ls |
| 看资源 | docker stats |
| 磁盘占用 | docker system df |
| 清理 | docker system prune -f |
| 备份卷 | docker run --rm -v <vol>:/data -v $(pwd):/backup alpine tar czf /backup/x.tar.gz -C /data . |
附录 A:Dockerfile 常用指令速查
FROM base:tag # 基础镜像(多阶段构建可写多个 FROM,取最后一个为运行镜像)
WORKDIR /app # 工作目录(不存在自动创建)
COPY src dest # 拷贝(推荐,比 ADD 语义明确;ADD 带自动解压,非必要不用)
RUN cmd # 构建期执行(装依赖/编译)
ENV KEY=value # 环境变量(构建期 + 运行期都生效)
EXPOSE 8080 # 声明端口(仅文档用途,真正映射在 run/compose 配)
USER nonroot # 切非 root 运行(安全)
CMD ["java","-jar","app.jar"] # 运行命令(可被 docker run 参数覆盖)
ENTRYPOINT ["sh","-c"] # 入口(不易覆盖;与 CMD 配合)
多阶段构建模板(Java 为例,其他语言同理):
# 阶段 1:构建(装全套工具)
FROM gradle:8-jdk21 AS build
WORKDIR /app
COPY build.gradle settings.gradle ./
COPY src ./src
RUN gradle bootJar --no-daemon -x test
# 阶段 2:运行(只拷产物,镜像小、攻击面小)
FROM eclipse-temurin:21-jre
COPY --from=build /app/build/libs/*.jar app.jar
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms256m -Xmx512m"
ENTRYPOINT ["sh","-c","java $JAVA_OPTS -jar app.jar"]
层缓存技巧: 把"不常变的依赖声明"COPY 在"频繁变的源码"之前,依赖下载层就能命中缓存。
附录 B:docker-compose.yml 常用字段说明
services:
web:
image: nginx:1.27 # 或 build: ./dir 二选一(或两者都要:build 构建 + image 命名)
build:
context: . # 构建上下文
dockerfile: Dockerfile
container_name: my-web # 固定容器名(一个 compose 内唯一)
ports:
- "8080:80" # 宿主:容器;只写 "80" 则随机宿主端口
expose:
- "8080" # 仅容器间可访问,不映射宿主
environment: # 环境变量(值可引用宿主变量 ${VAR})
KEY: value
env_file: .env # 从文件注入(密钥放这里,不进 git)
volumes:
- mydata:/data # 命名卷
- ./conf:/etc/nginx:ro # bind mount + 只读
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 5s
retries: 3
depends_on:
db:
condition: service_healthy
networks:
- mynet
logging:
driver: json-file
options: { max-size: "20m", max-file: "5" }
networks:
mynet: # 自定义网络(服务名互访)
driver: bridge
volumes:
mydata: # 声明命名卷(卷名 = <项目名>_mydata)
更多推荐

所有评论(0)