Nginx 处理 POST 请求出现 Internal Server Error 排查一则

前言 最近一个服务忽然出现问题,用户反馈,HTTP POST 一个小的 body 不会出错,POST 一个大的 body 就会 500 Internal Server Error。 排查 观察后端日志,发现没有出错的那一个请求。观察 Nginx 日志,发现最后一次日志是几个小时前。最后几条 Nginx 日志写的是 a client request body is buffered to a temporary file。 结论 继续研究后,发现是硬盘满了。Nginx 在处理 POST body 的时候,如果 body 超过阈值,会写入到临时文件中: Syntax: client_body_buffer_size size; Default: client_body_buffer_size 8k|16k; Context: http, server, location Sets buffer size for reading client request body. In case the request body is larger than the buffer, the whole body or only its part is written to a temporary file.

Read More

将 k8s rook ceph 集群迁移到 cephadm

背景 前段时间用 rook 搭建了一个 k8s 内部的 ceph 集群,但是使用过程中遇到了一些稳定性问题,所以想要用 cephadm 重建一个 ceph 集群。 重建过程 重建的时候,我首先用 cephadm 搭建了一个 ceph 集群,再把原来的 MON 数据导入,再恢复各个 OSD。理论上,可能有更优雅的办法,但我还是慢慢通过比较复杂的办法解决了。 cephadm 搭建 ceph 集群 首先,配置 TUNA 源,在各个节点上安装 docker-ce 和 cephadm。接着,在主节点上 bootstrap: cephadm bootstrap --mon-ip HOST1_IP 此时,在主节点上会运行最基础的 ceph 集群,不过此时还没有任何数据。寻找 ceph 分区,会发现因为 FSID 不匹配而无法导入。所以,首先要恢复 MON 数据。 参考文档:cephadm install。 恢复 MON 数据 首先,关掉 rook ceph 集群,找到留存下来的 MON 数据目录,默认路径是 /var/lib/rook 下的 mon-[a-z] 目录,找到最新的一个即可。我把目录下的路径覆盖到 cephadm 生成的 MON 目录下,然后跑起来,发现有几个问题: cephadm 生成的 /etc/ceph/ceph.client.admin.keyring 与 MON 中保存的 auth 信息不匹配,导致无法访问 FSID 不一致,而 cephadm 会将各个设置目录放到 /var/lib/ceph/$FSID 下 第一个问题的解决办法就是临时用 MON 目录下的 keyring 进行认证,再创建一个新的 client.

Read More

C++ 11 的 ABI 问题

背景 有同学遇到这样的一个问题,代码中链接了一个第三方的动态库,在链接的时候出现了不一致的问题,比如有一个函数签名如下: void foobar(std::string s) {} 使用 GCC 11.1.0 编译上面的代码,可以发现它需要的符号是 _Z6foobarNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE,但是第三方库里面却是 _Z6foobarSs,因此找不到对应的符号,链接失败。 问题 经过一番研究,发现 Ss 在 Itanium ABI 中表示的是缩写: In addition, the following catalog of abbreviations of the form "Sx" are used: <substitution> ::= St # ::std:: <substitution> ::= Sa # ::std::allocator <substitution> ::= Sb # ::std::basic_string <substitution> ::= Ss # ::std::basic_string < char, ::std::char_traits<char>, ::std::allocator<char> > <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > 这看起来很正常,_Z6foobarSs 表示的是 foobar(std::basic_string<char, std::char_traits<char>, std::allocator<char> >),但是 GCC 11.

Read More

硬盘相关的概念

ATA ATA 定义了发送给硬盘的命令,标准定义了命令: ech IDENTIFY DEVICE: 获取设备信息 25h READ DMA EXT: 读取扇区 35h WRITE DMA EXT: 写入扇区 ATA 同时也是接口,图片如下。ATA 前身是 IDE,现在 ATA 叫做 PATA。 AHCI AHCI 可以简单理解为 PCIe <-> SATA 的转换器。AHCI 暴露为一个 PCIe 设备: $ lspci -vv 00:1f.2 SATA controller: Intel Corporation C600/X79 series chipset 6-Port SATA AHCI Controller (rev 05) Kernel modules: ahci 处理器通过 IO port/MMIO 访问 AHCI,然后 AHCI HBA 连接到 SATA 设备。 SATA SATA 一般说的是接口。它一般分为两个部分,数据和电源。数据部分只有 7 个 pin,三个 GND 和两对差分线(A+A- B+B-),图片如下:

Read More

在 ESXi 中用 PERCCli 换 RAID 中的盘

背景 最近有一台机器的盘出现了报警,需要换掉,然后重建 RAID5 阵列。iDRAC 出现报错: Disk 2 in Backplane 1 of Integrated RAID Controller 1 is not functioning correctly. Virtual Disk 1 on Integrated RAID Controller 1 has become degraded. Error occurred on Disk2 in Backplane 1 of Integrated RAID Controller 1 : (Error 2) 安装 PERCCli 首先,因为系统是 VMware ESXi 6.7,所以在DELL 官网下载对应的文件。按照里面的 README 安装 vib: esxcli software vib install -v /vmware-perccli-007.1420.vib 需要注意的是,如果复制上去 Linux 版本的 PERCCli,虽然也可以运行,但是找不到控制器。安装好以后,就可以运行 /opt/lsi/perccli/perccli 。接着,运行 perccli show all,可以看到类似下面的信息:

Read More

用 fluentd 收集 k8s 中容器的日志

