尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Docker常用命令与实战排查:从环境安装到容器部署全指南

Docker常用命令与实战排查:从环境安装到容器部署全指南 前阵子帮同事排查Docker Desktop启动失败的问题折腾了一个下午最后发现是BIOS里虚拟化没打开。这种情况在刚接触docker常用命令学习阶段非常典型很多人还没跑到命令这一环就被环境安装卡住了。Docker的命令本身并不难记难的是你在敲每一条命令时脑子里有没有一幅正确的运行图像。这篇文章不打算给你罗列一份“史上最全命令清单”而是想从使用者的真实路径出发把最常用的Docker命令按逻辑分组讲透同时把我在Windows、Linux上实际踩过的问题排查链路完整贴出来。不管你是刚入门还是已经在容器里跑了好几个服务这几页内容应该都能帮你省下不少时间。1. 先搞明白Docker在解决什么问题1.1 容器和虚拟机的本质差别很多人学Docker时总喜欢先问“容器和虚拟机哪个好”这个问题其实会带偏方向。虚拟机是把一整台电脑的硬件虚拟化出来里面跑一个完整的操作系统所以体积大、启动慢、资源占用高。容器则不太一样它复用了当前Linux内核的能力通过namespace做隔离、通过cgroups做资源限制本质上就是一组互相隔离的进程。用生活类比来说虚拟机是搬家时把客厅、卧室、厨房整套搬进新屋容器则只需要带必需品大家共享同一套水电线路。理解这点很重要因为它直接决定了你使用Docker的心态。容器不是微型操作系统它内部跑的是业务进程所以当你看到“Alpine版”镜像只有几MB时不需要惊讶。因为你不需要在镜像里塞systemd、塞一堆系统工具只要运行库和依赖够用就行。这也是为什么容器能在秒级启动而虚拟机往往要等几十秒到几分钟的原因。1.2 镜像与容器的关系像烤蛋糕一样好理解镜像Image和容器Container是最容易绕晕的一对概念。我用烤蛋糕来比喻镜像就是菜谱和模具容器就是烤出来的那块蛋糕。菜谱是死的读一百遍也不会有变化但按菜谱烤蛋糕每次都能得到一块实实在在可以切的蛋糕。多个蛋糕可以来自同一份菜谱同理一个镜像可以启动多个容器它们之间互不影响。从技术细节上看镜像是由多个只读层layer叠加组成的容器则是在镜像最上面加了一层可写层。你启动一个容器后修改文件改动只发生在可写层里所以容器删掉后改动也就一起没了。这个特性也就引出了“为什么需要数据卷”的问题后面第4章会专门演示。理解了镜像与容器的关系你再看docker run、docker commit、docker build这些命令就不会觉得它们是一堆孤立操作了。1.3 为什么命令记不住因为缺了这套思维模型我在网上看到很多人求“docker常用命令大全”背完还是忘。原因很简单你在靠肌肉记忆背一个没有逻辑的列表而不是在理解Docker的组件模型。Docker的常用操作可以用四句话概括镜像管构建、容器管运行、网络管互通、数据卷管持久化。你敲的每一条命令都逃不出这四个维度。比如说docker pull拉的是镜像docker run也会自动拉镜像docker ps看的是容器docker images看的是镜像docker network和docker volume则负责另外两块。当你把命令挂在这根思维轴上时遇到新命令也能大概猜出它的功能不需要翻文档。接下来我会按这套模型带你过一遍真正高频的命令。2. 从安装到验证环境准备阶段的三个大坑2.1 Windows平台安装Docker Desktop的前置条件很多人在Windows上装Docker Desktop装完双击图标结果弹出“docker desktop failed to start because virtualisation support wasnt detected”或类似提示。我先说结论这基本不是Docker Desktop的问题而是你的Windows环境没满足前置条件。Docker Desktop在Windows上依赖两类后端老版本的Hyper-V以及现在主流的WSL2。无论哪类都要求CPU支持虚拟化并且已经在BIOS中开启。排查链路是这样的先打开任务管理器切到“性能”选项卡看右下角“虚拟化”那栏是否是“已启用”。如果显示“已禁用”那就需要重启电脑按品牌机型进BIOS界面找到Intel Virtualization Technology或AMD SVM Mode把它们设为Enabled。注意有些笔记本需要在安全设置中先关闭“Core Isolation”的内存完整性否则虚拟机监控程序加载会受影响这个坑我在新机器上踩过好几次。如果你不想折腾BIOS也可以尝试在Windows功能中勾选“虚拟机平台”和“适用于Linux的Windows子系统”然后安装并启用WSL2。Home版Windows没有Hyper-V但完全可以用WSL2前提是内核版本符合要求。安装完记得在PowerShell里执行wsl --set-default-version 2否则可能还是用的1代版本Docker Desktop会一直报连接异常。2.2 安装后第一件事配置镜像加速源环境装好后第一件事不要急着跑hello-world而是把容器镜像源配好。原因很现实默认从Docker Hub拉取镜像在部分网络环境下波动很大经常超时。我常用的做法是修改/etc/docker/daemon.jsonLinuxWindows则在Docker Desktop的Settings - Docker Engine里编辑。配置格式大致是{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ] }不同加速源的可用性随时会变建议你以官方或社区当前推荐的为准。配置完成后需要重启Docker才能生效。很多人改完发现没用就是因为没有重启还有人是把配置文件写坏了导致Docker服务起不来。验证是否生效的办法很简单执行docker info在输出里找到“Registry Mirrors”这一段如果看到你填的地址说明生效了。如果这里为空请检查配置文件格式和重启动作。2.3 验证安装的几条命令别急着跑容器安装验证不一定非要用docker run hello-world因为那还要拉取镜像。更快捷的验证方式是两条基础命令docker version docker infodocker version会分别显示Client和Server的信息。注意如果Server部分报错说明Docker引擎没起来这时候你去跑run命令只会得到“Cannot connect to the Docker daemon”的提示。docker info展示的不仅是版本还包括容器数量、镜像数量、存储驱动、镜像源等关键信息。我一般先看这两个输出确认无误后再开始干活。这里顺便提一下Linux下的权限问题如果你是用普通用户执行docker命令很容易遇到“permission denied”或socket权限错误。这是因为Docker默认通过/var/run/docker.sock这个Unix套接字通信只有root和docker组内的用户能用。最简单的解决方法是把当前用户加入docker组sudo usermod -aG docker $USER执行完重新登录终端才生效。注意把用户加进docker组相当于授予了较高权限生产环境一定要谨慎控制成员范围。3. 高频命令分组记忆法按生命周期来梳理3.1 镜像命令搜索、拉取、查看、删除与构建镜像相关的命令是Docker操作的第一步。搜索镜像docker search nginx这个命令会去Docker Hub搜索镜像名或描述匹配的镜像可以看到官方镜像、星级、是否自动构建等信息。不过说实话日常用起来我更推荐直接去官网页面搜因为页面上会有tag列表和文档说明docker search展示的信息有限。拉取镜像docker pull nginx:alpine这里的关键是指定tag。nginx是仓库名alpine是标签表示基于Alpine Linux的轻量版本。不写tag默认拉取latest但有风险因为latest的版本可能随着时间变化不可复现。生产环境建议固定用具体的版本号如1.25.3-alpine。查看本地镜像docker images docker image ls两者等价。常用参数包括-a显示所有中间层-q只显示镜像ID这个很常用因为在脚本里可能要用镜像ID来做变量。删除镜像docker rmi nginx:alpine注意如果某个镜像已经被容器引用必须先删除容器才能删除镜像。这是新手常遇到的删除失败原因。删除所有未被容器使用的镜像可以用docker image prune但谨慎操作。构建镜像docker build -t myweb:v1.0 .基于当前目录的Dockerfile构建一个叫myweb、标签v1.0的镜像。关于Dockerfile的细节这里不展开但要知道指令层级FROM基础镜像、RUN执行命令、COPY或ADD复制文件、CMD或ENTRYPOINT指定容器启动命令。理解的Dockerfile后你就不太需要依赖docker commit来生成镜像了。3.2 容器命令run、ps、exec、logs最常用的五件套容器命令是使用频率最高的。启动容器docker run -d --name mynginx -p 8080:80 nginx:alpine这个命令要拆开看-d表示后台运行--name给容器起个名字-p做了端口映射把宿主机8080端口映射到容器的80端口。这样你再访问http://localhost:8080就能看到nginx欢迎页。如果去掉-d容器会以前台方式运行输出直接打到终端更适合用来调试按CtrlC容器也就停了。查看容器docker ps docker ps -adocker ps只列出运行中的容器-a会把所有容器包括退出状态的都列出来。实际操作中我经常用docker ps -a找“挂掉”的容器再根据容器ID去查日志。在脚本里还可以用-q参数只拿容器ID配和awk使用非常顺手。查看日志docker logs mynginx docker logs -f --tail 200 mynginx-f表示持续跟踪输出--tail 200表示只看最后200行。如果服务启动失败第一条命令基本就能看到报错原因。很多“容器进了但服务没起来”的问题看日志比进容器里敲命令高效得多。进入容器docker exec -it mynginx sh这个命令固定用-it组合。-i表示交互-t分配终端。在容器内执行exit退出。如果容器内没有bash就用shalpine镜像通常只有sh。进入容器主要用于检查配置、手动运行命令但千万别依赖它去改生产环境的程序改完容器一删就没了正确做法是用挂载或重新构建镜像。停止与删除容器docker stop mynginx docker start mynginx docker restart mynginx docker rm mynginxstop发送SIGTERM给容器优雅关闭的机会如果超时再发SIGKILL。rm删除容器前会确认容器已停止所以你如果直接删运行中的容器会报错可以先stop再rm或者用rm -f强制删除。3.3 数据卷与网络命令这两个经常被搞混数据卷Volume和网络Network是容器之间实现共享和通信的基础。数据卷命令docker volume create mydata docker volume ls docker volume inspect mydata docker volume rm mydata数据卷的主要作用是让数据不随着容器生命周期而消失。可以把卷理解为宿主机上的一个特殊目录Docker替你接管它。在启动容器时用-v或者--mount参数挂载docker run -d --name db -v mydata:/var/lib/mysql mysql:8.0如果你的场景只是临时看看数据也可以用bind mount直接挂宿主机目录-v /host/path:/container/path。区别在于命名卷更便于迁移和备份bind mount更直观但容易受宿主机目录权限影响。网络命令docker network ls docker network create mynet docker network inspect mynet docker network connect mynet mynginx docker network disconnect mynet mynginx docker network rm mynet默认有bridge、host和none三种网络。bridge网络在宿主机上创建一个虚拟网桥容器通过它访问外部容器之间也可以通过容器名互相访问在同一个自定义网络里。host模式让容器直接共享宿主机网络栈不进行网络隔离性能和兼容性更强但端口不能冲突。多容器部署时我强烈建议创建自定义bridge网络用容器名通信比如后续那些需要主从关系的服务这比依赖IP地址可靠得多。3.4 几个组合命令一条命令顶十条学习命令有个偷懒技巧掌握几个带参数或组合的玩法能省掉大量重复劳动。临时测试某个镜像docker run --rm -it alpine:latest sh--rm表示容器退出后自动删除避免测试一次留下一个垃圾容器。查看容器资源占用docker stats实时显示CPU、内存、网络I/O排查性能问题时特别有用。查看磁盘占用docker system df能看到镜像和容器占了多少空间。配合清理命令docker system prune它会删除所有停止的容器、没有被使用的网络、悬空的镜像还会删除全部无用数据卷注意加-a才能连未使用的镜像一起清理。我每次清理前都先跑docker system df看下能释放多少免得清理完才后悔。日志清理容器日志会无限增长尤其某些服务长期运行大到几GB。可以通过设置daemon.json中的max-size和max-file来限制也可以定时执行docker logs --tail0 -f 容器名 /dev/null 21 不过这只能临时释放当前文件句柄彻底解决还是得靠配置轮转日志这是后话。4. 完整实操用nginx跑一个静态站点并挂载数据4.1 从拉取镜像到容器启动看下全过程光说命令容易飘我把最近一次给朋友搭静态页面的过程完整走一遍。先拉取镜像并启动容器docker pull nginx:alpine docker run -d --name mysite -p 8080:80 nginx:alpine执行完docker ps会看到mysite这个容器的状态是Up。接着在浏览器访问http://your-host:8080会看到nginx默认欢迎页。这一步能走通说明镜像拉取、容器启动、端口映射、网络访问整个链路都没有问题。在这个阶段常见的问题是端口占用如果你本机8080已经跑着别的服务Docker不会启动日志会提示bind: address already in use。解决办法很简单换一个宿主机端口映射比如-p 8081:80。4.2 端口映射的隐藏细节为什么8080:80这么写虽然-p 8080:80看起来只是简单的“左对右”但底层逻辑其实挺值得理解。右侧的80是nginx在容器内部监听的端口这个端口由镜像的用户确定左侧的8080是你选择对外开放的宿主机端口用户可以自己定。内外端口不一致的原因是容器是隔离的外部根本无法直接访问它的80端口必须通过宿主机端口把流量转发进去。Docker在Linux上通过iptables规则完成这个转发这也是为什么修改防火墙时不要随意清掉Docker创建的规则。如果你把端口写成-p 80:80那宿主机和容器共用80端口如果宿主机上已有web服务就会冲突。多项目部署时我一般习惯左端口按项目分配比如8010、8020这样通过端口就能快速区分是哪个服务。还有一个小参数-p 127.0.0.1:8080:80表示只绑定本机回环地址外网无法访问适合搭一些仅本机调试的服务。4.3 挂载目录后修改静态文件的正确姿势默认nginx镜像里的/usr/share/nginx/html是只读层你直接改很麻烦而且容器删除后改动就没了。为了能像操作普通目录一样管理静态文件我会把宿主机目录挂载进去。启动时加上-v参数docker run -d --name mysite -p 8080:80 -v /home/user/mysite/html:/usr/share/nginx/html:ro nginx:alpine后面的:ro表示宿主机目录以只读方式挂载给容器对nginx来说足够也避免容器内误改。这时候你只要在宿主机目录里放一个index.html刷新浏览器nginx就会直接渲染它不需要重新构建镜像。挂载目录最常见的问题就是权限由于容器内nginx进程默认以www-data用户运行宿主机目录的权限如果太严格容器内就读取不到。遇到403时先ls -l看一下目录是否至少具备755权限文件是否至少644。4.4 进入容器排查nginx问题并生成新镜像如果页面打开是500或502我会先看日志docker logs mysitenginx日志通常能直接告诉你配置错误行。如果日志不够再进容器检查docker exec -it mysite sh cat /etc/nginx/conf.d/default.conf改配置文件时我强烈建议不要把文件直接改在容器里而是把宿主机的conf文件挂载到容器的/etc/nginx/conf.d/目录这样既能保证宿主机留底又能让多个容器复用同一份配置。如果你确实需要对一个已经运行的容器做点修改并且容器会删除、你不想从头搭可以用docker commit保存现场docker commit mysite mysite:backup但我不推荐常规使用因为用commit生成的镜像不会保留构建过程后续追溯和变更管理都很痛苦。正确做法是把改动写进Dockerfile从源头构建。等到既要保留数据又要保持可迁移时数据卷的重要性就体现出来了这也是为什么我总强调容器“无状态化”。5. 实际工作中遇到的四个典型难题与完整排查链路5.1 Docker Desktop启动报错virtualisation support wasnt detected这个报错几乎每周都会在社区里看到我同事的电脑上就遇到过。完整提示一般是“Docker Desktop failed to start because virtualisation support wasnt detected.”。我第一次碰到时也以为是Docker坏了后来按下面链路一步步排发现是虚拟机监控程序没启用。排查步骤打开任务管理器在性能选项卡查看“虚拟化”状态如果不是“已启用”重启进BIOS开启对应的VT-x/AMD-V选项。如果虚拟化已经是启用状态检查Windows功能里“虚拟机监控程序”或“Windows Hypervisor Platform”是否勾选。确认WSL2是否安装且正常执行wsl --status查看版本。如果显示内核版本过旧执行wsl --update。在PowerShell执行bcdedit查看hypervisorlaunchtype的值如果是OffDocker Desktop无法启动。设为Auto命令是bcdedit /set hypervisorlaunchtype auto需要管理员权限。这四项里前两项占80%的原因。如果你用的是老版本Windows没有开启“基于虚拟化的安全性”VBS也可能导致Hyper-V无法工作。总之这类问题的核心是虚拟化支持没有进入“可用”状态跟Docker Desktop本身没有关系所以重装软件是无效的。5.2 连接Docker引擎失败npipe管线错误的排查过程在Windows上有时候Docker Desktop图标是绿的但你在命令行执行docker version却报错error during connect: This error may indicate that the docker daemon is not running: Get http://%2F%2F.%2Fpipe%2FdockerDesktopLinuxEngine: open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.这类npipe错误很让人抓狂因为表面看图形界面“一切正常”。我分析过各种可能最常见的是Docker Desktop后端容器引擎还没就绪但命令行连接被系统抢跑了。排查顺序是先关闭Docker Desktop然后到任务管理器里把所有Docker相关后台进程结束再重新打开。因为它有时候只是界面活了引擎没起来。执行docker context ls看当前context是不是指向desktop-linux。如果被切换到其他context比如default就会试图连接本地套接字导致失败。可以用docker context use desktop-linux切回来。确认WSL集成没有异常。Docker Desktop设置里Resources-WSL Integration勾选对应发行版让引擎从WSL内启动。如果是长期没有重启Windows的机器建议先重启一下WSL运行wsl --shutdown再启动Docker Desktop。这条链路走完绝大多数npipe报错都能解决。如果你在Linux上看到类似“Cannot connect to the Docker daemon at unix:///var/run/docker.sock”那就是Docker服务没起来执行systemctl start docker或service docker start即可。5.3 镜像拉取慢/超时换源后依然没解决的根因镜像拉取慢这件事大家首先想到的是配镜像加速器前面2.2节也写了。但有个现象是明明已经改好daemon.json里的registry-mirrors重启后还是慢得不行。我至少遇到过三次最后查下来的根因基本都是“默认源先行”。Docker拉取镜像的机制是如果镜像名没有显式指定registry地址比如nginx这种Docker会去第一个registry-mirrors尝试拉取全部失败后再回退到官方Docker Hub。如果你的加速器配置正确但网络到加速器也慢那就需要换更快的源或者直接指定镜像完整地址。比如docker pull docker.m.daocloud.io/library/nginx:alpine拉下来后用tag改回标准名称docker tag docker.m.daocloud.io/library/nginx:alpine nginx:alpine这样后续引用nginx:alpine不会再到官方源找。验证配置是否真的走了加速器可以用docker info查询同时也可以开启--debug模式看拉取请求具体发给了哪个地址。如果网络确实恶劣也可以考虑用其他工具做代理但这属于网络环境层面的方案不同场景限制很多这里就不展开了。5.4 容器内时间不是北京时间这个坑很隐蔽容器内时间不对尤其是差8小时是另一个让不少人挠头的问题。现象是你在宿主机的业务日志时间正常但容器内打出来的时间全是UTC。原因很简单容器镜像的默认时区很多是UTC它不会自动继承宿主机的时区设置。有几个办法解决。启动容器时加环境变量docker run -e TZAsia/Shanghai nginx:alpine这种方式要求镜像里有tzdata否则TZ不生效。Alpine镜像有时只有精简版需要先安装tzdata或者在启动时直接把宿主机的时区文件挂载进去-v /etc/localtime:/etc/localtime:ro注意有的镜像对/etc/localtime的符号链接比较敏感如果直接挂载还不行可以把/etc/timezone文件也挂进去。已经运行的容器可以执行docker cp /etc/localtime 容器名:/etc/localtime再重启容器。这个问题虽然不影响容器运行但对于日志聚合、任务调度来说非常致命经常出现日志时间比真实时间晚8小时排查数据时一头雾水。所以我把这条单独拎出来提醒大家在新环境里一开始就加上时区配置。6. 学习命令的最佳路径把Docker Compose也纳入常用命令6.1 单容器用docker run多容器就该上compose当你还是单容器跑一个nginx时docker run完全够用。但现实场景里一次部署往往涉及好几个服务比如前端、后端、数据库、缓存每个服务都要单独run然后手动处理网络、依赖顺序和数据卷命令变得又长又容易出错。这时候用Docker Compose可以大幅提效。Compose的核心思想是把多容器的定义写在一个YAML文件里然后通过docker compose命令管理整个服务栈。Compose本身不是容器它是一个用来编排的工具它的“常用命令”其实也很有限但价值很高。比如下面的docker-compose.yml片段定义了一个web服务和redis依赖services: web: image: nginx:alpine ports: - 8080:80 volumes: - ./html:/usr/share/nginx/html:ro networks: - appnet redis: image: redis:7-alpine networks: - appnet networks: appnet: driver: bridge这个YAML表达了第3章的多个概念服务、端口映射、数据卷挂载、自定义网络。用一条命令启动docker compose up -d它会把web和redis两个容器都启动起来并且加入同一个appnet网络。web服务里想连redis直接通过服务名redis访问不需要关心IP。6.2 常用compose命令轻松管理一组服务Compose的常用命令不多但每个都很实用。查看服务状态docker compose ps查看日志docker compose logs -f停止/启动docker compose stop docker compose start docker compose restartstop只是停掉容器服务定义还在销毁服务docker compose down这会停止并删除所有相关容器和网络默认不删除数据卷。如果希望连同卷一起清理用down -v但这句话一定要确认数据不再需要否则你会后悔。重新构建并启动docker compose up -d --build当服务使用了本地构建的镜像改动Dockerfile后这句命令非常有价值不需要手动先docker build再up。6.3 一个redis主从的compose例子顺带看数据卷应用之前搜热词里很多人关心“docker安装redis主从”这里就用compose给个简单模板。它虽然不是全套高可用方案但能让你直观看到网络和卷的配合。services: redis-master: image: redis:7-alpine container_name: redis-master command: [redis-server, --appendonly, yes] ports: - 6379:6379 volumes: - ./redis-master-data:/data networks: - redis-net redis-slave: image: redis:7-alpine container_name: redis-slave command: [redis-server, --slaveof, redis-master, 6379] depends_on: - redis-master ports: - 6380:6379 volumes: - ./redis-slave-data:/data networks: - redis-net networks: redis-net: driver: bridge启动之后slave容器通过服务名redis-master去连接主库这正是自定义网络里“容器名即主机名”的典型用法。数据目录通过bind mount挂载到宿主机重启容器数据还在这弥补了容器生命周期带来的数据丢失问题。这个例子完整串起了镜像、容器、端口、卷、网络、compose这几块内容。学习Compose的过程并不是要从零学一套新命令而是把已经掌握的docker run参数翻译成YAML。等到你翻译熟练了docker compose ps和docker compose logs就会变成比docker ps更常敲的命令。最后再分享一个我自己的习惯每次遇到一个记不清的命令不一定非要百度先在终端跑docker 命令 --helpDocker自带帮助就是最好的速查表。真正需要积累的不是命令清单而是你面对报错时能回忆起“它属于镜像、容器、卷、网络中的哪一层”再结合日志和--help去定位。这个思路远比背一百条命令更有用。
返回列表