躬行笔记 - 2025年10月
type: channel
link: https://fuzhoupyy.work/index.php/2025/10/
description: 古人学问无遗力，少壮工夫老始成。 纸上得来终觉浅，绝知此事要躬行。
items: 告别命令行配置地狱！这个可视化反向代理神器让运维工作轻松10倍
items: Windows服务器出问题？别慌！教你几招日志排查绝技，让故障无处遁形
items: Jenkins 从0基础到有点基础——如何安装
items: 这个开源知识库太香了！PandaWiki搭建全过程，踩坑经验全分享
items: 网络攻击套路大揭秘！这些年我见过的各种"妖魔鬼怪"
items: Python sh库：让运维脚本告别subprocess的痛苦，一行代码搞定系统命令
items: 从JumpServer安装脚本看Shell编程：一个运维人员的实战解析
items: CDN优化实战：从命中率30%到95%的血泪史，AWS CloudFront踩坑全记录
items: 服务器500错误又来了？别慌！这份排查指南让你秒变故障终结者
items: 网络慢如蜗牛？教你几招Linux测带宽的绝活，让网络问题无处遁形！

告别命令行配置地狱！这个可视化反向代理神器让运维工作轻松10倍
type: item
date: 2025-10-30T15:27:56+00:00
description: 最近在公司搭建测试环境的时候，又遇到了老问题——需要给十几个不同的服务配置反向代理。按照以前的做法，就是在nginx配置文件里一个个写server块，改完还得测试语法，重载服务...光是想想就头疼。正好前段时间在GitHub上看到了Nginx Proxy Manager这个项目，说是可以通过Web界面管理nginx反向代理配置。我想着反正也要重新搭环境，不如试试这个工具到底好不好用。用了一段时间后，我只能说——真香！今天就来跟大家分享一下这个让我彻底告别nginx配置文件的神器。什么是Nginx Proxy Manager官网地址：https://nginxproxymanager.com/简单来说，Nginx Proxy Manager就是给nginx套了个漂亮的Web管理界面。你不用再去编辑那些复杂的配置文件，所有的反向代理、SSL证书、访问控制都可以在浏览器里点点鼠标就搞定。这个项目是基于nginx的，但是把所有复杂的配置都封装起来了。你只需要在Web界面里填写源地址、目标地址，它就会自动生成对应的nginx配置。而且还支持自动申请Let's Encrypt证书，这个功能真的太实用了。我记得以前每次配置SSL证书都要折腾半天，现在点几下鼠标就能搞定，效率提升不是一点半点。在Debian 13上安装部署我这次用的是Debian 13系统，整个安装过程还算顺利。不过中间也踩了几个坑，一会儿会详细说。准备工作首先确保系统是最新的：sudo apt update && sudo apt upgrade -y然后安装Docker和Docker Compose，因为Nginx Proxy Manager官方推荐用Docker部署：# 安装必要的包 sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release -y # 添加Docker官方GPG密钥 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 添加Docker仓库 echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装Docker sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io -y # 安装Docker Compose sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose安装完成后记得把当前用户加到docker组里，这样就不用每次都sudo了：sudo usermod -aG docker $USER这里需要重新登录一下才能生效。创建Docker Compose配置我在/opt目录下创建了一个专门的文件夹来存放配置：sudo mkdir -p /opt/nginx-proxy-manager cd /opt/nginx-proxy-manager然后创建docker-compose.yml文件：cat <<eof>docker-compose.yml services: app: image: 'jc21/nginx-proxy-manager:latest' restart: unless-stopped ports: - '80:80' - '81:81' - '443:443' volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt eof这个配置文件里有几个要注意的地方。端口81是管理界面的端口，80和443是实际提供服务的端口。数据库我用的是MariaDB，密码什么的在生产环境记得改成复杂一点的。启动服务配置文件准备好后就可以启动了：sudo …

