Kubernetes 配置熱更新之 reloader
背景
配置中心問題:
對(duì)于在云原生中配置中心,例如configmap和secret對(duì)象,雖然可以進(jìn)行直接更新資源對(duì)象。
- 對(duì)于引用這些有些不變的配置是可以打包到鏡像中的,那可變的配置呢?
- 信息泄漏,很容易引發(fā)安全風(fēng)險(xiǎn),尤其是一些敏感信息,比如密碼、密鑰等。
- 每次配置更新后,都要重新打包一次,升級(jí)應(yīng)用。鏡像版本過多,也給鏡像管理和鏡像中心存儲(chǔ)帶來(lái)很大的負(fù)擔(dān)。
- 定制化太嚴(yán)重,可擴(kuò)展能力差,且不容易復(fù)用。
使用方式:
Configmap或Secret使用有兩種方式,一種是env系統(tǒng)變量賦值,一種是volume掛載賦值,env寫入系統(tǒng)的configmap是不會(huì)熱更新的,而volume寫入的方式支持熱更新!
- 對(duì)于env環(huán)境的,必須要滾動(dòng)更新pod才能生效,也就是刪除老的pod,重新使用鏡像拉起新pod加載環(huán)境變量才能生效。
- 對(duì)于volume的方式,雖然內(nèi)容變了,但是需要我們的應(yīng)用直接監(jiān)控configmap的變動(dòng),或者一直去更新環(huán)境變量才能在這種情況下達(dá)到熱更新的目的。
- 應(yīng)用不支持熱更新,可以在業(yè)務(wù)容器中啟動(dòng)一個(gè)sidercar容器,監(jiān)控configmap的變動(dòng),更新配置文件,或者也滾動(dòng)更新pod達(dá)到更新配置的效果。
解決方案
ConfigMap 和 Secret 是 Kubernetes 常用的保存配置數(shù)據(jù)的對(duì)象,你可以根據(jù)需要選擇合適的對(duì)象存儲(chǔ)數(shù)據(jù)。通過 Volume 方式掛載到 Pod 內(nèi)的,kubelet 都會(huì)定期進(jìn)行更新。但是通過環(huán)境變量注入到容器中,這樣無(wú)法感知到 ConfigMap 或 Secret 的內(nèi)容更新。
目前如何讓 Pod 內(nèi)的業(yè)務(wù)感知到 ConfigMap 或 Secret 的變化,還是一個(gè)待解決的問題。但是我們還是有一些 Workaround 的。
如果業(yè)務(wù)自身支持 reload 配置的話,比如nginx -s reload,可以通過 inotify 感知到文件更新,或者直接定期進(jìn)行 reload(這里可以配合我們的 readinessProbe 一起使用)。
如果我們的業(yè)務(wù)沒有這個(gè)能力,考慮到不可變基礎(chǔ)設(shè)施的思想,我們是不是可以采用滾動(dòng)升級(jí)的方式進(jìn)行?沒錯(cuò),這是一個(gè)非常好的方法。目前有個(gè)開源工具Reloader,它就是采用這種方式,通過 watch ConfigMap 和 Secret,一旦發(fā)現(xiàn)對(duì)象更新,就自動(dòng)觸發(fā)對(duì) Deployment 或 StatefulSet 等工作負(fù)載對(duì)象進(jìn)行滾動(dòng)升級(jí)。
reloader簡(jiǎn)介
reloader簡(jiǎn)介:
Reloader 可以觀察 ConfigMap 和 Secret 中的變化,并通過相關(guān)的 deploymentconfiggs、 deploymentconfiggs、 deploymonset 和 statefulset 對(duì) Pods 進(jìn)行滾動(dòng)升級(jí)。
reloader安裝:
helm安裝:
helm repo add stakater https://stakater.github.io/stakater-charts
helm repo update
helm install stakater/reloader
Kustomize:
kubectl apply -k https://github.com/stakater/Reloader/deployments/kubernetes
資源清單安裝:
kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
# 在此安裝在common-service 名稱空間下,
[root@master reloader]# kubectl apply -f reloader.yaml
clusterrole.rbac.authorization.k8s.io/reloader-reloader-role created
clusterrolebinding.rbac.authorization.k8s.io/reloader-reloader-role-binding created
deployment.apps/reloader-reloader created
serviceaccount/reloader-reloader created
[root@master reloader]# kubectl get all -n common-service
NAME READY STATUS RESTARTS AGE
pod/reloader-reloader-66d46d5885-nx64t 1/1 Running 0 15s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/reloader-reloader 1/1 1 1 16s
NAME DESIRED CURRENT READY AGE
replicaset.apps/reloader-reloader-66d46d5885 1 1 1 16s
配置忽略:
reloader能夠配置忽略cm或者secrets資源,可以通過配置在reader deploy中的spec.template.spec.containers.args,如果兩個(gè)都忽略,那就縮小deploy為0,或者不部署reoader。
Args | Description |
–resources-to-ignore=configMaps | To ignore configMaps |
–resources-to-ignore=secrets | To ignore secrets |
配置:
自動(dòng)更新:
reloader.stakater.com/search 和 reloader.stakater.com/auto 并不在一起工作。如果你在你的部署上有一個(gè) reloader.stakater.com/auto : “ true”的注釋,該資源對(duì)象引用的所有configmap或這secret的改變都會(huì)重啟該資源,不管他們是否有 reloader.stakater.com/match : “ true”的注釋。
kind: Deployment
metadata:
annotations:
reloader.stakater.com/auto: "true"
spec:
template: metadata:
制定更新:
指定一個(gè)特定的configmap或者secret,只有在我們指定的配置圖或秘密被改變時(shí)才會(huì)觸發(fā)滾動(dòng)升級(jí),這樣,它不會(huì)觸發(fā)滾動(dòng)升級(jí)所有配置圖或秘密在部署,后臺(tái)登錄或狀態(tài)設(shè)置中使用。
一個(gè)制定deployment資源對(duì)象,在引用的configmap或者secret種,只有reloader.stakater.com/match: "true"為true才會(huì)出發(fā)更新,為false或者不進(jìn)行標(biāo)記,該資源對(duì)象都不會(huì)監(jiān)視配置的變化而重啟。
kind: Deployment
metadata:
annotations:
reloader.stakater.com/search: "true"
spec:
template:
cm配置:
kind: ConfigMap
metadata:
annotations:
reloader.stakater.com/match: "true"
data:
key: value
指定cm:
如果一個(gè)deployment掛載有多個(gè)cm或者的場(chǎng)景下,我們只希望更新特定一個(gè)cm后,deploy發(fā)生滾動(dòng)更新,更新其他的cm,deploy不更新,這種場(chǎng)景可以將cm在deploy中指定為單個(gè)或著列表實(shí)現(xiàn)。
例如:一個(gè)deploy有掛載nginx-cm1和nginx-cm2兩個(gè)configmap,只想nginx-cm1更新的時(shí)候deploy才發(fā)生滾動(dòng)更新,此時(shí)無(wú)需在兩個(gè)cm中配置注解,只需要在deploy中寫入configmap.reloader.stakater.com/reload:nginx-cm1,其中nginx-cm1如果發(fā)生更新,deploy就會(huì)觸發(fā)滾動(dòng)更新。
如果多個(gè)cm直接用逗號(hào)隔開。
# configmap對(duì)象
kind: Deployment
metadata:
annotations:
configmap.reloader.stakater.com/reload: "nginx-cm1"
spec:
template: metadata:
# secret對(duì)象
kind: Deployment
metadata:
annotations:
secret.reloader.stakater.com/reload: "foo-secret"
spec:
template: metadata:
無(wú)需在cm或secret中添加注解,只需要在引用資源對(duì)象中添加注解即可。
測(cè)試驗(yàn)證
deploy:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# reloader.stakater.com/auto: "true"
reloader.stakater.com/search: "true"
labels:
run: nginx
name: nginx
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: nginx
template:
metadata:
labels:
run: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
# 必須匹配volumes的名稱,定義configmap
- name: nginx-cm
mountPath: /data/cfg
readOnly: true
volumes:
# 定義邏輯卷的名稱
- name: nginx-cm
configMap:
# 使用configmap資源的名稱
name: nginx-cm
items:
# 使用configmap中到那個(gè)key
- key: config.yaml
# 使用configmap中到key映射到容器中到文件名稱
path: config.yaml
mode: 0644
configmap:
apiVersion: v1
data:
config.yaml: |
# project settings
# go2cloud_api service config
DEFAULT_CONF:
port: 8888
# data disk api
UNITTEST_TENCENT_ZONE: ap-chongqing-1
kind: ConfigMap
metadata:
name: nginx-cm
annotations:
reloader.stakater.com/match: "true"
測(cè)試:
[root@master ns-default]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-68c9bf4ff7-9gmg6 1/1 Running 0 10m
[root@master ns-default]# kubectl get cm
NAME DATA AGE
nginx-cm 1 28m
# 更新cm內(nèi)容
[root@master ns-default]# kubectl edit cm nginx-cm
configmap/nginx-cm edited
# 查看po發(fā)生了滾動(dòng)更新,重新加載配置文件
[root@master ns-default]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-66c758b548-9dllm 0/1 ContainerCreating 0 4s
nginx-68c9bf4ff7-9gmg6 1/1 Running 0 10m
注意事項(xiàng)
- reloader為全局資源對(duì)象,建議部署在一個(gè)公共服務(wù)的ns下,然后其他ns也可以正常使用reloader特性。
- Reloader.stakater.com/auto : 如果配置configmap或者secret在 deploymentconfigmap/deployment/daemonsets/Statefulsets
- secret.reloader.stakater.com/reload 或者 configmap.reloader.stakater.com/reload 注釋中被使用,那么 true 只會(huì)重新加載 pod,不管使用的是 configmap 還是 secret。
- reloader.stakater.com/search 和 reloader.stakater.com/auto 不能同時(shí)使用。如果你在你的部署上有一個(gè) reloader.stakater.com/auto : “ true”的注釋,那么它總是會(huì)在你修改了 configmaps 或者使用了機(jī)密之后重新啟動(dòng),不管他們是否有 reloader.stakater.com/match : “ true”的注釋。
反思
Reloader通過 watch ConfigMap 和 Secret,一旦發(fā)現(xiàn)對(duì)象更新,就自動(dòng)觸發(fā)對(duì) Deployment 或 StatefulSet 等工作負(fù)載對(duì)象進(jìn)行滾動(dòng)升級(jí)。
如果我們的應(yīng)用內(nèi)部沒有去實(shí)時(shí)監(jiān)控配置文件,利用該方式可以非常方便的實(shí)現(xiàn)配置的熱更新。