
先问个直奔灵魂的问题你在Linux服务器上第一次用vi时有没有被“按了i之后不知道怎么退出差点直接关终端”的经历我在早年带新人时发现大部分第一次接触Linux的人都卡在同一个地方——不是命令记不住而是不知道vi的“模式”这件事。后来大家开始接触Docker又有一堆同事分不清镜像和容器的关系、docker ps和docker ps -a的区别、docker run的一堆参数全靠死记硬背稍微换个场景就翻车。这篇文章不打算写成命令大全而是把“vi命令”和“Docker命令”这两条线串起来讲清楚它们背后解决问题的逻辑以及我在真实运维中踩过的坑。内容包括vi的模式切换和高频操作、Docker从镜像到容器的完整工作流、在容器里用vi改配置文件的实操路径以及几个典型的故障排查案例比如Docker API授权失败、MySQL容器安装不上、vi粘贴乱掉。适合刚接触Linux运维、准备考Linux认证、或者第一次用Docker部署服务的同学。1. vi 编辑器先搞懂“模式”比背一百条命令都管用1.1 为什么vi容易劝退它像遥控器不像是输入框vi不是一个普通文本编辑器它从诞生起就是为键盘操作设计的核心思路是“双手不离开键盘”。所以在vi里同一个按键在不同模式下含义完全不同。刚接触时最容易犯的错误就是一进去就开始敲字母结果发现屏幕没有任何反应或者敲了一堆英文字母屏幕上出现一堆莫名其妙的内容。vi有三种基本模式命令模式默认模式所有按键都是命令用来移动光标、删除、复制等。插入模式按下i、a、o等进入可以输入文字此时按Esc返回命令模式。末行模式在命令模式下按冒号:进入可以输入保存、退出、替换等命令。用生活里的类比来说vi更像遥控器而不是文本框。遥控器上同一个按钮在设置菜单和正常播放菜单下功能不同vi里同一个j在命令模式是“光标下移”在插入模式就是字母j本身完全取决于当下处于什么模式。理解了“模式”这个概念再来看vi的核心操作就顺理成章了。下面这张表是我在实际运维中用得最多、也最建议新人优先掌握的。1.2 高频操作一张表解决90%的编辑需求功能命令说明进入插入模式i/a/oi在光标前插入a在光标后插入o在下一行新开一行返回命令模式Esc无论在哪先按它总能回到命令模式移动光标hjkl左、下、上、右相当于方向键按单词移动wbw跳到下一单词开头b跳到上一单词开头跳到行首/行尾0/$0到行首$到行尾删除一行dd光标所在整行删除也支持dG删到文件末尾删除当前字符x相当于Delete键撤销/重做u/Ctrlr撤销上次操作重做复制当前行yy复制到缓冲区粘贴p在光标之后粘贴查找关键字/keyword输入后回车搜索n下一个N上一个全局替换:s/old/new/g当前行替换全文件用:%s/old/new/g保存修改并退出:wq写入并退出强制退出不保存:q!丢弃所有修改退出但提醒保存:q有未保存修改时会报错这里重点说两个容易记混的地方。第一dd和yy后面可以跟数字比如3dd是连续删除3行2yy是复制2行。这个在我们快速整理配置文件时特别好用。第二查找和替换是vi里效率提升最明显的功能。假设你要把Nginx配置里所有http改成https直接:1,$s/http/https/g或者:%s/http/https/g就行。注意%代表整个文件g代表全局替换不是只替换每行第一个匹配。如果不想一个个确认就加个c变成:%s/http/https/gc逐个确认避免误伤。1.3 保存退出与异常恢复那些年按了Esc还是退不出去的时刻新人最容易翻车的场景就是“我想退出但退不出去”。其实保存退出只有几个组合:wq保存并退出最常用。:x和:wq类似但如果文件没有改动不会更新修改时间。ZZ在命令模式下按大写ZZ等于:wq少打一个冒号老手常用。如果只想退出不保存用:q!。如果只想保存不退出用:w。被劝退的常见原因还有按了CtrlS。在终端里CtrlS会把输出暂停掉看起来像死机其实vim还在运行。此时按CtrlQ解除暂停。这一点在Xshell、SecureCRT、以及各种SSH终端里都可能发生。还有一个高频问题vim打开文件时提示“Swap file exists”。这是上次编辑异常退出时留下的.swp文件。可以输入vim -r 文件名找回上次未保存的内容确认不需要恢复后再把这个隐藏的.swp文件删掉比如rm .文件名.swp。注意.swp是隐藏文件用ls -a才能看到。另外如果你用普通用户打开一个只有root能写的文件编辑完保存时会出现“E212: Cant open file for writing”。我以前的做法是直接用sudo vim打开但这样会生成root所有的.swp文件留下一点麻烦。更优雅的方式是在vim里执行:w !sudo tee %这串命令的意思是把当前缓冲区内容通过sudo tee写回原文件。用的时候会提示输入密码相当于以root权限保存。注意执行完vim会提示文件已修改直接:q退出就行。2. Docker 命令从镜像到容器的完整工作流2.1 镜像与容器先建立正确的心智模型很多同学把Docker命令记不住根本原因是没分清“镜像”和“容器”。我用一张图来比喻镜像相当于光盘里的ISO安装包容器相当于从安装包装好并运行起来的一台小电脑。你可以从同一个镜像启动无数个容器每个容器之间互不影响修改容器里的文件也不会改回镜像。这就是为什么部署时我总提醒大家镜像只管“长什么样”容器才管“跑什么”。比如docker pull nginx只是把镜像拉到本地真正提供服务的是docker run创建出来的容器。Docker命令的主线其实只有一条拉取镜像 - 创建容器 - 查看容器 - 进入容器 - 停止/删除容器对应命令docker pull docker run docker ps / docker ps -a docker exec docker stop / docker start / docker rm如果把这条主线记在脑子里后续不管加什么参数都是围绕这条主线打补丁。2.2 日常运维最高频的一组命令下面这张表是我在服务器上用得最多的Docker命令建议直接“抄作业”。目的命令示例说明拉取镜像docker pull nginx:1.24不写tag默认latest查看本地镜像docker images显示镜像列表和大小运行容器docker run -d --name web -p 8080:80 nginx:1.24-d后台运行--name起名-p端口映射查看运行中容器docker ps只显示正在运行的查看所有容器docker ps -a包含已退出、已创建的容器查看容器日志docker logs -f web-f持续跟踪输出进入容器docker exec -it web bash在容器里开一个交互式shell停止/启动docker stop web/docker start web停止后容器还在可再启动删除容器docker rm web删除已停止的容器删除镜像docker rmi nginx:1.24删除前需确保没有容器使用该镜像查看资源占用docker stats实时显示容器CPU/内存这里重点说一下docker run最常用的几个参数因为很多安装类故障都出在参数上。-d后台运行。不加-d时容器在前台运行CtrlC就停了。新手部署MySQL、Redis这类服务时如果不加-d一关终端服务就断还以为自己没装好。-p 宿主机端口:容器端口把容器内端口暴露到宿主机。访问容器内的MySQL比如容器内MySQL跑在3306宿主机需要-p 3306:3306这样才能在宿主机上通过127.0.0.1:3306访问。很多人只写了容器端口没写映射结果在外面怎么连都连不上。-e传入环境变量。典型是MySQL的MYSQL_ROOT_PASSWORD、Redis的requirepass。-v 宿主机目录:容器目录挂载目录让容器里的文件映射到宿主机。这是持久化的关键后文会展开。--network host直接用宿主机网络省去端口映射但要注意端口冲突。2.3 进入容器与前后台切换小心exit把容器也停了用docker exec -it web bash进入容器后交互shell看起来和普通Linux终端没什么两样。但有一个细节很容易踩坑如果你是用docker run -it不带-d启动的容器直接输入exit会让容器退出因为容器的主进程就是那个交互shellshell一退容器就停了。如果你想要“只退出连接但保留容器后台运行”应该用CtrlPQ。这个组合键是detach相当于把终端从容器里“拔”出来容器继续在后台跑。我习惯上还是推荐生产环境服务一律用-d后台运行然后需要排查时再用docker exec -it进入这样exit不会影响容器状态。另外docker ps -a是排查问题的利器。很多容器安装失败后消失了你以为没创建成功其实可能是创建了但立刻退出了。用docker ps -a能看到它再用docker logs 容器名看日志马上就知道为什么退出的。比如MySQL镜像首次启动时如果没设置MYSQL_ROOT_PASSWORD容器会创建失败退出日志里会明确提示这时候就不需要瞎猜。3. 在容器里用 vi 改配置文件一场真实的演练3.1 场景修改 Nginx 容器里的配置文件并生效假设我用官方镜像跑了Nginx但想把默认首页路径改一下或者加一个反向代理配置。操作路径一般是docker exec -it nginx bash vi /etc/nginx/conf.d/default.conf进入vi后用/查找server_name然后用i进入插入模式修改修改完按Esc输入:wq保存退出容器最后在宿主机上执行docker exec nginx nginx -s reload这里要注意一个细节官方镜像里的Nginx配置目录结构各不相同。比如nginx官方镜像的conf.d目录通常存在而某些基于Alpine的镜像里可能连bash都没有只有sh。进入容器时如果docker exec -it nginx bash报错可以改用docker exec -it nginx sh。修改配置时还有一个常见的坑vi显示的内容有乱码或者换行不对。常见原因是容器里默认的locale不是UTF-8或者文件是CRLF换行。遇到这种情况先不要急着甩锅给vi在末行模式里执行:set ffunix :set encodingutf-8然后再保存。ff是fileformat改成unix表示LF换行这对于Nginx、MySQL、Redis的配置来说都能避免奇怪的解析问题。3.2 容器里没有 vi 怎么办三条替代路线很多精简镜像里没有安装vi或vim连vi命令都提示not found。这时候有三种路线按效率排序一是直接装一个。对于Debian/Ubuntu系镜像apt-get update apt-get install -y vim对于CentOS/RHEL系镜像yum install -y vim但要注意容器重建后安装的软件全部丢失所以这种办法只适合临时调试不适合做标准化操作。二是把文件拷出来改完再拷回去。在宿主机上执行docker cp nginx:/etc/nginx/nginx.conf ./nginx.conf vi ./nginx.conf docker cp ./nginx.conf nginx:/etc/nginx/nginx.conf这种方式不需要进入容器也不用装vim而且宿主机上通常有完整的编辑器环境。文件校验、diff、备份都方便是我最推荐的长久解决方案。三是用sed做无交互替换。比如要把文件里的80端口改成8080docker exec nginx sed -i s/listen 80;/listen 8080;/ /etc/nginx/conf.d/default.confsed -i直接改文件适合配置项明确、改动小的场景也适合写进自动化脚本。3.3 持久化的坑容器里的vi修改重建后什么都没了刚学Docker时我在容器里用vi精心改了一堆Nginx配置结果容器重建后全部还原当时很崩溃。原因很简单容器是“一次性”的所有写在容器可写层的修改都随容器删除而消失。解决方案是挂载目录。在宿主机建一个配置目录运行容器时用-v挂载进去docker run -d -p 80:80 --name nginx \ -v /data/nginx/conf.d:/etc/nginx/conf.d \ nginx:1.24这样一来vi修改的是宿主机/data/nginx/conf.d下的文件容器只是把这些文件“映射”进去。容器删了重建配置依然在宿主机上再挂载一次即可。数据库容器也同理MySQL的数据目录、Redis的持久化文件都应该挂卷出来。这个教训后来帮我省了很多事。每次需要改容器配置第一件事就是问自己这个改动能活过容器重建吗不能的话尽早把相关文件挂出来而不是硬改容器内部。4. 高频故障排查Docker 连接失败、MySQL 容器装不上4.1 Permission denied while trying to connect to the Docker API在Linux上刚装完Docker执行docker ps却收到permission denied while trying to connect to the Docker API这个报错几乎每个Docker新手都会遇到。原因是Docker守护进程默认监听在/var/run/docker.sock这个socket文件属于root组。普通用户不在这个组里自然没权限访问。临时解决办法是给每条命令加sudo。但我建议直接把自己加入docker组sudo usermod -aG docker $USER然后重新登录服务器或者执行newgrp dockernewgrp docker是让当前shell会话直接用新的组权限不用重新SSH。不过要注意如果你使用的是企业安全加固过的系统把普通用户加入docker组相当于给了root级权限因为docker组用户能操控宿主机文件系统。在跳板机和生产环境上这事需要和运维安全规范对齐不能为了省事随意操作。4.2 安装 MySQL 容器失败端口冲突、密码变量、空间不足在热词里看到“docker安装mysql失败”出现的频率很高。我排查过一次同事的问题执行的是docker run -d --name mysql -e MYSQL_ROOT_PASSWORD123456 mysql:8.0结果容器一启动就退出。用docker logs mysql一看日志提示[ERROR] [MY-010131] The server option lower_case_table_names is configured ...这其实是MySQL 8.0对配置项有严格校验但更常见的原因有这么几类。第一端口被占用。错误日志会显示bind-address: Address already in use。这时把-p 3306:3306改成-p 3307:3306或者先ss -tlnp | grep 3306查看谁占用了端口。第二没给root密码或密码策略太弱。MySQL 8.0要求通过MYSQL_ROOT_PASSWORD环境变量设置密码而且现在的镜像版本默认密码校验策略可能较严格太简单的密码会启动失败。可以先用一个临时密码启动进去后再ALTER USER改策略。第三磁盘空间不足。拉取镜像没问题但创建容器时写入数据失败df -h查看分区使用率接近100%。清理/var/lib/docker或者执行docker system prune可以回收悬空镜像和停止容器的数据。还有一个特别容易忽略的问题在容器里访问MySQL。如果你在宿主机上用127.0.0.1:3306访问不到检查一下-p是否写了宿主机端口:容器端口而不是只写了3306。例如正确写法是-p 3306:3306如果写成-p 3306Docker会随机映射一个宿主机端口用docker port mysql可以查看到底映射到哪。4.3 Docker Desktop 启动失败virtualization support not detected热词里有“virtualization support not detected docker desktop failed to start because v”这主要出现在Windows上安装Docker Desktop时。Docker Desktop在Windows上依赖WSL2或Hyper-V而WSL2需要CPU开启虚拟化。如果BIOS里没开VT-x/AMD-VDocker Desktop就会直接拒绝启动。排查顺序是任务管理器 - 性能 - CPU看“虚拟化”是否显示“已启用”。没启用就去BIOS打开Intel Virtualization Technology或AMD SVM。如果BIOS已启用确认Windows功能里“适用于Linux的Windows子系统”和“虚拟机平台”两个选项是否勾选。装完Docker Desktop之后命令行里还要确认能用docker version正常输出Client和Server两部分。如果只输出了Client说明客户端能跑但连接不上服务端大概率是WSL2问题。可以先在PowerShell里执行wsl --status看下内核版本如果内核太旧需要wsl --update。4.4 vi 粘贴乱格式与换行符问题用vi往配置文件里粘贴一大段内容时经常出现缩进全乱的情况粘贴的代码一行比一行多一个缩进。这是因为vim开启了自动缩进在插入模式下粘贴时它会把缩进再处理一遍。解决方法是粘贴前先进入一个特殊模式:set paste然后按i进入插入模式再粘贴。粘贴完恢复:set nopaste这个经验在配置Dockerfile、YAML文件时特别管用。YAML对缩进极其敏感粘贴错乱会直接导致容器编排解析失败。另外如果发现文件行尾是^M可能是Windows格式的换行符执行:set ffunix再保存就正常了。5. 贴在工位上的一页速查手抄5.1 Linux 常用命令速查在vi和Docker之外还有一批Linux命令平时用的频率极高我把它们压成一页场景命令说明查看目录ls -la显示隐藏文件和权限切换目录cd /path返回上一级用cd ..查看进程ps -efgrep name实时资源top或htop查看CPU/内存占用磁盘占用df -h查看分区剩余空间目录大小du -sh /path查看目录总大小端口监听ss -tlnp查看端口占用和对应进程查找文件find / -name xxx按名字搜索文本过滤grep -r 关键词 /path按内容递归搜索服务管理systemctl start/stop/restart xxxsystemd系统的服务管理5.2 vi 速查进入插入模式i回命令模式Esc删除一行dd撤销u查找/保存退出:wq不保存退出:q!粘贴不乱:set paste后再粘贴5.3 Docker 速查拉镜像docker pull 镜像:tag看镜像docker images跑容器docker run -d --name xxx -p 本机端口:容器端口 镜像看容器docker ps -a看日志docker logs -f xxx进容器docker exec -it xxx bash清垃圾docker system prune -f重启容器docker restart xxx实际使用中docker system prune是个宝藏命令它会清除所有已停止的容器、没有容器使用的镜像和缓存网络。我在磁盘吃紧时定期执行一次经常能清出几个G的空间。不过执行前最好确认没有需要保留的停止容器毕竟一旦清除容器文件层就没有了。数据一定要提前挂在卷目录里。最后再分享一个小技巧学vi和Docker都不需要专门背命令最好的方式是“用坏一个环境再修好它”。我在一台测试服务器上反复练习过容器启动、停止、删除、挂卷、vi改配置大概一周之后这些命令就变成了肌肉记忆。你需要的东西不多只要模式切换搞懂了工作流记住了故障日志会看就已经超过大部分只在教程里看过的人了。