天天看點

內建 Kubernetes 來建構微服務-spring cloud 入門教程

Spring Cloud和Kubernetes是目前Java平台下微服務應用的使用得最多的産品。然而,當談到微服務架構時,它們有時被描述為具有競争力的解決方案。它們都在微服務架構中實作流行的模式,如服務發現、分布式配置、負載平衡或斷路。當然,他們的做法不同。

Kubernetes 是一個用于運作、擴充和管理容器化應用程式的平台。Kubernetes 最重要的元件之一是etcd。該高度可用的鍵值存儲負責存儲所有叢集資料,包括服務系統資料庫和應用程式配置。我們不能用任何其他工具代替它。可以使用Istio或 Linkerd等第三方元件來實作更進階的路由和負載均衡政策。要在 Kubernetes 上部署和運作應用程式,我們無需在源代碼中添加任何内容。編排和配置是在應用程式之外實作的——在平台上。

Spring Cloud 提出了一種不同的方法。所有元件都必須在應用程式端包含和配置。它為我們提供了許多與用于雲原生開發的各種工具和架構內建的可能性。但是,一開始 Spring Cloud 是圍繞 Eureka、Ribbon等 Netflix OSS 元件建構的、Hystrix 或 Zuul。它為我們提供了一種機制,可以輕松地将它們包含到我們基于微服務的架構中,并将它們與其他雲原生元件內建。一段時間後,必須重新考慮這種方法。今天,我們有很多由 Spring Cloud 開發的元件,比如 Spring Cloud Gateway(Zuul 替代品)、Spring Cloud Load Balancer(Ribbon 替代品)、Spring Cloud Circuit Breaker(Hystrix 替代品)。還有一個相對較新的與Kubernetes內建的項目——Spring Cloud Kubernetes。

為什麼選擇 Spring Cloud Kubernetes?

在我們将微服務遷移到 OpenShift 時,Spring Cloud Kubernetes 項目正處于孵化階段。由于我們沒有任何其他有趣的從 Spring Cloud 遷移到 OpenShift 的選擇,包括從 Spring Boot 應用程式中删除用于發現(Eureka 用戶端)和配置(Spring Cloud Config 用戶端)的元件。當然,我們仍然可以使用其他 Spring Cloud 元件,如 OpenFeign、Ribbon(通過 Kubernetes 服務)或 Sleuth。那麼,問題是我們真的需要 Spring Cloud Kubernetes 嗎?哪些功能對我們來說會很有趣。

首先,讓我們看看在 Spring Cloud Kubernetes 文檔站點上建構一個新架構的動機。

Spring Cloud Kubernetes 提供使用 Kubernetes 原生服務的 Spring Cloud 通用接口實作。此存儲庫中提供的項目的主要目标是促進在 Kubernetes 内運作的 Spring Cloud 和 Spring Boot 應用程式的內建。

簡單來說,Spring Cloud Kubernetes 提供了與Kubernetes Master API 的內建,以允許以 Spring Cloud 的方式使用發現、配置和負載平衡。

在本文中,我将介紹 Spring Cloud Kubernetes 的以下有用功能:

  • 使用 DiscoveryClient 支援在所有命名空間中擴充發現
  • 在 Spring Cloud Kubernetes Config 中使用 ConfigMap 和 Secrets 作為 Spring Boot 屬性源
  • 使用 Spring Cloud Kubernetes pod 健康名額實作健康檢查

啟用 Spring Cloud Kubernetes

假設我們将使用 Spring Cloud Kubernetes 提供的更多功能,我們應該将以下依賴項包含到我們的 Maven 中

pom.xml

。它包含用于發現、配置和功能區負載平衡的子產品。

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-kubernetes-all</artifactId>
</dependency>           

跨所有命名空間的發現

Spring Cloud Kubernetes 通過提供

DiscoveryClient

