我的解题之路: 开篇
参加工作这么多年,碰到过挺多问题,也解决了许多问题,有的留在了记忆中,有的却很模糊。好记性不如一个烂笔头,如果将大脑记忆比作是WAL,那我现在写日志记录算是落盘喽。回归正题,之所以想写这个系列,是因为最近我通过看官方文档、翻开源项目 issues的方式,帮助同事解决了几个看似非常“棘手”的问题,我在前司也有几次类似的经历,这种感觉就很奇妙,至今我都没有彻底明白这些事情的内核是怎么样的,只能提笔记录下来,以作后观。
编译不过?
这是在前司时发生的事情。因为上游业务方使用了腾讯mars库做日志加密,我所在的团队作为下游需要将这些日志解密并保存,负责这个事情的同事H就去github上翻了源码,发现这个库是用C++写的,于是H参照官方文档以及这个issue打算将其编译成可执行文件来用,但是发现按照文档的描述,编译总是失败,于是找我帮忙。虽然上学的时候都学过C/C++,但并没有在工作中使用过,只能死马当活马医。我先从github上将源码clone下来(当然默认是master分支),然后根据H提供的文档进行编译,确实失败了:
❯ gcc decode_log_file.c micro-ecc-master/uECC.c -o decode_log_file -O0 -ggdb -lz
decode_log_file.c:26:10: fatal error: 'zstd/lib/zstd.h' file not found
#include "zstd/lib/zstd.h"
^~~~~~~~~~~~~~~~~
1 error generated.
这个错误看起来是挺简单的,记得当时我们也尝试了几种方案,均没有成功。于是我开始换思路了,前面提到的issue时间是Apr 25, 2019
, 而我们使用的是master分支,距离那个issue最近一个tagv1.3.0
(时间是Mar 8, 2019
), 于是果断将代码切到v1.3.0
, 果不其然,同样的命令,编译成功,而且也跑通了官网的给的示例。
这个不熟悉的问题最终能够得到解决,经验因素居多吧。因为在我的意识里面,一个开源项目的文档更新可能不会那么及时,但是功能要发版本,大概率是要打tag的。
数据迁移?
这是发生在贵司的事情。这个背景有点复杂:贵司跟某银行“联合”开发一套大数据平台(其实是贵司开发,后面用cm指代),这套平台的监控使用的是Prometheus(后面简称prom),prom部署在K8s的kube-system里面,prom数据存储挂PV(使用NFS),只存储最近30天的数据。这套cm部署在某银行的预发环境中,因为最近cm升级,prom的部署需要从kube-system迁移到另一个namespace(后面用xyz指代),但是呢,某银行要求这些监控数据不丢失,需要贵司提供数据迁移的技术方案支持。值得一提的是,因为不是生产环境,所以prom其实可以停服。这事最早是交到同事L手中的。L也就毕业三年,觉得这是运维的事情,于是要求运维提供支持,不巧的是运维出差,于是要求架构师提供支持……然后一周后运维回公司了,这事又流转到运维那里,运维的思路是通过prom提供的API接口,编写go代码将历史数据读取出来再存储到新的prom中去,然后发现prom的读写接口不好使,于是在晨会上提想把这事交出去,因为团队只有我是专职写go的,于是被接受了这个活……
这事的背景终于讲完了,个中曲折,还是稍等有点复杂的。毕竟曾经主导并设计过监控告警方案,此时的我,成竹在胸。先捋清几个事情
prom只存储最近30天的数据;
prom可以停服;
这两点挺关键的,因为prom是支持远程读的,也有联邦部署的架构设计,所以解决方案就呼之欲出了
保留kube-system中的旧prom实例,并停止scrape
在xyz中部署新prom实例,与1中旧的prom组成联邦集群
总结一下解题思路:客户要的是数据不丢,并没有说数据必须合为一处,采用联邦部署方式,30天之后旧的prom就可停服了,代价小,落地快,现场的同事操作起来也很方便,甚至基于我的思路提供了一份更详实的操作文档给到了客户方。
NFS不管用了?
这也是发生在贵司的事情。这次背景并不复杂,贵司跟某行谈合作,要去某行现场进行poc部署。贵司的大数据平台cm部署在K8s中,数据持久化依赖NFS,需要在K8s中安装nfs-subdir-external-provisioner。现场部署的运维同事发现部署不上,遇到以下问题:
unexpected error getting claim reference: selfLink was empty, can't make reference
然后我就被拉到了某个工作群,跟进这个问题。查了一下,原来
Kubernetes v1.20 (opens new window)开始,默认删除了
metadata.selfLink
字段,然而,部分应用仍然依赖于这个字段,例如nfs-client-provisioner
。如果仍然要继续使用这些应用,您将需要重新启用该字段。
不幸的是cm在测试的过程中一直使用的K8s均是1.20以下的,这次客户现场正好是1.20以上的K8s版本,仓促之下现场运维也找到解法,需要修改apiserver的启动参数:
- --feature-gates=RemoveSelfLink=false
但是某行的安全部门需要贵司给出:selfLink是干什么的,有什么风险?然的现场运维也给不出所以然来。
以下是我让AI(claude)帮忙总结的selfLink知识要点:
在 Kubernetes(K8s)中,selfLink 是一个对象的 URL 标识符。每个 Kubernetes 对象都会有一个 selfLink 属性,它指向该对象的唯一 URL。selfLink 的主要作用有:1. 定位对象通过 selfLink 可以唯一地定位到 Kubernetes 集群中的某个对象。可以通过 GET 请求来获取对象的详细信息。例如,对于一个 Pod 对象,其 selfLink 属性可能是:
/api/v1/namespaces/default/pods/my-pod
发送 GET 请求到这个 URL 就可以获取该 Pod 的完整信息。2. 跨命名空间引用对象某些 Kubernetes 对象需要引用其他对象,如果这两个对象在不同的命名空间,则需要使用 selfLink 来实现跨命名空间引用。例如,ServiceAccount 对象可以引用 Secret,如果 Secret 在另一个命名空间,则需要使用 Secret 的 selfLink 作为引用。3. 语言无关性selfLink 使用 URL 作为对象标识符,这使得它对编程语言无依赖。你可以在任何语言中使用 selfLink 来获取 Kubernetes 对象的相关信息。4. 稳定性对象的 selfLink 在对象创建后不会更改。这使得你可以安全地保存一个对象的 selfLink,以便将来引用该对象。即使对象的名称或命名空间发生变化,通过 selfLink 仍然可以访问到该对象。所以,总的来说,selfLink 为每个 Kubernetes 对象提供了一个唯一的 URL 标识符。通过 selfLink,你可以定位、引用和访问对象,而且这种访问方式稳定可靠且语言无关。这使得 selfLink 在 Kubernetes 对象管理与交互中发挥着重要的作用。
看完之后,其实我对selfLink从一无所知到有了一个具体的印象:它是URL的标识符。之所以被废弃掉,是因为它的创建和维护会影响性能。了解了这些之后,我觉得这不应该成为一个阻塞点,我笃定社区一定有其它更合理的解法,果然我在issue中翻到了
No more workarounds please :-) - this issue was closed for a reason guys! Just use new available docker image:
gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0
and it works fine. Do not edit kube-apiserver.yaml, there is no need to.
嗯,果然,这个方法被证实是可行的。于是我将此方法同步给现场运维,算是以较小代价解决了问题,但这次cm暴露出来的问题还是比较多的,先按下不表。
总结
上述几次解题,单独看起来真的毫无技术含量,它们当然不如高并发、大流量、分布式等问题高级,但它却真真实实地发生在工作中,组成了我们日常工作的部分。经验是挺重要的,但思路、方法、方式同样不可忽视,我能感觉到当年从后端开发转测开,以及云原生、DevOps、监控告警等经历,真的极大地开拓了我的个人技术视野,解放了我的思维局限性。当然,我也深知,经验是一把双刃剑,它也可能过时,我能做的,只有持续保持学习而已。