Windows服务器出问题？别慌！教你几招日志排查绝技，让故障无处遁形
type: item
date: 2025-10-29T14:14:22+00:00
description: 最近客户遇到windows服务器出问题了一时半会不知道怎么办？出问题最好的办法就是看日志，但是我平常分享的都是linux系统的排查，今天就来盘盘windows服务器的！我记得刚入行那会儿，遇到服务器问题就是一顿乱操作，重启、重装，能折腾的都折腾一遍（重启能解决90%的问题）。后来被师傅骂了好几次才明白，日志才是解决问题的关键。今天就跟大家分享一下Windows Server环境下如何查看和排查日志，这些都是我这些年踩坑总结出来的经验。事件查看器 - 你的第一站Windows的事件查看器就像是服务器的"黑匣子"，记录着系统运行的方方面面。打开方式很简单，Win+R输入eventvwr.msc就行，或者在服务器管理器里也能找到。进去之后你会看到左边有个树状结构，主要分为几个大类：Windows日志这块是重点关注的地方。应用程序日志记录的是各种软件的运行情况，我经常在这里找到数据库连接失败、Web服务异常之类的问题。系统日志更多是硬件和系统级别的事件，比如磁盘错误、内存问题等等。安全日志这个就比较有意思了，记录着登录失败、权限变更这些敏感操作。有一次我们服务器被人暴力破解密码，就是通过安全日志发现的，里面密密麻麻全是登录失败的记录，IP地址还都是国外的。应用程序和服务日志这里面的内容就更丰富了，各种角色和功能都有自己的日志。比如你装了IIS，就会有IIS相关的日志；装了SQL Server，也会有对应的日志分类。看日志的时候要注意几个关键信息：时间、事件ID、来源、级别。级别分为信息、警告、错误、严重错误几种，一般我们重点关注警告和错误级别的事件。事件ID这个东西特别有用，每种错误都有固定的ID，你可以直接拿这个ID去微软官网搜索，基本都能找到详细的解释和解决方案。比如事件ID 1074表示系统重启，6005表示事件日志服务启动，这些都是有规律可循的。还可以通过事件id来查日志信息：Windows 服务器常见事件 ID 列表类别事件 ID描述系统事件1系统时间已更改 6系统启动 7系统关闭 12操作系统启动 13操作系统关闭 41系统崩溃重启 1074系统关机/重启安全事件4624账户成功登录 4625账户登录失败 4634账户注销 4648显式凭据登录 4672使用特权登录 4720创建用户账户 4724重置密码尝试 4725禁用用户账户 4728将成员添加到安全组 4732将成员添加到本地安全组 4740用户账户被锁定 4776域控制器尝试验证账户凭据应用程序事件1000应用程序错误 1001Windows 错误报告 1002应用程序挂起 1005应用程序终止服务事件7000服务无法启动 7009服务超时 7022服务正常启动 7023服务异常终止 7024服务无法启动 7031服务尝试重启 7034服务意外终止 7035服务发送控制 7036服务状态改变Active Directory 事件1644目录服务无法分配相对标识符 2886目录服务暂停 2887目录服务已恢复 5137目录服务对象创建 5141目录服务对象删除DNS 服务器事件4013DNS 服务器启动 4015DNS 服务器暂停 6702DNS 事件文件复制服务13508文件复制服务无法与主域控制器建立会话 13509文件复制服务成功与主域控制器建立会话磁盘和存储事件51磁盘错误 55文件系统结构损坏 7设备驱动程序错误PowerShell - 命令行的威力虽然图形界面看起来直观，但有时候用PowerShell查日志效率更高，特别是需要筛选大量数据的时候。Get-EventLog这个命令是基础中的基础：Get-EventLog -LogName System -Newest 100这样就能看到系统日志的最新100条记录。如果你想看特定时间段的日志：Get-EventLog -LogName Application -After "2024-01-01" -Before "2024-01-02"更强大的是Get-WinEvent命令，功能比Get-EventLog丰富多了：Get-WinEvent -FilterHashtable @{LogName='System'; Level=2,3}这里Level=2表示错误，Level=3表示警告，这样就只显示有问题的事件，不用在一堆信息级别的日志里翻来翻去。有时候我需要查找包含特定关键词的日志：Get-WinEvent -FilterHashtable @{LogName='Application'} | Where-Object {$_.Message -like "*SQL*"}这样就能找到所有消息中包含"SQL"的事件，对于定位特定应用的问题很有帮助。IIS日志 - Web服务的秘密如果你的服务器跑着Web服务（一…

Jenkins 从0基础到有点基础——如何安装
type: item
date: 2025-10-26T14:55:01+00:00
description: CICD是什么CI/CD这个词听起来很高大上，其实说白了就是让代码从开发到上线这个过程变得自动化。CI是Continuous Integration的缩写，中文叫持续集成。简单理解就是，开发人员每次提交代码后，系统会自动把所有人的代码合并在一起，然后跑一遍测试，看看有没有冲突或者bug。就像搭积木一样，每加一块都要检查一下整体结构是不是还稳固。CD有两个意思，一个是Continuous Delivery（持续交付），另一个是Continuous Deployment（持续部署）。持续交付是说代码随时都处于可发布状态，就像工厂流水线上的产品，每个环节都质检过了，随时可以出厂。持续部署更进一步，直接自动发布到生产环境，完全不需要人工干预。举个例子，以前我们部署一个网站，可能需要手动上传文件、重启服务、清缓存等等，一套流程下来半小时，还容易出错。有了CI/CD之后，开发人员只要把代码推送到Git仓库，剩下的事情全部自动完成：自动测试、自动打包、自动部署、自动重启服务，几分钟就搞定了。CI/CD的核心思想就是"小步快跑，快速反馈"。与其攒一堆功能一次性发布（风险大），不如每个小功能都快速上线，出问题也能快速定位和修复。这样既提高了开发效率，又降低了上线风险，是现代软件开发的标配。为什么选择Jenkins官方文档：https://www.jenkins.io/zh/doc/book/installing/说实话，CI/CD工具现在选择挺多的，GitLab CI、GitHub Actions、Azure DevOps什么的都不错。但是我最终还是选择了Jenkins，主要原因有几个：Jenkins的插件生态真的很丰富，基本上你能想到的功能都有对应的插件。而且它是开源的，不用担心费用问题。最重要的是，Jenkins对PHP项目的支持很好，配置起来也比较灵活。当然了，Jenkins也有它的缺点，比如界面看起来有点老旧，配置相对复杂一些。不过习惯了就好，功能强大才是硬道理。环境准备和Jenkins安装我们的服务器环境是debain13。Jenkins可以用Docker来部署，这样比较干净，也方便管理。docker run \ -u root \ --rm \ -d \ -p 8080:8080 \ -p 50000:50000 \ -v jenkins-data:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ jenkinsci/blueocean开始下载我镜像一直下载失败，换了直接用软件包安装（记得安装java环境），文档地址：https://www.jenkins.io/zh/doc/book/installing/#war%E6%96%87%E4%BB%B6wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add - sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list' sudo apt-get update sudo apt-get install jenkins启动后访问http://your-server:8080，按照提示完成初始化配置。初始密码在容器日志里能找到：必要插件安装Jenkins装好后，需要安装一些必要的插件。进入"系统管理" -> "插件管理"，安装以下插件（这些插件记得装！！！）：Git plugin（代码拉取）Pipeline（流水线支持）Blue Ocean（更好看的界面）Publish Over SSH（SSH部署）Build Timestamp（构建时间戳）Email Extension（邮件通知）插件安装完成后记得重启Jenkins。有时候插件之间会有依赖关系，Jenkins会自动帮你安装依赖的插件，这点还是很贴心的。配置Git仓库连接我们的代码托管在GitLab上，需要配置Jenkins能够拉取代码。在"系统管理" -> "全局工具配置"中配置Git路径，一般Jenkins会自动检测到。然后在"系统管理" -> "系统配置"中添加Git凭据。我建议使用SSH密钥的方式，比较安全：# 在Jenkins服务器上生成SSH密钥 ssh-keygen -t rsa -b 4096 -C "jenkins@yourcompany.com" # 将公钥添加到GitLab的Deploy Keys中 cat ~/.ssh/id_rsa.pub把私钥内容添加到Jenkins的凭据管理中，类型…

