写点什么

spring-cloud-kubernetes 自动同步 k8s 的 configmap 更新

作者:程序员欣宸
  • 2022 年 4 月 22 日
  • 本文字数:8748 字

    阅读完需:约 29 分钟

spring-cloud-kubernetes自动同步k8s的configmap更新

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本文是《spring-cloud-kubernetes 实战系列》的第七篇,在上一篇《spring-cloud-kubernetes与k8s的configmap》,我们的 springboot 应用将 k8s 的 configmap 当做配置中心,从 configmap 中获取 yml 配置文件使用,就像使用 spring cloud config 服务一样,但遗憾的是,配置文件发生变化时我们的应用上还是旧的配置信息,只能通过重启应用来重新加载,今天的实战就要解决这个问题:当 configmap 中的配置信息变更后,我们的 springboot 应用能自动更新;

提前小结和上一篇的差异

  • 要达到实时同步 configmap 变更的效果,需要将上一章的应用作以下改动:

  1. 增加以下两个 jar 依赖:

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-actuator</artifactId></dependency><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-actuator-autoconfigure</artifactId></dependency>
复制代码


  1. bootstrap.yml 增加以下配置:

management:  endpoint:    restart:      enabled: true    health:      enabled: true    info:      enabled: true
复制代码


  1. bootstrap.yml 中的 spring.cloud.kubernetes 节点下增加子节点 reload 的配置,完整的 bootstrap.yml 内容如下:

management:  endpoint:    restart:      enabled: true    health:      enabled: true    info:      enabled: truespring:  application:    name: springcloudk8sconfigdemo  profiles:    active: development  cloud:    kubernetes:      reload:        #自动更新配置的开关设置为打开        enabled: true        #更新配置信息的模式是主动拉取        mode: polling        #主动拉取的间隔时间是500毫秒        period: 500      config:        sources:          - name: ${spring.application.name}            namespace: default
复制代码


  1. 在 controller 中增加 path 为/health 的服务响应,在 k8s 部署时,健康和就绪探针会调用此接口,如果没有响应,pod 就无法正常使用:

@GetMapping("/health")    public String health() {        return "success";    }
复制代码


  • 以上就是开启自动更新的步骤了,您基于上一章的源码做上述更改即可,也可以随同本文一起重新开发一个全新应用,来实现获取 configmap 的配置,并且实时同步 configmap 的变化;

环境信息

  • 本次实战的环境和版本信息如下:

  1. 操作系统:CentOS Linux release 7.6.1810

  2. minikube:1.1.1

  3. Java:1.8.0_191

  4. Maven:3.6.0

  5. fabric8-maven-plugin 插件:3.5.37

  6. spring-cloud-kubernetes:1.0.1.RELEASE

  7. springboot:2.1.6.RELEASE

  • 准备完毕,可以开始实战啦!

源码下载

  • 如果您不打算写代码,也可以从 GitHub 上下载本次实战的源码,地址和链接信息如下表所示:

  • 这个 git 项目中有多个文件夹,本章的应用在 springcloudk8sreloadconfigdemo 文件夹下,如下图所示:

接下来,一起开始实战,开发一个 java 应用吧;

开发 Java 应用

  1. 通过 maven 创建名为 springcloudk8sreloadconfigdemo 的 springboot 工程,pom.xml 内容如下,要注意的是新增了依赖 spring-cloud-starter-kubernetes-configspring-boot-actuatorspring-boot-actuator-autoconfigure,这是本次实战的重点:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>2.1.6.RELEASE</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <groupId>com.bolingcavalry</groupId>    <artifactId>springcloudk8sreloadconfigdemo</artifactId>    <version>0.0.1-SNAPSHOT</version>    <name>springcloudk8sreloadconfigdemo</name>    <description>Demo project for Spring Cloud Kubernetes with Kubernetes ConfigMap,Change of configmap is reloadable</description>
<properties> <java.version>1.8</java.version> <spring-boot.version>2.1.6.RELEASE</spring-boot.version> <maven-checkstyle-plugin.failsOnError>false</maven-checkstyle-plugin.failsOnError> <maven-checkstyle-plugin.failsOnViolation>false</maven-checkstyle-plugin.failsOnViolation> <maven-checkstyle-plugin.includeTestSourceDirectory>false</maven-checkstyle-plugin.includeTestSourceDirectory> <maven-compiler-plugin.version>3.5</maven-compiler-plugin.version> <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version> <maven-failsafe-plugin.version>2.18.1</maven-failsafe-plugin.version> <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version> <fabric8.maven.plugin.version>3.5.37</fabric8.maven.plugin.version> <springcloud.kubernetes.version>1.0.1.RELEASE</springcloud.kubernetes.version> <spring-cloud.version>Greenwich.SR2</spring-cloud.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes-config</artifactId> <version>${springcloud.kubernetes.version}</version> </dependency>
</dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin>
<plugin> <!--skip deploy --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> <version>${maven-deploy-plugin.version}</version> <configuration> <skip>true</skip> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>${maven-surefire-plugin.version}</version> <configuration> <skipTests>true</skipTests> <!-- Workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588 --> <useSystemClassLoader>false</useSystemClassLoader> </configuration> </plugin> <plugin> <groupId>io.fabric8</groupId> <artifactId>fabric8-maven-plugin</artifactId> <version>${fabric8.maven.plugin.version}</version> <executions> <execution> <id>fmp</id> <goals> <goal>resource</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
<profiles> <profile> <id>kubernetes</id> <build> <plugins> <plugin> <groupId>io.fabric8</groupId> <artifactId>fabric8-maven-plugin</artifactId> <version>${fabric8.maven.plugin.version}</version> <executions> <execution> <id>fmp</id> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> <configuration> <enricher> <config> <fmp-service> <type>NodePort</type> </fmp-service> </config> </enricher> </configuration> </plugin> </plugins> </build> </profile> </profiles></project>
复制代码


  1. 项目的 src\main\resources 路径下不要创建 application.yml 文件,只创建名为 bootstrap.yml 的文件,内容如下:

