加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.51zhanzhang.com/)- 应用程序、AI行业应用、CDN、低代码、区块链!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

Linux老手也常踩的5个Unix环境搭建坑

发布时间:2026-10-15 08:16:04 所属栏目:Unix 来源:DaWei
导读:  跟老板拍账单——去年中考期间,我蹲在边缘机房拿热成像仪扫散热片,后端发来第七封告警邮件说“/etc/resolv.conf 被覆盖三次”,我盯着那行 nameserver 127.0.0.53 发了十八秒呆。不是 DNS 本身,是它后面那个被 system

  跟老板拍账单——去年中考期间,我蹲在边缘机房拿热成像仪扫散热片,后端发来第七封告警邮件说“/etc/resolv.conf 被覆盖三次”,我盯着那行 nameserver 127.0.0.53 发了十八秒呆。不是 DNS 本身,是它后面那个被 systemd-resolved 篡改的、没加 # no-restart 注释的 stub 文件。运维小王递来半杯凉透的雀巢速溶,杯底印着某云厂商的闪电logo,他手抖得厉害,说是刚和厂商销售电话吵完——对方说“你们环境没按白皮书配”,可白皮书第4页的 shell 配置命令,连 exec 前少了个反斜杠都抄错了。


  第一个坑:systemd 的 unit 文件里写 ExecStart=/usr/bin/python3 /opt/app/main.py,你敢打包票这东西跑起来不卡?我原以为加个 Type=simple 就稳了,结果发现 systemd 默认会把 stdout/stderr buffer 到内存里,日志满打满算卡在 128KB,而我们某台边缘节点上有个 Python 进程每秒吐三百七十二条 purge 规则,第十分钟它就僵在那儿,syslog 里只剩一句 “Main process exited, code=killed, status=9/KILL”——杀它的不是 OOM killer,是 journalctl 自己的 ring buffer 溢出触发的 timeout kill。这个我敢打包票,因为我在三台不同型号的 ARM64 边缘网关上复现过,包括那台贴着配电箱装的、散热口常年结灰的 Zynq-7000。


  监控大屏右下角那个“GPU 温度”指标抖了一下,0.3℃,持续两帧,没人点开看。其实那天上午我们还发现 /var/log/journal 下某个子目录权限是 0750 不是 0755,但 journald 启动没报错,journalctl --disk-usage 却显示已用 98%,进去一 ls,全是 .journal~ 临时文件没被清理——因为 tmpfiles.d 里那行 d /var/log/journal 0755 root root - - 写成了 d /var/log/journal 0755 root root - 1w,多敲了个空格,systemd-tmpfiles 拒绝加载整条规则,连带下面三行也全跳过。我说不准这是哪个版本开始的解析策略,但至少从 v245 到 v252,全踩一遍才信。


文章配图,仅供参考

  第二个坑:alias ll='ls -la' 加进 ~/.bashrc 就真以为它活在所有上下文里?错。cron job 执行时,sh -c 跑的是 POSIX sh,不是 bash;Ansible 的 shell 模块默认走 /bin/sh;更绝的是某些容器 base image 的 entrypoint 是 dash,alias 不仅不展开,还会让整行命令直接 fail ——dash 根本不认 alias。我见过一个部署脚本,用 alias 替代 find 命令删旧日志,在开发机上好好的,上产线第一晚就攒出四十七G 的 /tmp/logs-legacy-。你说气不气?我倒不是心疼磁盘,是心疼那个连夜重写为 /usr/bin/find 的后端,他改完提交前顺手给咖啡杯续了水,杯垫上还压着张采购流程单,写着“边缘设备维保延期需走 KPI 折算补签”,字迹被水洇开,像张褪色的罚单。


  第三个坑:用 sed -i 's/foo/bar/g' 处理配置文件前,你 check 过它的 inode 吗?去年六月,某家厂商的 OTA 工具更新了 /etc/systemd/system/myservice.service,用了 in-place rewrite,但没留备份;我们自己的监控 agent 用 inotifywait -m 监听文件内容变更,结果 on_modify 触发两次——第一次是写临时文件,第二次才是 mv 覆盖。agent 每次都 reload service,reload 时 systemd 把旧 PID 杀了又起新进程,新进程读的是旧版本 config,因为 /proc//exe 指向还在 mmap 的旧文本段。节点分布图上有个无关的小红点,标在华北-3B 区,后来查是温度传感器误报,但当时没人敢动那个节点的任何东西,包括 reboot。我原以为问题出在 inotify 监听粒度,结果翻内核文档发现:mv 跨文件系统才改 inode,同文件系统只是改 dentry,而我们的根分区和 /etc 共享同一个挂载点。所以不是监听错了,是 reload 逻辑错了。


  第四个坑:别信“ulimit -n 65536”能生效到服务级。你在交互式终端里设了,甚至写了 /etc/security/limits.conf,可 systemd 从 v219 开始,默认忽略 PAM limits 对 services 的继承,非得在 service unit 里显式写 LimitNOFILE=65536。有次 debug 某个 TCP 连接数卡在 1024 的问题,我花了三天,中间还让厂商销售又打来两次电话催测试报告,直到看见 systemctl show myservice | grep LimitNOFILE,回显是 “LimitNOFILE=1024”——不是 inherit,不是 fallback,是硬编码死的默认值。我懒得改 unit,直接在 ExecStart 前加一行 prlimit --nofile=65536:65536 --,运行起来是通了,但 log 里多了两百多行 prlimit 的 stderr 输出,全被 syslog 拆成独立事件入库……现在 Grafana 上还有个 dashboard 叫“prlimit 喷射频率”,谁也没关。


  第五个坑:用 set -e 在 shell script 里防失败?哈。set -e 在管道、子 shell、while/until 循环里行为完全不一致。我见过一个初始化脚本,最后写 if [ "$status" = "ok" ]; then systemctl start app; fi,但前面某条 curl -fS 命令失败了,set -e 却没 abort,因为它是 curl ... | jq ... 的一部分。那个 while 循环里还有个 continue 语句,continue 之后的代码居然也能执行……这个我说不准是不是 bash 版本差异,但我亲眼看着它在 Debian 11 的 bash 5.1.4 和 Alpine 3.18 的 ash 里表现不同。对了,运维小王后来辞职了,听说去干嵌入式 bootloader 了,说“至少汇编里没 set -e 这种骗人的东西”。


  我现在每次搭新环境,第一件事不是拉镜像,是把 /etc/sysctl.conf 里 net.ipv4.ip_forward = 1 这行注释掉,先看看有没有谁悄悄开着 iptables NAT 链——上上周刚遇到一台边缘盒子,iptables-save 出来有三十六行 PREROUTING 规则,全是 vendor pre-install 的,其中一条匹配 HTTP User-Agent 的规则把 Prometheus 的 scrape 请求全 redirect 到本地 nginx,结果 metrics 少了一半,debug 时候发现 node_exporter 的 /metrics 接口返回的是 nginx 的 404 页面……页面 footer 写着“Powered by CloudOS v2.8.3 (c) 2021”,但 release note 里根本没提这个劫持功能。这事我还没跟任何人说,包括老板。

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!