资讯动态

Docker实战手册:常用命令、数据卷与避坑排查指南

发布时间:2026/9/18 19:30:26 来源:尧图企业网站定制
工作这几年我几乎每天都要和 Docker 打交道。从最开始在自己电脑上装个 Docker Desktop 跑个测试环境到后来帮同事排查容器起不来、镜像拉不下来这类问题Docker 已经从一个新鲜玩具变成了吃饭的家伙事儿。但是我也见过不少同学包括一些写过几年代码的人面对 Docker 的常用命令还是靠百度出了问题不知道怎么下手。这篇东西不打算讲什么高深原理就把我平时真正用得最多的那些命令捋一遍再把最容易踩的坑和排查思路一起写出来。你要是刚开始学 Docker或者用了一段时间但总在细节上卡壳这篇应该能帮你省不少时间。1. 先把环境搞定安装、启动与镜像加速不知道你们有没有这种体验学 Docker 的第一个拦路虎其实不是命令而是环境本身。尤其是 Windows 用户装完 Docker Desktop 双击图标结果弹出来一句 failed to start because virtualisation support wasnt detected人直接就懵了。所以我先把环境这部分讲透后面再聊命令才有意义。1.1 Windows 与 Mac 用户Docker Desktop 安装与虚拟化检查先说 Windows。Docker Desktop 现在默认用 WSL 2 后端也就是说它需要在 Windows 里跑一个轻量级 Linux 虚拟机而虚拟机的前提是你的 CPU 得开启硬件虚拟化。很多人装完启动报错十有八九是 BIOS 里的虚拟化没开或者 Windows 功能里没启用「适用于 Linux 的 Windows 子系统」和「虚拟机平台」这两个选项。打开 PowerShell管理员执行dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart然后重启电脑。如果还不行进 BIOS 找 Intel VT-x 或者 AMD SVM 的开关把它设为 Enabled。这一步非常关键我之前帮一个同事排查过他折腾了一下午没搞定结果就是 BIOS 里虚拟化被禁用了。Mac 用户相对省心Intel 芯片装 Docker Desktop 需要系统版本满足要求M1/M2 芯片则对应安装 arm64 版本注意别下成 x86_64 版本跑起来性能会有问题。装完以后可以在终端里执行docker version看下客户端和服务端版本如果 Server 部分也正常输出版本号说明 Docker 引擎已经跑起来了。顺带说一句老一点的机器如果开了 Hyper-V也可能和 Docker Desktop 的 WSL 后端冲突。这种情况可以在 Docker Desktop 的 Settings - General 里勾选 Use the WSL 2 based engine或者反过来如果你必须用 Hyper-V就把 WSL 后端关掉二选一不能同时用。1.2 Linux 服务器命令行安装与源的选择生产环境或者自己买的一台云服务器装 Docker 就干净利落多了。Ubuntu 系可以这样先更新索引再装依赖sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg lsb-release然后把 Docker 官方 GPG key 和仓库加进去装 docker-ce 系列包。不过国内服务器直接连官方源经常超时建议把源换成阿里云或者清华的镜像源。以阿里云为例安装完仓库后装包Ubuntu 路径示例curl -fsSL https://mirrors.aliyun.com/docker-ce/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://mirrors.aliyun.com/docker-ce/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-ce-cli containerd.io docker-compose-pluginCentOS 7 的话以前我常用yum install -y yum-utils然后yum-config-manager --add-repo加仓库再直接装 docker-ce。但 CentOS 7 的内核版本偏老跑 Docker 有时候会碰到 iptables 相关的兼容问题能用新系统尽量用新的。装完以后设置开机自启sudo systemctl enable docker --now--now这个参数就是同时完成启动和设置开机自启。执行完sudo docker run hello-world能看到 Hello from Docker! 那段输出说明环境彻底没问题了。1.3 配置镜像加速器解决拉取慢的痛点环境装好了紧接着就会遇到第二个痛点拉官方镜像慢得离谱。因为 Docker Hub 在国外国内网络环境下经常几 KB/s 甚至直接超时。这个问题的解法是配置镜像加速器。我个人的习惯是编辑/etc/docker/daemon.jsonWindows 上对应 Docker Desktop 的 Settings - Docker Engine{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.nju.edu.cn ] }改完以后重启 dockersudo systemctl daemon-reload sudo systemctl restart docker然后随便拉一个镜像试试比如sudo docker pull nginx:alpine速度正常的话就说明加速生效了。这里有个小经验不同加速器服务的可用性会变如果你发现某个加速地址突然拉不动了别死磕换一个就行。我试过好几个加速地址有些一段时间后就失效了所以养成配多个加速源的习惯最稳妥。2. 搞懂核心概念再动手镜像、容器、数据卷与网络很多人命令背得滚瓜烂熟但是一遇到为什么容器删了数据就没了这种问题就懵。说到底是没有把 Docker 的几个基础概念理清楚。2.1 镜像和容器的关系以及为什么删除容器数据会丢镜像Image和容器Container的关系我一般拿菜谱和做出来的菜来打比方。镜像是一份只读的菜谱里面有完整的操作系统文件、运行环境和应用代码容器是根据菜谱做出来的一道菜它是镜像的运行实例。你可以从一个镜像启动多个容器这些容器相互隔离互不影响。容器在运行期间产生的一切改动——比如往 MySQL 里写了数据、在容器里安装了软件包——都存在于容器可写层里。当你执行docker rm 容器名把这个容器删掉这些改动也就随之消失了。这就是为什么很多人 MySQL 容器一删数据全没了吓得以为镜像出了问题其实就是没用数据卷把数据持久化到宿主机。要解决这个问题就得靠数据卷Volume或者 bind mount把宿主机的目录映射进容器。这是 Docker 使用里最基础也最重要的一个认知。2.2 数据卷与挂载让数据活下来数据卷的作用简单说就是把容器里的指定目录指向宿主机的一个目录。这样容器写数据其实是写到宿主机磁盘上容器删了数据还在。用-v参数就能完成挂载。举个例子docker run -d --name mysql-test \ -v /my/own/datadir:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:8.0这里把宿主机的/my/own/datadir目录挂到了容器的/var/lib/mysql目录以后 MySQL 写的数据就落在宿主机上了。哪怕容器删了只要这个目录还在重新起一个容器指定同一个目录数据就还在。如果你在用 Docker Compose写法也差不多services: mysql: image: mysql:8.0 volumes: - ./mysql-data:/var/lib/mysql这里把当前目录下的mysql-data目录映射进去比较好管理。数据卷这块我多说一句别图省事把什么都挂到跟目录下面最好单独建一个目录比如/data/mysql后面备份和迁移都省心。2.3 网络模式理解端口映射和容器互通网络这块是新手最容易迷惑的地方。默认情况下容器内跑的服务在宿主机不能直接访问需要做端口映射。用-p 宿主机端口:容器端口来暴露服务比如docker run -d --name nginx-web -p 8080:80 nginx意思是把宿主机的 8080 端口转发到容器的 80 端口这样访问http://宿主机IP:8080就能访问到容器里的 nginx。容器之间要互通的话推荐用 Docker 网络来实现。先创建网络docker network create my-net然后在运行容器时指定网络docker run -d --name app1 --network my-net myapp:v1 docker run -d --name app2 --network my-net myapp:v2在这同一个网络里容器之间可以直接用容器名通信。比如 app1 要访问 app2 的接口直接写http://app2:8080就行不用记 IP 地址。比默认的 bridge 网络要直观得多。3. 高频常用命令清单记下这些就够了现在进入正题。我不打算把几十条命令都罗列一遍那没有意义。我只挑我平时真正高频使用的按照使用场景分好类看得懂、用得上。3.1 镜像命令拉取、查看、删除、导入导出镜像相关命令是使用 Docker 的第一步也是最频繁接触的。拉取镜像docker pull nginx:latest docker pull mysql:8.0不写标签就默认拉 latest但生产建议明确指定版本避免日常更新把环境搞崩了。查看本地镜像docker images docker images | grep mysqldocker images会列出仓库名、标签、镜像 ID、创建时间和大小。有时候本地镜像很多用grep过滤是标配操作。删除镜像docker rmi nginx:latest docker rmi -f 镜像ID # 强制删除删除有两个前置注意点一是有容器正在用它的时候得先把相关容器删掉才能删镜像二是-f强制删除慎用容易误删。导入导出镜像docker save -o nginx.tar nginx:latest docker load -i nginx.tar这个在离线环境部署非常有用。我在内网环境部署过应用就是先在能联网的机器上docker save打成 tar 包再用docker load导进去比配置内网 registry 简单直接多了。查看镜像和容器的详细信息docker inspect nginx:latest这个命令输出 JSON 格式的详细信息包含环境变量、挂载点、网络配置、入口命令等。排查为什么这个容器配置了环境变量却没生效这类问题docker inspect是首选。3.2 容器命令运行、启停、进入、日志、复制文件容器命令是日常用的核心我把它们分成几个小场景。运行容器docker run -d --name my-nginx -p 8080:80 nginx:alpine-d表示后台运行--name给容器起名-p端口映射。还有几个常用参数-it交互式运行比如docker run -it ubuntu bash会直接进入容器的 shell--rm容器退出时自动删除适合跑一次性任务-e KEYVALUE设置环境变量比如 MySQL 的MYSQL_ROOT_PASSWORD--restartalwaysDocker 服务重启或服务器重启后自动拉起容器写docker run的时候可以顺手加上-v目录挂载上面已经讲过查看容器列表docker ps # 只看运行中的容器 docker ps -a # 看所有容器包括已停止的 docker ps -a | grep mysql-a这个参数非常重要很多容器秒退但你没看到报错就是因为docker ps看不见已退出的容器加了-a才能看到。记住排查问题第一步永远是docker ps -a。启停与删除docker start my-nginx docker stop my-nginx docker restart my-nginx docker rm my-nginxdocker rm默认只能删已停止的容器如果要强制删除运行中的可以加-f。批量清理退出状态的容器我用这个命令docker rm $(docker ps -a -q -f statusexited)进入容器docker exec -it my-nginx bash注意容器里不一定有 bash有些精简镜像只有 sh那就用docker exec -it my-nginx sh。进入容器以后可以做配置检查、看进程、或者手动执行一些脚本。docker attach也可以进入容器但是不推荐日常使用它会把 stdin/stdout 直接连到容器主进程操作不当容易误关容器exec相对安全。查看日志docker logs my-nginx docker logs -f my-nginx # 实时跟踪输出 docker logs --tail 200 my-nginx容器起不来了第一件事就是看日志。我遇到过的绝大多数启动失败最后都是靠docker logs找到原因。复制文件docker cp test.txt my-nginx:/tmp/ # 从宿主机复制到容器 docker cp my-nginx:/etc/nginx/nginx.conf ./ # 从容器复制到宿主机有些镜像里连 vi 都没有改配置不方便我就直接docker cp把文件拷出来改完再放回去比在容器里折腾编辑器省事。查看资源占用docker stats docker top my-nginxdocker stats有点类似top实时看每个容器的 CPU、内存、网络 IO。排查哪个容器把服务器内存吃满了这类问题很有用。3.3 Docker Compose 与快捷操作单容器用docker run完全没问题但当你需要一次启动 MySQL Redis 后端服务 前端服务一条条docker run写起来就像流水账还容易漏参数。这时候应该用docker compose。写docker-compose.yml的通用习惯是把每个服务定义成一个 service指定镜像、端口、环境变量、依赖关系。用的最多的几个命令docker compose up -d # 后台启动所有服务 docker compose up -d --build # 重新构建镜像再启动 docker compose ps # 查看服务状态 docker compose logs -f # 查看所有服务日志 docker compose down # 停止并删除容器/网络 docker compose down -v # 不仅删除容器和网络还删除数据卷慎用我这里要提醒一句docker compose down -v会把数据卷也删掉如果 MySQL 的数据卷挂在里面数据直接就没。我身边真有人手一抖敲过这个命令后半天都在做恢复。要用-v之前务必确认数据有没有备份。还有一个日常清理的神命令docker system prune它会清理所有停止的容器、未被占用的网络、悬空的镜像和构建缓存跑完以后磁盘经常能释放出好几个 G。如果想把缓存和没有使用的镜像一并清掉docker system prune -a这个就比较大刀阔斧了建议在确定本地镜像都不需要保留的前提下执行。4. 实操一把用 Docker 部署 MySQL 8.0含 Compose 方案光罗列命令太干我拿一个最经典的场景——部署 MySQL 8.0把前面讲的命令串起来走一遍。这个场景几乎是所有后端项目都需要的而且踩坑点特别多。4.1 单机 MySQL 的 run 命令逐项拆解先拉镜像docker pull mysql:8.0然后运行docker run -d \ --name mysql-dev \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDroot123456 \ -e TZAsia/Shanghai \ -v /data/mysql/dev:/var/lib/mysql \ -v /etc/localtime:/etc/localtime:ro \ --restartalways \ mysql:8.0逐项拆解-d后台运行不加这个终端就会被 MySQL 的日志刷屏--name mysql-dev给容器命名后面所有操作都用这个名字-p 3306:3306宿主机 3306 映射到容器 3306。如果宿主机的 3306 已经被占用了把左边的端口改成 3307 就行-e MYSQL_ROOT_PASSWORD初始化 root 密码。注意这个环境变量只在首次初始化数据目录时生效对已经初始化的容器改这个变量没用-e TZAsia/Shanghai设置时区不设的话 MySQL 的now()会返回 UTC 时间比北京时间慢 8 小时-v /data/mysql/dev:/var/lib/mysql数据持久化容器删了数据不丢-v /etc/localtime:/etc/localtime:ro宿主机时区文件挂载进去能进一步保证时间对齐--restartalways服务器重启后自动拉起这个参数在真实环境里几乎是必须的4.2 用 docker compose 管理多个容器一个项目里通常不只有 MySQL我用一个最小的 docker-compose.yml 示例version: 3.8 services: mysql: image: mysql:8.0 container_name: mysql-dev restart: always environment: MYSQL_ROOT_PASSWORD: root123456 TZ: Asia/Shanghai ports: - 3306:3306 volumes: - /data/mysql/dev:/var/lib/mysql - /etc/localtime:/etc/localtime:ro redis: image: redis:7-alpine container_name: redis-dev restart: always ports: - 6379:6379 command: redis-server --appendonly yes volumes: - /data/redis/dev:/data这个 yml 里面container_name相当于docker run --name端口、环境变量、数据卷都变成声明式写法command用来覆盖镜像默认的启动命令这里给 Redis 开启了 AOF 持久化启动docker compose up -d查看状态docker compose ps如果改了 yml 配置重新执行docker compose up -d它会自动识别配置变化并重建受影响的容器其他容器不动。用 Compose 管理多服务真的会让人舒心很多。4.3 常见验证与后续扩展起完以后验证几个点docker ps | grep mysql docker logs mysql-dev | tail -100看到ready for connections之类的日志说明 MySQL 初始化成功了。然后再测试连接docker exec -it mysql-dev mysql -uroot -p输入密码能进 MySQL 就大功告成。之后可以用 Navicat 或者命令行连宿主机的 3306 端口测试外部访问注意云服务器安全组要放行对应的端口。这套环境搭好以后后续扩展也比较方便。比如要部署一个前后端分离项目就在 compose 文件里继续加backend和frontend两个 service连接 MySQL 的地址不需要写成 IP直接写服务名mysql就好因为 Compose 会为项目创建独立的网络容器之间自动就能通过服务名互相解析。还有一个很常见的需求给 MySQL 做主从复制。思路是先起一个主库容器和一个从库容器从库的启动命令里加上--server-id2再用 SQL 配置主从关系。核心还是把端口和数据目录分开各自独立挂载。这个场景用 compose 管理更省心因为两个容器要在同一个网络里才能互相访问。5. 避坑指南实际操作中遇到的高频问题这部分是整篇内容里我最想写的部分。网上的教程都在讲这个命令做什么但很少有人告诉你你报了哪个错其实是因为什么。我把自己遇到过的、帮别人排查过的高频问题整理成速查表按频率排序。5.1 Docker Desktop 启动失败虚拟化与 WSL 问题还记得前面说的那个报错吗Docker Desktop failed to start because virtualisation support wasnt detected这可能是 Windows 用户在 Docker 上面临的第一道坎。排查步骤按顺序做确认系统虚拟化已开启。打开任务管理器 - 性能 - CPU看右下角虚拟化是否是已启用如果显示已禁用需要进 BIOS 打开 VT-xIntel或 SVMAMD确认 Windows 功能里已启用虚拟机平台和适用于 Linux 的 Windows 子系统上面给了命令如果使用 WSL 2执行wsl --set-default-version 2确保发行版使用的是 WSL 2 而不是 WSL 1检查 Windows 更新到最新版本老版本的系统对 WSL 2 支持不完整还有一个常见报错是failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinuxen这个一般出现在 Docker Desktop 已经安装但引擎还没启动成功的时候。右键右下角鲸鱼图标看状态如果是 Docker Desktop is starting... 状态等它启动完成再操作如果一直是这个状态把 Docker Desktop 退出重启一次再不行就重启电脑。Windows 下 Docker Desktop 的重启大法虽然不是万能但确实能解决七八成问题。5.2 容器秒退、端口不通先别急着删容器一启动就退出docker ps看不到十个人里有八个会直接搜为什么启动失败。我的建议是先执行docker ps -a docker logs 容器名这两个命令基本能锁定 90% 的原因。常见的有以下几种前台进程退出Docker 容器必须有一个前台进程在前面跑如果镜像默认命令是nginx -g daemon off;这种还好但有些镜像默认跑一个很快结束的脚本容器启动完事就退出了。解法是用-it交互式运行或者把启动命令改成前台模式端口被占用容器启动时如果报bind: address already in use说明宿主机端口已经被别的进程占了。用lsof -i:8080或者netstat -tlnp | grep 8080看一下是谁占的内存不足有时候没有明显报错但启动一个大应用时容器直接被 OOM killer 杀了。看docker inspect 容器名里的State.OOMKilled是否为 true是的话就说明内存不给力。可以通过-m 512m等方式限制内存使用或者给宿主机增加内存挂载目录权限问题容器启动时如果报 permission denied大概率是宿主机的挂载目录权限不对。比如 MySQL 的/var/lib/mysql目录必须是 mysql 用户可写宿主机目录权限不对就直接起不来。解法是chown -R 1000:1000 /data/mysql之类的操作MySQL 容器默认以 uid 1000 运行端口不通的话先确认docker ps里容器确实在运行再用curl 127.0.0.1:8080在宿主机上测如果宿主机可以但外部不通就去检查防火墙和云安全组。很多人忽视安全组其实云服务器的安全组不放行端口其他一切都是白搭。5.3 镜像拉取失败、磁盘占用爆表镜像拉取失败的经典场景是超时或者EOF。除了换加速器还有一个常见原因是 Docker Hub 的限速。遇到toomanyrequests这种报错没有太好的办法只能等一会儿再拉或者换一个镜像源。镜像和容器日积月累磁盘占用会越来越夸张。docker system df可以直观看到镜像、容器、数据卷、缓存各自占了多少空间docker system df如果宿主机磁盘告警先执行docker system prune清理悬空资源然后再看df -h是否释放。还不行就用docker system prune -a把所有未被使用镜像也清掉。这两个命令在执行之前要把自己真正要保留的镜像确认好防止误删。5.4 权限、时区和其他细节Linux 上运行 docker 命令如果报权限错误Got permission denied while trying to connect to the Docker daemon socket这是因为当前用户不在 docker 用户组里。解法sudo usermod -aG docker $USER然后重新登录一次 shell 再试比每次sudo docker要舒服很多。时区问题前面已经提到过容器默认是 UTC 时区尤其是 Java 应用和数据库最容易踩这个坑。除了在容器运行时挂载/etc/localtime和设置TZ环境变量还可以在 Dockerfile 里加上ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone这样生成的镜像本身时区就是对的不用每次跑容器都挂载时区文件。还有一个细节镜像 tag 的latest问题。latest不是一成不变的它指向的镜像内容一直在变。你在服务器上docker pull xxx:latest得到的可能和本地的完全不同。所以不管是写 compose 文件还是脚本最好把版本号写死配合docker image ls审阅一下本地镜像避免昨天还能跑今天就不行的诡异问题。6. 从会用到熟练还需要知道这些到这里常用命令和常见问题基本覆盖了。但如果你想把 Docker 用得再顺手一点还有几个点值得留意。一是给镜像打标签。自己构建镜像的时候用docker tag可以方便地管理版本docker build -t myapp:v1.0.0 . docker tag myapp:v1.0.0 myapp:latest二是构建镜像时注意减少镜像体积。尽量用精简基础镜像比如alpine、slim在 Dockerfile 里把多个 RUN 合并这样生成的镜像小拉取和部署都快不少。我自己写过最夸张的一次从 1.2GB 压到 400MB 左右传输效率提升非常明显。三是可以给 Docker 命令配置自动补全。zsh 和 bash 都有对应的 completion 脚本配上以后敲docker run --按 Tab 能补全参数效率提升立竿见影。不过这个是锦上添花初学者先不用纠结。四是别把容器当成虚拟机来用。很多新手习惯进到容器里apt-get install装东西一重启就没了然后很困惑。正确的姿势是写 Dockerfile把安装步骤固化到镜像里或者通过挂载把配置和数据放进来。容器设计哲学是不可变基础设施这个理念越早理解后面做编排就越顺。最后再说两句我在实际排查问题时有个习惯不管遇到什么报错先做三步docker ps -a看状态docker logs看日志docker inspect看配置。这三板斧下来大多数问题都能定位到七八成。学 Docker 这个事说难也难说简单也简单关键是把基础命令用成肌肉记忆把挂载数据、端口映射、查看日志这几个高频操作搞熟练剩下遇到什么新场景查文档的时候也知道该往哪个方向查。还有个小技巧愿意分享给你们写 Docker 命令时尽量养成完整参数的习惯不要把--name、-v、-p这些省略。我见过太多人图省事跑容器什么都不带结果容器一重启名字随机变数据也没挂载IP 地址也找不到排查问题时追悔莫及。我的习惯是凡是跑一个要长期用的容器必须把名字、挂载、端口、重启策略都写清楚这样哪怕过了几个月再回去看也知道这个容器当初是怎么起出来的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价