k8s系列-k8s中部署Spring Cloud Config

2,348 阅读8分钟

Spring Cloud Config简介

配置文件是我们再熟悉不过的了,尤其是 Spring Boot 项目,除了引入相应的 maven 包之外,剩下的工作就是完善配置文件了,例如 mysql、redis 、security 相关的配置。除了项目运行的基础配置之外,还有一些配置是与我们业务有关系的,比如说七牛存储、短信相关、邮件相关,或者一些业务上的开关。

对于一些简单的项目来说,我们一般都是直接把相关配置放在单独的配置文件中,以 properties 或者 yml 的格式出现,更省事儿的方式是直接放到 application.properties 或 application.yml 中。但是这样的方式有个明显的问题,那就是,当修改了配置之后,必须重启服务,否则配置无法生效。

Spring Cloud Config 应运而生。

使用Spring Cloud Config可以实现以下的功能

  • 集中管理配置
  • 不同环境,不同配置
  • 运行时期动态调整。并且在修改配置时不会停止微服务
  • 配置修改后自动更新

Spring Cloud Config 为分布式系统外部化配置提供了服务器端和客户端的支持,它包括Config Server 和 Config Client 两部分。默认使用 Git 存储配置内容(也可以使用Subversion、本地文件系统或 Vault 存储配置)。Config Client 会在微服务启动时,请求 Config Server以获取所需要的配置属性,并且缓存在本地以提高性能。

简单的逻辑视图如下

Spring Cloud Config

Spring Cloud Config项目结构

首先参照上篇文章将Eureka Server部署到kubernetes中,然后就能开始部署融入了Eureka的Spring Cloud Config搭建之路了。

首先我们需要在github上面创建一个仓库用于存放配置文件

关于仓库的组织结构可以参看我的另外一篇文章

Spring Cloud Config 管理 Git仓库的两种方式

此项目中我采用的是上文中的第一种组织方式,即多个项目共用一个git仓库,如图所示,每个目录对应一个项目。

仓库地址:github.com/zjy5755202/…

然后我们在Idea中创建一个Spring Cloud Config项目。

Spring Cloud Config需要配置核心maven依赖如下

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- spring cloud config 服务端包 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

<!-- eureka client 端包 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Spring Cloud Config中也不需要写任何的业务代码,只需要在启动类上面加上对应的注解即可。

@SpringBootApplication 标识这是一个启动类,并且把该启动类注入到容器中

@EnableConfigServer 标识该项目作为Spring Cloud中的配置中心

@EnableEurekaClient 标识该项目作为Spring Cloud中d的Eureka Client

Spring Cloud Config

同时,我们也需要创造两个配置文件bootstrap.yamlapplication.yaml

bootstrap.yaml和application.yaml的区别可以查看这篇文章。

Spring Cloud中bootstrap.yaml和application.yaml的区别

bootstrap.yaml

spring:
  application:
    name: ConfigServer
  cloud:
    config:
      server:
        git:
          #配置Git仓库地址以及账号密码
          uri: https://github.com/zjy5755202/spring-cloud-config.git
          username: github账号
          password: github密码
          #配置了文件搜索的位置
          search-paths: /{application}
          default-label: master


application.yaml

server:
  port: 8762

#配置eureka相关信息
eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      #此处的url填些的是上一篇文章中Eureka部署后在集群中的service IP:port/eureka
      defaultZone: http://10.152.183.24:8761/eureka
  instance:
    prefer-ip-address: true

Spring Cloud Config 部署到 k8s

首先需要在在项目中创建一个DockerFile文件

在idea中连接上远程机的docker

然后将此镜像推送到机器上面

此时在我们的机器上面运行docker images即可查看到镜像已经推送到机器上面, 然后使用docker tag命令重命名镜像

docker tag config:latest 1181370590/config:v0.0.1

使用docker push命令将此docker镜像推送到dockerHub中

docker push 1181370590/config:v0.0.1

然后创建Config.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: config
  labels:
    app: config

spec:
  replicas: 1
  selector:
    matchLabels:
      app: config
  template:
    metadata:
      labels:
        app: config
    spec:
      containers:
      - name: config
        image: 1181370590/config:v0.0.1
        ports:
        - containerPort: 8761
---
apiVersion: v1
kind: Service
metadata:
  name: config-server
spec:
  ports:
  - port: 8762
    protocol: TCP
    targetPort: 8762
  type: NodePort
  selector:
    app: config

使用命令部署

kubectl create -f Config.yaml

使用命令查看pod和service是否部署成功

kubectl get pods

kubectl get services

即可看到Eureka部署到了k8s集群当中

成功注册到Eureka中

能够查看仓库中的配置文件。

Spring Cloud Config 融入 Spring Cloud Bus

Spring Cloud Config 在项目启动时加载配置内容这一机制,导致了它存在一个缺陷,修改配置文件内容后,不会自动刷新。例如我们上面的项目,当服务已经启动的时候,去修改 github 上的配置文件内容,这时候,再次刷新页面,对不起,还是旧的配置内容,新内容不会主动刷新过来。

但是,总不能每次修改了配置后重启服务吧。如果是那样的话,还是不要用它了为好,直接用本地配置文件岂不是更快。

如果只有一个 client 端的话,那我们用 webhook的方法来手动刷新 ,设置手动刷新都不算太费事,但是如果端比较多的话呢,一个一个去手动刷新未免有点复杂。这样的话,我们可以借助 Spring Cloud Bus 的广播功能,让 client 端都订阅配置更新事件,当配置更新时,触发其中一个端的更新事件,Spring Cloud Bus 就把此事件广播到其他订阅端,以此来达到批量更新。