这个开源知识库太香了！PandaWiki搭建全过程，踩坑经验全分享
type: item
date: 2025-10-23T14:40:42+00:00
description: 最近公司要搭建一个内部知识库，领导让我调研几个方案。说实话，市面上的知识库产品真的是五花八门，什么Confluence、Notion、语雀啥的，但要么收费贵得离谱，要么功能不够用。偶然间发现了PandaWiki这个开源项目，试用了一下发现还真不错。界面简洁，功能够用，关键是免费！今天就把我搭建的整个过程分享给大家，希望能帮到有需要的朋友。什么是PandaWiki项目地址：https://github.com/chaitin/PandaWiki演示体验demo：https://192.168.198.133:2443/doc/editor/019a131f-12df-759c-a1a9-194d3c5ae47cPandaWiki是一个基于Go语言（好多项目都是go开发的，看来确实得学go了！！！）开发的轻量级知识库系统，支持Markdown编辑，有着不错的用户体验。相比其他重量级的知识库系统，它的部署和维护都相对简单。我之前用过MediaWiki，那个配置起来真的是要命，光是数据库配置就能折腾半天。PandaWiki就不一样了，基本上几个命令就能跑起来。环境准备在开始之前，我们需要准备一台Linux服务器。我这里用的是Debian 13（老演员了！），配置是2核4G，对于小团队使用完全够了。首先更新一下系统：apt update && apt upgrade -y然后安装一些必要的工具：apt install -y wget curl git vim开始部署PandaWiki一条命令搞定安装！！舒服！bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)"选择安装还是升级！会让你确认安装目录，无脑回车就行，也是通过docker部署(最喜欢看这种安装界面了哈哈哈哈)还有交流群二维码！！哈哈哈初始化配置打开浏览器访问 http://你的服务器IP:8080，应该能看到PandaWiki的初始化页面。第一次访问会要求你创建管理员账户。我建议用户名不要用admin这种太常见的，密码也要设置复杂一点。初始化完成后，你就能看到一个干净的知识库界面了。界面还是挺清爽的，左侧是目录树，右侧是内容区域。让你配置大模型很丰富注册靠谱白嫖一个（不是广告！）基本使用新手文档：https://192.168.198.133:2443/doc/editor/019a131f-12da-76b3-bafe-3cfbe1069e69创建文档点击"新建文档"按钮，可以选择创建普通文档或者文件夹。PandaWiki支持Markdown语法，写起来还是很顺手的。我试着创建了几个测试文档，发现它的Markdown渲染效果还不错，代码高亮、表格、图片都支持得挺好。我这里直接通过rss来导入自己博客的文档！通过rss订阅可以直接拉取很多地方的操作文档！这是拉取到的博客文章：去发布导入本地文本这就是财富！！！发布！！！使用统计！常用配置使用体验用了一段时间下来，感觉PandaWiki还是挺不错的。界面简洁，功能够用，性能也还可以。我们团队大概20多个人在用，响应速度还是很快的。当然也有一些不足的地方，比如权限管理相对简单，插件生态也不够丰富。但对于大多数中小团队来说，这些功能已经够用了。最重要的是它是开源免费的，不用担心突然收费或者服务停止。而且代码托管在GitHub上，如果有需要还可以自己修改。我感觉很nice！！会给出具体的引用，我准备用这个来替代我的博客搜索了哈哈哈写在最后PandaWiki作为一个轻量级的知识库解决方案，确实有它的优势。部署简单，维护方便，功能够用，关键是免费开源。虽然在一些高级功能上可能不如商业产品，但对于大多数团队来说已经足够了。特别是对于预算有限的小团队，这绝对是个不错的选择。如果你也在寻找知识库解决方案，不妨试试PandaWiki。反正是免费的，试试又不会怀孕。部署过程中如果遇到问题，可以查看官方文档或者GitHub上的issue。社区虽然不大，但还是比较活跃的。好了，今天的分享就到这里。如果这篇文章对你有帮助，记得点个赞转发一下。有问题的话也可以在评论区留言，我看到会回复的。如果这篇文章对你有帮助，别忘了点赞转发支持一下！想了解更多运维实战经验和技术干货，记得关注微信公众号@运维躬行录，领取学习大礼包！！！我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习，共同进步！公众号：运维躬行录个人博客：躬行笔记

