一. 概述
我們在 k8s 中使用 ConfigMap
作為配置文件的時候會遇到一個問題:修改 ConfigMap
后無法實現(xiàn)熱部署舵揭,也就是更改了 ConfigMap
配置文件后需要手動重啟 Pod 配置才會生效,為了處理這個問題 github 專門有個開源的項目 Reloader 來解決這個問題舟舒,項目地址如下:
Reloader 可以觀察 ConfigMap 和 Secret 中的變化煤伟,并對 pod 及其關(guān)聯(lián)的 DeploymentConfigs
癌佩,Deployments
,Daemonsets
便锨,Statefulsets
和 Rollouts
進行滾動升級驼卖。
本文主要對 Reloader 的使用進行一個簡單的介紹,詳細(xì)的配置與使用可以查看源碼文檔鸿秆。
二. Reloader 實現(xiàn)滾動升級的原理
當(dāng) Reloader 檢測到 ConfigMap 發(fā)生變化的時候酌畜,會使用 SHA1 計算 ConfigMap 的哈希值(使用 SHA1 是因為它高效且不易發(fā)生沖突),計算完哈希值之后卿叽,Reloader 獲取所有的 Deployments
桥胞,Daemonsets
恳守,Statefulsets
和 Rollouts
列表,并查找其 anotations 中是否配置了 Reloader 相關(guān)的注解贩虾,比如配置了如下 annotations :
metadata:
annotations:
reloader.stakater.com/auto: "true"
接著 Reloader 會查找配置了 Reloader 相關(guān) annotations 的 Deployments
催烘,Daemonsets
,Statefulsets
中一個特殊的環(huán)境變量缎罢。
如果找到這個環(huán)境變量伊群,則獲取其值并將其與前面計算的新 ConfigMap 哈希值進行比較,如果環(huán)境變量中的舊值與新哈希值不同策精,則 Reloader 會更新環(huán)境變量舰始。
如果環(huán)境變量不存在,那么它會從 ConfigMap 創(chuàng)建一個具有最新哈希值的新環(huán)境變量并更新相關(guān)的deployment
咽袜,daemonset
或者statefulset
丸卷。
k8s 檢測到這個環(huán)境變量發(fā)生變化,則會觸發(fā) pod 關(guān)聯(lián)的 deployment
询刹,daemonset
或者statefulset
的滾動升級谜嫉。
修改 Secret 實現(xiàn)滾動升級的原理上述相同
環(huán)境變量的名字
這個環(huán)境變量的名字定義如下:
生成 ConfigMap 的環(huán)境變量的名稱為:
STAKATER_{configmap_name}_CONFIGMAP
,比如 ConfigMap 的名稱為 foo凹联,則生成的環(huán)境變量的名稱為:STAKATER_FOO_CONFIGMAP
沐兰。生成 Secret 的環(huán)境變量的名稱為:
STAKATER_{secret_name}_SECRET
,比如 Secret 的名稱為 foo蔽挠,則生成的環(huán)境變量的名稱為:STAKATER_FOO_SECRET
僧鲁。
環(huán)境變量的值
這個環(huán)境變量的值為使用 SHA1 計算的 ConfigMap 或者 Secret 的哈希值。
Reloader 監(jiān)控特定命名空間
默認(rèn)情況下象泵,reloader 部署在默認(rèn)命名空間中并監(jiān)視所有命名空間中的更改寞秃,要監(jiān)視特定命名空間中的更改,請在該命名空間中部署 Reloader偶惠,并將watchGlobally
標(biāo)志設(shè)置為false
春寿。
三. 在 k8s 中安裝 Reloader
在 Reloader 的源碼文檔中提供了三種安裝方式:
- 使用 Manifests 安裝
- 使用 kustomize 安裝
- 使用 helm 安裝
這里只介紹使用 helm 安裝,個人覺得使用 helm 安裝的優(yōu)點是方便管理忽孽、升級和修改配置绑改,你可以根據(jù)自己的需求選擇其他的安裝方式,詳細(xì)的說明可以查看源碼文檔兄一。
使用下面的命令添加 reloader 倉庫地址:
helm repo add stakater https://stakater.github.io/stakater-charts
使用下面的命令更新倉庫:
helm repo update
使用下面的命令搜索 reloader:
helm search repo reloader
為了方便修改配置厘线,我們可以使用下面的命令下載 Reloader 的 chart 包:
helm pull stakater/reloader
下載成功后獲取到一個壓縮包 reloader-v0.0.105.tgz
,使用下面的命令解壓:
tar -zxvf reloader-v0.0.105.tgz
解壓后得到 reloader
文件夾出革,其中的內(nèi)容如下:
[root@node01 reloader]# ll
total 20
-rw-r--r-- 1 root root 789 Feb 13 20:16 Chart.yaml
drwxr-xr-x 2 root root 4096 Feb 17 10:26 templates
-rw-r--r-- 1 root root 341 Feb 13 20:16 values.schema.json
-rw-r--r-- 1 root root 4284 Feb 13 20:16 values.yaml
我們根據(jù)需要修改 values.yaml
文件的配置即可造壮。
修改完成后,可以使用下面的命令根據(jù)修改后的配置進行安裝:
helm install -name reloader -n default ./reloader
如果不通過 -n namespace
指定安裝的命名空間,則默認(rèn)安裝在 default
命令空間耳璧,可以根據(jù)自己的需要安裝到特定的命名空間成箫。
使用下面的命令查看 reloader 是否安裝成功:
[root@node01 ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
reloader-reloader 1/1 1 1 15m
四. 使用 Reloader 滾動升級
前面簡單介紹了使用 helm 安裝 reloader,接下來將介紹如何使用 reloader旨枯。
源碼文檔中介紹了三種 reloader 的使用場景:
1. 檢測所有命名空間中的 ConfigMap 或者 Secret 的變化蹬昌,并實現(xiàn)滾動升級
在DeploymentConfigs
,Deployments
攀隔,Daemonsets
皂贩,Statefulsets
和 Rollouts
中的 annotations 中添加如下內(nèi)容:
metadata:
annotations:
reloader.stakater.com/auto: "true"
之后 reloader 會檢測所有命名空間中其相關(guān)聯(lián)的 ConfigMap 或者 Secret 的變化,并實現(xiàn)滾動升級昆汹。
2. 限制只檢測帶有特殊 annotations 的 ConfigMap 或者 Secret 的變化
首先在DeploymentConfigs
明刷,Deployments
,Daemonsets
筹煮,Statefulsets
和 Rollouts
中的 annotations 中添加如下內(nèi)容:
kind: Deployment
metadata:
annotations:
reloader.stakater.com/search: "true"
并且在 ConfigMap
或者 Secret
中的 annotations 中添加如下內(nèi)容:
kind: ConfigMap
metadata:
annotations:
reloader.stakater.com/match: "true"
3. 檢測指定的 ConfigMap 或者 Secret 的變化
在DeploymentConfigs
,Deployments
居夹,Daemonsets
败潦,Statefulsets
和 Rollouts
中的 annotations 中指定多個要檢測的 ConfigMap 的名稱:
kind: Deployment
metadata:
annotations:
configmap.reloader.stakater.com/reload: "foo-configmap,bar-configmap,baz-configmap"
spec:
template:
metadata:
在DeploymentConfigs
,Deployments
准脂,Daemonsets
劫扒,Statefulsets
和 Rollouts
中的 annotations 中指定多個要檢測的 Secret 的名稱:
kind: Deployment
metadata:
annotations:
secret.reloader.stakater.com/reload: "foo-secret,bar-secret,baz-secret"
spec:
template:
metadata:
五. 驗證 Reloader 的滾動升級
這里使用 ConfigMap 作為 spring boot 項目的外部配置,它的原理就是將 ConfigMap 中配置的 application.yaml
文件掛載到容器中 spring boot 項目 jar 包所在目錄的 config
文件夾中狸膏,因為 spring boot優(yōu)先讀取 config
目錄中的配置文件并覆蓋內(nèi)部的配置沟饥。
掛載配置文件后,在容器中的目錄內(nèi)容如下:
root@springboot-demo-7ddbc4dfd5-sxnqv:/app# ls -l
total 99
drwxrwxrwx 3 root root 4096 Feb 16 19:28 config
-rw-r--r-- 1 root root 102043 Feb 16 15:48 springboot-demo.jar
其中 config
文件夾中的內(nèi)容如下:
root@springboot-demo-7ddbc4dfd5-sxnqv:/app# ls -l config/
lrwxrwxrwx 1 root root 22 Feb 17 10:28 application.yaml -> ..data/application.yaml
定義一個 springboot-demo 項目湾戳,其 Dockerfile
文件內(nèi)容如下:
FROM openjdk:8u232-jdk
WORKDIR /app
LABEL maintainer="peterwd" app="springboot-demo"
COPY target/springboot-demo.jar springboot-demo.jar
EXPOSE 8080
CMD java -jar springboot-demo.jar
相關(guān)的部署文件如下:
deployment.yaml
文件內(nèi)容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot-demo
namespace: default
labels:
app: springboot-demo
annotations:
reloader.stakater.com/auto: "true"
spec:
replicas: 1
selector:
matchLabels:
app: springboot-demo
template:
metadata:
labels:
app: springboot-demo
spec:
containers:
- name: springboot-demo
image: springboot-demo
imagePullPolicy: Always
env:
- name: TZ
value: Asia/Shanghai
- name: NAMESPACE
value: default
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /app/config
name: config
volumes:
- configMap:
name: springboot-demo
name: config
imagePullSecrets:
- name: docker-secret
---
apiVersion: v1
kind: Service
metadata:
name: springboot-demo
namespace: default
spec:
ports:
- name: http-port
port: 80
protocol: TCP
targetPort: 8080
selector:
app: springboot-demo
type: ClusterIP
springboot-demo-configmap.yaml
文件的內(nèi)容如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-demo
namespace: default
data:
application.yaml: |-
server:
port: 8080
servlet:
context-path: /springboot-demo
spring:
application:
name: demo
當(dāng)我們修改 ConfigMap 中的 application.yaml
配置的 context-path 后贤旷,可以看到相關(guān) pod 完成了自動重啟,并且使用下面的命令查看 deployment 的 yaml 內(nèi)容:
kubectl get deploy -o yaml
可以發(fā)現(xiàn)增加了一個環(huán)境變量:
spec:
containers:
- env:
- name: TZ
value: Asia/Shanghai
- name: NAMESPACE
value: default
- name: STAKATER_SPRINGBOOT_DEMO_CONFIGMAP
value: 7b36c3bd0a7c0a87db028cf1037eb994df4de49e
參考文檔
https://github.com/stakater/Reloader/blob/master/docs/How-it-works.md