1. 内容整体设计与思路拆解为什么你的 Docker 命令总是记不住1.1 核心痛点命令数量爆炸靠背诵永远不够用我接触 Docker 这些年被问得最多的一句话不是Docker 怎么装而是这么多命令到底怎么记才记得住。说实话如果一个一个命令去背学完 Docker 的下一个月就忘掉大半了。这很正常因为 Docker 的命令体系本身就不是设计出来让人背的它是结构化、分层级的。很多人第一次用 Docker最直观的感受是docker ps、docker run、docker images、docker pull这些高频命令看起来很简单但一旦遇到容器怎么进日志怎么看端口怎么映射数据怎么持久化这些问题就卡住了然后翻文档翻半天。这时候你就会意识到Docker 命令是有内在逻辑的不是平铺的一堆参数。1.2 把命令拆成三大块记忆负担直接减半我习惯把 Docker 命令分成三层镜像层、容器层、编排层。镜像层解决的是从哪来、怎么管理的问题对应pull、images、rmi、tag、build、save、load。容器层解决的是怎么跑、怎么管的问题对应run、ps、start、stop、restart、rm、exec、logs。编排层解决的是多个容器怎么协同的问题对应compose、network、volume、swarm这些。你只要抓住这条主线命令就变成了我镜像有了吗我要不要让镜像个容器跑起来跑起来之后我要进去看什么多容器我要怎么编排这样一条操作链而不是一百条独立的记不住的黑命令。这篇指南我按这条主线来写每一步都配合实际场景和参数解析你可以直接拿过去用。2. 环境准备从安装 Docker 到第一个容器的完整闭环2.1 不同系统的安装路径以及 Docker Desktop 的坑Docker 安装是老生常谈但实际操作中坑特别多。Linux 上安装相对简单以 Ubuntu 为例先更新软件源然后装apt-transport-https、ca-certificates、curl这些前置工具再添加 Docker 官方 GPG 密钥最后安装docker-ce和docker-compose-plugin。sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo deb [archamd64 signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-compose-plugin注意安装完 Docker 后默认需要sudo才能执行 Docker 命令。如果你不想每次敲命令都带sudo把当前用户加入docker用户组即可命令是sudo usermod -aG docker $USER。加入用户组后要重新登录一次终端才能生效这一步很多人容易忽略结果回头又来问为什么我加了还要 sudo。Windows 和 macOS 上的方案是 Docker Desktop。下载安装包后一路下一步就行但有两个高频问题你很可能遇到。一个是 Windows 安装时提示virtualization support not detected或者Docker Desktop failed to start because virtualisation support wasnt detected这类问题的根源是 Hyper-V 或 WSL2 没启用。解决方法是先到启用或关闭 Windows 功能里勾选虚拟机平台和适用于 Linux 的 Windows 子系统然后重启再打开 PowerShell 执行wsl --set-default-version 2。如果还是不行进 BIOS 确认虚拟化已经打开。另一个常见问题是镜像拉取过程中出现 not supported 等奇怪的网络报错这通常和 Docker Desktop 的代理设置有关后面我会专门讲镜像源配置。2.2 验证安装和 Docker 守护进程状态装完之后先跑两条命令确认环境正常。docker version会显示 Client 和 Server 两部分信息。正常情况下两条信息都要能显示出来如果只有 Client 没有 Server说明 Docker 守护进程没起来。Linux 上执行sudo systemctl start docker和sudo systemctl enable docker让 Docker 开机自启。docker info可以查看更详细的信息包括容器数量、镜像数量、存储驱动、Cgroup 版本、网络配置等。我建议每次在新环境装完 Docker 都习惯性看一眼docker info尤其要确认存储驱动是overlay2因为老旧的aufs驱动在新内核上兼容性差遇到奇怪问题先检查这里。docker version docker info接下来跑第一个容器验证环境是否可用。我的习惯是先拉一个hello-world镜像虽然它几乎什么都没做但能验证镜像拉取、容器创建、运行、退出这整条链路是否正常。docker pull hello-world docker run --name hello-demo hello-world如果看到 Hello from Docker! 的输出说明整个 Docker 环境已经通了。这时候你也可以装一个自己真正会用到的镜像来进一步验证比如 Nginx 或者 MySQL我在后面第 4 章会详细拆解一个完整的 MySQL 8.0 部署实例。3. 镜像管理命令从拉取、查看到离线迁移3.1 镜像拉取与版本标注Docker 镜像管理的核心起点是docker pull。命令本身很简单docker pull 镜像名:标签。但有个细节很多人没搞清楚标签的默认值是latest。如果你直接docker pull nginx实际拉的是nginx:latest。而latest标签不等于最新稳定版它只是镜像维护者手动标记的一个标签很多项目的latest实际上是开发版或者预发布版。生产环境部署时我强烈建议指定具体版本标签比如nginx:1.27-alpine、mysql:8.0.37这样后续可复现、可回滚。镜像名还分单段和两段比如nginx和library/nginx是同一个东西因为官方镜像默认属于library这个顶层命名空间而像mysql/mysql-server这样的两段式镜像名前面是命名空间后面是镜像名。从第三方仓库拉取时还要在前面加仓库地址比如registry.cn-hangzhou.aliyuncs.com/xxx/xxx。实操心得我一般会在拉镜像前先用docker search看下镜像有哪些版本标签。虽然docker search查不到全部版本列表它返回的是镜像概要信息但能确认镜像是否存在、是否为官方镜像、星标数和描述是否匹配。想看全部版本列表最可靠的办法是直接访问 Docker Hub 官方网站或者用docker pull --help确认参数后拉取试探。版本选择的另一个重要策略是尽量选择alpine变体。alpine是基于 Alpine Linux 的精简版本体积比常规版本小好几倍比如nginx:latest大概 190MBnginx:alpine只有 45MB 左右。对于内存和磁盘敏感的场景用 alpine 变体能显著降低资源占用。缺点是 Alpine 基于 musl libc个别软件编译依赖会出问题但绝大多数主流镜像官方都维护了 alpine 版本踩坑率很低。3.2 镜像查看、删除与离线迁移docker images查看本地镜像列表这个命令显示的字段包括REPOSITORY、TAG、IMAGE ID、CREATED和SIZE。IMAGE ID是镜像的唯一标识但它是短 ID完整的 ID 是 64 位。删除镜像用docker rmi可以接IMAGE ID或镜像名:标签。如果要强制删除加-f参数但这个参数要慎用因为它会跳过镜像正在被容器使用的保护机制可能导致正在运行的容器异常。docker images docker rmi nginx:alpine docker image prunedocker image prune这个清理命令很实用它会删除所有悬挂镜像即没有标签且不被任何容器引用的中间镜像也就是 dangling images。做镜像构建频繁的时候本机会积累很多none镜像占用大量磁盘跑一次docker image prune基本就清干净了。镜像离线迁移是内网环境必备技能。docker save把镜像导出成 tar 文件docker load把 tar 文件再导回镜像。这两个命令我习惯搭配使用比如要把一台服务器上的镜像迁移到另一台离线服务器第一台机器上执行docker save -o nginx-alpine.tar nginx:alpine把 tar 包拷贝到第二台机器后执行docker load -i nginx-alpine.tar注意docker save和docker export是完全不同的两个命令。docker save保存的是镜像docker export导出的是容器的文件系统快照。前者可以完整保留镜像层和历史版本信息适合镜像分发后者不保留镜像元数据导入后会丢失 CMD、ENTRYPOINT 等启动配置适合做容器备份或迁移运行的容器状态。这两个场景不一样千万别混用。3.3 镜像标签和仓库上传docker tag的作用是给镜像打标签常用场景有两个一个是给本地镜像重新命名以便推送另一个是给镜像打特定版本标签。比如本地有个myapp:latest要推送到自己的仓库docker tag myapp:latest registry.example.com/myteam/myapp:v1.0.0 docker push registry.example.com/myteam/myapp:v1.0.0docker push之前必须先用docker login登录目标仓库。Docker Hub 的默认登录地址是index.docker.io/v1/私有仓库则填具体地址。我建议用docker login时配合访问令牌登录 Docker Hub 后在账号设置里生成不要直接使用账号密码因为访问令牌可以按需撤销安全性高很多。4. 容器生命周期命令docker run 到 docker rm 的每一步都拆开讲4.1 docker run 参数解析一次运行一个容器的完整理解docker run是整个 Docker 命令体系里最核心的命令没有之一。它的语法可以拆成三部分启动参数、镜像名和启动命令。启动参数决定容器的运行方式、资源限制和挂载情况镜像名决定容器运行的模板启动命令会覆盖镜像里定义的默认 CMD。我举一个实际生产中用到的完整例子启动一个带端口映射、数据卷、环境变量和自动重启策略的 MySQL 8.0 容器docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDMyPass123 \ -e TZAsia/Shanghai \ -v /data/mysql:/var/lib/mysql \ --restartalways \ mysql:8.0.37逐段解释一下-d后台运行容器容器启动后在后台运行不占用终端。不加-d的话容器会以前台方式运行日志直接输出到当前终端用CtrlC会停止容器。调试阶段我会先用前台方式跑确认日志没异常再改成后台方式。--name mysql8给容器指定名称后续所有对容器的操作logs、exec、stop、rm都可以用这个名字定位。不指定的话 Docker 会生成一个随机名字操作起来很麻烦。-p 3306:3306端口映射格式是宿主机端口:容器端口。外部程序连接宿主机的 3306 端口就能访问到容器内的 MySQL。注意宿主机端口不能冲突如果宿主机上已经有人在监听 3306你就可以映射为-p 3307:3306。-e环境变量MySQL 镜像通过MYSQL_ROOT_PASSWORD来设置 root 密码。不同镜像支持的环境变量不同使用前先看镜像文档。-v /data/mysql:/var/lib/mysql将宿主机的/data/mysql目录挂载到容器的 MySQL 数据目录。这样容器删了、重建了数据还在宿主机上这是实现数据持久化的核心手段。--restartalways容器退出或 Docker 重启后自动拉起。生产环境建议用always或unless-stopped区别在于unless-stopped不会在你手动停止容器后自动拉起而always在 Docker 重启时会启动一切标记为 always 的容器即使你之前手动停过。实操心得-it这个组合参数是交互式进入容器的关键。-i表示保持标准输入打开-t分配一个伪终端。在docker run里交互式创建容器时就把它加上比如docker run -it ubuntu bash会直接进入 Ubuntu 容器的 bash 终端。而docker exec -it是进入一个已经在运行的容器的标准姿势我在下面的章节里专门说。4.2 docker ps 和 docker logs查看容器状态与日志docker ps查看正在运行的容器docker ps -a查看所有容器包括已退出状态的。输出的字段很多最常用的是CONTAINER ID、IMAGE、STATUS、PORTS和NAMES。STATUS字段如果显示Up 3 hours说明容器正在运行显示Exited (0)说明容器已正常退出Exited (1)就是异常退出了。docker logs查看容器日志这个命令在排查容器启动失败时几乎是第一选择。常用参数是-f实时跟随输出类似 tail -f、--tail只显示最后 N 行、--since显示某个时间之后的日志。docker logs -f --tail 100 mysql8这个命令会先打印最后 100 行日志然后保持实时跟进。我调试容器时基本固定用这个组合。4.3 docker exec -it进入容器的正确姿势当容器已经跑起来你想进去执行命令docker exec -it 容器名 /bin/bash是最常用的方式。比如进入 MySQL 容器执行 SQLdocker exec -it mysql8 bash -c mysql -uroot -p这里有个小知识点很多精简镜像里没有bash只有sh。比如alpine系列镜像默认只有sh如果你执行docker exec -it alpine-container /bin/bash会报exec: /bin/bash: stat /bin/bash: no such file or directory。遇到这种情况把/bin/bash换成/bin/sh就行。还有一个思路是在镜像封装时把 bash 装进去但为了一个 sh 能解决的问题去膨胀镜像体积不值得。注意docker exec -it 容器名 bash不加完整路径时Docker 会按默认 PATH 查找命令有时候因为 PATH 配置问题找不到。我建议无论 bash 还是 sh都写完整路径既稳定又快速。4.4 stop、start、restart、kill、rm容器生命周期管理容器生命周期管理的命令其实挺直观stop优雅停止发送 SIGTERM给进程一段时间处理收尾工作kill强制停止直接发 SIGKILLstart启动已存在的容器restart重启容器rm删除容器只能删除已停止的容器如果想删运行中的容器加-f。docker stop mysql8 docker rm mysql8 docker stop mysql8 docker rm mysql8比较实用的一个组合是从停止到删除一气呵成docker stop xxx docker rm xxx。因为我经常需要重建容器用这个方式能防止忘记删掉旧容器导致重名冲突。批量清理容器的需求也很常见用docker ps -a -q获取所有容器的 ID 列表然后配合docker rm批量删除docker rm $(docker ps -a -q)这条命令把$()里的命令输出作为参数传给docker rm所以能一次删掉所有已停止的容器。更稳妥的做法是加-fdocker rm -f $(docker ps -aq)4.5 docker run 之后的资源限制启动容器时还能限制 CPU 和内存这对生产环境尤其重要。不限制的话容器可以吃满宿主机的所有资源一旦某个容器内存泄漏整台机器都会被拖垮。docker run -d --name app_demo --memory512m --cpus1.5 nginx:alpine--memory限制最大内存超限容器会被 OOM Killer 杀掉--cpus限制 CPU 核数1.5 表示最多用 1.5 个核。如果只想限制内存但不想让它被杀死加--memory-swap和--oom-kill-disable但后者要谨慎因为无限交换 / 无限内存意味着可能拖垮宿主机。5. 数据卷与容器网络理解 Docker 的持久化与通信5.1 数据卷管理数据不随容器消失而消失容器的隔离性让数据持久化成为一个矛盾点。容器本身是临时的删除容器后里面写的文件就没了。要保住数据必须使用数据卷或者 bind mount。数据卷的推荐做法是命名卷named volume创建和管理都是docker volume系列命令docker volume create mysql-data docker volume ls docker volume inspect mysql-data挂载命名卷docker run -d --name mysql8 -v mysql-data:/var/lib/mysql mysql:8.0.37关键点在于这里-v参数左边mysql-data是卷名不是宿主机路径。当你只写了一个名字而没写路径分隔符的时候Docker 会把mysql-data当作命名卷来处理自动在宿主机/var/lib/docker/volumes/mysql-data/_data下创建目录。还有一种方式是我前面章节提到的 bind mount将宿主机绝对路径直接挂载进容器docker run -d --name nginx-web -v /home/user/nginx/html:/usr/share/nginx/html:ro nginx:alpinebind mount 的好处是你直接能看到文件、直接编辑适合开发调试。我在开发环境 Nginx 静态文件就是用 bind mount改代码不用重新构建镜像生产环境则优先用命名卷因为 Docker 管理更规范备份恢复也更方便。实操心得-v挂载目录如果宿主机上不存在Docker 会自动帮你创建这个目录。听起来很方便但坑点在于它创建目录的所有者是 root权限往往是 755这时候容器内非 root 用户往挂载目录写文件就会权限不足。遇到明明挂载了却写不进去的报错先检查宿主机目录的属主和权限再用-v挂载时配合:ZSELinux 环境或者在镜像里调整用户权限。5.2 容器网络bridge、host、none 与自定义网络Docker 默认网络模式是 bridge容器通过虚拟网桥docker0通信和宿主机之间也有 NAT 转换。docker network ls能看到当前有哪些网络默认有bridge、host、none三个。实际业务里最常用的是自定义 bridge 网络。自定义网络相比默认 bridge 的优势在于内置 DNS 解析容器之间可以直接用容器名互相访问。比如搭建 Redis 主从时主从容器通过网络用同一套内部网络从节点连接主节点时地址写主节点容器名就行不需要知道具体 IP。docker network create app-net docker run -d --name redis-master --network app-net redis:6.2-alpine docker run -d --name redis-slave --network app-net redis:6.2-alpineHOST 模式直接把容器进程绑到宿主机网络栈性能更好但隔离性差一般用于对网络性能要求极高的场景比如一些高性能代理。none 模式容器没有网络做网络隔离测试时才会用到。查看容器网络详情用docker inspect。这个命令输出的是 JSON 格式的巨量信息包括容器的网络配置、挂载情况、环境变量、启动命令等。查看某个字段时加--format参数更高效比如docker inspect --format{{.NetworkSettings.IPAddress}} mysql8这条命令只输出容器的 IP 地址。docker inspect配合--format是排查容器问题的利器我建议花点时间熟悉 Go template 的基本语法很多信息用一条 inspect 就能精准捞出来。5.3 清理磁盘docker system 系列命令容器和镜像用久了磁盘会莫名其妙小下去。罪魁祸首往往是镜像、无用的容器、悬空数据卷和构建缓存。docker system df可以一次性看磁盘占用情况docker system df输出会列出IMAGES、CONTAINERS、LOCAL VOLUMES、BUILD CACHE四类资源以及 RECLAIMABLE 列这一列显示可回收的空间。清理命令我用得最多的是docker system prunedocker system prune -a这个命令会删除所有未使用的镜像包括历史镜像、停止的容器、未被容器使用的网络和构建缓存。加-a会连未被任何容器引用的镜像一起删而且会提示你确认不放心的话可以加--volumes把未使用的数据卷也清理掉。我在 CI 构建机上定期跑一次能回收大量空间。6. 构建命令与 Compose 编排从单容器到多服务的进阶实战6.1 docker build用 Dockerfile 打包应用镜像有了基础镜像之后真正属于你自己的镜像是通过docker build构建出来的。Dockerfile 里最关键的有几个指令FROM指定基础镜像WORKDIR切换工作目录COPY复制文件RUN执行构建期命令EXPOSE声明容器监听端口CMD或ENTRYPOINT设置容器启动时的默认命令。一个典型的 Node.js 应用 DockerfileFROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install --registryhttps://registry.npmmirror.com COPY . . EXPOSE 3000 CMD [npm, start]构建命令docker build -t myapp:1.0.0 .尾部那个.是构建上下文Dockerfile 里的COPY . .就是从上下文中复制文件。构建上下文越大构建越慢所以.dockerignore文件里要排除node_modules、dist、.git等不需要的文件。6.2 多容器编排docker compose up 一行启全套单容器可以用docker run硬扛一旦服务多了比如 Nginx 后端 Redis MySQL 四个服务你还用一条条docker run去启动管理命令会变得非常痛苦。这时候就需要 Docker Compose。Compose 的核心是docker-compose.yml。我以一个最小可跑的 Nginx Redis 服务为例version: 3.8 services: web: image: nginx:alpine ports: - 8080:80 volumes: - ./html:/usr/share/nginx/html depends_on: - cache cache: image: redis:6.2-alpine然后在同目录执行docker compose up -d-d后台运行。查看日志用docker compose logs -f停止并删除服务用docker compose down重新构建并启动用docker compose up -d --build。如果你改了 compose 文件docker compose up -d会自动检测配置变更并重建受影响的服务。实操心得比较docker-compose和docker compose要注意老版本的 Compose 是 Python 写的docker-compose命令新版 Docker 已经把 Compose 集成到 Docker CLI 里了命令是docker compose。如果执行docker compose报 unknown command说明你装的是老版本 Docker需要单独安装docker-compose-plugin。现在主流 Linux 发行版默认都给的是新命令但很多旧教程还在用旧命令看教程时注意区分。在 Compose 配置里我会给每个服务单独设置restart: unless-stopped这样节点重启后服务能自动恢复这是生产部署的一个基本素养。资源限制也可以直接写在 compose 文件里比如web: image: nginx:alpine deploy: resources: limits: memory: 256M6.3 一个完整的 Redis 主从编排示例Redis 主从是面试和实操都经常遇到的需求。用 Compose 编排两个 Redis 容器实现主从复制version: 3.8 services: redis-master: image: redis:6.2-alpine container_name: redis-master command: redis-server --requirepass 123456 ports: - 6379:6379 networks: - redis-net redis-slave: image: redis:6.2-alpine container_name: redis-slave command: redis-server --slaveof redis-master 6379 --masterauth 123456 ports: - 6380:6379 depends_on: - redis-master networks: - redis-net networks: redis-net:启动docker compose up -d docker exec -it redis-slave redis-cli -a 123456 info replication你能看到role:slave输出master_link_status:up说明主从已经通了。这个示例的核心在于两个容器都在同一个自定义网络redis-net里从容器通过redis-master这个容器名就能解析到主容器地址这就是自定义网络内置 DNS 的威力。7. 常见问题与排查技巧实录7.1 Windows Docker Desktop 启动失败Windows 上最常见的报错就是Docker Desktop failed to start because virtualisation support wasnt detected其次是 incompatible version of Windows。先看第一个。虚拟化支持没被检测到按这个顺序排查先进 BIOS 确认Intel VT-x或AMD-V已经开启然后打开启用或关闭 Windows 功能勾选虚拟机平台和适用于 Linux 的 Windows 子系统接着用管理员 PowerShell 执行wsl --set-default-version 2最后重启再启动 Docker Desktop。如果系统提示需要安装 WSL2 内核按提示下载安装即可。第二个报错是 Windows 版本过旧。Docker Desktop 对 Windows 10 的版本有要求必须 2004 以上版本并确保系统更新补丁打全。老版本系统直接升级或者干脆装 Docker Toolbox 这种遗留方案但不建议维护成本很高。7.2 镜像拉取慢、失败以及重启后镜像源丢失镜像拉取慢是国内 Docker 用户最头疼的问题之一。常规思路配置镜像加速器Docker Desktop 在 Settings - Docker Engine 里加一段配置{ registry-mirrors: [ https://docker.m.daocloud.io ] }保存后 Docker Engine 会自动重启然后重新docker pull试试。加速器地址选择要谨慎优先选公共可信度高的镜像站同时注意配置到多个地址轮流用不要吊死在一棵树上。如果拉取还是失败可以用docker pull时指定直连官方仓库的代理规避方式不过这块限于篇幅不展开核心思路是让 Docker 进程的网络走可用通道。注意配置完镜像加速器后老 Docker Desktop 版本可能存在重启后配置丢失的情况。解决办法是确认保存成功后再重启 Docker Desktop或者在启动脚本里动态写入配置。我自己踩过几次昨天还能拉今天又不行了的坑排查到最后发现是配置被覆盖了。7.3 容器启动后秒退docker ps看到容器状态是Exited (0)或者Exited (1)大概率原因有几种第一种前台进程不存在。容器的主进程是一个前台进程它一旦退出容器就结束。比如你docker run nginx没加-dnginx 正常前台运行但如果你跑一个docker run ubuntu bashbash 执行完就退出容器自然就 Exited 了。解决办法是给容器一个常驻前台命令比如docker run -d ubuntu tail -f /dev/null。第二种应用启动失败了比如 MySQL 密码参数没传、端口被占用、数据目录权限不对。这种就要看日志docker logs 容器名基本能找到线索。我开发时看到容器退出第一反应永远是这几条命令轮番上docker ps -a docker logs --tail 50 容器名 docker inspect 容器名第三种资源不足。物理机内存不够容器内的 Java 或 Node 进程直接被 OOM 掉。docker inspect 容器名里OOMKilled字段是true就能确认解决办法是调整--memory限制或换大内存机器。7.4 exec 进不去容器、权限和交互问题docker exec进不去容器最常见的问题是镜像里没有 bash前面已经说过换/bin/sh。另一个问题是容器主进程状态异常导致 exec 无法连接这种先docker restart再 exec。交互式操作时记住两点-i不分配终端也能保持输入流但光标、颜色、回车表现会不正常所以基本都配-t组合成-it环境变量不完整时某些命令会报错比如mysql命令找不到MYSQL_HOME可以先env看看当前容器环境变量再决定是直接补全命令还是进容器里 export。实操心得怎么判断容器里有没有 bash最简单是docker exec 容器名 which bash有输出就是有 bash没有则执行docker exec 容器名 which sh兜底。这个技巧我在排障时几乎天天用比盲猜快得多。7.5 容器内文件拷贝与备份在容器和宿主机之间拷贝文件用docker cp。方向有两种宿主机到容器容器到宿主机docker cp /host/file.txt mysql8:/tmp/ docker cp mysql8:/var/lib/mysql/mysql.sock /host/mysql.sock注意docker cp的命令格式是docker cp src container:dest或反着来容器名和路径之间是冒号。拷贝目录时记得加-r参数递归复制。这个命令在调试时很实用比如要临时把宿主机上的配置文件覆盖进容器测试但又不修改镜像。备份场景下如果要备份整个 MySQL 数据库更好的方案是走 mysqldump因为docker cp直接拷贝数据文件可能因为版本不一致或者表锁问题导致数据不一致。8. 我的几个经验总结与学习建议8.1 把命令当工具链而不是当考试题我见过太多人花大量时间背命令最后收效甚微。Docker 命令的掌握方式应该是用一个学一个用到哪个命令就去查它的--help理解了它在整个操作链里的位置再用几次就记住了。别急着把所有命令都背下来先记住run、ps、logs、exec、stop、rm这一条最核心的生命周期管线再逐步扩展。Docker 官方文档的参考页写得不错每次看到不熟悉的命令我的习惯是docker command --help先看参数列表再对照官方文档确认细节。命令行里直接输出帮助信息比翻浏览器快得多。8.2 用 alias 和脚本简化高频操作高频命令可以做成 alias比如我经常用dps代替docker ps --format table {{.Names}}\t{{.Status}}\t{{.Ports}}把输出格式精简成只关心名字、状态和端口。这个--format技巧也很实用能让你一屏看到更多容器而不是被长 ID 和 Image 占满。更复杂的场景我会写一个部署脚本比如在服务器上发布新版应用#!/bin/bash docker build -t myapp:$1 . docker stop myapp || true docker rm myapp || true docker run -d --name myapp -p 8080:8080 myapp:$1脚本第一行接收版本号参数构建对应版本的镜像然后停掉旧容器、删掉旧容器最后用新镜像跑新容器。|| true的意思是即使前一个命令失败也不中断脚本防止因为容器本来就不存在导致脚本卡住。8.3 最后补一句关于命令安全的小提醒Docker 的很多命令有强制参数-f、--force、-v在删卷时是危险操作。docker rm -f会直接杀掉正在运行的容器docker volume rm -f会删数据卷删完之后数据无法恢复。我在生产环境执行删除操作前习惯先docker ps -a和docker volume ls看清楚对象再执行删除。这不算胆小是做运维的基本素养。以上就是我这些年用 Docker 命令的一点积累。命令本身只是工具真正值钱的是你清楚每一步操作背后的逻辑和可能产生的影响。把这些命令用熟悉你会发现容器化部署并不神秘无非是拿着镜像跑容器再把容器管明白这回事。