网络攻击套路大揭秘！这些年我见过的各种"妖魔鬼怪"
type: item
date: 2025-10-22T16:08:47+00:00
description: 做运维这么多年，我算是见识过各种各样的网络攻击了。从最初的懵懵懂懂被攻击搞得焦头烂额，到现在能够淡定应对各种攻击手段，这中间踩过的坑真的是数不胜数。前几天有个粉丝朋友问我，现在网络攻击都有哪些类型，怎么防护？我想了想，确实有必要系统地梳理一下这些年遇到过的各种攻击手段。毕竟知己知彼，才能百战不殆嘛。今天就跟大家聊聊我这些年见过的各种网络攻击，从技术原理到防护方法，希望能帮到正在被攻击困扰的兄弟们。SQL注入攻击 - 数据库的噩梦说到网络攻击，SQL注入绝对是我遇到最多的一种。这玩意儿简直就是Web应用的头号杀手。攻击原理SQL注入的原理其实不复杂，就是利用应用程序对用户输入过滤不严，在数据库查询中插入恶意SQL代码。我记得刚工作那会儿，维护过一个老系统，登录页面的代码是这样写的：SELECT * FROM users WHERE username='$username' AND password='$password'看起来没问题对吧？但如果用户在用户名框里输入：admin' OR '1'='1' --那么实际执行的SQL就变成了：SELECT * FROM users WHERE username='admin' OR '1'='1' --' AND password='xxx'由于'1'='1'永远为真，而--会注释掉后面的密码验证，攻击者就能直接以admin身份登录了。常见的注入类型这些年我见过的SQL注入攻击大概有这几种：联合查询注入：通过UNION语句获取其他表的数据。我处理过一个案例，攻击者通过这种方式把整个用户表都下载走了，包括密码哈希。布尔盲注：通过构造真假条件来逐个猜测数据库内容。这种攻击比较隐蔽，日志里看起来都是正常请求，但实际上在一点点窃取数据。时间盲注：利用数据库的延时函数，通过响应时间来判断条件真假。我见过攻击者用这种方法花了几个小时把管理员密码给猜出来的。报错注入：故意触发数据库错误，从错误信息中获取敏感数据。有些开发为了调试方便，会把详细的错误信息显示给用户，这就给了攻击者可乘之机。防护措施防护SQL注入其实也不难，关键是要养成好习惯：参数化查询：这是最有效的防护方法。使用预编译语句，把SQL代码和数据分离。现在主流的开发框架都支持这个功能。输入验证：对所有用户输入进行严格验证，过滤掉危险字符。不过这个方法容易被绕过，不能作为唯一的防护手段。最小权限原则：数据库用户只给必要的权限，不要用root或sa这种超级用户来连接数据库。WAF防护：部署Web应用防火墙，可以识别和阻断大部分SQL注入攻击。我现在维护的系统都强制使用ORM框架，基本杜绝了SQL注入的可能性。虽然性能会有一点影响，但安全性大大提升了。XSS攻击 - 浏览器里的陷阱跨站脚本攻击（XSS）是另一个让我头疼的问题，特别是在处理用户生成内容的网站时。攻击原理XSS攻击的核心是在网页中插入恶意脚本，当其他用户访问时，这些脚本就会在他们的浏览器中执行。我印象最深的一次XSS攻击发生在一个论坛网站。攻击者在帖子里插入了这样的代码： 结果所有查看这个帖子的用户，他们的Cookie都被发送到了攻击者的服务器上。攻击者拿到Cookie后，就能冒充这些用户登录网站了。XSS的分类根据我的经验，XSS攻击主要分为三种：反射型XSS：恶意脚本通过URL参数传递，服务器直接把参数内容输出到页面上。这种攻击需要诱骗用户点击特制的链接。存储型XSS：恶意脚本被保存在服务器上（比如数据库），每次有用户访问相关页面时都会执行。这种危害最大，因为影响面广。DOM型XSS：攻击发生在客户端，通过修改页面的DOM结构来执行恶意脚本。这种攻击比较隐蔽，服务器端很难检测到。实际案例我处理过一个比较典型的存储型XSS案例。那是一个电商网站的商品评论功能，攻击者在评论中插入了恶意脚本： 这段代码看起来像是一个破损的图片，但实际上会执行JavaScript代码，把用户的Cookie编码后发送给攻击者。更可怕的是，攻击者还在脚本中加入了蠕虫功能，被感染的用户会自动发布包含恶意脚本的评论，导致攻击快速传播。防护策略防护XSS攻击需要多管齐下：输出编码：对所有输出到HTML页面的内容进行编码，把<、>、"等特殊字符转换成HTML实体。输入过滤：对用户输入进行过滤，移除或转义危险的HTML标签和JavaScript代码。CSP策略：配置内容安全策略（Content Security Policy），限制页面可以加载的资源来源。HttpOnly Cookie：设置Cookie的HttpOnly属性，防止JavaScript访问Cookie。我现在管理的网站都部署了严格的XSS防护策略，用户输入的任何内容都会经过多层过滤和编码。虽然偶尔会误杀一些正常内容，但总比被攻击强。CSRF攻击 - 身…

