由来
现场部署业务后发现访问有问题,排查后发现业务网关访问 etcd 的 keepalived IPVS svc 不通
排查
基础排查
1 | curl 169.254.20.4:12379 |
这个是我们 etcd 的 svc 的,curl real server
正常:
1 | $ curl <本机IP>:12379 |
然后看了下 iptables -t filter -S
无额外规则,怕客户安全加固啥的前面 insert 了规则影响。
1 | sysctl --all |& grep vs.conn |
vs.conntrack
正常,不是 0,查看下 ipvs 规则:
1 | docker exec keepalived-ipvs ipvsadm -ln | grep -A3 169.254.20.4 |
现场说为空,让去掉 grep 直接看也是为空:
1 | docker exec keepalived-ipvs ipvsadm -ln |
让看下 keepalived 日志,发现有个错误:
1 | daemon is already running |
源码
因为 keepalived 容器需要操作 lvs 规则,所以是有 privileged: true
的,感觉还是内核相关问题导致的,那就看源码了。我们用的 keepalived 版本是最新的 v2.3.4
,搜索源码 Locking pid file
搜到:
1 | // https://github.com/acassen/keepalived/blob/v2.3.4/keepalived/core/pidfile.c#L183-L194 |
看这个宏定义内的代码就是 fcntl 使用 F_OFD_SETLK
针对 Pid 文件上锁,这个特性是内核特性,现场是 CentOS 7.4 ,内核版本 3.10.0-693.el7.x86_64
,想看下这块提交,于是下载源码后找到下面俩个 commmit:
- https://github.com/acassen/keepalived/commit/2c4cd3b927e5f12f59c62481261621b70375a304
- https://github.com/acassen/keepalived/commit/7d2b85d1f03d3ae2944237c60c3eeb5edc4fa12a
第一个 commit 是增加 Pid 锁,第二个是允许宏定义不用这个特性在老系统上构建,利用 autoconf 检测支持 F_OFD_SETLK
不。
编译
因为我们使用的是容器化部署,基础镜像换成欧拉了,而欧拉的包管理安装的 keepalived 版本太低,所以我是 Dockerfile 内编译安装的 keepalived,而构建这个镜像的机器的内核比较高,只能构建的时候传递选项关闭了。
影响面也不需要关注,因为是容器,并且镜像的启动脚本内我在启动的时候先删除 pid 文件的,无脑编译关闭即可,不要 hack 修改代码,autoconf 啥的都是大家遵守的规范,主要是 configure.ac
下面的:
1 | dnl -- Linux 3.15 |
看下面逻辑,"ac_cv_have_decl_"+"F_OFD_SETLK"="yes"
,在 ./configure
后面加就行:
1 | ... |
编译打包镜像后测试没问题。