. 我們還可以利用與 Ribbon 用戶端的内置內建,在不使用 Kubernetes 服務的情況下直接與 Pod 通信。Ribbon 用戶端可以被更進階别的 HTTP 用戶端——OpenFeign 所利用。要實作這樣的模型,我們必須啟用發現用戶端、Feign 用戶端和 Mongo 存儲庫,因為我們使用 Mongo 資料庫作為後端存儲。

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableMongoRepositories
public class DepartmentApplication {
   
   public static void main(String[] args) {
      SpringApplication.run(DepartmentApplication.class, args);
   }

}
           

讓我們考慮一下我們有三個微服務的場景,每個微服務都部署在不同的命名空間中。劃分命名空間隻是一個邏輯分組,例如我們有三個不同的團隊負責每個微服務,我們希望隻将命名空間的權限授予負責給定應用程式的團隊。在位于不同命名空間的應用程式之間的通信中,我們必須在調用 URL 上包含一個命名空間名稱作為字首。我們還需要設定一個可能因應用程式而異的端口号。在這種情況下,Spring Cloud Kubernetes 發現會提供幫助。由于 Spring Cloud Kubernetes 與主 API 內建,是以能夠擷取為同一應用程式建立的所有 pod 的 IP。這是說明我們場景的圖表。

內建 Kubernetes 來建構微服務-spring cloud 入門教程

要啟用跨所有命名空間的發現,我們隻需要使用以下屬性。

spring:
  cloud:
    kubernetes:
      discovery:
        all-namespaces: true
           

現在,我們可以實作負責消費目标端點的 Feign 用戶端接口。這是來自部門服務的示例用戶端,專門用于與員工服務進行通信。

@FeignClient(name = "employee")
public interface EmployeeClient {

   @GetMapping("/department/{departmentId}")
   List<Employee> findByDepartment(@PathVariable("departmentId") String departmentId);
   
}
           

Spring Cloud Kubernetes 需要通路 Kubernetes API,以便能夠檢索為單個服務運作的 pod 的位址清單。使用 Minikube 時最簡單的方法是

ClusterRoleBinding

使用

cluster-admin

特權建立預設值。運作以下指令後,您可以確定每個 Pod 都有足夠的權限與 Kubernetes API 通信。

$ kubectl create clusterrolebinding admin --clusterrole=cluster-admin --serviceaccount=default:default
           

使用 Kubernetes PropertySource 進行配置

Spring Cloud Kubernetes

PropertySource

實作允許我們直接在應用程式中使用

ConfigMap

和使用,

Secret

而無需将它們注入

Deployment

. 預設行為基于

metadata.name

inside 

ConfigMap

or 

Secret

,它必須與應用程式名稱相同(由其

spring.application.name

屬性定義)。您還可以使用更進階的行為,您可以為配置注入定義命名空間和對象的自定義名稱。您甚至可以使用多個

ConfigMap

Secret

執行個體。但是,我們使用預設行為,是以假設我們有以下内容

bootstrap.yml

spring:
  application:
    name: employee
           

我們将定義以下内容

ConfigMap

kind: ConfigMap
apiVersion: v1
metadata:
  name: employee
data:
  logging.pattern.console: "%d{HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
  spring.cloud.kubernetes.discovery.all-namespaces: "true"
  spring.data.mongodb.database: "admin"
  spring.data.mongodb.host: "mongodb.default"
           

或者,您可以在

ConfigMap

.

apiVersion: v1
kind: ConfigMap
metadata:
  name: employee
data:
  application.yaml: |-
    logging.pattern.console: "%d{HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
    spring.cloud.kubernetes.discovery.all-namespaces: true
    spring:
      data:
        mongodb:
          database: admin
          host: mongodb.default
           

在配置映射中,我們定義了 Mongo 位置、日志模式和負責允許多命名空間發現的屬性。Mongo 憑據應在

Secret

對象内部定義。規則與配置映射相同。

apiVersion: v1
kind: Secret
metadata:
  name: employee
type: Opaque
data:
  spring.data.mongodb.username: UGlvdF8xMjM=
  spring.data.mongodb.password: cGlvdHI=
           

值得注意的是,出于安全原因,預設情況下不啟用通過 API 使用機密。但是,我們已經設定了預設