背景 在维护一个 k8s 集群的时候,一个很常见的需求就是把日志持久化存下来,一方面是方便日后回溯,一方面也是聚合 replicate 出来的同一个服务的日志。 在我目前的需求下,只需要把日志持久下来,还不需要做额外的分析。所以我并没有部署类似 ElasticSearch 的服务来对日志进行索引。 实现 实现主要参考官方的仓库:https://github.com/fluent/fluentd-kubernetes-daemonset。它把一些常用的插件打包到 docker 镜像中,然后提供了一些默认的设置,比如获取 k8s 日志和 pod 日志等等。为了达到我的需求,我希望: 每个结点上有一个 fluentd 收集日志,forward 到单独的 log server 上的 fluentd log server 上的 fluentd 把收到的日志保存到文件 由于 log server 不由 k8s 管理,所以按照官网的方式手动安装: $ curl -L https://toolbelt.treasuredata.com/sh/install-debian-buster-td-agent4.sh | sh 然后,编辑配置 /etc/td-agent/td-agent.conf: <source> @type forward @id input_forward bind x.x.x.x </source> <match **> @type file path /var/log/fluentd/k8s compress gzip <buffer> timekey 1d timekey_use_utc true timekey_wait 10m </buffer> </match> 分别设置输入:监听 fluentd forward 协议;输出:设置输出文件,和 buffer 配置。如有需要,可以加鉴权。

Read More

静态编译 ipmitool

为了在 ESXi 上运行 ipmitool,需要静态编译 ipmitool。网上已经有一些解决方案: https://github.com/ryanbarrie/ESXI-ipmitool https://github.com/hobbsh/static-ipmitool https://github.com/ewenmcneill/docker-build-static-ipmitool 我稍微修改了一下,用来编译最新 ipmitool: #!/bin/bash set -x export VERSION=1.8.18 rm -rf ipmitool_$VERSION curl -L -o ipmitool_$VERSION.tar.bz2 http://deb.debian.org/debian/pool/main/i/ipmitool/ipmitool_$VERSION.orig.tar.bz2 tar xvf ipmitool_$VERSION.tar.bz2 cd ipmitool-$VERSION CC=gcc CFLAGS=-m64 LDFLAGS=-static ./configure make -j24 cd src ../libtool --silent --tag=CC --mode=link gcc -m64 -fno-strict-aliasing -Wreturn-type -all-static -o ipmitool.static ipmitool.o ipmishell.o ../lib/libipmitool.la plugins/libintf.la file $PWD/ipmitool.static 复制下来,编译完成后 scp 到 esxi 中即可使用。

Read More

通过 ipmitool 配置 iLO 4 管理端口

ipmitool 自带了对 iDRAC 的支持,可以通过 ipmitool delloem 设置 iDRAC 的管理端口。但是对 iLO 的支持并没有实现。研究了一番,找到了通过 raw command 配置 iLO 4 管理端口的方法。 这篇文章 讲述了 ipmitool lan 命令实际会发送的命令: 读取配置: $ ipmitool raw 0x0c 0x02 CHANNEL KEY SET BLOCK 一般来说 SET 和 BLOCK 都是 0。KEY 的常见取值: 3: IP 地址 4: IP 地址来源 5: MAC 地址 6: 子网掩码 12: 默认网关 返回的数据中,第一个字节忽略,剩下的就是数据了。 写入配置: $ ipmitool raw 0x0c 0x01 CHANNEL KEY DATA... 知道如何读取配置后,接下来就是找到 iLO 4 配置 NIC 的地方了。一番搜索,找到了 HPE iLO IPMI User Guide。在第 101 页,可以找到一个用于配置 iLO NIC 选择的设置:

Read More

ESXi 网络配置

用过 ESXi 的大家都知道,它网页版对网络的配置功能有限,特别是 IPv6 的部分,有的事情无法实现。更好的办法是 SSH 到 ESXi 上直接用命令行进行配置。 可能会用到的一些命令: esxcfg-vmknic: 用来给 vmkernel 配置地址 esxcfg-route: 设置系统路由表 esxcli: 大杂烩,很多功能都在里面 tcpdump-uw:魔改版 tcpdump 一些例子: 设置 IPv6 默认路由: [root@esxi:~]esxcfg-route -f V6 -a default $IPV6 删除 vmkernel 的 IPv6 地址: [root@esxi:~]esxcli network ip interface ipv6 address remove -i $VMKERNEL -I $IPV6/$PREFIX 参考:https://kb.vmware.com/s/article/1002662

Read More

Linksys E8450 OpenWRT 配置 w/ 802.11ax

背景 之前用的 newifi 路由器(Lenovo y1s)无线网总是出问题,于是换了一个新的支持 802.11ax 的路由器 Linksys E8450,目前在 openwrt snapshot 支持。Openwrt 的支持页面:Linksys E8450。 过程 按照支持页面,下载固件: $ wget https://downloads.openwrt.org/snapshots/targets/mediatek/mt7622/openwrt-mediatek-mt7622-linksys_e8450-squashfs-sysupgrade.bin 然后访问固件升级页面:http://192.168.1.1/config-admin-firmware.html#firmware,选择下载的 bin 文件。点击 “开始升级”,然后等待。一段时间后,ssh 到路由器: $ ssh root@192.168.1.1 The authenticity of host '192.168.1.1 (192.168.1.1)' can't be established. ED25519 key fingerprint is SHA256:REDACTED. No matching host key fingerprint found in DNS. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '192.

Read More