management:  endpoint:    restart:      enabled: true    health:      enabled: true    info:      enabled: truespring:  application:    name: springcloudk8sreloadconfigdemo  cloud:    kubernetes:      reload:        #自动更新配置的开关设置为打开        enabled: true        #更新配置信息的模式:polling是主动拉取,event是事件通知        mode: polling        #主动拉取的间隔时间是500毫秒        period: 500      config:        sources:        - name: ${spring.application.name}          namespace: default
复制代码


  • 可见新增了配置项 spring.cloud.kubernetes.reload 和 spring.cloud.kubernetes.config,前者用于开启自动更新配置,执行更新模式为 500 毫秒拉取一次,后者指定配置来源于 kubernetes 的哪个 namespace 下的哪个 configmap;

  1. 增加一个配置类 DummyConfig.java,注解 ConfigurationProperties 的 prefix="greeting"表示该类用到的配置项都是名为"greeting"的配置项的子内容 :

package com.bolingcavalry.springcloudk8sreloadconfigdemo;
import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Configuration;
/** * @Description: 配置类,此处可以加载配置文件中的内容 * @author: willzhao E-mail: zq2599@gmail.com * @date: 2019/7/27 18:24 */@Configuration@ConfigurationProperties(prefix = "greeting")public class DummyConfig {
private String message = "This is a dummy message";
public String getMessage() { return this.message; }
public void setMessage(String message) { this.message = message; }}
复制代码


  1. 启动类 Springcloudk8sreloadconfigdemoApplication.java,简单起见,将用于验证配置项是否生效的 web 接口也写在了这里面,即 hello 方法 ,这个方法是应用的关键,方法内会返回配置文件的值,我们的应用能否成功取得 k8s 的 configmap 的配置文件,通过此方法的返回值就能验证了,还要增加 path 为/health 的方法,因为在 k8s 部署时健康探针和就绪探针会调用此接口,如果没有响应 pod 就无法正常使用:

package com.bolingcavalry.springcloudk8sreloadconfigdemo;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;import java.util.Date;

@SpringBootApplication@RestController@EnableConfigurationProperties(DummyConfig.class)public class Springcloudk8sreloadconfigdemoApplication {
@Autowired private DummyConfig dummyConfig;
@GetMapping("/health") public String health() { return "success"; }
@GetMapping("/hello") public String hello() { return dummyConfig.getMessage() + " [" + new SimpleDateFormat().format(new Date()) + "]"; }
public static void main(String[] args) { SpringApplication.run(Springcloudk8sreloadconfigdemoApplication.class, args); }}
复制代码


  • 以上就是实战工程的所有代码了,仅仅只是引入了少量 jar 依赖,以及在启动配置文件中指定了 configmap 的信息和同步模式,即完成了获取配置文件的所有操作,至于代码中用到配置文件的地方,和使用 SpringCloud Config 并无差别。

解决权限问题

  • 我这里的是 minikube,在部署了应用之后,默认的 serviceaccount 是没有权限访问 K8S 的 API Server 资源的,执行以下命令可以提升权限:

kubectl create clusterrolebinding permissive-binding \  --clusterrole=cluster-admin \  --user=admin \  --user=kubelet \  --group=system:serviceaccounts
复制代码


  • 注意:以上办法只能用于开发和测试环境,不要用在生产环境,生产环境应参考 Kubernetes 的 RBAC 授权相关设置来处理,步骤如下:

  1. 创建 role:

apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:  namespace: default  name: pod-readerrules:  - apiGroups: [""]    resources: ["pods","configmaps"]    verbs: ["get", "watch", "list"]
复制代码


  1. 创建 ServiceAccount:

apiVersion: v1kind: ServiceAccountmetadata:  name: config-reader  namespace: default
复制代码


  1. 绑定 Role 和 ServiceAccount:

apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:  name: pod-reader  namespace: defaultroleRef:  apiGroup: rbac.authorization.k8s.io  kind: Role  name: pod-readersubjects:  - kind: ServiceAccount    name: config-reader    namespace: default
复制代码


  1. 在 deployment 中指定上面的 ServiceAccount;

