【k8s】使用 Reloader 实现热部署

一. 概述

我们在 k8s 中使用 ConfigMap 作为配置文件的时候会遇到一个问题:修改 ConfigMap 后无法实现热部署,也就是更改了 ConfigMap 配置文件后需要手动重启 Pod 配置才会生效,为了处理这个问题 github 专门有个开源的项目 Reloader 来解决这个问题,项目地址如下:

Reloader 项目地址:https://github.com/stakater/Reloader

Reloader 可以观察 ConfigMap 和 Secret 中的变化,并对 pod 及其关联的 DeploymentConfigsDeploymentsDaemonsetsStatefulsetsRollouts进行滚动升级。

本文主要对 Reloader 的使用进行一个简单的介绍,详细的配置与使用可以查看源码文档。

二. Reloader 实现滚动升级的原理

当 Reloader 检测到 ConfigMap 发生变化的时候,会使用 SHA1 计算 ConfigMap 的哈希值(使用 SHA1 是因为它高效且不易发生冲突),计算完哈希值之后,Reloader 获取所有的 DeploymentsDaemonsetsStatefulsetsRollouts 列表,并查找其 anotations 中是否配置了 Reloader 相关的注解,比如配置了如下 annotations :

metadata:
  annotations:
    reloader.stakater.com/auto: "true"

接着 Reloader 会查找配置了 Reloader 相关 annotations 的 DeploymentsDaemonsetsStatefulsets 中一个特殊的环境变量。

如果找到这个环境变量,则获取其值并将其与前面计算的新 ConfigMap 哈希值进行比较,如果环境变量中的旧值与新哈希值不同,则 Reloader 会更新环境变量。

如果环境变量不存在,那么它会从 ConfigMap 创建一个具有最新哈希值的新环境变量并更新相关的deploymentdaemonset或者statefulset

k8s 检测到这个环境变量发生变化,则会触发 pod 关联的 deploymentdaemonset或者statefulset 的滚动升级。

修改 Secret 实现滚动升级的原理上述相同

环境变量的名字

这个环境变量的名字定义如下:

  • 生成 ConfigMap 的环境变量的名称为:STAKATER_{configmap_name}_CONFIGMAP ,比如 ConfigMap 的名称为 foo,则生成的环境变量的名称为:STAKATER_FOO_CONFIGMAP

  • 生成 Secret 的环境变量的名称为:STAKATER_{secret_name}_SECRET ,比如 Secret 的名称为 foo,则生成的环境变量的名称为:STAKATER_FOO_SECRET

环境变量的值

这个环境变量的值为使用 SHA1 计算的 ConfigMap 或者 Secret 的哈希值。

Reloader 监控特定命名空间

默认情况下,reloader 部署在默认命名空间中并监视所有命名空间中的更改,要监视特定命名空间中的更改,请在该命名空间中部署 Reloader,并将watchGlobally标志设置为false

三. 在 k8s 中安装 Reloader

在 Reloader 的源码文档中提供了三种安装方式:

  1. 使用 Manifests 安装
  2. 使用 kustomize 安装
  3. 使用 helm 安装

这里只介绍使用 helm 安装,个人觉得使用 helm 安装的优点是方便管理、升级和修改配置,你可以根据自己的需求选择其他的安装方式,详细的说明可以查看源码文档。

使用下面的命令添加 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 文件夹,其中的内容如下:

[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

我们根据需要修改 values.yaml 文件的配置即可。

修改完成后,可以使用下面的命令根据修改后的配置进行安装:

helm install -name reloader -n default ./reloader

如果不通过 -n namespace 指定安装的命名空间,则默认安装在 default 命令空间,可以根据自己的需要安装到特定的命名空间。

使用下面的命令查看 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 的变化,并实现滚动升级

DeploymentConfigsDeploymentsDaemonsetsStatefulsetsRollouts 中的 annotations 中添加如下内容:

metadata:
  annotations:
    reloader.stakater.com/auto: "true"

之后 reloader 会检测所有命名空间中其相关联的 ConfigMap 或者 Secret 的变化,并实现滚动升级。

2. 限制只检测带有特殊 annotations 的 ConfigMap 或者 Secret 的变化

首先在DeploymentConfigsDeploymentsDaemonsetsStatefulsetsRollouts 中的 annotations 中添加如下内容:

kind: Deployment
metadata:
  annotations:
    reloader.stakater.com/search: "true"

并且在 ConfigMap 或者 Secret 中的 annotations 中添加如下内容:

kind: ConfigMap
metadata:
  annotations:
    reloader.stakater.com/match: "true"

3. 检测指定的 ConfigMap 或者 Secret 的变化

DeploymentConfigsDeploymentsDaemonsetsStatefulsetsRollouts 中的 annotations 中指定多个要检测的 ConfigMap 的名称:

kind: Deployment
metadata:
  annotations:
    configmap.reloader.stakater.com/reload: "foo-configmap,bar-configmap,baz-configmap"
spec:
  template: 
    metadata:

DeploymentConfigsDeploymentsDaemonsetsStatefulsetsRollouts 中的 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优先读取 config 目录中的配置文件并覆盖内部的配置。

挂载配置文件后,在容器中的目录内容如下:

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 文件夹中的内容如下:

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 文件内容如下:

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

相关的部署文件如下:

deployment.yaml 文件内容如下:

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 文件的内容如下:

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

当我们修改 ConfigMap 中的 application.yaml 配置的 context-path 后,可以看到相关 pod 完成了自动重启,并且使用下面的命令查看 deployment 的 yaml 内容:

kubectl get deploy -o yaml

可以发现增加了一个环境变量:

    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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容