记一次k8s-rbd-provisioner改造后编译问题
背景
这次的项目是准备修改一下external provisioner里的rbd provisioner,使之支持使用pvc的命名空间和名称组合起来作为ceph rbd镜像名称,就像cephfs provisioner一样。默认的rbd只支持随机镜像名或使用pv的名称两种方案,而这两种方案本质上都是非完全固定的,不能满足我更换集群保持pvc和image一一对应的需求,因此需要改造。
这次的改造需要修改少量代码,主要是增加一个检查ceph集群image存在状态的函数,然后对provision的逻辑做少许修改即可:每次provision rbd的时候,检查ceph集群里是否已经存在需要用到的image,是的话就不再创建新的。
奇怪的问题
第一次改好后,go build、docker build、docker push、kubectl apply一条龙服务,然后测试效果发现有点问题。于是排查后增加了一些调试代码,准备再次测试。
这时奇怪的问题出现,我明明改了代码里provision包的代码,但是docker build在拷贝二进制文件时却仍然在用cache。
于是查了下docker build时的缓存机制,首先排查下是不是docker build时错误地使用了缓存,最后没有发现docker build缓存有什么问题。
于是就怀疑二进制文件本身了,所以微调代码并且build然后观察md5,发现改代码前后编译出来的文件竟然md5一样……
于是又查了下go build的缓存机制,发现用-a一般就可以解决缓存问题了。就在我百思不得其解的时候,开始往代码结构上考虑。对于k8s里的组件,通常的结构是build cmd目录里的main包,然后引用同项目下的pkg里的其他包,完成实际功能。
想到这里就恍然大悟了,是因为我fork了官方的代码后,启用go module时把项目名字中的github账户换成了我自己的,所以在main包中引用时也应该做相应修改。如果不改,那么引用的还是官方的pkg包,自然代码从未改变过所以编译出的文件从未改变。
思考与总结
这次设计到的问题主要是由于对go、go module的引用机制理解不够深刻,以及第一次动手进行这类实践,从而简单手动修改go module包名引发了问题。
学习后发现,在fork别人的go项目进行修改后,包和引用的解决方案有两种思路:
- 自立门户:将项目中涉及到对项目本身的package引用通通修改,要改彻底。适用于不再和原项目发生关系的fork。
- go module replace:原来这就是go module replace命令非常合适的一种使用情境。在fork后,只需要在go mod文件中将原项目地址replace成自己的项目地址,即可方便地实现不改代码的前提下全部使用fork后的项目构建。
外部参考
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。