躬行笔记 - 2026年4月
type: channel
link: https://fuzhoupyy.work/index.php/2026/04/
description: 古人学问无遗力，少壮工夫老始成。 纸上得来终觉浅，绝知此事要躬行。
items: 手把手教你落地网络入侵检测系统（NIDS），从选型到上线全记录
items: 别让你的Nginx裸奔！生产环境下的访问控制实战，全是填坑经验
items: 从零开始搞定Chef自动化部署，让服务器管理不再头疼
items: 蓝绿部署实战指南：从零到一搭建生产级无缝发布系统
items: 从零开始搞懂DDoS和CC攻击：运维人员必备的防护攻略
items: Pingora实战：从零搭建比Nginx还快的反向代理，手把手教你玩转Cloudflare开源神器
items: Linux 内存泄漏排查全攻略：从现象到根因，一文讲透生产环境实战经验
items: K8s持久化存储深度解析：PV、PVC、StorageClass三剑客的生产实战
items: Docker Swarm 搞定高可用集群，生产环境再也不怕服务挂掉了
items: 还在手动点控制台建资源？Terraform和CloudFormation入门实战，这篇够你喝一壶了

手把手教你落地网络入侵检测系统（NIDS），从选型到上线全记录
type: item
date: 2026-04-22T14:07:50+00:00
description: 说实话，搞安全这块东西，很多运维同学是又爱又恨。爱的是确实能帮你挡住不少事儿，恨的是部署起来各种坑，配不好还一堆误报，搞得你天天看告警看到想吐。我之前在客户公司负责过一套NIDS的完整落地，从前期调研到最后稳定运行，前前后后折腾了差不多两个月。今天就把这个过程掏出来跟大家聊聊，尽量把踩过的坑和一些实际经验都说清楚。先搞清楚你到底要监控什么很多人上来就想装Snort、装Suricata，工具先搞起来再说。我一开始也是这个思路，后来发现这样搞完全是在浪费时间。你得先坐下来想清楚几个问题：你的网络环境里，哪些流量是需要重点盯着的？敏感数据在哪？常见的威胁类型是什么？拿我们当时的情况来说，公司有一套对外的Web业务系统，还有内部的OA和数据库集群。对外的业务系统天天被扫描、被尝试SQL注入、XSS什么的，这块肯定是重点。内部的话，主要担心的是横向移动，就是万一有人进来了，在内网里到处乱窜。我当时列了一个简单的表格：监控区域流量类型关注的威胁优先级DMZ区HTTP/HTTPSWeb攻击、扫描探测高核心交换全流量横向移动、C2通信高数据库段DB协议流量异常查询、数据外泄中办公网混合流量恶意软件、钓鱼中这个表看起来简单，但真的很有用。后面选工具、写规则、部署探针的时候，都是围绕这个来的。不然你部署完了发现，关键的地方没覆盖到，不关键的地方一堆告警，那就白忙活了。工具选型：Snort还是Suricata？开源的NIDS工具，绕不开这两个。商业的像Palo Alto、FireEye那些，预算够当然好，但大多数公司的安全预算你懂的...所以我们还是聊开源方案。Snort 是老牌子了，社区大，规则多，文档也全。但它有个问题，单线程。在流量大的环境里，性能瓶颈很明显。我之前在测试环境里跑过，跑到2Gbps左右的流量就开始丢包了。Suricata 是后来者，天然支持多线程，性能上确实比Snort强不少。而且它兼容Snort的规则格式，也就是说Snort的规则你拿过来基本能直接用。另外Suricata原生支持输出EVE JSON格式的日志，对接ELK那套东西非常方便。我们最后选的是Suricata，原因很直接：核心交换那个位置的流量峰值能到5Gbps，Snort扛不住。不过也不是说Snort就不好。如果你的网络规模不大，流量也就几百兆，Snort完全够用，而且上手更简单一些。还有一个值得提的是 Zeek（以前叫Bro），严格来说它不算传统的IDS，更偏向于网络流量分析和日志生成。它不做实时告警，但生成的连接日志、DNS日志、HTTP日志这些，拿来做事后分析和威胁狩猎非常好用。我们后来也部署了Zeek，和Suricata配合着用，一个管实时告警，一个管深度分析。硬件和网络架构怎么搞工具选好了，接下来就是怎么把流量喂给它。NIDS是旁路部署的，不像防火墙那样串在链路上。它需要的是流量的镜像副本。一般有两种方式：1. 交换机端口镜像（SPAN/Mirror Port）这是最常见的方式。在核心交换机上配一个镜像端口，把需要监控的VLAN流量或者特定端口的流量镜像出来，接到NIDS传感器上。我们用的是华为的交换机，配置大概长这样：# 创建观察端口（连接NIDS传感器的端口） observe-port 1 interface GigabitEthernet 0/0/24 # 配置镜像源端口 interface GigabitEthernet 0/0/1 port-mirroring to observe-port 1 both如果是思科的设备：monitor session 1 source interface Gi0/1 both monitor session 1 destination interface Gi0/24这里有个坑要注意：镜像端口的带宽要够。如果你镜像的源端口是10G的，但目标端口只有1G，那流量大的时候肯定丢包。我们当时就吃了这个亏，一开始用的1G口做镜像，结果高峰期丢了将近30%的包，好多攻击流量直接漏掉了。后来换成了10G的口才解决。2. TAP设备如果预算允许，用网络TAP（Test Access Point）是更好的选择。TAP是一个硬件设备，直接接在链路上，把流量复制一份出来。它的好处是不依赖交换机的镜像功能，也不会因为交换机负载高而丢包。我们在DMZ区的出口就用了一个TAP，大概花了几千块钱，买的国产的，效果还行。传感器的硬件配置跑Suricata的服务器，配置不能太寒酸。我们用的配置是：CPU：Intel Xeon E5-2680 v4（14核28线程）内存：64GB DDR4网卡：Intel X710 10GbE（支持多队列）硬盘：500GB SSD（主要存日志，日志量大的话还得考虑外挂存储）网卡这块特别说一下，一定要选支持多队…

