人是目的,而非手段

运维软件服务的是运维人员,管好 IT 资源也是为了给用户更好的信息化体验

现状

H 所面对的客户,目前有这样一些困境

  • 与维护的 IT 资源数量,和服务的信息化用户相比,运维人员相对缺失
  • 除较少的编内人员,还可能会有代维、驻厂等三方人员,且这些人流动性高,水平一般
  • 与校内的其它部门相比,信网中心与教育教学的相关性较低,分到的经费,得到的关注都可能有限
  • 部门一把手可能是空降的,并不一能具备相关的专业知识。但却又是能分这块不大的蛋糕的人

我们把软件的使用者分为三类,希望能够站在不同的角度去思考功能设计

管理员 Admin

关键词: 知识 经验

网在心中,手拿把掐。不一定是部门的领导,但是技术绝对的大头

运维软件要想能落地,转起来,首先要去讨好这些人,取得他们的信赖,哄着他们把心中的网,记录到系统中,即所谓的 CMDB

  • 基本信息: 管理 IP,访问凭据
  • 资产信息: 合同,维保,备件,配件
  • 归属信息: 资源谁用的,子网划给了谁,域名谁申请的,策略为谁服务
  • 地理信息: 园区,机房,机柜信息资源与所在位置
  • 综合布线: 从用户接入的 AP 或面板网口,到园区网出口,一些是可以通过 DP 协议计算的,更多的如这个接口出去连到哪个楼的哪个房间,是人工录入的
  • IP 地址规划
  • 出口配额

还有要管好 IT 资源所需要的经验和知识,不仅限于知识库,还有结合自身情况,适应部门运行的各种细化的设置

  • 告警相关: 细化的阈值,自定的等级,何时发通知,要不要升级
  • 看板与报表: 定制实用的看板,配置周期性报表
  • 常用信息: 快速故障恢复
  • 实用信息: 实用工具,实用命令

这些信息记在心中,停留在纸上,都没有录入系统能发挥更大的价值。信网中心,人来人往,唯有电子化、信息化才能最大限度的共享信息,分享价值。信息化中心自身的信息化,本就该是其它部门的标杆模范

这样的管理员是行业中的中流砥柱,与他们站在一起,倾听他们的需求,是好的运维软件替客户着想,为客户分忧的前提

在这些信息的收集上,真应该向游戏学习。你做对了什么,立刻就给正反馈,引导用户不断地按照游戏策划设想的那样去玩这个游戏。反观运维软件,又想从管理员那些套取大量信息,又没有明确及时的正反馈,这软件怎么能落地?怎么能真正在运维工作中发挥作用呢?怎么能产生用户粘性呢?

运维人员 Operator

关键词: 时间 绩效

虽说我们希望系统或软件替人去完成那些简单、机械、重复、低价值的工作,但诸如设备上下架、布线、出现场等还是要人工的。运维软件的价值,就是把系统先把能做的都做了,然后再所谓的 人在回路

工作台

H 倾向于在真正干活的时候,系统提供一个工作台看板。这类似游戏中的任务板,任务板上没有任务,或者看板中一片绿,说明万事大吉,我可以继续摸鱼。任务板上有任务了,那我就开始干活

任务也应该是由系统判断后,精心处理且分门别类的呈现在工作台上。每一种分类的任务不能太多,会给人一种虱子多了不痒,债多了不愁的懈怠感。H 见了太多的客户,告警列表里躺着几百几千条,从最近到一年前发生的,未处理未恢复的告警。

可能分类有

  • 告警: 现在而今眼目下,你的什么东西出问题了。系统已经帮你排除了 a, b, c…几种原因,还剩 d, e, f…种可能;也自动的按照 1, 2, 3…尝试恢复,但未能成功,需要你来介入一下。这些告警应该有一个合理的严重等级,可以是根据事件类型,影响范围,影响对象(大领导办公室的 AP,就影响一个人,但你说比不比宿舍楼的重要吧)。常用的事件等级有 CRITICAL, ERROR, WARNING, INFO 等。但可能还不够,归于某一等级的告警还是太多。还有许多帮助给事件排出个一二三顺序的方法,后面详见事件及告警篇
  • 信息完善: 有一条链路可能变动了,确认一下;有一颗 AP 可能更换了,确认一下
  • 提醒: 某些资产维保要到期了;机柜的空间容量不够了;某些软件的授权要到期了,你也不希望到时候全校分不到地址吧

