使用kubernetes做为底层平台, 对于配置文件的部署形式, 如果没有统一的配置管理, 使用最多的就是configmap及secret
但有时候只会将敏感的信息放在secret中,而大多数的配置会放在configmap, 这就造成要么把secret以env的形式存在于容器中,要么就以volumn的形式挂载到容器中, 需要从两个源来引用配置, 从本质上, configmap与secret是一个东西, 有时候会觉得这种场景其实可以优化到一个配置中, 官方到目前为止并不打算支持在configmap中引用secret, 这是在github上讨论的issue
某天随便逛github时,发现一个可以实现该功能的开源库configmapsecrets,它能够在configmap中引用secret中的变量, 最后生成一个完整的secret. 这样, 应用直接把这个secret挂载到指定路径即可, 同时,支持热更新.
经过一番研究后,发现用在GitOps流程中还是非常方便的, 结合SealedSecrets对secret的加密, 两者结合更好的支持了配置安全,方便统一管理
原理
原理非常简单,通过CRD来监控集群中特定资源(configmapSecret), 分析该资源引用的secret, 填充变量生成secret.
同时为了支持多个实例,多实例之间的竞争关系, 使用了sync.RWMutex
使用
安装CRD
按照github上的说明, 先生成CRD, 这里需要注意的是, 如果只想监视特定的ns中有效, 修改deployment.yaml中的容器的启动参数,
添加all-namespaces=false
,这样,configmapsecret只会处理这个ns中的对象
kubectl apply -f manifest
secret
1 | apiVersion: v1 |
ConfigmapSecret
1 | apiVersion: secrets.mz.com/v1alpha1 |
vars中内容即是引用的变量, 上面引用的是secret, 当然也可以引用configmap.
注意: 引用的必须是同一ns中secret/configmap
使用命令生成以上2个对象
1 | kubectl apply -f secret.yaml |
最终会在同一ns中生成一个secret,名字跟ConfigMapSecret对象的名字相同, 当然secret的data数据是被base64加密的
其它测试
- 如果修改引用的secret,会提示以下日志
1 | {"level":"INFO","time":"2020-06-28T03:52:57.386Z","source":"controllers.controller.ConfigMapSecret","caller":"controllers/configmapsecret_controller.go:271","msg":"Updating Secret","configmapsecret":"monitoring/alertmanager-config","secret":"monitoring/alertmanager-config"} |
- 修改configmapsecret本身,会提示以下错误, 但并不影响
1 | {"level":"ERROR","time":"2020-06-28T03:50:08.555Z","source":"controllers.controller.ConfigMapSecret","caller":"controllers/configmapsecret_controller.go:462","msg":"Unable to update status","configmapsecret":"monitoring/alertmanager-config","error":"Operation cannot be fulfilled on configmapsecrets.secrets.mz.com \"alertmanager-config\": the object has been modified; please apply your changes to the latest version and try again" |
1、2两种情况最终的secret会跟着被修改
- 而如果直接修改最终生成的secret,修改完之后会立即被复原.
1 | {"level":"INFO","time":"2020-06-28T04:23:43.699Z","source":"controllers.controller.ConfigMapSecret","caller":"controllers/configmapsecret_controller.go:271","msg":"Updating Secret","configmapsecret":"monitoring/alertmanager-config","secret":"monitoring/alertmanager-config"} |
- 删除configmapsecret, 则最终生成的secret也会被删除, 引用的secret则不会.
源码分析
关键代码在/pkg/controllers/configmapsecret_controller.go
中
首先通过SetupWithManager
启动manager, 该manager用于监控configmapsecret及secret
关键函数sync
用于同步相关资源的变更,通过对比OwnerReferences的UID来判断是否有变更,它调用renderSecret
根据configmapsecret及引用的secret/configmap来渲染生成最终的secret
而处理引用变量的逻辑则是在makeVariables
函数
不足
如果使用容器平台,如rancher, UI上不支持显示crd, 因此configmapsecret无法显示在页面上.
如果最终生成的形式为secret, 被base64编码,不能够直观地显示配置, 如果能够直接生成configmap,我觉得更合理
但生成的secret也不影响这个库用于GitOps中,结合SealedSecrets对secret的加密处理, 至此可以实现整个资源端到端的闭环.