一、Spring Cloud 支持的常见注册中心和配置中心。
- Spring Cloud 自带的注册中心Eureka以及config配置中心
- Nacos,支持注册中心和配置中心等,可以参考:https://www.cnblogs.com/laoqing/p/17797759.html
- Zookeeper
- Consul
- Etcd
- Kubernetes ,当Spring Cloud 服务都是通过Kubernetes 部署时,可以使用Kubernetes 作为注册中心和配置中心。
二、Spring Cloud 部署时如何使用 Kubernetes 作为注册中心和配置中心
Spring Cloud Kubernetes提供了使用Kubernete本地服务的Spring Cloud通用接口实现。该存储库中提供的项目的主要目标是促进在Kubernetes中运行的Spring Cloud和Spring Boot应用程序的集成。
在Springboot中,Starters 是一种方便的依赖描述符,可以包含在应用程序中。包括一个启动器来获取特性集的依赖项和Spring Boot自动配置。在使用Kubernetes 作为注册中心和配置中心时,需要集成如下的Starters 。
1、将服务名称解析为Kubernetes Services的发现客户端实现。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>
示例代码:
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
//Then you can inject the client in your code simply by autowiring it, as the following example shows:
@Autowired
private DiscoveryClient discoveryClient;
配置项:
spring:
cloud:
kubernetes:
enabled: true
# discovery:
# all-namespaces: true
# enabled: true
2、从Kubernetes ConfigMaps和Secrets加载应用程序属性。ConfigMap或Secret更改时重新加载应用程序属性。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-config</artifactId>
</dependency>
使用 Kubernetes 的ConfigMap或Secret作为配置中心。
Kubernetes提供了一个名为ConfigMap的资源,以键值对或嵌入式application.properties或application.yaml文件的形式将要传递给应用程序的参数外部化。Spring Cloud Kubernetes Config项目使Kubernete ConfigMap实例在应用程序引导期间可用,并在观察到的ConfigMap实例上检测到更改时触发bean或Spring上下文的热重新加载。
默认行为是基于Kubernetes ConfigMap创建ConfigMapPropertySource,该ConfigMap的metadata.name值为Spring应用程序的名称(由其Spring.application.name属性定义)或bootstrap.properties文件中定义的自定义名称,位于以下键下:Spring.cloud.Kubernetes.config.name。
但是,可以使用多个ConfigMap实例进行更高级的配置。spring.cloud.kubernetes.config.sources列表使这成为可能。例如,您可以定义以下ConfigMap实例:
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
config:
name: default-name
namespace: default-namespace
sources:
# Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
- name: c1
# Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
- namespace: n2
# Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
- namespace: n3
name: c3
如果没有设置spring.cloud.kubernetes.config.namespace,则将在应用程序运行的命名空间中查找名为c1的ConfigMap。
找到的任何匹配的ConfigMap都将按如下方式进行处理:
应用各个配置属性。
将任何名为application.yaml的属性的内容作为yaml应用。
将任何名为application.properties的属性的内容作为属性文件应用。
上述流的唯一例外是ConfigMap包含单个键,该键指示文件是YAML或属性文件。在这种情况下,键的名称不必是application.yaml或application.properties(它可以是任何东西),并且属性的值被正确处理。此功能有助于使用类似以下内容创建ConfigMap的用例:
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
假设我们有一个名为demo的Spring Boot应用程序,它使用以下属性来读取其线程池配置。
pool.size.core
pool.size.maximum
这可以外部化为yaml格式的配置映射,如下所示:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
pool.size.core: 1
pool.size.max: 16
单个属性在大多数情况下都可以正常工作。然而,有时,嵌入yaml更方便。在这种情况下,我们使用一个名为application.yaml的属性来嵌入我们的yaml,如下所示:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yaml: |-
pool:
size:
core: 1
max:16
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
custom-name.yaml: |-
pool:
size:
core: 1
max:16
您还可以根据读取ConfigMap时合并在一起的活动配置文件,对Spring Boot应用程序进行不同的配置。您可以使用application.properties或application.yaml属性为不同的配置文件提供不同的属性值,指定特定于配置文件的值,每个值都在自己的文档中(由---序列表示),如下所示:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
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
要告诉Spring Boot应该在引导时启用哪个配置文件,可以传递Spring_PROFILES_ACTIVE环境变量。为此,您可以使用环境变量启动Spring Boot应用程序,您可以在容器规范的PodSpec中定义该环境变量。部署资源文件,如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-name
labels:
app: deployment-name
spec:
replicas: 1
selector:
matchLabels:
app: deployment-name
template:
metadata:
labels:
app: deployment-name
spec:
containers:
- name: container-name
image: your-image
env:
- name: SPRING_PROFILES_ACTIVE
value: "development"
使用ConfigMap实例的另一个选项是通过运行Spring Cloud Kubernetes应用程序并让Spring Cloud Kubornetes从文件系统中读取它们,将它们装载到Pod中。此行为由spring.cloud.kubernetes.config.paths属性控制。您可以在前面描述的机制的基础上使用它,也可以使用它来代替前面介绍的机制。可以使用、分隔符在spring.cloud.kubernetes.config.path中指定多个(精确的)文件路径。
Name | Type | Default | Description |
---|---|---|---|
spring.cloud.kubernetes.config.enabled |
Boolean |
true |
Enable Secrets PropertySource |
spring.cloud.kubernetes.config.name |
String |
${spring.application.name} |
Sets the name of ConfigMap to look up |
spring.cloud.kubernetes.config.namespace |
String |
Client namespace | Sets the Kubernetes namespace where to lookup |
spring.cloud.kubernetes.config.paths |
List |
null |
Sets the paths where ConfigMap instances are mounted |
Kubernetes有Secrets的概念,用于存储密码、OAuth令牌等敏感数据。该项目提供了与Secrets集成,使Spring Boot应用程序可以访问机密。您可以通过设置spring.cloud.kubernetes.secrets.enabled属性来显式启用或禁用此功能。
启用后,SecretsPropertySource从以下来源查找Kubernetes的Secrets:
从秘密装载中递归读取
以应用程序命名(由spring.application.name定义)
匹配一些标签
请注意,默认情况下,由于安全原因,不会启用通过API(上面第2点和第3点)使用Secrets。此外,我们建议容器通过装入的卷共享机密。如果您启用通过API消费机密,我们建议您使用[授权策略,如RBAC]来限制对机密的访问(https://kubernetes.io/docs/concepts/configuration/secret/#best-实践)。
如果发现了这些秘密,应用程序就可以使用它们的数据。
假设我们有一个名为demo的spring-boot应用程序,它使用属性读取其数据库配置。我们可以使用以下命令创建Kubernetes机密:
oc create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd
前面的命令将创建以下机密(可以通过使用oc-get-secrets-db-secret-o yaml看到):
apiVersion: v1
data:
password: cDQ1NXcwcmQ=
username: dXNlcg==
kind: Secret
metadata:
creationTimestamp: 2017-07-04T09:15:57Z
name: db-secret
namespace: default
resourceVersion: "357496"
selfLink: /api/v1/namespaces/default/secrets/db-secret
uid: 63c89263-6099-11e7-b3da-76d6186905a8
type: Opaque
请注意,数据包含create命令提供的文本的Base64编码版本。
然后您的应用程序可以使用此机密 --- 例如,通过将机密的值导出为环境变量:
apiVersion: v1
kind: Deployment
metadata:
name: ${project.artifactId}
spec:
template:
spec:
containers:
- env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
3、功能区客户端负载均衡器,具有从Kubernetes端点获得的服务器列表。
调用微服务的Spring Cloud客户端应用程序应该对依赖客户端负载平衡功能感兴趣,以便自动发现它可以在哪个端点访问给定的服务。这个机制已经在spring-cloud kubernetes ribbon项目中实现,其中kubernetes客户端填充一个ribbon ServerList,其中包含有关这些端点的信息。
该实现是以下启动器的一部分,您可以通过将其依赖项添加到pom文件中来使用它:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>
当填充端点列表时,Kubernetes客户端通过匹配Ribbon客户端注释中定义的服务名称来搜索当前命名空间或项目中的已注册端点,如下所示:
@RibbonClient(name = "name-service")
您可以通过使用以下格式在application.properties中提供属性(通过应用程序的专用ConfigMap)来配置Ribbon的行为:<服务名称>.bribbon<功能区配置键>,其中:
<服务的名称>对应于您通过Ribbon访问的服务名称,如使用@RibbonClient注释配置的(如前面示例中的名称服务)。
<Ribbon configuration key>是Ribbon的CommonClientConfigKey类定义的Ribbon配置键之一。
此外,spring cloud kubernetes ribbon项目定义了两个额外的配置键,以进一步控制ribbon与kubernetes的交互方式。特别是,如果一个端点定义了多个端口,则默认行为是使用找到的第一个端口。要更具体地选择要在多端口服务中使用的端口,可以使用PortName键。如果你想指定应该在哪个Kubernetes命名空间中查找目标服务,你可以使用KubernetsNamespace键,记住在这两种情况下都要用你的服务名称和功能区前缀作为这些键的前缀,如前所述。
Property Key | Type | Default Value |
---|---|---|
spring.cloud.kubernetes.ribbon.enabled | boolean | true |
spring.cloud.kubernetes.ribbon.mode | KubernetesRibbonMode |
POD |
spring.cloud.kubernetes.ribbon.cluster-domain | string | cluster.local |
spring.cloud.kubernetes.ribbon.mode支持POD和SERVICE模式。
POD模式是通过获取Kubernetes的POD IP地址并使用Ribbon来实现负载平衡。POD模式使用Ribbon的负载平衡不支持Kubernetes的负载平衡,不支持Istio的流量策略。
SERVICE模式直接基于功能区的服务名称。Get Kubernetes服务被连接到服务名称中。{namespace}.svc。{cluster.domain}:{port},例如:demo1.default.svc.cluster.local:8080。SERVICE模式使用Kubernetes服务的负载平衡来支持Istio的流量策略。
spring.cloud.kubernetes.ribbon.cluster-domain设置自定义的kubernetes集群域后缀。默认值为:"cluster.local"
4、所有Spring Cloud Kubernetes功能,当选择这个maven选项时,可以只加入这一个依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-all</artifactId>
</dependency>
更多关于Spring Cloud如何同Kubernetes 进行结合,可以参考https://cloud.spring.io/spring-cloud-kubernetes/spring-cloud-kubernetes.html