验证

  • 现在进入验证阶段,验证步骤:

  1. 在 kubernetes 环境创建 configmap;

  2. 再将 springcloudk8sreloadconfigdemo 在 kubernetes 部署和启动;

  3. 访问 springcloudk8sreloadconfigdemo 的 http 接口,验证应用能取得 configmap 中的配置;

  4. 修改 configmap 中的配置;

  5. 再次访问 springcloudk8sreloadconfigdemo 的 http 接口,看返回的配置内容是否是修改后的;

  • 接下来,验证开始:

  1. 在 kubernetes 环境新建名为 springcloudk8sreloadconfigdemo.yml 的文件,内容如下:

kind: ConfigMapapiVersion: v1metadata:  name: springcloudk8sreloadconfigdemodata:  application.yml: |-    greeting:      message: Say Hello to the World    farewell:      message: Say Goodbye    ---    spring:      profiles: development    greeting:      message: Say Hello to the Developers    farewell:      message: Say Goodbye to the Developers    ---    spring:      profiles: production    greeting:      message: Say Hello to the Ops
复制代码


  1. 在 springcloudk8sreloadconfigdemo.yml 文件所在目录执行以下命令,即可在 kubernetes 创建名为 springcloudk8sreloadconfigdemo 的 configmap 的资源:

kubectl apply -f springcloudk8sreloadconfigdemo.yml
复制代码


  1. 在 springcloudk8sreloadconfigdemo 项目的 pom.xml 文件所在目录,执行以下命令,即可编译构建部署全部完成:

mvn clean install fabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes
复制代码


  • 操作成功后的控制台信息如下:

...[INFO] [INFO] <<< fabric8-maven-plugin:3.5.37:deploy (default-cli) < install @ springcloudk8sreloadconfigdemo <<<[INFO] [INFO] [INFO] --- fabric8-maven-plugin:3.5.37:deploy (default-cli) @ springcloudk8sreloadconfigdemo ---[INFO] F8: Using Kubernetes at https://192.168.121.128:8443/ in namespace default with manifest /usr/local/temp/201907/27/springcloudk8sreloadconfigdemo/target/classes/META-INF/fabric8/kubernetes.yml [INFO] Using namespace: default[INFO] Creating a Service from kubernetes.yml namespace default name springcloudk8sreloadconfigdemo[INFO] Created Service: target/fabric8/applyJson/default/service-springcloudk8sreloadconfigdemo.json[INFO] Using namespace: default[INFO] Creating a Deployment from kubernetes.yml namespace default name springcloudk8sreloadconfigdemo[INFO] Created Deployment: target/fabric8/applyJson/default/deployment-springcloudk8sreloadconfigdemo.json[INFO] F8: HINT: Use the command `kubectl get pods -w` to watch your pods start up[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time:  08:38 min[INFO] Finished at: 2019-07-27T18:56:21+08:00
复制代码


  1. 如果您的环境也是 minikube,可以执行以下命令查看服务地址:

minikube service springcloudk8sreloadconfigdemo --url
复制代码


  • 得到服务地址是:http://192.168.121.128:31178

  1. 浏览器访问地址:http://192.168.121.128:31178/hello ,得到响应如下图,可见已经从 configmap 取得了配置文件,并且加载成功:

修改 configmap 的配置

  • 接下来修改 configmap 的配置,看能不能在应用上立即生效。


  1. 执行以下命令进入 configmap 的编辑模式:


kubectl edit configmap springcloudk8sreloadconfigdemo
复制代码
  1. 在编辑模式下,就像 vim 编辑文本文件一样修改配置 springcloudk8sreloadconfigdemo 的内容,如下图红框所示,在原有的内容基础上增加一段"123456789":

  • 修改完毕后记得保存退出;

3. 浏览器访问地址:http://192.168.121.128:31178/hello ,得到响应如下图,可见刚刚的修改已经立即生效了:


  • 至此验证通过,confimap 修改的内容可以实时同步到我们的 java 应用;

尝试另一种同步模式

  • 回顾一下 bootstrap.yml 中和同步配置相关的参数,如下图红框所示:

  • polling 是定时拉取的模式,间隔时间太大会影响实时性,太小又导致请求过于密集,所以 spring-cloud-kubernetes 框架还给出了另一种模式:事件通知,对应的值是 event;

  • 设置事件通知模式的步骤:先将 mode 的值从 polling 改为 event,再将 period 参数注释掉(该参数只在 mode 等于 polling 时有效),修改后如下:

  • 修改后,再次执行 mvn 命令构建和部署应用,然后将前面的验证步骤再做一次,看修改能否立即生效,具体的操作就不在此重复了,您自行验证即可;

  • 至此,spring-cloud-kubernetes 与 k8s 的 configmap 的实战就完成了,尽管上一章已经能使用 k8s 的 configmap,但是无法实时获取到 configmap 的变更,今天的实战弥补了这一遗憾,通过两种同步方式,任何配置的变更都能同步到我们的应用中。

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 2022 年 04 月 22 日阅读数: 38
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
spring-cloud-kubernetes自动同步k8s的configmap更新_Java_程序员欣宸_InfoQ写作社区