Spring Cloud 部署時如何使用 Kubernetes 作為註冊中心和配置中心

张永清發表於2024-05-10

一、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中指定多個(精確的)檔案路徑。

NameTypeDefaultDescription

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

spring.cloud.kubernetes.config.enableApi

Boolean

true

Enable or disable consuming ConfigMap instances through APIs

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 KeyTypeDefault 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

相關文章