统一处理带来方便考核

分类带来知识积累、效率与专精

领导 Leader

关键词: 容量 业绩

领导从宏观的角度看问题,自然可以看成是各种模拟经营类游戏的玩家。试想,哪个模拟经营类游戏没有几个面板,告诉玩家你的资源现在有多少,用了多少,运行得多平稳高效,达到了多大规模,服务了多少用户,助力了多少发展,(击败了百分之多少的同行)。系统就应该提供这些情绪价值

  • 大屏: 精心设计的,突出容量、用量
  • 报表: 月度的、季度的、年度的
  • 总结: 面向最终用户的,能让他们体会到信网中心和重要性,体会到中心领导的高瞻远瞩和辛勤付出

写在前面

2014 - 2024 作者 H 入职一家 IT 运维软件开发公司十年来,对 ITMS 的一些想法

主要工作对象为高校的园区网、数据中心等 IT 基础设施

想法很多、很杂,先记录下来,有空慢慢整理、归类、迭代

网络设备 配置管理

设想,理想情况下如果一个网络,硬件没变过,配置也没变过,那么这个网络只要今天是好的,那么明天肯定也是好的

虽然现实中有更多的意外会发生,如断电、断线、被偷等等,但配置管理应该是 ITMS 中的重要一环

硬件确定了,配置确定了,那么这个网络就确定了,网络的功能和行为都确定了

Configuration-as-code

CaC 配置即代码

借鉴代码管理中应用最广的 git 版本管理的经验,网络的配置也有必要这么管理

我们不妨来对应一下

  • repo: 一张网就是一个 repo,其中有文件,即某台设备的配置,和文件类,即某种分类组织方式
  • branch, tag: 如果有条件做网络仿真,倒也可以区分 dev 和 prod 分支,但一般不太可能;tag 打标签是有用的
  • commit: 配置一般可分为 startup config 和 running config,如果有差异,则可视 running config 为未提交的修改

除了版本管理之外,在代码管理方面的成熟经验也很有启发

  • comment: 备注,这段配置是干嘛的 for who, for what
  • diff: 设备间横向对比,时间上纵向对比
  • template: 许多接入设备是不是配置都差差不多,模板库不考虑一下么
  • snippet: 实用配置收集
  • static analysis: 合规性检查
  • ci/cd: 持续集成,hook
  • ai: 输入硬件型号、固件版本,输入想做的操作,让 AI 帮你生成配置吧

汇总一些用过的 keepalived 问题的排查方法

  1. 统计信息
1
kill -USR2 $(cat /var/run/keepalived.pid)

向 keepalived 进程发 signal,其它可用的参考man keepalived

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HUP or SIGFUNC=RELOAD
This causes keepalived to close down all interfaces, reload its configuration, and start up with the new
configuration.

TERM, INT or SIGFUNC=STOP
keepalived will shut down.

USR1 or SIGFUNC=DATA
Write configuration data to /tmp/keepalived.data

USR2 or SIGFUNC=STATS
Write statistics info to /tmp/keepalived.stats

SIGFUNC=JSON
Write configuration data in JSON format to /tmp/keepalived.json

默认会生成/tmp/keepalived.stats,包含各 Instance 的统计信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
VRRP Instance: VI_0
Advertisements:
Received: 7233644
Sent: 8
Became master: 2
Released master: 2
Packet Errors:
Length: 0
TTL: 0
Invalid Type: 0
Advertisement Interval: 0
Address List: 0
Authentication Errors:
Invalid Type: 0
Type Mismatch: 0
Failure: 0
Priority Zero:
Received: 2
Sent: 0
  1. 当前状态
1
snmpwalk -v2c -cpublic 127.0.0.1 -mALL .1.3.6.1.4.1.9586