cluster-admin

角色,是以我們不必擔心。我們唯一需要做的就是通過 Spring Cloud Kubernetes 的 API 啟用使用機密,預設情況下該 API 是禁用的。為此,我們必須在

bootstrap.yml

spring:
  cloud:
    kubernetes:
      secrets:
        enableApi: true
           

在 Minikube 上部署 Spring Cloud 應用程式

首先,讓我們使用

kubectl create namespace

指令建立所需的命名空間。下面是建立命名空間的指令

a

b

c

d

內建 Kubernetes 來建構微服務-spring cloud 入門教程

然後,讓我們通過執行 Maven

mvn clean install

指令來建構代碼。

內建 Kubernetes 來建構微服務-spring cloud 入門教程

我們還需要設定

cluster-admin

新建立的命名空間,以允許在這些命名空間内運作的 Pod 讀取主 API。

內建 Kubernetes 來建構微服務-spring cloud 入門教程

現在,讓我們看看我們的 Kubernetes 部署清單。它非常簡單,因為它沒有從

ConfigMap

和注入任何屬性

Secret

。它已經由 Spring Cloud Kubernetes Config 執行。這是employee-service的部署 YAML 檔案。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: employee
  labels:
    app: employee
spec:
  replicas: 1
  selector:
    matchLabels:
      app: employee
  template:
    metadata:
      labels:
        app: employee
    spec:
      containers:
      - name: employee
        image: piomin/employee:1.1
        ports:
        - containerPort: 8080
           

最後,我們可以在 Kubernetes 上部署我們的應用程式。每個微服務有

ConfigMap

Secret

Deployment

Service

對象。YAML 清單在

/kubernetes

目錄内的 Git 存儲庫中可用。我們使用

kubectl apply

如下所示的指令依次應用它們。

出于測試目的,您可以通過定義

NodePort

類型在節點外公開示例應用程式。

apiVersion: v1
kind: Service
metadata:
  name: department
  labels:
    app: department
spec:
  ports:
  - port: 8080
    protocol: TCP
  selector:
    app: department
  type: NodePort
           

公開有關 Pod 的資訊

如果你定義了你

Service

NodePort

你可以在 Minikube 之外輕松通路它。要檢索目标端口,隻需執行

kubectl get svc

如下所示。現在,您可以使用 address 調用它

http://192.168.99.100:31119

內建 Kubernetes 來建構微服務-spring cloud 入門教程

使用 Spring Cloud Kubernetes,每個 Spring Boot 應用程式都會公開有關 pod ip、pod 名稱和命名空間名稱的資訊。要輸入它,您需要調用

/info

端點,如下所示。

內建 Kubernetes 來建構微服務-spring cloud 入門教程

這是部署所有示例微服務和網關後分布在所有命名空間之間的 pod 清單。

內建 Kubernetes 來建構微服務-spring cloud 入門教程

還有一個部署清單。

內建 Kubernetes 來建構微服務-spring cloud 入門教程

運作網關

我們架構中的最後一個元素是網關。我們使用 Spring Cloud Netflix Zuul,它通過 Ribbon 用戶端與 Kubernetes 發現內建。它公開了分布在多個命名空間中的所有示例微服務的 Swagger 文檔。這是所需依賴項的清單。

<dependencies>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-kubernetes-all</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-sleuth</artifactId>
   </dependency>
   <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.2</version>
   </dependency>
   <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
   </dependency>
</dependencies>
           

路由的配置非常簡單。我們隻需要使用 Spring Cloud Kubernetes 發現功能。

apiVersion: v1
kind: ConfigMap
metadata:
  name: gateway
data:
  logging.pattern.console: "%d{HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n"
  spring.cloud.kubernetes.discovery.all-namespaces: "true"
  zuul.routes.department.path: "/department/**"
  zuul.routes.employee.path: "/employee/**"
  zuul.routes.organization.path: "/organization/**"
           

雖然 Zuul 代理與

DiscoveryClient