Python sh库：让运维脚本告别subprocess的痛苦，一行代码搞定系统命令
type: item
date: 2025-10-21T14:27:45+00:00
description: 最近在整理服务器监控脚本的时候，发现自己写的代码里到处都是subprocess.Popen()，看着就头疼。想起刚入行那会儿，为了执行个简单的ls命令，愣是写了十几行代码处理各种异常和输出，现在想想真是太蠢了。直到遇到了Python的sh库，我才发现原来执行系统命令可以这么优雅。今天就来聊聊这个让我爱不释手的库，相信看完之后你也会和我一样，再也不想碰subprocess了。为什么我会选择sh库说实话，Python标准库里的subprocess功能很强大，但用起来真的很繁琐。每次想执行个简单命令都要考虑一堆问题：怎么获取输出？怎么处理错误？怎么传参数？import subprocess # 传统的subprocess写法，光看着就累 result = subprocess.run(['ls', '-la'], capture_output=True, text=True, check=True) print(result.stdout)而用sh库呢？import sh print(sh.ls('-la'))就这么简单！一行代码搞定，看着就舒服多了。sh库的安装和基本使用安装很简单，pip一下就行：pip install sh基本使用更简单，直接把系统命令当成Python函数调用就可以了：import sh # 执行ls命令 print(sh.ls()) # 带参数的命令 print(sh.ls('-la', '/home')) # 管道操作也很简单 print(sh.grep(sh.ps('aux'), 'python'))我第一次看到这种写法的时候，真的被震撼到了。这不就是我一直想要的那种简洁的方式吗？实际项目中的应用场景在我日常运维中，sh库真的帮了大忙。比如说服务器健康检查脚本：import sh from datetime import datetime def check_server_status(): # 检查磁盘使用情况 disk_usage = sh.df('-h') print(f"磁盘使用情况：\n{disk_usage}") # 检查内存使用 memory_info = sh.free('-h') print(f"内存使用情况：\n{memory_info}") # 检查CPU负载 load_avg = sh.uptime() print(f"系统负载：{load_avg}") # 检查特定进程 try: nginx_processes = sh.pgrep('nginx') print(f"Nginx进程数：{len(nginx_processes.strip().split())}") except sh.ErrorReturnCode_1: print("警告：Nginx进程未运行！")这种写法比subprocess清爽太多了，而且代码可读性特别好。处理命令输出和错误sh库在处理命令输出方面也很贴心：import sh # 获取命令输出 output = sh.ls('/home') print(type(output)) # <class 'sh.RunningCommand'> print(str(output)) # 转换为字符串 # 实时处理输出 def process_line(line): print(f"处理行: {line.strip()}") sh.tail('-f', '/var/log/syslog', _out=process_line)错误处理也很直观：import sh try: # 执行可能失败的命令 result = sh.ls('/nonexistent') except sh.ErrorReturnCode_2 as e: print(f"命令执行失败: {e}") print(f"错误输出: {e.stderr}") print(f"标准输出: {e.stdout}") print(f"退出码: {e.exit_code}")高级功能：管道和重定向sh库对管道的支持让我印象深刻，写起来就像在shell里一样自然：import sh # 管道操作 result = sh.ps('aux') | sh.grep('python') | sh.wc('-l') print(f"Python进程数量: {result}") # 更复杂的管道 log_errors = sh.tail('-n', '1000', '/var/log/app.log') | sh.grep('ERROR') print(log_errors) # 重定向到文件 sh.dmesg(_out='/tmp/dmesg.log') # 从文件读取输入 sh.sort(_in='/tmp/unsort…