别让你的Nginx裸奔！生产环境下的访问控制实战，全是填坑经验
type: item
date: 2026-04-22T14:07:30+00:00
description: 咱们搞运维的，Nginx那是吃饭的家伙，平时大家可能更多关注的是负载均衡、反向代理，或者怎么调优性能。但说句掏心窝子的话，安全这东西，平时不出事你觉得它多余，一出事那就是“救命稻草”。今天咱们不整那些虚头巴脑的理论，直接上生产环境的实战，聊聊Nginx访问控制那些事儿。这些配置都是我在无数次填坑过程中总结下来的，希望能给大伙提个醒，别让你的服务器在互联网上“裸奔”。咱们先从最简单的说起，很多人觉得访问控制不就是设个密码，或者封个IP嘛。其实没那么简单。拒绝不速之客：基于IP的访问控制这应该是最直接的手段了。就像咱们小区的门禁，只让业主进，外人一律挡在门外。Nginx里的allow和deny指令就是干这个活的。这俩模块是ngx_http_access_module自带的，默认就装了，不用你去折腾编译安装。我记得有一次，公司有个内部管理系统，原本是挂在内网域名下的，结果开发哥们为了方便测试，临时挂到了公网，也没做任何限制。结果没过两天，就被安全扫描器扫到了，虽然没出大事故，但那个报警邮件看得我后背发凉。后来我就给所有的内部后台都加上了IP白名单。配置起来其实特简单，打开你的nginx.conf或者对应的站点配置文件，在server块或者location块里加上几行就行：location /admin/ { allow 192.168.1.0/24; # 允许内网网段 allow 10.0.0.1; # 允许某个特定的跳板机 deny all; # 拒绝其他所有人 }这里有个小细节，很多人容易踩坑。Nginx匹配规则是从上往下匹配，一旦匹配成功就停止。所以顺序千万不能乱。你要是把deny all写在第一行，那后面所有的allow都白搭，谁都进不去，这叫“误伤友军”。我就干过这种傻事，配置完 reload 了一下，结果把自己关在外面了，只能灰溜溜地去机房连控制台改配置，那场面，别提多尴尬了。还有个事儿得注意，如果你用了CDN，比如阿里云CDN或者Cloudflare，那你在这个allow里配置的IP可能就不是用户的真实IP了，而是CDN节点的IP。这时候你得先用set_real_ip_from把CDN的IP段设置一下，用X-Forwarded-For或者X-Real-IP头来获取真实用户IP，然后再做限制。不然你限制了个寂寞，或者把正常用户给封了。给目录加把锁：基于用户的认证有时候，我们需要给某个测试环境、或者某个临时的API接口加个密码，不想让随便什么人都能访问。这时候IP限制就不太灵活了，比如出差在外，IP是动态的，咋办？这时候就得请出ngx_http_auth_basic_module模块了。这玩意儿就像给目录加了一把锁，只有输入对了用户名和密码才能进。配置分两步走。第一步，得先有个密码文件。别想着自己去手写加密密码，Linux底下有现成的工具，Apache的htpasswd工具最方便。一般服务器装了Apache或者httpd-tools就有。没有的话装一下：yum install httpd-tools -y然后生成密码文件，比如我们建个/etc/nginx/.htpasswd文件，添加一个叫pyy的用户：htpasswd -c /etc/nginx/.htpasswd pyy回车后它会让你输入两次密码。注意那个-c参数是create的意思，如果你是第一次创建文件用-c，如果是追加用户，千万别带-c，不然原来的文件会被覆盖掉，我就因为这个被同事投诉过，把他们的账号给弄丢了。文件有了，接下来就是Nginx配置：location /test/ { auth_basic "Restricted Area"; # 这个是提示信息，随便写 auth_basic_user_file /etc/nginx/.htpasswd; }配置完nginx -t测试一下，没问题就nginx -s reload。这时候你再去访问那个目录，浏览器就会弹出一个原生的登录框，丑是丑了点，但胜在实用。这个功能在临时分享一些敏感数据，或者保护还没上线的功能时特别好用。不过要注意，这个Basic认证是Base64编码传输的，安全性并不是特别高，如果不配合HTTPS，密码其实相当于明文传输，抓个包就能看见。所以，能上HTTPS尽量上HTTPS。更高级的玩法：结合GeoIP做地域封禁有时候我们不仅想封IP，还想封地区。比如公司的业务只在国内开展，但是每天日志里全是来自大洋彼岸的扫描攻击，看着都烦。这时候就可以用GeoIP模块。现在的Nginx默认应该都支持ngx_http_geoip_module，如果不支持，那你可能得重新编译安装一下，带上--with-http_geoip_module参数。不过现在很多都是动态加载模块，看情况而定。首先你得下载GeoIP的数据库文…

从零开始搞定Chef自动化部署，让服务器管理不再头疼
type: item
date: 2026-04-17T15:58:10+00:00
description: 最近公司的服务器数量又增加了不少，每次部署新应用都要重复执行一堆命令，配置文件改来改去的，实在是太麻烦了。我琢磨着得找个自动化工具来解决这个问题，经过一番调研，最终选择了Chef。说实话，刚开始接触Chef的时候，被它的概念搞得有点晕。什么Cookbook、Recipe、Node、Role的，感觉像是在学做菜一样。不过用了一段时间后发现，这玩意儿还真挺好使的，今天就把我踩过的坑和实践经验分享给大家。Chef到底是个啥简单来说，Chef就是一个自动化配置管理工具。你可以把它理解成一个"厨师"，按照你写好的"菜谱"（Cookbook），自动在服务器上"做菜"（配置软件和服务）。我觉得Chef最大的优势就是它用Ruby写配置，代码即配置的理念让运维工作变得更加程序化。不像以前写shell脚本那样，到处都是if-else判断，Chef的DSL（领域特定语言）让配置文件看起来更清晰。搭建Chef环境部署Chef主要有三个组件：Chef Server、Chef Workstation和Chef Client。我当时是在Ubuntu 20.04上搭建的，过程还算顺利。安装Chef其实挺简单的，在工作站上执行：curl -L https://omnitruck.chef.io/install.sh | sudo bash这个脚本会自动检测你的系统，下载对应版本的Chef。安装完成后，可以用chef --version检查一下版本。配置Chef Server稍微麻烦点。我是直接用的Chef官方提供的包，大概有200多MB：wget https://packages.chef.io/files/stable/chef-server/14.0.0/ubuntu/20.04/chef-server-core_14.0.0-1_amd64.deb sudo dpkg -i chef-server-core_14.0.0-1_amd64.deb sudo chef-server-ctl reconfigure配置过程需要等一会儿，它会自动安装PostgreSQL、RabbitMQ等依赖服务。配置完成后，创建管理员用户和组织：sudo chef-server-ctl user-create admin Admin User admin@example.com 'password' --filename admin.pem sudo chef-server-ctl org-create myorg 'My Organization' --association_user admin --filename myorg-validator.pem这里生成的.pem文件很重要，是后续连接Chef Server的凭证，一定要保存好。写第一个CookbookCookbook是Chef的核心概念，可以理解为一个配置包，里面包含了Recipe（具体的配置步骤）、Attributes（变量）、Templates（模板文件）等。创建Cookbook很简单：chef generate cookbook nginx_setup这会生成一个标准的Cookbook目录结构。我第一次写的是一个安装配置Nginx的Cookbook，在recipes/default.rb里写入：# 安装nginx包 package 'nginx' do action :install end # 创建网站目录 directory '/var/www/mysite' do owner 'www-data' group 'www-data' mode '0755' action :create end # 配置nginx template '/etc/nginx/sites-available/mysite' do source 'mysite.conf.erb' owner 'root' group 'root' mode '0644' variables( server_name: node['nginx_setup']['server_name'], port: node['nginx_setup']['port'] ) notifies :restart, 'service[nginx]', :delayed end # 启用站点 link '/etc/nginx/sites-enabled/mysite' do to '/etc/nginx/sites-available/mysite' notifies :restart, 'service[nginx]', :delayed end # 确保nginx服务运行 service 'nginx' do action [:enable, :start]…

蓝绿部署实战指南：从零到一搭建生产级无缝发布系统
type: item
date: 2026-04-16T15:06:11+00:00
description: 蓝绿部署实战指南：从零到一搭建生产级无缝发布系统我在公司做运维这几年，最怕的就是发布新版本的时候出问题。记得有一次周五下午发版本，结果服务挂了两个小时，用户投诉电话打爆了，我在机房里忙活到晚上11点才搞定。从那以后，我就开始研究各种发布策略，蓝绿部署就是其中最实用的一种。今天就把我这几年摸索出来的蓝绿部署经验分享给大家，全是生产环境踩过的坑和总结出的干货。什么是蓝绿部署蓝绿部署说白了就是准备两套一模一样的生产环境，一套叫蓝环境，一套叫绿环境。当前用户访问的是蓝环境，我要发新版本的时候，就把新版本部署到绿环境上，测试没问题了再把流量切过去。这样做的好处是什么？如果新版本有问题，我立马就能切回到旧版本，用户基本感受不到服务中断。我之前用滚动更新的方式，每次更新都要重启服务，虽然时间很短，但还是会有那么几秒钟的服务不可用。用了蓝绿部署之后，这个问题彻底解决了。蓝绿部署的核心原理整个流程其实很简单：当前蓝环境在线提供服务在绿环境部署新版本应用绿环境测试通过后，负载均衡器流量从蓝环境切换到绿环境绿环境成为新的生产环境，蓝环境变成备用环境关键点就是这个流量切换，必须要做到瞬间完成，不能有中间状态。实现蓝绿部署的几种方式方式一：基于Nginx的蓝绿部署这是我最常用的方式，成本低，配置简单。先准备两台服务器，192.168.1.10（蓝）和192.168.1.11（绿），前面放一台Nginx做负载均衡。Nginx配置文件关键部分：upstream blue_pool { server 192.168.1.10:8080 weight=1 max_fails=3 fail_timeout=30s; } upstream green_pool { server 192.168.1.11:8080 weight=1 max_fails=3 fail_timeout=30s; } # 当前生产环境指向蓝环境 upstream production { server 192.168.1.10:8080; } server { listen 80; server_name api.example.com; location / { proxy_pass http://production; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }切换的时候，写个脚本：#!/bin/bash # switch.sh NGINX_CONF="/etc/nginx/conf.d/app.conf" CURRENT_ENV=$(grep -A1 "upstream production" $NGINX_CONF | grep server | awk '{print $2}' | cut -d: -f1) if [ "$CURRENT_ENV" = "192.168.1.10" ]; then # 当前是蓝环境，切换到绿环境 sed -i 's/server 192.168.1.10:8080;/server 192.168.1.11:8080;/' $NGINX_CONF echo "已切换到绿环境" else # 当前是绿环境，切换到蓝环境 sed -i 's/server 192.168.1.11:8080;/server 192.168.1.10:8080;/' $NGINX_CONF echo "已切换到蓝环境" fi # 重新加载Nginx配置 nginx -s reload这个方案的优点是简单直接，缺点是需要手动执行切换脚本。不过对于中小型项目来说已经够用了。方式二：基于HAProxy的蓝绿部署HAProxy在流量切换方面比Nginx更灵活，支持动态权重调整。HAProxy配置：global daemon maxconn 4096 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms frontend web_frontend bind *:80 default_backend web_servers backend web_servers balance roundrobin # 初始状态：蓝环境权重100，绿环境权重0 server blue 192.168.1.10:8080 weight 100 check server green 192.168.1.11:8080 weight 0 check # 管理接口 …

从零开始搞懂DDoS和CC攻击：运维人员必备的防护攻略
type: item
date: 2026-04-15T14:45:00+00:00
description: 作为一个在运维岗位摸爬滚打好几年的人，我想和大家聊聊DDoS和CC攻击这个话题。这两种攻击方式虽然都能让你的服务器瞬间趴窝，但原理和防护方法却大不相同。今天就把我这些年踩过的坑和积累的经验分享给大家。DDoS攻击到底是个什么鬼DDoS全称是Distributed Denial of Service，翻译过来就是分布式拒绝服务攻击。听起来很高大上，其实原理挺简单的。你可以想象一下，平时你家门口最多同时来3-5个客人，你能应付得过来。但如果突然来了100个人，都要进你家坐坐，你家的门、客厅、厕所...肯定就瘫痪了。DDoS攻击就是这个道理，通过控制大量的"肉鸡"（被感染的计算机）同时向目标服务器发送请求，把服务器的带宽、CPU、内存等资源耗尽。DDoS攻击主要分几种类型：流量型攻击（Volume-based attacks）这种最直接，就是用大量的垃圾流量把你的带宽塞满。常见的有UDP洪水攻击、ICMP洪水攻击等。攻击者会发送大量的UDP包或者ping包，把你的网络带宽占满，正常用户就访问不了了。协议型攻击（Protocol attacks）这种攻击利用网络协议的缺陷，比如SYN洪水攻击。TCP三次握手大家都知道吧，客户端发SYN，服务器回SYN-ACK，然后等客户端的ACK。攻击者只发SYN不发ACK，服务器就一直等着，连接池很快就满了。应用层攻击（Application layer attacks）这种攻击针对应用程序，看起来像正常的请求，但会消耗大量的服务器资源。比如不断请求复杂的数据库查询，或者上传大文件等。CC攻击又是怎么回事CC攻击的全称是Challenge Collapsar，中文叫挑战黑洞。听这名字就知道不是什么好东西。CC攻击和DDoS攻击的区别在于，CC攻击更加"精准"。它不需要很大的流量，而是模拟正常用户的行为，不断地请求那些消耗资源比较大的页面或接口。CC攻击的特点是：流量不大，但请求频繁看起来像正常用户行为针对消耗资源较大的功能难以通过简单的流量限制来防护两种攻击的本质区别说到区别，我觉得可以用一个比喻来解释。DDoS攻击就像是在你家门口堵了一大群人，把路都堵死了，正常客人根本进不来。这种攻击比较"粗暴"，流量大，容易发现。CC攻击则像是派了几个人，每个人都很有礼貌地敲门，但一进来就要你做很复杂的事情，比如帮忙搬家具、修电器...虽然人不多，但你很快就累趴下了。从技术角度来说：DDoS主要消耗带宽和网络资源CC主要消耗服务器的CPU、内存和数据库资源DDoS流量特征明显，CC攻击更隐蔽DDoS防护相对简单粗暴，CC防护需要更精细的策略防护策略：不只是买个高防就完事很多人以为防DDoS和CC攻击就是买个高防服务器或者CDN，其实远没有这么简单。我这些年总结下来，防护需要多层次的策略。基础防护措施首先是服务器层面的优化。我一般会调整一些系统参数，比如增加TCP连接池大小，调整超时时间等。在nginx配置里也会做一些限制：# 限制单个IP的连接数 limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m; limit_conn conn_limit_per_ip 20; # 限制请求频率 limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s; limit_req zone=req_limit_per_ip burst=20 nodelay;这些配置能在一定程度上缓解攻击，但面对大规模DDoS还是不够的。应用层防护对于CC攻击，我会在应用层做一些防护。比如给那些消耗资源大的接口加上缓存，限制单个用户的请求频率，对异常请求进行识别和拦截。我记得有次优化一个电商网站的搜索功能，发现搜索结果页面的数据库查询特别复杂。于是我们加了Redis缓存，把热门搜索词的结果缓存起来，这样即使遇到CC攻击，数据库压力也不会太大。CDN和云防护现在各大云厂商的防护产品确实很强大。我用过阿里云的DDoS高防，腾讯云的大禹，华为云的Anti-DDoS等，效果都不错。这些产品的原理基本相似：在你的服务器前面部署一层防护节点，所有流量先经过这些节点进行清洗，正常流量才会转发到你的服务器。流量清洗的那些门道流量清洗听起来很神秘，其实原理并不复杂。就是在海量的网络流量中，把攻击流量识别出来并丢弃，让正常流量通过。特征识别最基础的方法是基于特征识别。比如DDoS攻击的流量往往有一些明显特征：源IP分布异常（大量来自同一地区或AS）请求模式单一（相同的User-Agent、请求路径等）流量突增（短时间内流量暴涨几十倍）我见过一些简单的攻击，所有请求的User-Agent都一样，这种很容易识别。但…

Pingora实战：从零搭建比Nginx还快的反向代理，手把手教你玩转Cloudflare开源神器
type: item
date: 2026-04-14T15:55:05+00:00
description: 前两天看到Cloudflare开源了Pingora这个项目，说是用Rust写的反向代理框架，性能比Nginx还要快，我就坐不住了。咱们做运维的，对新东西总是要保持好奇心，何况这玩意儿号称每秒能处理百万级请求，这不得赶紧试试？说实话，刚开始看到这个消息的时候我还挺怀疑的。Nginx可是咱们运维圈的老伙计了，用了这么多年，稳定可靠，你说一个新出来的框架能比它快？不过转念一想，Cloudflare可是全球最大的CDN服务商之一，他们每天处理的流量那都是天文数字，既然敢开源出来，肯定是有两把刷子的。抱着试试看的心态，我在测试环境折腾了几天，把整个安装配置流程都跑了一遍。不得不说，这东西确实有点东西，今天就把我的实践经验分享给大家，希望能帮到想尝鲜的朋友们。Pingora是个啥？咱们先聊聊Pingora到底是个什么东西。简单来说，它是Cloudflare用Rust语言开发的一个高性能反向代理框架[1]。Cloudflare大家应该都不陌生吧，全球最大的CDN服务商之一，每天处理的HTTP请求那是数以万亿计的。以前Cloudflare也是用Nginx，但是随着业务规模越来越大，Nginx的一些局限性就开始显现出来了。比如说，Nginx的配置文件虽然灵活，但是要做一些复杂的逻辑处理就比较麻烦；还有就是性能瓶颈，在某些极端场景下已经满足不了需求了。于是Cloudflare就开始自己造轮子，用Rust写了这个Pingora。根据官方的说法，Pingora在性能、安全性、可扩展性方面都有很大的提升[2]。特别是在高并发场景下，表现相当亮眼。我看过一些性能测试的对比数据，Pingora在某些场景下确实比Nginx快不少[3]。当然，这个"快"也要看具体场景，不是说什么情况下都快的。咱们做技术的，不能盲目迷信，得自己动手测试才知道。环境准备好了，说了这么多，咱们开始动手吧。不过在安装Pingora之前，得先把环境准备好。Pingora是用Rust写的，所以首先你得有Rust的环境。要是你系统里还没有Rust，那就得先装一下。我这边测试用的是debain13，其他Linux发行版应该也差不多。安装Rust其实挺简单的，官方提供了一个脚本：curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh运行这个脚本，一路回车就好。装完之后记得重启一下终端，或者手动source一下环境变量：source $HOME/.cargo/env然后验证一下安装是否成功：rustc --version cargo --version看到版本号输出就说明OK了。对了，还得提醒一下，Pingora对Rust的版本有要求，最好是1.70以上的版本。要是版本太老，可能编译的时候会报错。我一开始就是用的系统自带的旧版本，结果折腾半天编译不过，后来升级了Rust版本才解决。除了Rust，你还得有一些基础的编译工具，比如gcc、make之类的。debain13的话可以这样装：apt-get install -y gcc make openssl-devel pkg-config这些工具在编译Pingora的时候会用到，少了哪个都会报错，到时候再装就麻烦了。创建项目环境准备好了，接下来就是创建项目。Pingora不是一个独立的可执行程序，而是一个框架，你需要基于它来开发自己的代理服务。这个跟Nginx不太一样，Nginx是直接装好就能用的，Pingora更像是一个开发框架。用Cargo创建一个新项目：cargo new my_pingora_proxy cd my_pingora_proxy创建后的目录结构：然后编辑Cargo.toml文件，添加Pingora的依赖：[package] name = "my_pingora_proxy" version = "0.1.0" edition = "2024" [dependencies] pingora = { version = "0.1", features = ["proxy"] } async-trait = "0.1"这里要注意一下，Pingora的版本号可能会更新，具体可以去crates.io上看最新的版本。我写这篇文章的时候是0.1版本，现在可能已经更新了。添加依赖的时候，那个features = ["proxy"]不能少，不然编译的时候会提示找不到某些模块。我第一次搞的时候就忘了这个，折腾了好久才发现。写第一个代理程序依赖配好了，接下来就是写代码了。说实话，第一次看到Pingora的代码的时候，我还挺懵的。跟Nginx那种配置文件的方式完全不一样，Pingora是用代码来定义代理逻辑的。不过仔细看看，其实也不难理解。咱们先写一个最简单的反向代理，把请求转发到后…

Linux 内存泄漏排查全攻略：从现象到根因，一文讲透生产环境实战经验
type: item
date: 2026-04-13T13:50:40+00:00
description: 做运维这么多年，内存泄漏这事儿真是没少碰。有些时候程序跑着跑着内存就蹭蹭往上涨，重启一下好了，过两天又不行了。这种问题最烦人，不像CPU高那样容易定位，也不像磁盘满了那样好处理。内存泄漏就像个隐形杀手，藏在代码深处，等你发现的时候往往已经酿成事故了。今天咱们不聊虚的，直接上干货，把Linux下排查内存泄漏的方法系统梳理一遍。从基础的命令行工具到高级的调试技巧，能用的都给大家整理出来。内存泄漏到底是咋回事说白了就是申请了内存用完不释放。程序向系统申请了一块内存空间，用完了却没告诉系统"我不用了"，这块内存就被标记为占用状态。时间一长，这种"僵尸内存"越来越多，可用内存越来越少，最后系统扛不住了，触发OOM Killer把进程干掉，或者整个系统卡死。Linux的内存管理机制本身是没问题的，问题出在应用程序层面。C/C++这种需要手动管理内存的语言是重灾区，Java、Go这种有垃圾回收的语言理论上好点，但也不代表不会泄漏。比如Java里的对象引用没释放，或者堆外内存用多了，照样会出问题。内存泄漏有个特点：渐进性。刚启动的时候没事，运行几天甚至几周才开始显现。所以排查起来特别费劲，你得知道是哪个时间点开始泄漏的，做了什么操作触发的。怎么发现内存泄漏监控是第一道防线。我们生产环境用的是Prometheus + Grafana，内存使用率曲线一目了然。正常的内存使用应该是波动的，有升有降，垃圾回收或者缓存清理后内存会下来。如果看到一条斜向上的直线，那八成有问题。命令行下最常用的是free命令：free -h total used free shared buff/cache available Mem: 15Gi 8.5Gi 2.1Gi 256Mi 4.9Gi 6.2Gi Swap: 8.0Gi 1.2Gi 6.8Gi重点看available这列，这才是真正可用的内存。free那列看起来少，但很多是缓存，系统需要的时候可以回收。如果available持续下降，那就要警惕了。top命令更直观，能看到每个进程的内存占用：top - 14:30:25 up 10 days, 3:45, 2 users, load average: 0.52, 0.58, 0.59 Tasks: 156 total, 1 running, 155 sleeping, 0 stopped, 0 zombie %Cpu(s): 3.2 us, 1.5 sy, 0.0 ni, 94.8 id, 0.5 wa, 0.0 hi, 0.0 si, 0.0 st MiB Mem : 16384.0 total, 2150.5 free, 8720.3 used, 5513.2 buff/cache MiB Swap: 8192.0 total, 6800.2 free, 1391.8 used. 6352.1 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 12345 app 20 0 4.2g 3.5g 123m S 3.2 22.1 12:34.56 java按M可以按内存排序。VIRT是虚拟内存，RES是实际物理内存，SHR是共享内存。排查内存泄漏主要看RES，这个才是真正占用的物理内存。还有个命令vmstat，能看内存变化趋势：vmstat 1 10 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 1425400 2150352 451232 5060992 0 0 2 15 12 15 3 1 95 0 0 0 0 1425400 2148320 451240 5061124 0 0 0 0 1234 2156 3 1 95 0 0看free列是不是在持续减少。si和so是swap in和swap out，如果这两个值很大，说明系统在频繁换页，内存已经紧张了。定位问题进程发现系统内存不够了，下一步就是找出是谁在搞鬼。top命令能看到进程级别的内存占用，但有时候进程下面有很多线程，想知道具体是哪个线程占的多，可以用：top -H -p <pid>这样能显示进程下所有线程的资源占用情况。还有一个很好用的命令是ps，可以按内存排序：ps aux --sort=-%mem | head -10这会列出内存占用最高的10个进程。有时候进程名都一样，比如Java程序都叫java，怎么区分？看命令行参数：ps aux | grep java或者看/proc/<pid>…

K8s持久化存储深度解析：PV、PVC、StorageClass三剑客的生产实战
type: item
date: 2026-04-12T15:02:37+00:00
description: 做了这么多年运维，K8s的存储这块一直是个让人又爱又恨的东西。说它复杂吧，确实概念挺多的，PV、PVC、StorageClass这些名词听起来就头大；说它简单吧，一旦搞明白了原理，用起来还是很顺手的。今天我就把自己这些年在生产环境中踩过的坑、总结的经验分享给大家，让你们少走点弯路。为什么需要持久化存储容器本身是无状态的，这个大家都知道。Pod一重启，里面的数据就没了，这对于数据库、文件存储这些有状态应用来说简直是灾难。我记得刚开始用K8s的时候，有次MySQL的Pod重启了，结果所有数据都丢了，那个心情...简直想死的心都有。从那以后我就深刻认识到，持久化存储在K8s中有多重要。K8s的持久化存储主要解决这么几个问题：数据持久性：Pod重启、迁移后数据不丢失数据共享：多个Pod可以访问同一份数据存储抽象：屏蔽底层存储实现细节PV、PVC、StorageClass的关系这三个概念的关系，我用一个比较接地气的比喻来解释：PV（PersistentVolume）就像是一个仓库，管理员提前准备好的存储空间。PVC（PersistentVolumeClaim）就像是租仓库的申请单，用户说我要多大的空间、什么类型的。StorageClass就像是仓库的分类标准，比如高性能仓库、普通仓库、便宜仓库等。具体来说：PV（持久卷）PV是集群级别的资源，由管理员创建，代表集群中的一块存储。它包含存储实现的具体细节，比如NFS、iSCSI、云存储等。apiVersion: v1 kind: PersistentVolume metadata: name: my-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain nfs: server: 192.168.1.100 path: /data/nfs这个配置我在生产环境用过很多次，需要注意几个点：capacity定义存储大小accessModes定义访问模式，RWO（ReadWriteOnce）表示只能被一个节点挂载persistentVolumeReclaimPolicy定义回收策略PVC（持久卷声明）PVC是用户对存储的请求，它会去寻找合适的PV进行绑定。apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi这里有个坑要注意，PVC请求的存储大小必须小于等于PV提供的大小，而且访问模式也要匹配。StorageClass（存储类）StorageClass提供了动态创建PV的方式，不需要管理员手动创建PV。apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-ssd provisioner: kubernetes.io/aws-ebs parameters: type: gp2 zone: us-west-2a静态供应 vs 动态供应静态供应静态供应就是管理员提前创建好PV，然后用户创建PVC去绑定。这种方式比较传统，适合小规模或者对存储有特殊要求的场景。我在一个项目中就是用的静态供应，因为客户要求数据必须存储在指定的NFS服务器上，所以只能手动创建PV。动态供应动态供应通过StorageClass自动创建PV，用户只需要在PVC中指定StorageClass即可。apiVersion: v1 kind: PersistentVolumeClaim metadata: name: dynamic-pvc spec: accessModes: - ReadWriteOnce storageClassName: fast-ssd resources: requests: storage: 20Gi这种方式更灵活，特别适合云环境。我现在基本都用动态供应，省事多了。生命周期管理PV和PVC的生命周期有几个关键阶段：Available（可用）PV已创建，但还没有被PVC绑定。Bound（已绑定）PV已经被PVC绑定，正在使用中。Released（已释放）PVC被删除，但PV还没有被回收。Failed（失败）自动回收失败。这里要特别说一下回收策略，有三种：Retain：保留数据，需要手动清理Delete：自动删除PV和底层存储Recycle：已废弃，不建议使用我在生产环境中一般用Retain策略，因为数据安全第一，宁可手动清理也不能误删数据。访问模式详解K8s支持三种访问模式：…

Docker Swarm 搞定高可用集群，生产环境再也不怕服务挂掉了
type: item
date: 2026-04-11T14:09:37+00:00
description: Docker Swarm是什么？Docker Swarm 是 Docker 官方推出的容器集群管理工具，基于 Go 语言实现。代码开源在：https://github.com/docker/swarm 使用它可以将多个 Docker 主机封装为单个大型的虚拟 Docker 主机，快速打造一套容器云平台。Docker Swarm 是生产环境中运行 Docker 应用程序最简单的方法。作为容器集群管理器，Swarm 最大的优势之一就是 100% 支持标准的 Docker API。各种基于标准 API 的工具比如 Compose、docker-py、各种管理软件，甚至 Docker 本身等都可以很容易的与 Swarm 进行集成。大大方便了用户将原先基于单节点的系统移植到 Swarm 上，同时 Swarm 内置了对 Docker 网络插件的支持，用户可以很容易地部署跨主机的容器集群服务。Docker Swarm 和 Docker Compose 一样，都是 Docker 官方容器编排工具，但不同的是，Docker Compose 是一个在单个服务器或主机上创建多个容器的工具，而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务，对于微服务的部署，显然 Docker Swarm 会更加适合。为什么选 Docker Swarm 而不是 K8s说实话，Kubernetes 确实强大，但对我们这种中小团队来说，K8s 的学习成本和维护成本都太高了。光是搭建一套高可用的 K8s 集群就得折腾好几天，更别说日常维护了。Docker Swarm 就不一样了，它是 Docker 原生自带的编排工具，学过 Docker 的基本上一个小时就能上手。而且功能足够强大，服务发现、负载均衡、滚动更新、健康检查这些该有的都有，完全能满足大部分生产场景的需求。客户现在的业务规模大概有 30 多个微服务，每天访问量在百万级别，用 Docker Swarm 完全够用。如果你的规模跟我差不多，真心建议别一上来就搞 K8s，Swarm 真的够用了。环境准备5 台服务器，配置如下：3 台 Manager 节点：16G 内存，4 核 CPU2 台 Worker 节点：8G 内存，2 核 CPU为什么 Manager 要 3 台？这个后面会详细说。系统用的是 CentOS 7.9，Docker 版本是 20.10.14。在开始之前，有几件事得先做好：1. 主机名和 hosts 配置每台机器都要设置不同的主机名，不然等会儿集群建起来都叫 localhost，看着就头疼。# 在 manager1 上执行 hostnamectl set-hostname manager1 # 其他机器类似，改成 manager2、manager3、worker1、worker2然后修改 /etc/hosts 文件，把所有节点的 IP 和主机名都写进去：192.168.1.101 manager1 192.168.1.102 manager2 192.168.1.103 manager3 192.168.1.104 worker1 192.168.1.105 worker22. 关闭防火墙或者开放端口Docker Swarm 需要几个端口：2377/tcp：集群管理通信7946/tcp+udp：节点间通信4789/udp：覆盖网络流量生产环境建议还是开防火墙，只开放这些端口。测试环境图省事直接关了也行：systemctl stop firewalld systemctl disable firewalld3. 时间同步这个特别重要！如果节点时间不同步，集群选举会出问题，服务调度也会乱套。我们用 chrony 做时间同步：yum install -y chrony systemctl start chronyd systemctl enable chronyd初始化 Swarm 集群准备工作做完了，现在开始正式搭建集群。在 manager1 上执行初始化命令：docker swarm init --advertise-addr 192.168.1.101执行完会输出一串命令，大概是这样的：Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssm7h7g6w7br5d7vwlh 192.…

还在手动点控制台建资源？Terraform和CloudFormation入门实战，这篇够你喝一壶了
type: item
date: 2026-04-11T14:09:17+00:00
description: 提到搭建环境，很多兄弟可能还停留在“手工匠人”的模式。打开AWS控制台，点那个EC2，选镜像，配安全组，搞子网，再加个负载均衡……这一套下来，脑子都大了。最要命的是，你根本记不住上次那个安全组的入站规则到底是开了80端口还是8080端口。这种“雪花服务器”，配置漂移，环境不一致，简直是运维人的噩梦。这就是为什么我们今天必须得聊聊基础设施即代码这档子事儿。这玩意儿不是什么新概念，但真正能落地用好的，真能救命。咱们今天挑两个最重量级的选手——Terraform和CloudFormation，来一场从入门到实战的“保姆级”教学。别被那些英文单词吓到了，咱们用大白话把它拆开了揉碎了讲。咱们先说说这俩到底是啥如果你还没接触过IaC，可能觉得这俩词儿挺高大上。其实吧，说白了，就是把你的服务器、网络、数据库这些基础设施，像写代码一样定义出来。以前我们要建个仓库，得找施工队，拿图纸，一砖一瓦砌墙。现在有了IaC，就像是给了你一个3D打印机，你写好配置文件，告诉它我要几层楼、几个窗户、门朝哪开，一按按钮，房子自己就长出来了。CloudFormation，这可是AWS的亲儿子。它是AWS自家出的模板服务，专门用来管理AWS的资源。你想想，亲儿子肯定最了解家里的情况，所以它对AWS新特性的支持是最快的，而且跟AWS的控制台集成得非常深。你写个JSON或者YAML文件，往S3桶里一扔，CloudFormation引擎一读，哗啦啦给你创建一堆资源。如果中间出错了，它还能自动回滚，就像撤销键一样，这点特别稳。Terraform，则是HashiCorp公司搞的一个开源工具。这家公司简直是运维界的瑞士军刀厂，Vagrant、Consul都是他们家的。Terraform最大的特点就是“花心”，它不绑定任何一家云厂商。它支持AWS、Azure、Google Cloud，甚至还能管理本地的VMware、Kubernetes。这就好比你找了个全能装修队，既能给你家盖别墅，也能给隔壁老王家盖洋房，用的还是同一套图纸。这对于多云架构来说，简直是神器。那到底选哪个？如果你公司只死磕AWS一家，CloudFormation确实稳，毕竟是亲生的。但如果你不想被一家云厂商绑定死，或者将来有上多云的打算，那我强烈建议你从Terraform入手。咱们今天也主要拿Terraform来举例，顺便把CloudFormation的坑也给你填上。工欲善其事，必先装个“破”软件咱们别光说不练，先把环境搭起来。如果你用的是Mac，那简单，打开终端，如果你装了Homebrew，直接敲：brew install terraform要是Linux或者Windows，去官网下个二进制包，解压后把路径加到环境变量里就行。这没什么技术含量，我就不贴那些流水账似的教程了。装好后，敲个 terraform version，只要能蹦出版本号，那就说明成了。CloudFormation这玩意儿不需要你单独装软件，它就在AWS的控制台里，或者说它本身就是AWS的一部分。你只要有个AWS账号，有AK/SK密钥，用AWS CLI或者直接在网页上点都行。不过为了显得咱们专业点，咱们还是推荐用CLI操作，毕竟天天点鼠标那是文员干的事儿。Terraform入门：从Hello World开始咱们先来搞定Terraform。这玩意儿的核心就是那个 .tf 文件。别看到代码就头大，Terraform用的语言叫HCL（HashiCorp Configuration Language），这语言设计得特别人性化，基本上你只要会点英语，就能猜个八九不离十。咱们先建个文件夹，叫 terraform_demo，进去之后，先建个 main.tf 文件。这就像是咱们写文章的大纲，所有资源都在这儿定义。第一步，咱们得告诉Terraform，我们要用哪个云厂商的服务。这叫Provider。terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.0" } } } provider "aws" { region = "ap-northeast-1" # 咱们选东京区域，速度还行 # 这里默认会读取你环境变量里的 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY }你看，这段代码多直白。terraform 块里声明了我们要用 hashicorp/aws 这个provider，版本大概是4.0以上的。然后 provider "aws" 里指定了区域。这就好比你去饭店，先告诉服务员我要点川菜，然后找个位置坐下。接下来，咱们来点实际的，建个最简单的EC2服务器（虚拟机）。resource "aws_instance" "my…