我們自動內建,但我們可以輕松配置微服務公開的動态解析 Swagger 端點。

@Configuration
public class GatewayApi {

   @Autowired
   ZuulProperties properties;

   @Primary
   @Bean
   public SwaggerResourcesProvider swaggerResourcesProvider() {
      return () -> {
         List<SwaggerResource> resources = new ArrayList<>();
         properties.getRoutes().values().stream()
               .forEach(route -> resources.add(createResource(route.getId(), "2.0")));
         return resources;
      };
   }

   private SwaggerResource createResource(String location, String version) {
      SwaggerResource swaggerResource = new SwaggerResource();
      swaggerResource.setName(location);
      swaggerResource.setLocation("/" + location + "/v2/api-docs");
      swaggerResource.setSwaggerVersion(version);
      return swaggerResource;
   }

}
           

通常,我們必須配置 Kubernetes

Ingress

才能通路網關。使用 Minikube,我們隻需要建立一個類型為 的服務

NodePort

。最後,我們可以開始使用在網關上公開的 Swagger UI 來測試我們的應用程式。但是在這裡,我們得到了一個意想不到的驚喜……跨所有命名空間的發現不适用于 Ribbon 用戶端。它僅适用于

DiscoveryClient

. 我認為 Ribbon 自動配置應該尊重 property 

spring.cloud.kubernetes.discovery.all-namespaces

,但在這種情況下,除了準備解決方法之外我們别無選擇。我們的解決方法是覆寫 Spring Cloud Kubernetes 中提供的 Ribbon 用戶端自動配置。我們

DiscoveryClient

直接使用它,如下所示。

public class RibbonConfiguration {

    @Autowired
    private DiscoveryClient discoveryClient;

    private String serviceId = "client";
    protected static final String VALUE_NOT_SET = "__not__set__";
    protected static final String DEFAULT_NAMESPACE = "ribbon";

    public RibbonConfiguration () {
    }

    public RibbonConfiguration (String serviceId) {
        this.serviceId = serviceId;
    }

    @Bean
    @ConditionalOnMissingBean
    public ServerList<?> ribbonServerList(IClientConfig config) {

        Server[] servers = discoveryClient.getInstances(config.getClientName()).stream()
                .map(i -> new Server(i.getHost(), i.getPort()))
                .toArray(Server[]::new);

        return new StaticServerList(servers);
    }

}
           

Ribbon 配置類需要在主類上設定。

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@EnableSwagger2
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)
public class GatewayApplication {

   public static void main(String[] args) {
      SpringApplication.run(GatewayApplication.class, args);
   }

}
           

現在,我們終于可以利用多命名空間發現和負載平衡,并使用網關上公開的 Swagger UI 輕松測試它。

內建 Kubernetes 來建構微服務-spring cloud 入門教程

使用 Zuul、Ribbon、Feign、Eureka 和 Sleuth、Zipkin 建立簡單spring cloud微服務用例-spring cloud 入門教程

微服務內建SPRING CLOUD SLEUTH、ELK 和 ZIPKIN 進行監控-spring cloud 入門教程

使用Hystrix 、Feign 和 Ribbon建構微服務-spring cloud 入門教程

使用 Spring Boot Admin 監控微服務-spring cloud 入門教程

基于Redis做Spring Cloud Gateway 中的速率限制實踐-spring cloud 入門教程

內建SWAGGER2服務-spring cloud 入門教程

Hystrix 簡介-spring cloud 入門教程

Hystrix 原理深入分析-spring cloud 入門教程 

使用Apache Camel建構微服務-spring cloud 入門教程

內建 Kubernetes 來建構微服務-spring cloud 入門教程

內建SPRINGDOC OPENAPI 的微服務實踐-spring cloud 入門教程

SPRING CLOUD 微服務快速指南-spring cloud 入門教程

基于GraphQL的微服務實踐-spring cloud 入門教程

最火的Spring Cloud Gateway 為經過身份驗證的使用者啟用速率限制實踐-spring cloud 入門教程

繼續閱讀