从JumpServer安装脚本看Shell编程：一个运维人员的实战解析
type: item
date: 2025-10-18T11:53:49+00:00
description: 最近在部署JumpServer的时候，仔细研究了一下它的安装脚本，发现这个脚本写得还挺有意思的。作为一个天天和Shell打交道的运维，我觉得这个脚本很适合用来讲解Shell编程的一些实用技巧。说实话，很多人觉得Shell脚本就是简单的命令堆砌，但实际上一个好的Shell脚本包含了很多编程思想和最佳实践。今天就通过这个JumpServer的jmsctl.sh脚本，来聊聊Shell编程中那些值得学习的地方。脚本结构设计：模块化思维很重要看这个脚本的整体结构，我第一眼就被它的组织方式吸引了。作者把整个脚本分成了几个清晰的部分：#!/usr/bin/env bash export SHELLOPTS PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" cd "${PROJECT_DIR}" || exit 1 . "${PROJECT_DIR}/scripts/utils.sh"这几行代码看似简单，但包含了很多门道。#!/usr/bin/env bash这个shebang比直接写#!/bin/bash要好，因为它会在PATH中查找bash，兼容性更强。export SHELLOPTS这行我之前还真没怎么用过，查了一下发现它是用来导出Shell选项的，这样在调用子脚本时能保持一致的行为。获取脚本所在目录的那行代码写得很巧妙：PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"${BASH_SOURCE[0]}比$0更可靠，特别是在脚本被source的时候。&>/dev/null把错误输出也重定向了，避免在某些环境下出现奇怪的错误信息。参数处理：简单但实用action=${1-} target=${2-} args=("$@")这种参数处理方式很实用。${1-}的写法比直接用$1安全，当没有参数时不会报错。把所有参数存到数组里也是个好习惯，后面需要传递给其他命令时很方便。我以前写脚本经常直接用$1、$2，但在一些边界情况下容易出问题。现在我也开始用这种写法了。配置文件检查：防御性编程function check_config_file() { if [[ ! -f "${CONFIG_FILE}" ]]; then echo "$(gettext 'Configuration file not found'): ${CONFIG_FILE}" echo "$(gettext 'If you are upgrading from v1.5.x, please copy the config.txt To') ${CONFIG_FILE}" return 3 fi # ... }这个函数体现了防御性编程的思想。不仅检查配置文件是否存在，还给出了具体的解决建议。返回值用3而不是1，这样可以区分不同类型的错误。软链接的处理也很细致：if -f .env ; then if ! ls -l .env | grep "${CONFIG_FILE}" &>/dev/null; then echo ".env $(gettext 'There is a problem with the soft connection, Please update it again')" rm -f .env fi fi检查软链接是否正确指向目标文件，如果不对就重新创建。这种处理方式在实际运维中很有用，避免了因为软链接问题导致的各种奇怪错误。国际化支持：细节决定成败脚本中大量使用了$(gettext '...')来支持多语言，这个细节让我印象深刻。虽然很多人写脚本时不会考虑国际化，但对于要分发给全球用户的开源项目来说，这确实很重要。echo "$(gettext 'JumpServer Deployment Management Script')"gettext是GNU的国际化工具，通过它可以根据系统语言环境显示对应的文本。虽然在内部项目中可能用不到，但这种思维方式值得学习。帮助信息：用户体验很关键function usage() { echo "$(gettext 'JumpServer Deployment Management Script')" echo echo "Usage: " echo " ./jmsctl.sh [COMMAND] [ARGS...]" echo " ./jmsctl.sh --help" echo echo "Installation Commands: " echo " install $(gettext 'Install JumpServer'…

CDN优化实战：从命中率30%到95%的血泪史，AWS CloudFront踩坑全记录
type: item
date: 2025-10-16T14:14:55+00:00
description: 最近客户cdn命中率异常，让我优化下缓存策略。经过一番折腾，总算把命中率提上来了！！！今天就把这些年踩过的坑和一些实用的经验分享给大家。其实CDN优化这事儿，说简单也简单，说复杂也复杂。很多人以为接入个CDN就万事大吉了，结果发现命中率低得可怜，钱花了不少效果却不明显。我之前就遇到过这种情况，CDN命中率只有30%多，简直是在烧钱。先说说CDN的那些关键指标做CDN优化，你得先知道怎么看数据。就像开车要看仪表盘一样，不然怎么知道车子跑得怎么样？命中率（Hit Ratio）这个是最重要的指标，没有之一。命中率就是CDN直接返回缓存内容的请求占总请求的比例。一般来说，静态资源的命中率应该在90%以上，如果你的命中率只有50-60%，那肯定有问题。在AWS CloudFront里查看命中率很简单，进入CloudFront控制台，选择你的分发，然后点击"Monitoring"标签页。这里会显示Cache hit rate的图表，可以看到不同时间段的命中率变化。回源率（Origin Request Rate）这个和命中率是相对的，回源率高说明CDN经常要去源站拿数据，这样就失去了CDN的意义。正常情况下回源率应该控制在10%以下。响应时间包括CDN响应时间和回源响应时间。CDN响应时间一般应该在100ms以内，如果超过这个数值就要检查是不是节点选择有问题。我记得有次优化一个电商网站，发现图片加载特别慢。一查监控发现CDN响应时间居然有2秒多，后来才发现是缓存策略配置错误，每次都要回源验证。带宽使用情况这个主要是看成本，CDN的费用很大一部分就是带宽费用。通过监控带宽使用情况，可以了解流量分布，优化成本。在AWS CloudFront的监控面板里，你还能看到：Origin latency（回源延迟）Error rate（错误率）Requests（请求数）Bytes downloaded（下载字节数）这些数据都很有用，特别是错误率，如果突然飙升可能是源站出问题了。命中率低的常见原因和解决方案说到命中率低，我遇到过各种奇葩的情况。缓存策略配置不当这是最常见的问题。很多人图省事，直接用默认配置，结果发现很多本该缓存的内容都没有缓存。比如说，有些动态参数会导致URL不同，CDN就认为是不同的资源。像这种情况：https://example.com/image.jpg?timestamp=1234567890 https://example.com/image.jpg?timestamp=1234567891CDN会认为这是两个不同的文件，实际上内容是一样的。解决办法是在CloudFront的Behavior设置里配置Query String参数处理，可以选择忽略某些参数或者只转发特定参数。TTL设置太短Time To Live设置太短会导致缓存频繁过期。我见过有人把图片的TTL设置成5分钟，这不是瞎搞吗？静态资源的TTL至少要设置几个小时，甚至几天。在CloudFront里可以设置三种TTL：Minimum TTL：最小缓存时间Maximum TTL：最大缓存时间Default TTL：默认缓存时间一般我会这样设置：图片、CSS、JS等静态资源：24小时到7天HTML页面：1-6小时API接口：根据业务需求，可能几分钟到几小时源站响应头配置问题有时候源站返回了不合适的Cache-Control头，比如no-cache或者max-age=0，这会导致CDN不缓存内容。我之前遇到过一个案例，开发在Nginx配置里给所有静态资源都加了no-cache，结果CDN命中率惨不忍睹。后来改成这样：location ~* \.(jpg|jpeg|png|gif|css|js)$ { expires 7d; add_header Cache-Control "public, immutable"; }预热不充分新上线的CDN或者清除缓存后，需要一段时间来"预热"。这期间命中率会比较低，这是正常现象。但如果长时间命中率都上不去，就要检查其他配置了。CloudFront支持手动预热，可以通过Invalidation功能清除缓存，然后用脚本批量访问重要资源来预热缓存。CDN优化策略详解现在说说aws托管的缓存策略AWS CDN托管的缓存策略详细说明策略名称缓存内容不缓存内容使用场景Amplify缓存大多数静态资源和部分动态内容不缓存包含特定身份验证头的请求Amplify应用程序的通用缓存策略Amplify-Default缓存静态资源和基于常用头部的内容，保留某些Cookie不缓存带有特定认证头的请求，某些动态API响应Amplify应用的标准配置，平衡缓存与个性化Amplify-Default-V2与Amplify-Default类似，但有优化的TTL设置与Ampli…

