美文网首页
【k8s】使用 Reloader 实现热部署

【k8s】使用 Reloader 实现热部署

作者: 惜鸟 | 来源:发表于2022-02-17 14:16 被阅读0次

    一. 概述

    我们在 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

    相关文章

      网友评论

          本文标题:【k8s】使用 Reloader 实现热部署

          本文链接:https://www.haomeiwen.com/subject/owcslrtx.html