【k8s】使用 Reloader 实现热部署

一. 概述

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

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

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

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

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

当 Reloader 检测到 ConfigMap 发生变化的时候,会使用 SHA1 计算 ConfigMap 的哈希值(使用 SHA1 是因为它高效且不易发生冲突),计算完哈希值之后,Reloader 获取所有的 DeploymentsDaemonsetsStatefulsets 和 Rollouts 列表,并查找其 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 的变化,并实现滚动升级

DeploymentConfigsDeploymentsDaemonsetsStatefulsets 和 Rollouts 中的 annotations 中添加如下内容:

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

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

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

首先在DeploymentConfigsDeploymentsDaemonsetsStatefulsets 和 Rollouts 中的 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 的变化

DeploymentConfigsDeploymentsDaemonsetsStatefulsets 和 Rollouts 中的 annotations 中指定多个要检测的 ConfigMap 的名称:

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

DeploymentConfigsDeploymentsDaemonsetsStatefulsets 和 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优先读取 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

本文作者:blogwd

本文链接:https://www.cnblogs.com/blogwd/p/15904428.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   blogwd  阅读(442)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 不要说话 REOL
  2. 2 这世界那么多人 REOL
  3. 3 盛夏的果实 REOL
不要说话 - REOL
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 小柯

作曲 : 小柯

编曲 : Mac Chew

深色的海面布满白色的月光

我出神望着海 心不知飞哪去

听到他在告诉你

说他真的喜欢你

我不知该 躲哪里

爱一个人是不是应该有默契

我以为你懂得每当我看着你

我藏起来的秘密

在每一天清晨里

暖成咖啡 安静的拿给你

愿意 用一支黑色的铅笔

画一出沉默舞台剧

灯光再亮 也抱住你

愿意 在角落唱沙哑的歌

再大声也都是给你

请用心听 不要说话

爱一个人是不是应该有默契

我以为你懂得每当我看着你

我藏起来的秘密

在每一天清晨里

暖成咖啡 安静的拿给你

愿意 用一支黑色的铅笔

画一出沉默舞台剧

灯光再亮 也抱住你

愿意 在角落唱沙哑的歌

再大声也都是给你

请用心听 不要说话

愿意 用一支黑色的铅笔

画一出沉默舞台剧

灯光再亮 也抱住你

愿意 在角落唱沙哑的歌

再大声也都是给你

请原谅我 不会说话

愿意 用一支黑色的铅笔

画一出沉默舞台剧

灯光再亮 也抱住你

愿意 在角落唱沙哑的歌

再大声也都是给你

爱是用心吗 不要说话