服务器500错误又来了？别慌！这份排查指南让你秒变故障终结者
type: item
date: 2025-10-16T11:48:57+00:00
description: 前言说起500错误，我想每个做运维的朋友都有一肚子苦水要倒。昨天晚上11点多，我正准备洗洗睡了，手机突然疯狂震动——客户问题又来了。打开一看，果然是熟悉的HTTP 500错误，用户访问网站直接白屏。这种时候真的是又爱又恨，爱的是能锻炼自己的技术能力，恨的是为什么总是在最不合适的时候出现。不过经过这么多年的摸爬滚打，我总结出了一套比较实用的排查思路，今天就分享给大家。500错误其实就是服务器内部错误，说白了就是服务器遇到了意外情况，不知道怎么处理了。但是这个"意外情况"可能的原因太多了，从代码bug到服务器资源不足，从数据库连接问题到配置文件错误，每一个都可能是罪魁祸首。第一步：快速定位问题范围遇到500错误，我的第一反应不是立马去翻日志，而是先搞清楚影响范围。这个很重要，因为它决定了你处理问题的优先级和方式。我一般会快速检查几个点：是所有页面都500还是只有特定页面（可以通过浏览器f12查看报错接口）是所有用户都受影响还是部分用户错误是突然出现的还是逐渐增多的记得有一次，有个业务网站突然开始报500错误。我当时就先测试了几个不同的页面，发现只有特定页有问题，首页和其他功能页面都正常。这就大大缩小了排查范围，基本可以确定是相关的功能出了问题。如果你用的是负载均衡，还要检查一下是不是某台服务器的问题。我习惯直接访问每台服务器的IP，看看是不是所有服务器都有问题。有时候可能只是其中一台服务器出了状况。深入日志分析确定了影响范围之后，就该看日志了。日志是我们排查问题最重要的线索，但是看日志也有技巧。Web服务器日志先看Web服务器的错误日志，比如Nginx的error.log或者Apache的error_log。这里通常能看到最直接的错误信息。tail -f /var/log/nginx/error.log我经常看到的错误类型有：连接超时：upstream timed out连接被拒绝：connect() failed (111: Connection refused)文件权限问题：Permission denied配置语法错误：nginx configuration test failed有一次我遇到一个很奇怪的问题，Nginx日志显示"upstream timed out"，但是应用服务器看起来运行正常。后来发现是因为某个接口的处理时间突然变长了，超过了Nginx设置的超时时间。调整了一下proxy_read_timeout就解决了。系统资源检查有时候500错误不是代码问题，而是服务器资源不够用了。这种情况下，即使代码没问题，服务器也处理不了请求。内存使用情况free -h如果可用内存很少，或者swap使用率很高，那很可能就是内存不足导致的问题。我遇到过好几次因为内存不足导致的500错误，特别是在流量突然增大的时候。还可以用top或者htop看看哪个进程占用内存最多：top -o %MEMCPU使用率topCPU使用率持续100%也会导致服务器响应缓慢或者直接返回500错误。我见过有些服务器因为某个进程死循环，CPU占用率一直是100%，导致整个网站都访问不了。磁盘空间df -h磁盘空间不足也是一个常见原因，特别是日志文件增长太快的时候。我就遇到过因为某个日志文件疯狂增长，把磁盘空间占满了，导致应用无法写入临时文件而报500错误。不同应用类型的专项排查根据我这些年的经验，不同技术栈的应用出现500错误时，排查重点还是有些区别的。Java应用排查Java应用的500错误排查，我一般从这几个方面入手：JVM内存问题Java应用最容易出现的就是内存问题，特别是OutOfMemoryError。jstat -gc <pid> jmap -histo <pid>我记得有一次，一个Spring Boot应用突然开始频繁500，通过jstat发现老年代内存使用率一直在99%以上，明显是内存泄漏了。后来用MAT分析heap dump，发现是某个缓存没有设置过期时间，导致对象越积累越多。线程池状态jstack <pid>线程池满了也会导致请求无法处理。我见过有些应用因为某个接口响应特别慢，把线程池都占满了，新的请求进来就直接500了。GC问题jstat -gc <pid> 1s如果Full GC频繁或者GC时间过长，也会影响应用响应。我遇到过一次，应用每隔几分钟就会卡顿几秒钟，用户访问就会超时报500，原因就是Full GC时间太长了。应用日志Java应用的日志通常在logs目录下，或者通过logback、log4j配置的路径：tail -f /app/logs/application.log grep "ERROR" /app/logs/application.log | tail -20常见的错误类型：数据库连接池耗尽空指针异常类加载失败配置文…

