ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

vi与Docker实战指南:从容器基础命令到高效运维

vi与Docker实战指南:从容器基础命令到高效运维 做 Linux 运维和开发这些年我见过太多人被两个东西劝退一个是 vi进去之后不知道怎么退出另一个是 Docker装完不知道容器和镜像到底啥关系。vi 是 Linux 环境里最底层的编辑工具Docker 是现在部署应用绕不开的容器引擎表面上一个管文件、一个管运行环境实际干活的时候两者天天配合。这篇文章就把这两块按我的实战经验串起来讲从 vi 的模式、高频操作、寄存器到 Docker 的安装、镜像管理、容器生命周期、数据卷、Compose 编排最后再落几个真实场景怎么在容器里改配置、怎么写 Dockerfile、怎么用 Docker 跑 MySQL 和 Redis 主从。适合刚接触 Linux 的同学照着抄也适合已经入行但有些细节一直没搞透的兄弟查漏补缺。1. 为什么把 vi 和 Docker 放在一起学1.1 一个运维老兵的日常写照我平时的工作流大概是这样的本地用 VS Code 写代码提交到服务器之后要么直接 ssh 上去用 vi 改配置文件要么写个 Dockerfile 让 CI 去构建镜像。无论哪条路vi 和 Docker 命令都会出现在同一个画面里。举个例子线上 MySQL 容器需要改一下 my.cnf 的字符集参数。我先docker ps找到容器然后docker exec -it mysql bash进到容器里结果发现镜像里根本没有 vim只有最基础的 vi。这时候你要是不会 vi 的基础操作连个文件都打不开更别提改参数了。反过来你用 vi 改完了配置文件如果不了解docker cp和容器重启的机制改完等于白改容器一重启数据又回去了。这两个技能是互相成就的vi 解决“在 Linux 环境里怎么高效改文本”的问题Docker 解决“改完之后怎么让它可靠地跑起来”的问题。我甚至面试别人的时候也会先问 vi 的几个命令再问 Docker 的基础命令这两关过了基本能判断这人有没有真在命令行环境下干过活。1.2 两者结合最典型的三个场景第一类是手动运维场景。服务器上出了告警你要快速看一眼容器日志改个环境变量重启下容器。整个过程里docker logs、vi、docker restart三个命令循环出现。第二类是镜像构建场景。写Dockerfile本身就是纯文本编辑工作你要在 vi 里起草然后用docker build构建构建失败又得回到 vi 里改。改的过程中还得规律性检查RUN、COPY、ENTRYPOINT这些指令的写法稍有差池镜像就会报错。第三类是故障排查场景。容器起不来最常见的操作就是用 vi 改挂载出来的配置文件或者docker exec进容器看一眼进程状态。你可以没有花哨的 K8s 集群但不能连 vi 和 Docker 命令都不熟。明白了为什么两者要一起学下面就把命令掰开了讲。2. vi 命令精讲从卡住到顺手2.1 三种模式是理解 vi 的第一道门很多新手第一次用 vi敲了几个字母发现屏幕上什么都没出来再一敲文字开始乱跳整个人就慌了。这是因为 vi 分三种模式而你大概率处在“普通模式”下不知道自己在干嘛。普通模式Normal Mode是刚打开文件时的状态。这个模式下你敲的每个字母都是命令不是输入的文字。比如x表示删除当前字符dd表示删除当前行按i才进入插入模式去写字。插入模式Insert Mode是你真正打字的状态。进入方式有几种i在当前光标前插入a在当前光标后插入o在当前行下方新建一行并插入O在当前行上方新建一行。很多人误以为打开 vi 就应该直接打字其实不是。这个模式最大的问题就是“怎么退出去”答案是按Esc键。可视化模式Visual Mode用于选中文本。按v进入字符选中按V进入按行选中按Ctrlv进入块状选中可以一次选中多行做列编辑。选中后配合y复制、d删除、缩进效率比鼠标高得多。模式作用进入方式退出方式普通模式执行删除、复制、跳转等命令打开文件默认进入按v进入可视按i进入插入插入模式输入文本内容iaoO等按Esc可视化模式选中文本做批量操作vVCtrlv按Esc这个“模式”设计初看很反人类但用顺手了就会发现它极其高效你的手不用离开键盘去摸鼠标编辑和命令切换就在几个按键之间完成。2.2 高频移动与编辑命令清单vi 的移动命令是效率的核心记住下面这组就够了hjkl左、下、上、右不用多说。w/b按单词向后 / 向前跳适合长行文本。0/$跳到行首 / 行尾。gg/G跳到文件第一行 / 最后一行前面加数字表示跳转指定行比如10G跳到第 10 行。Ctrld/Ctrlu向下 / 向上翻半页读日志文件时特别有用。f加字符在当前行向后找到该字符并跳过去比如fx跳到下一个x的位置。编辑命令方面我实际使用频率最高的是x删除当前字符。dd删除当前行dG删除光标到文件末尾dw删除一个单词。yy复制当前行p在光标后粘贴P在光标前粘贴。u撤销Ctrlr重做。这句话值得默念三遍vi 的撤销不是 Ctrlz是按小写u。ciw删掉当前单词并进入插入模式适合改代码里的变量名。r加字符把当前字符替换成指定字符不用进入插入模式。我看到过不少面试题会出现“如何快速删除 5 行”的题答案是5dd数字加命令的组合几乎适用于所有 vi 命令比如5yy复制 5 行、5加j往下跳 5 行。这个逻辑一旦掌握效率立刻上一个台阶。2.3 查找、替换与全局命令查找是日常排查日志和定位错误的利器。在普通模式下按/输入关键词回车后按n跳到下一个匹配项按N跳到上一个。比如排查服务报错直接/ERROR就能快速定位。替换命令是 vi 里最能体现“不装插件也能办公”的功能。基本语法是:s/old/new # 替换当前行的第一个匹配 :s/old/new/g # 替换当前行的全部匹配 :%s/old/new/g # 替换整个文件的全部匹配 :%s/old/new/gc # 全局替换每次询问确认%表示整个文件g表示全局c表示确认。加c这个选项在小范围替换时特别稳不会误伤不想改的地方。很多人搜“vi g”其实就是在问全局命令。vi 里真正的全局命令是:g它能在匹配某个模式的所有行上执行指定命令。举个例子你想删除所有包含DEBUG的行:g/DEBUG/d这个命令的意思是找到所有匹配DEBUG的行并删除。比手动一行行dd快得多。还有更进阶的用法比如把所有包含TODO的行前面加上注释符号可以这样写:g/TODO/s/^/#/^表示行首s/^/#/就是在行首插入#。:g命令配合替换能省下大量重复劳动。2.4 寄存器、宏与可视化操作寄存器是 vi 里最被低估的高级功能。Vi 支持编号寄存器0到9命名寄存器a到z还有系统剪贴板寄存器。默认的复制粘贴用的是无名寄存器你复制了新的内容旧的就被覆盖了。如果你复制一段内容后马上又复制另一段第一段想粘贴就找不回来了。解决方法是使用命名寄存器ayy # 把当前行复制到寄存器 a ap # 粘贴寄存器 a 的内容当你在多个文件之间搬运内容时这个功能简直救命。系统剪贴板可以用y复制、p粘贴这样 vi 里面复制的内容可以直接粘到浏览器或其它编辑器里反过来也行。宏功能更适合批量处理重复操作。按q加一个字母开始录制比如qa然后正常执行一系列操作再按q结束录制最后用a重放5a重放五次。我遇到过要批量给 100 行配置加前缀的场景录一个宏然后重放 100 次十几秒搞定。可视化模式配合块操作也非常实用。按Ctrlv进入列模式用j/k选择多行按I输入内容再按Esc你会看到输入的内容一次性插到了所有选中行的同一位置。比如给多行配置统一加注释这是最顺手的办法。2.5 退出 vi 的正确姿势与常见翻车现场“退出 vi”是每个 Linux 新手都绕不过去的坎也是最容易成为玩笑梗的环节。退出方式其实很固定:wq保存并退出。:q直接退出文件没改动时可用。:q!不保存强制退出。:x保存并退出和:wq功能类似。ZZ普通模式下直接保存退出不需要输入冒号。还有一种特殊场景文件只读或想放弃所有修改时ZQ可以不保存直接退出。我见过不少新手在 vi 里按下Ctrls然后整个终端就没反应了以为死机。其实Ctrls在终端里是“暂停输出”的快捷键这时候画面冻住但 vi 还活着按Ctrlq就能恢复。这个坑特别隐蔽网上搜“vi 卡死”有一半是这个原因。另一个经典报错是E37: No write since last change (use ! to override)。意思是文件有改动你没有保存就想退出。这时候要么先:w保存要么用:q!强行放弃。还有一个情况是在某些精简系统里默认安装的是vi而不是vim。老版本的 vi 功能不全方向键在插入模式下会输出 ABCD 字符体验很差。遇到这种环境先用vi --version看一下装不了 vim 就尽量用h j k l移动别依赖方向键。这个细节在嵌入式 Linux 设备上特别常见学会基础移动键位到哪儿都不慌。3. Docker 命令实战从装好到会用3.1 安装与启动 Docker 的完整流程Docker 的安装方式因发行版而异但核心逻辑一致。Debian/Ubuntu 系用aptCentOS/RHEL 系用yum或dnf。这里分享我最常用的一套方式以 Ubuntu 为例sudo apt update sudo apt install -y docker.io sudo systemctl enable --now docker docker versionenable --now的作用是设置开机自启并立刻启动服务这比“启一次忘一次”靠谱得多。安装完成后用docker version确认 Client 和 Server 都在如果只显示 Client 而 Server 报错说明守护进程没起来。装完后有个必经步骤把当前用户加入docker组避免每条命令都带sudosudo usermod -aG docker $USER执行完必须重新登录或重启终端才生效。我不止一次看到有人加完组不重新登录然后一直报permission denied还以为是权限设置错了。检查 Docker 是否完全正常可以用两个命令sudo systemctl status docker docker infodocker info会输出容器数量、镜像数量、存储驱动、运行引擎等关键信息也是排查问题第一手信息来源。启动命令本身也要记牢systemctl start docker手动启动、systemctl enable docker设置开机启动这两个是运维面试高频题。3.2 镜像管理拉取、查看、删减镜像Image是容器的模板容器Container是镜像的运行实例。这个概念如果没建立起来后面所有命令都会学得很混乱。打个生活中的比方镜像是做菜的菜谱容器是按照菜谱做出来的一盘菜你可以按同一个菜谱做无数盘菜每盘菜都是独立的。拉取镜像用docker pull比如docker pull nginx:alpine docker pull mysql:8.0查看本地镜像用docker images这个命令会列出仓库名、标签、镜像 ID、创建时间和大小。docker image是完整管理子命令但日常直接用docker images就够了。删除镜像用docker rmi比如docker rmi nginx:alpine。删除前要确保没有容器在用这个镜像否则会报冲突。清理悬空镜像没有标签、被遗弃的中间层镜像可以用docker image prune网络上有种说法是“镜像少用 latest 标签尽量用明确版本号”。这个我非常认同尤其是 MySQL、Redis 这类数据敏感的中间件latest 一升级数据格式和行为都可能变踩了坑都不知道怎么回退。镜像仓库方面默认是 Docker Hub。如果拉取速度不理想可以给 Docker 配置 registry mirror镜像加速器。不同云厂商都有自己的加速地址具体配置写在/etc/docker/daemon.json里sudo vi /etc/docker/daemon.json改完重启 Dockersudo systemctl restart docker。这个文件是 JSON 格式写错一个标点都会导致 Docker 启动失败所以改完后第一时间docker info验证一下。我自己就吃过亏当时一个多余的逗号让整个守护进程起不来排查了半天才发现是配置文件的锅。3.3 容器生命周期从 run 到 rm容器操作是 Docker 的核心。docker run是最常用也最复杂的命令需要在心里拆成几部分来理解镜像、名称、后台运行、端口映射、数据卷、重启策略、环境变量。一个典型的运行命令docker run -d \ --name nginx-web \ -p 8080:80 \ -v /opt/html:/usr/share/nginx/html \ --restartalways \ nginx:alpine拆开讲一下-d表示后台运行。如果不加容器会以前台模式跑终端关了容器就停。--name给容器起名字方便后续docker exec和docker logs引用。-p 8080:80把宿主机的 8080 端口映射到容器的 80 端口。访问宿主机 IP 的 8080就相当于访问容器内的 nginx。-v挂载数据卷把宿主机目录映射到容器目录目的是让数据存在宿主机上。--restartalways设置容器异常退出后自动重启。查看运行中的容器用docker ps查看所有容器包括已停止的用docker ps -a。每次看到一堆容器时我都会先用docker ps -a排查因为很多故障现场是“容器已经退出了”只查运行中的容器会漏掉重要信息。进入容器内部的命令是docker exec -it nginx-web bash-i表示交互-t表示分配终端bash是进入后要执行的 shell。如果容器里没有 bash可以换成sh。这个细节等会儿还会再提确实是高频坑。看日志是排查问题的第一动作docker logs nginx-web docker logs -f --tail 100 nginx-web-f是跟随输出--tail 100表示只要最后 100 行。容器崩溃后第一件事永远是看日志不要瞎猜。停止和删除docker stop nginx-web docker rm nginx-web如果要强制删除一个正在运行的容器直接docker rm -f nginx-web。查看容器资源占用用docker stats它跟 top 类似能实时看 CPU 和内存消耗排查性能问题很有用。最后还有一个进出自由的问题docker attach可以附着到容器的标准输入输出上但使用起来很容易把终端卡住我现在基本只用docker exec -it。attach再按Ctrlc有时候会直接把容器进程杀掉而exec只是开个新进程不会影响主进程。这个差别在运维时要特别注意。3.4 数据卷与网络持久化和通信容器是“用完即弃”的容器一删内部数据跟着没。要让数据留下来必须用数据卷Volume或绑定挂载Bind Mount。数据卷的几种用法docker volume create mydata docker run -d -v mydata:/var/lib/mysql mysql:8.0这里mydata:/var/lib/mysql的含义是把名为mydata的卷挂载到容器内的/var/lib/mysql路径。卷由 Docker 管理存在宿主机特定目录下。绑定挂载则是直接把宿主机的某个绝对路径映射进容器docker run -d -v /home/user/mysql-data:/var/lib/mysql mysql:8.0好处是你能用 vi 直接查看宿主机路径下的文件方便排查和备份。我个人在生产环境更推荐绑定挂载因为一切都在明面上vi直接就能看配置和日志。挂载的时候还可以加:ro表示只读比如docker run -d -v /opt/app/config:/app/config:ro nginx:alpine这种配置适合只给容器提供配置、不让容器反向修改宿主机文件的场景能防止应用乱写文件。网络方面Docker 默认创建了三个网络bridge、host和none。最常见的bridge网络里容器通过 IP 通信默认使用 NAT 访问外网。想让多个容器互相访问最好创建一个自定义网络docker network create mynet docker run -d --networkmynet --nameweb1 nginx:alpine docker run -d --networkmynet --nameweb2 nginx:alpine在同一个自定义网络里容器可以直接用容器名互访比如web1里访问http://web2:80。这个特性在后面讲 Redis 主从的时候会直接用到值得记住。3.5 docker compose 一键编排单容器用docker run还应付得来一旦涉及多个容器比如应用 数据库 缓存命令又长又容易忘这时候就该上docker compose。Compose 的核心是一个 YAML 文件把容器的配置声明式地写进去。一个最小可用的示例version: 3.8 services: web: image: nginx:alpine ports: - 8080:80 volumes: - ./html:/usr/share/nginx/html restart: always mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: appdb volumes: - mysql-data:/var/lib/mysql ports: - 3306:3306 volumes: mysql-data:启动整个项目只需要docker compose up -d docker compose ps docker compose logs -f docker compose down注意新版本 Docker 推荐用docker compose中间有空格而不是旧的docker-compose。当然老机器上旧命令还能用但新环境建议直接用新语法。docker compose down会停止并删除所有相关容器但卷不会自动删数据还在。如果真想连数据一起清理用docker compose down -v。这个命令我每次都要默念一遍-v是删卷慎用。Compose 最大的价值是把“跑一套服务”这件事变成可复制的文件不用再到处翻历史命令。把这个文件放仓库里同事拉下来up -d就能起一样的服务。3.6 典型部署案例MySQL 8.0 与 Redis 主从纸上谈兵不如实操一组典型案例。先看 MySQL 8.0docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDmy-secret-pw \ -e MYSQL_DATABASEtestdb \ -v /opt/mysql8/data:/var/lib/mysql \ --restartalways \ mysql:8.0-e是设置环境变量MySQL 镜像必需的两个是MYSQL_ROOT_PASSWORD和MYSQL_DATABASE。没有 root 密码镜像会直接报错退出启动失败先用docker logs mysql8看输出十有八九是某个环境变量没设置。MySQL 8.0 默认使用caching_sha2_password认证插件。如果你用的是老版本的客户端工具连接会报Authentication plugin caching_sha2_password cannot be loaded。解决办法有两个一是升级客户端驱动二是在启动时加参数修改默认认证方式-e MYSQL_ROOT_HOST% docker run ... -e MYSQL_ROOT_PASSWORDmy-secret-pw mysql:8.0 --default-authentication-pluginmysql_native_password镜像后面跟的--default-authentication-pluginmysql_native_password会作为 MySQL 服务启动参数传进去不需要进容器手动改配置文件。再看 Redis 主从。建立主从有两种方式命令行slaveof或配置文件。用 Docker 跑最稳妥的方式是启动两个容器让从节点连主节点。假设主容器叫redis-master映射 6379 端口从容器启动后进入容器执行docker exec -it redis-slave redis-cli slaveof redis-master 6379如果用容器名作为主机名两个容器必须在同一个自定义网络里docker network create redis-net docker run -d --name redis-master --network redis-net -p 6379:6379 redis:7 docker run -d --name redis-slave --network redis-net redis:7 docker exec redis-slave redis-cli -p 6379 slaveof redis-master 6379验证主从状态docker exec redis-slave redis-cli info replication这个场景是网上搜“docker安装redis主从”最常遇到的需求只要理解了“同网络 容器名互访”这两件事配置过程其实非常短。4. vi 和 Docker 的组合实操4.1 在容器里改配置文件的几种靠谱方式进了容器发现没有 vi 或者不太好用这事我遇见太多次了。极简镜像比如alpine默认甚至没有 bash只有/bin/sh。这时候改容器内文件有几种思路按推荐程度排序第一用挂载目录的方式在宿主机直接改。最推荐的方案。如果你的容器启动时就挂载了/opt/app/config:/app/config那根本不用进容器直接在宿主机用 vi 改/opt/app/config下的文件改完docker restart 容器名即可。数据在宿主机文件操作也在宿主机两边都舒服。第二临时进容器安装 vim。适合调试场景比如基于 Ubuntu 的容器docker exec -it mysql bash apt update apt install -y vimAlpine 系列则是apk add vim改完配置后重启容器或重启进程容器一旦被删除安装的 vim 也没了所以这只适合临时处理不该作为常规手段。第三用 docker cp 把文件拷出来改。把容器内文件复制到宿主机用 vi 改完再复制回去docker cp mysql:/etc/mysql/my.cnf ./my.cnf.bak vi ./my.cnf.bak docker cp ./my.cnf.bak mysql:/etc/mysql/my.cnf docker restart mysql这种方式不需要容器里有编辑器宿主机上有什么用什么文件也能留下备份。但注意docker cp是重新拷贝文件容器内原来的文件属主、软链接关系可能受影响。改配置文件后的属主最好确认一下必要时chown修正。4.2 用 vi 写 Dockerfile 的实战经验Dockerfile 的写作质量直接决定镜像的构建成功率。我在 vi 里写 Dockerfile 时积累了几个习惯。首先Dockerfile 的关键指令就那几个FROM指定基础镜像RUN构建时执行命令COPY复制本地文件进镜像WORKDIR设置工作目录EXPOSE声明端口CMD或ENTRYPOINT指定启动命令。CMD和ENTRYPOINT的区别是高频面试题。简单说ENTRYPOINT定义容器启动时的主命令CMD提供默认参数docker run后面跟的参数会覆盖CMD而不是ENTRYPOINT。举个例子ENTRYPOINT [nginx] CMD [-g, daemon off;]容器启动时实际执行的是nginx -g daemon off;。用 vi 写 Dockerfile 时我必然会开行号这样构建报错时能迅速定位是哪一行:set nu还要养成分层阅读的习惯。Docker 构建时每一步RUN都会生成新层把apt install之类需要缓存的步骤写在前面把经常变动的COPY写在后面这样改代码重新构建时能命中缓存构建速度差好几倍。一个典型的优化写法FROM node:18 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD [npm, start]先复制package.json、安装依赖、再复制源码每次改代码后依赖层不用重装。另外我习惯在项目目录下建.dockerignore写出哪些文件不要打进构建上下文比如node_modules、.git、*.log。这能显著减小构建上下文体积尤其是大项目效果立竿见影。4.3 Docker Desktop 在 Windows 上的启动问题提到 Docker Desktop是因为不少朋友在 Windows 上用它结果碰到 “Docker Desktop failed to start because virtualization support wasnt detected” 的提示直接卡住。这个报错的意思是你的系统没有满足虚拟化要求Docker Desktop 需要虚拟化支持来运行 Linux 容器。排查步骤一般是这样的第一步进入 BIOS确认 Intel VT-x 或 AMD-V 已经开启。不同品牌主板路径不同但关键词就是 Virtualization / Virtual Machine。第二步在 Windows 功能里勾选“虚拟机平台”和“适用于 Linux 的 Windows 子系统”也就是 WSL2 支持。Docker Desktop 现在默认基于 WSL2 后端没有它肯定起不来。第三步打开“任务管理器-性能-CPU”看右下角有没有“虚拟化已启用”。如果是“已禁用”问题大概率出现在 BIOS 或安全软件拦截。第三步是很多人忽略的检查是否有其它虚拟机软件或旧版超管理器占用了虚拟化资源。装了某些第三方虚拟化软件会和 Docker Desktop 抢资源解决办法是把冲突的软件卸载或关闭其相关服务只用 Docker Desktop 搭配 WSL2。启动成功后网络和卷的性能在 Windows 上有时会偏慢尤其是大量小文件读写。尽量把项目代码放到 WSL2 虚拟磁盘里而不是放在 Windows 的 NTFS 分区下性能差距经常是成倍的。我刚从 Windows 迁移到纯 Linux 环境时同样的 Docker 项目构建时间从五分钟缩短到一分钟这种差异值得留意。5. 高频报错与排查实录5.1 vi 场景的经典坑坑一swap 文件存在。打开文件时提示Swap file .my.cnf.swp already exists!说明之前有别的进程在编辑或者上次异常退出留下了残留文件。处理方式是先看是谁在编辑如果确定没人占用直接按 D 删除 swap 文件或rm .my.cnf.swp。坑二Ctrls 导致界面冻结。前面提过这是终端流控而不是 vi 的问题按Ctrlq恢复。这个坑在远程 ssh 和本地终端都会遇到记住一次后面就很省事。坑三Backspace 在插入模式下删不了字符。多出现在老版本的 vi 或终端类型设置不对时。按:set backspaceindent,eol,start能缓解或者干脆切换到普通模式用x删除再重新插入。坑四中文乱码。有时候打开 gbk 编码的文件界面上一片乱码。先:set encodingutf-8再:e encgbk重新加载。实在不行就在外面用iconv转码后再打开。5.2 Docker 场景的经典坑坑一Cant connect to Docker daemon。报错内容通常是permission denied或者Cannot connect to the Docker daemon at unix:///var/run/docker.sock。先sudo systemctl status docker看服务状态如果没启动就启动如果权限问题就检查是否加入了 docker 组加入后是否重新登录。坑二端口被占用。启动容器时报Bind for 0.0.0.0:3306 failed: port is already allocated。用ss -lntp | grep 3306或lsof -i:3306查看占用进程改映射端口或停掉占用进程。坑三exec 进入容器失败提示executable file not found。常见于 Alpine 镜像没有 bash你敲了docker exec -it 容器名 bash找不到 bash。改成sh就好或者先docker exec -it 容器名 /bin/sh确认 shell 类型。坑四容器启动后立刻退出。先用docker logs看输出。比如 MySQL 没设置密码直接退出Redis 没有配置文件直接退出。容器短暂存活本身就是问题信号不要反复 restart先把日志读明白。坑五docker compose 命令不存在。老版本可能只有docker-compose新版本推荐用docker compose。执行前先docker compose version确认别两个命令混着用。我把这些问题整理成一张速查表方便大家直接对号入座现象排查命令常见原因容器启动失败docker logs 容器名环境变量缺失、配置错误端口冲突ss -lntp | grep 端口宿主机端口已被占用exec 找不到 shelldocker exec ... /bin/sh镜像只有 sh 没有 bash连不上 Docker daemonsystemctl status docker服务未启动或用户无权限数据丢失检查挂载卷配置未使用卷或绑定挂载镜像拉取失败docker pull重试仓库地址或网络问题5.3 从面试题视角看这些命令的原理现在不少 Linux 面试题喜欢考“为什么”而不是“是什么”。比如问你为什么容器能隔离底层依赖 Linux 的 namespace 和 cgroup进程、网络、文件系统都被隔离资源占用受到限制。这些问题看起来跟命令无关但理解了原理用起命令来心里更有底。再比如问你为什么docker exec -it 容器 bash能在容器里开 shell因为 exec 会在容器的命名空间里启动一个新进程指向容器内的文件系统。这也解释了为什么容器里没装的东西exec 进去照样找不到。vi 相关的面试题更多是考察操作熟练度。常见的有如何退不出 vi、如何在 100 行文本里批量加注释:1,100s/^/#/、如何删除包含特定关键字的行:g/关键字/d。本质上考的都是模式切换和命令组合能力。我自己面试时还会问一个问题容器里的进程是 PID 1为什么 PID 1 的退出信号处理和普通进程不同这是个延伸题能答上来的人通常对 Linux 进程模型理解比较深。用 Docker 跑 Nginx 或 MySQL 时为什么有些镜像的CMD要特意写成nginx -g daemon off;就是因为容器要求前台进程保持 PID 1 存活。这些原理层面的内容配合 vi 和 Docker 命令一起消化知识体系才完整。6. 几个让我少踩坑的日常习惯最后分享几个我实际操作中保留至今的习惯不一定写进文档但确实帮我省了不少事。第一个习惯是拿到一台新服务器先顺手确认 vi 和 Docker 的基础状态。vi --version看一眼版本docker version看 Client 和 Server 是否齐全。这两个动作加起来不到十秒却能避免后面一堆莫名其妙的问题。第二个习惯是给容器打名字。所有docker run我都强制带--name。没有名字的容器docker logs、docker exec、docker rm都得去查容器 ID一次两次还好容器多了真的会乱。第三个习惯是重要配置全部走挂载不进容器内部改。容器内部改配置文件版本升级、容器重建后改动就丢了而且镜像本身应该保持“不可变”。把配置放在宿主机目录里用 vi 改宿主机文件然后docker restart这套流程既安全又可追溯。第四个习惯是删除操作前三思。docker rm -f、docker compose down -v、docker rmi这类命令我通常在敲回车前会再用docker ps -a或docker volume ls确认一遍目标。尤其是卷的删除数据没了就是真没了。第五个习惯是遇到问题先看日志再动手。容器问题看docker logsvi 问题看:set和文件属性不要一上来就重启再重启。重启能暂时掩盖问题但下次遇到同样的故障还是会花时间排查。vi 和 Docker 看着是两个独立的知识域实际用起来是同一套工作方式的左右手。把命令记熟只是第一步更重要的是形成“在命令行环境下解决问题”的思路。你不需要背下所有参数但至少要知道哪几个命令能救你于水火以及出了问题第一眼该看哪里。把这些基础打牢后面的容器编排、自动化部署学起来都会顺很多。
返回列表