利用 SNMP 查询,结果包含当前状态和一些配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
KEEPALIVED-MIB::version.0 = STRING: Keepalived v2.0.20 (01/22,2020)
KEEPALIVED-MIB::routerId.0 = STRING: ***
KEEPALIVED-MIB::smtpServerAddressType.0 = INTEGER: ipv4(1)
KEEPALIVED-MIB::smtpServerAddress.0 = Hex-STRING: 00 00 00 00
KEEPALIVED-MIB::smtpServerTimeout.0 = Gauge32: 0 seconds
KEEPALIVED-MIB::smtpServerPort.0 = Gauge32: 0
KEEPALIVED-MIB::smtpEmailFaults.0 = INTEGER: enabled(1)
KEEPALIVED-MIB::smtpEmailSmtpAlert.0 = INTEGER: unset(3)
KEEPALIVED-MIB::smtpEmailSmtpAlertVrrp.0 = INTEGER: unset(3)
KEEPALIVED-MIB::smtpEmailSmtpAlertChecker.0 = INTEGER: unset(3)
KEEPALIVED-MIB::trapEnable.0 = INTEGER: disabled(2)
KEEPALIVED-MIB::linkBeat.0 = INTEGER: netlink(1)
KEEPALIVED-MIB::lvsFlush.0 = INTEGER: disabled(2)
KEEPALIVED-MIB::netNamespace.0 = STRING:
KEEPALIVED-MIB::dynamicInterfaces.0 = INTEGER: false(2)
KEEPALIVED-MIB::lvsFlushOnStop.0 = INTEGER: disabled(2)
KEEPALIVED-MIB::vrrpInstanceName.1 = STRING: VI_0
KEEPALIVED-MIB::vrrpInstanceVirtualRouterId.1 = Gauge32: 29
KEEPALIVED-MIB::vrrpInstanceState.1 = INTEGER: backup(1)
KEEPALIVED-MIB::vrrpInstanceInitialState.1 = INTEGER: backup(1)
KEEPALIVED-MIB::vrrpInstanceWantedState.1 = INTEGER: backup(1)
KEEPALIVED-MIB::vrrpInstanceBasePriority.1 = INTEGER: 100
KEEPALIVED-MIB::vrrpInstanceEffectivePriority.1 = INTEGER: 100
KEEPALIVED-MIB::vrrpInstanceVipsStatus.1 = INTEGER: notAllSet(2)
KEEPALIVED-MIB::vrrpInstancePrimaryInterface.1 = STRING: eth0
KEEPALIVED-MIB::vrrpInstanceTrackPrimaryIf.1 = INTEGER: tracked(1)
KEEPALIVED-MIB::vrrpInstanceAdvertisementsInt.1 = Gauge32: 1 seconds(VRRPv2) / centiseconds(VRRPv3)
KEEPALIVED-MIB::vrrpInstancePreempt.1 = INTEGER: preempt(1)
KEEPALIVED-MIB::vrrpInstancePreemptDelay.1 = Gauge32: 0 seconds
KEEPALIVED-MIB::vrrpInstanceAuthType.1 = INTEGER: password(1)
KEEPALIVED-MIB::vrrpInstanceLvsSyncDaemon.1 = INTEGER: disabled(2)
KEEPALIVED-MIB::vrrpInstanceGarpDelay.1 = Gauge32: 5 seconds
KEEPALIVED-MIB::vrrpInstanceSmtpAlert.1 = INTEGER: disabled(2)
KEEPALIVED-MIB::vrrpInstanceNotifyExec.1 = INTEGER: enabled(1)
KEEPALIVED-MIB::vrrpInstanceScriptFault.1 = STRING: ***
KEEPALIVED-MIB::vrrpInstanceAccept.1 = INTEGER: 0
KEEPALIVED-MIB::vrrpInstancePromoteSecondaries.1 = INTEGER: false(2)
KEEPALIVED-MIB::vrrpInstanceUseLinkbeat.1 = INTEGER: false(2)
KEEPALIVED-MIB::vrrpInstanceVrrpVersion.1 = INTEGER: vrrpv2(2)
KEEPALIVED-MIB::vrrpTrackedScriptName.1.1 = STRING: ***
KEEPALIVED-MIB::vrrpTrackedScriptWeight.1.1 = INTEGER: 0
KEEPALIVED-MIB::vrrpTrackedScriptWgtRev.1.1 = INTEGER: false(2)
KEEPALIVED-MIB::vrrpAddressType.1.1 = INTEGER: ipv4(1)
KEEPALIVED-MIB::vrrpAddressValue.1.1 = STRING: "
{zE"
KEEPALIVED-MIB::vrrpAddressBroadcast.1.1 = Hex-STRING: 00 00 00 00
KEEPALIVED-MIB::vrrpAddressMask.1.1 = Gauge32: 32
KEEPALIVED-MIB::vrrpAddressScope.1.1 = INTEGER: global(14)
KEEPALIVED-MIB::vrrpAddressIfIndex.1.1 = INTEGER: 2
KEEPALIVED-MIB::vrrpAddressIfName.1.1 = STRING: eth0
KEEPALIVED-MIB::vrrpAddressStatus.1.1 = INTEGER: unset(2)
KEEPALIVED-MIB::vrrpAddressAdvertising.1.1 = INTEGER: advertised(1)
KEEPALIVED-MIB::vrrpScriptName.1 = STRING: ***
KEEPALIVED-MIB::vrrpScriptCommand.1 = STRING: ***
KEEPALIVED-MIB::vrrpScriptInterval.1 = INTEGER: 5 seconds
KEEPALIVED-MIB::vrrpScriptWeight.1 = INTEGER: 0
KEEPALIVED-MIB::vrrpScriptResult.1 = INTEGER: good(3)
KEEPALIVED-MIB::vrrpScriptRise.1 = Gauge32: 2
KEEPALIVED-MIB::vrrpScriptFall.1 = Gauge32: 2
KEEPALIVED-MIB::vrrpScriptWgtRev.1 = INTEGER: false(2)
  1. 抓包

一般来说,就以往遇到的问题,往往都是 VRRP 包的收发不对劲,所以可以通过 tcpdump 抓包查看

同时结合 keepalived 的配置,关注抓包的网口,进出方向,vrid, prio

1
tcpdump -i any -n vrrp and inbound

最近用到 s6-overlay 记录一下踩到的坑

定位

容器中的 supervisor

https://github.com/just-containers/s6-overlay

上手

以 alpine 为例

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM alpine

# dev
RUN apk update && apk add bash
ENV S6_KEEP_ENV=1

RUN apk add --no-cache redis s6-overlay

COPY s6-overlay /etc/s6-overlay

ENTRYPOINT ["/init"]

CMD ["bash"]

官方推荐用新格式启服务,即使用 s6-rc.d 目录

默认安装 s6 后,会自带 user, user2 目录

user 目录的 type 为 bundle

用法为,在 s6-rc.d 下新建服务定义目录,然后在 user/contents.d 下 touch 一下同名空文件

1
2
3
4
5
6
7
8
9
   0   B          ┌─  redis-server
- ┌─  contents.d
4.0 KiB ├─  type
4.0 KiB ┌─  user
4.0 KiB │ ┌─  type
4.0 KiB │ ├─  run
8.0 KiB ├─  redis-server
12.0 KiB ┌─  s6-rc.d
12.0 KiB  s6-overlay

redis-server/type 为 longrun

redis-server/run 为

1
2
3
#!/usr/bin/execlineb -P
s6-setuidgid redis
redis-server /etc/redis.conf
  • 官方文档中都是#!/command/execlineb -P,但没办法,alpine 中没有把 execlineb 放在 /command 下
  • s6-setuidgid 让 redis-server 以 redis 的用户跑
  • 显示指定 conf 文件,主要为了确保 dump.rdb 的生成目录对 redis 用户可写,默认 /var/lib/redis

可能遇到的问题

  • dockerfile COPY 一行报错,找不到文件

想想有没有 .dockerignore

  • cd 或 composer 报找不到 HOME 的定义

s6-overlay 默认会接手环境变量,可以使用 with-contenv 使单个命令继承原 env,with-contenv env

或指定 S6_KEEP_ENV=1 (default = 0),方便开发环境

近日在维护的某业务系统中发现 dockerd 进程的 CPU 占用高达 55%

感觉上不太可能,开始排查

perf top -g -p <pid> 发现大量调用发生在 logger, json 读写等

1
2
github.com/docker/docker/daemon/logger/loggerutils.(*forwarder).Do
github.com/docker/docker/daemon/logger/jsonfilelog.(*decoder).Decode

docker 默认的 logging driver 为 json-file,json 的读写还是开销大啊!

反正重要的日志也有其它记录方式,不需要依赖 docker logs,果断切换日志记录方式

https://docs.docker.com/config/containers/logging/configure/#configure-the-default-logging-driver

1
2
3
{
"log-driver": "local"
}

重启 dockerd,效果显著,目前 CPU 占用小于 5%

现象

macOS 上 PHP Cli 启动缓慢

php -v等都启动缓慢,大概需要5秒左右

导致 PhpCsFixer 也巨慢,我还以为本身就要花这么久

原因

https://github.com/php/php-src/issues/11673

PHP 的 imap 扩展使用了一个不再更新的库 cclient,且这个库在一些情况下会去解你本机的 hostname

解决方法就是写 /etc/hosts

1
2
3
# FUCK Handle Slow PHP cli with IMAP extension on macOS
::1 localhost HMBP.local
127.0.0.1 localhost HMBP.local

高兴的是 https://wiki.php.net/rfc/unbundle_imap_pspell_oci8

该库将在 PHP 8.4 移出默认 bundle

REF

Handle Slow PHP cli with IMAP extension on macOS

https://samsonasik.wordpress.com/2023/09/30/handle-slow-php-cli-with-imap-extension-on-macos/

1
nmap --script ssh2-enum-algos -sV -p <port> <host>

很好用,结果一目了然

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
PORT      STATE SERVICE VERSION
22/tcp open ssh OpenSSH 4.3 (protocol 2.0)
| ssh2-enum-algos:
| kex_algorithms: (3)
| diffie-hellman-group-exchange-sha1
| diffie-hellman-group14-sha1
| diffie-hellman-group1-sha1
| server_host_key_algorithms: (2)
| ssh-rsa
| ssh-dss
| encryption_algorithms: (13)
| aes128-ctr
| aes192-ctr
| aes256-ctr
| arcfour256
| arcfour128
| aes128-cbc
| 3des-cbc
| blowfish-cbc
| cast128-cbc
| aes192-cbc
| aes256-cbc
| arcfour
| rijndael-cbc@lysator.liu.se
| mac_algorithms: (6)
| hmac-md5
| hmac-sha1
| hmac-ripemd160
| hmac-ripemd160@openssh.com
| hmac-sha1-96
| hmac-md5-96
| compression_algorithms: (2)
| none
|_ zlib@openssh.com

附一些为了兼容老版本 SSH 的配置

1
2
3
KexAlgorithms +diffie-hellman-group1-sha1
HostKeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa

终于解决了这个困扰了我半年的问题,记录一下过程和解决方法

环境

  • 出口线路: 北京联通
  • 出口设备: RB5009UPr+S+
  • 协议: IPv4 & IPv6

现象

  • 手机访问阿里系应用有问题,如支付宝、淘宝、盒马,加载很久,也可能很久也加载不出来
  • 开代理科学上网后正常,但按理说大多请求应该还是走的 Direct 规则
  • 怀疑是 IPv6 的问题,于是起了 SmartDNS 的 force-AAAA-SOA yes,BAN 掉了所有的 v6 解析后,有所改善!

坑就在这儿了,又是向着错误的方向优化了一下,神奇的好了

因为这个问题在 IPv6 上的确比 IPv4 上更常见、更严重

解决

无意同事聊起过这个问题,前几天吃饭的时候灵光一闪,想起来这个 PMTU 黑洞的问题

配了一下竟然好了!

1
2
3
4
5
6
7
8
9
/ip/firewall/mangle
add action=change-mss chain=forward comment="IPv4 MSS clamp to PMTU" \
new-mss=clamp-to-pmtu out-interface="<你的PPPoE出口>" passthrough=yes \
protocol=tcp tcp-flags=syn

/ipv6/firewall/mangle
add action=change-mss chain=forward comment="IPv6 MSS clamp to PMTU" \
new-mss=clamp-to-pmtu out-interface="<你的PPPoE出口>" passthrough=yes \
protocol=tcp tcp-flags=syn

参考

Synology DSM7 的 Plex 在某一版更新之后,桌面图标消失了

Synology Plex icon missing

原因为群晖的权限系统严格了

可以通过如下步骤找回

  1. 控制面板
  2. 应用程序权限
  3. 找到 Plex Media Server,双击
  4. 在用户账号中给相应的账号赋允许权限,或在用户群组中给相应的组赋允许权限
  5. 保存并刷新

Plex 图标回来啦!

REF: https://forums.plex.tv/t/synology-faq-questions-answers-and-a-few-how-tos/490215/40

有时候遇到 SSH 到远端服务器,需要下载 Github 的一些东西,但是远端无法科学上网

此时使用 SSH 隧道转发本地的科学上网代理,就很好用了!

1
2
# 在本地
ssh -N -R 1080:localhost:7890 remotehost
1
2
3
4
# 在远端
[root@byrpt ~]# curl www.google.com.hk -x 127.0.0.1:1080
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-SG"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop=
# 科学!
0%