网络慢如蜗牛？教你几招Linux测带宽的绝活，让网络问题无处遁形！
type: item
date: 2025-10-14T14:53:41+00:00
description: 昨天又有客户问我，说他们的应用突然变慢了，怀疑是网络问题。我问他网络带宽多少，他说不知道...这种情况我见得太多了，很多人遇到网络问题就是一脸懵，完全不知道从哪里下手。其实测网络带宽这个事情，我刚开始做运维的时候也是摸着石头过河。记得有一次领导问我们机房的带宽利用率怎么样，我愣是说不出个所以然来，那个尴尬啊...从那以后我就下定决心要把这些基本功练扎实。今天就来分享一下我这些年积累的Linux网络带宽测试经验，保证让你以后遇到网络问题不再抓瞎。speedtest-cli - 最简单粗暴的方法说到测带宽，我第一个想到的就是speedtest-cli。这玩意儿就像网页版的speedtest.net，但是可以在命令行里跑，特别适合我们这些服务器党。安装很简单：# CentOS/RHEL系列 yum install epel-release yum install python-pip pip install speedtest-cli # Ubuntu/Debian系列 apt update # 安装 pipx sudo apt install pipx pipx ensurepath # 安装应用 pipx install speedtest-cli #添加环境变量 echo 'export PATH="$PATH:/root/.local/bin"' >> ~/.bashrc source ~/.bashrc装好之后直接运行：speedtest-cli它会自动帮你选择最近的测试服务器，然后开始测试。输出大概是这样的：不过有时候自动选择的服务器不太理想，你可以手动指定。先看看附近有哪些服务器：speedtest-cli --list | grep China然后选一个延迟比较低的：speedtest-cli --server 服务器ID我记得有一次我们的业务突然变慢，用户投诉不断。我用speedtest-cli一测，发现下载速度只有平时的一半，赶紧联系运营商，原来是他们在做线路维护忘记通知我们了。iperf3 - 专业级的带宽测试工具speedtest-cli虽然方便，但有个问题就是测试的是到公网的速度。如果你想测试内网带宽，或者两台服务器之间的带宽，那就得用iperf3了。安装iperf3：# CentOS/RHEL yum install iperf3 # Ubuntu/Debian apt install iperf3iperf3需要一台服务器做服务端，一台做客户端。在服务端运行：iperf3 -s在客户端运行：iperf3 -c 服务端IP默认测试10秒钟，你也可以指定时间：iperf3 -c 服务端IP -t 30测试UDP带宽：iperf3 -c 服务端IP -u客户端结果：服务端结果：我特别喜欢用iperf3测试新部署的服务器之间的网络性能。有一次我们要在两个机房之间做数据同步，用iperf3测了一下专线带宽，发现实际速度比运营商承诺的要低不少，最后让他们重新调试了线路。wget/curl - 简单实用的下载测试有时候你就想快速测一下下载速度，不想装额外的工具，那wget和curl就够用了。用wget测试：wget -O /dev/null http://speedtest.tele2.net/100MB.zip这个命令会下载一个100MB的文件到/dev/null（相当于丢弃），然后显示下载速度。用curl测试：curl -o /dev/null http://speedtest.tele2.net/100MB.zip如果你想看更详细的信息：curl -o /dev/null -w "下载速度: %{speed_download} bytes/sec\n总时间: %{time_total}s\n" http://speedtest.tele2.net/100MB.zip这种方法的好处是可以测试到特定服务器的速度，比如你的CDN节点或者合作伙伴的服务器。nload - 实时监控网络流量有时候你不是要测最大带宽，而是想看看当前的网络使用情况，nload就很合适。安装nload：# CentOS/RHEL yum install nload # Ubuntu/Debian apt install nload运行很简单：nload它会显示一个实时的图表，显示当前的上传和下载速度。如果你有多个网卡，可以用左右箭头键切换。我经常用nload来监控服务器的网络使用情况，特别是在做数据迁移或者大文件传输的时候，可以实时看到网络利用率。iftop - 看看谁在占用带宽iftop比nload更进一步，它不仅能显示总的流量，还能显示每个连接的流量情况。安装iftop：# CentOS/RHEL yum install iftop # U…