在此项目中我使用的是Spring Cloud Config + Spring Cloud Bus(其中选用了RabbitMQ)来实现自动更新配置中心的功能。

逻辑视图如下

项目融入Spring Cloud Bus

融入Spring Cloud Bus,首先需要做的就是在Spring Config Server端导入Spring Cloud Bus的maven依赖

    <!-- springcloud-bus依赖实现配置自动更新,rabbitmq -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>

然后在Server端的application.yaml中添加部分配置信息

server:
  port: 8762

  #配置bus相关消息
  cloud:
    bus:
      enabled: true
      trace:
        enabled: true
  #配置rabbitmq相关信息
  rabbitmq:
    host: rabbmq的地址,文章后部分会提到
    port: 5672
    username: guest
    password: guest

#配置eureka相关信息
eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://10.152.183.24:8761/eureka
  instance:
    prefer-ip-address: true
    status-page-url-path: actuator/info
    health-check-url-path: actuator/health

#暴露所有接口,暴露/bus/refresh接口
management:
  endpoints:
    web:
      exposure:
        #暴露/bus/refresh接口
        include: refresh
  endpoint:
    health:
      show-details: always

至此,Config Server端的改造基本完成。

接下来我们还需要在Config Client端做部分配置才能真正实现Bus自动刷新。

在Config Client中,需要在maven中导入如下依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

然后到application.yaml中添加如下配置

management.endpoints.web.exposure.include=refresh

最后在Controller上面加上@RefreshScope即可

部署融合后的项目到kubernetes

首先需要在k8s部署rabbitmq来提供消息总线的功能。

创建Rabbitmq.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    fabric8.io/iconUrl: https://raw.githubusercontent.com/docker-library/docs/81187b7b50f5af5bdb64d75882f4d9c782ad52c3/rabbitmq/logo.png
  labels:
    app: rabbitmq
    provider: rabbit
    version: 3.6.11-management
    group: com.rabbit
  name: rabbitmq
spec:
  replicas: 1
  selector:
    matchLabels:
      app: rabbitmq
      provider: rabbit
      group: com.rabbit
  template:
    metadata:
      annotations:
        fabric8.io/iconUrl: https://raw.githubusercontent.com/docker-library/docs/81187b7b50f5af5bdb64d75882f4d9c782ad52c3/rabbitmq/logo.png
      labels:
        app: rabbitmq
        provider: rabbit
        version: 3.6.11-management
        group: com.rabbit
    spec:
      containers:
      - env:
        - name: RABBITMQ_DEFAULT_USER
          value: "guest"
        - name: RABBITMQ_DEFAULT_PASS
          value: "guest"
        image: rabbitmq:3.6.11-management
        imagePullPolicy: IfNotPresent
        name: rabbitmq
        ports:
        - containerPort: 15672
          name: manager
        - containerPort: 5672
          name: broker
---
apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: Service
  metadata:
    annotations:
      api.service.kubernetes.io/path: /
      fabric8.io/iconUrl: https://raw.githubusercontent.com/docker-library/docs/81187b7b50f5af5bdb64d75882f4d9c782ad52c3/rabbitmq/logo.png
    labels:
      expose: "true"
      app: rabbitmq
      provider: rabbit
      version: 3.6.11-management
      group: com.rabbit
    name: mqadmin
  spec:
    ports:
    - name: http
      port: 15672
      protocol: TCP
      targetPort: 15672
    selector:
      app: rabbitmq
      provider: rabbit
      group: com.rabbit
- apiVersion: v1
  kind: Service
  metadata:
    annotations:
      api.service.kubernetes.io/path: /
      fabric8.io/iconUrl: https://raw.githubusercontent.com/docker-library/docs/81187b7b50f5af5bdb64d75882f4d9c782ad52c3/rabbitmq/logo.png
    labels:
      expose: "true"
      app: rabbitmq
      provider: rabbit
      version: 3.6.11-management
      group: com.rabbit
    name: rabbitmq
  spec:
    ports:
    - name: http
      port: 5672
      protocol: TCP
      targetPort: 5672
    selector:
      app: rabbitmq
      provider: rabbit
      group: com.rabbit

运行命令部署rabbitmq

kubectl create -f Rabbitmq.yaml

然后我们需要将spring cloud config中的rabbitmq的地址更改为rabbitmq在k8s中的service Ip.

修改好后就和之前一样,打包镜像到主机,重命名,上传到dockerhub即可。

kubectl delete -f Config.yaml
docker tag config-bus:latest 1181370590/config-bus:v0.0.1
docker push 1181370590/config-bus:v0.0.1

创建Config-bus.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: config
  labels:
    app: config

spec:
  replicas: 1
  selector:
    matchLabels:
      app: config-bus
  template:
    metadata:
      labels:
        app: config-bus
    spec:
      containers:
      - name: config-bus
        image: 1181370590/config-bus:v0.0.1
        ports:
        - containerPort: 8761
---
apiVersion: v1
kind: Service
metadata:
  name: config-server
spec:
  ports:
  - port: 8762
    protocol: TCP
    targetPort: 8762
  type: NodePort
  selector:
    app: config-bus

使用命令部署config-bus

kubectl create -f Config-bus.yaml

部署成功啦

参考文章

Spring Cloud Config 实现配置中心,看这一篇就够了

docker+k8s+springcloud微服务集群部署实例

SpringCloud系列教程 | 第八篇:Spring Cloud Bus 消息总线

SpringCloud学习系列之五-----配置中心(Config)和消息总线(Bus)完美使用版

k8s 部署rabbitmq单节点