Guide to Spring Cloud Kubernetes – Spring Cloud Kubernetes指南

最后修改: 2019年 4月 12日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

When we build a microservices solution, both Spring Cloud and Kubernetes are optimal solutions, as they provide components for resolving the most common challenges. However, if we decide to choose Kubernetes as the main container manager and deployment platform for our solution, we can still use Spring Cloud’s interesting features mainly through the Spring Cloud Kubernetes project.

当我们构建微服务解决方案时,Spring CloudKubernetes都是最佳解决方案,因为它们提供了用于解决最常见挑战的组件。但是,如果我们决定选择Kubernetes作为我们解决方案的主要容器管理器和部署平台,我们仍然可以主要通过Spring Cloud Kubernetes项目使用Spring Cloud的有趣功能。

This relatively new project undoubtedly provides easy integration with Kubernetes for Spring Boot applications. Before starting, it may be helpful to look at how to deploy a Spring Boot application on Minikube, a local Kubernetes environment.

这个相对较新的项目无疑为Spring Boot应用程序提供了与Kubernetes的轻松集成。在开始之前,看看如何在Minikube上部署Spring Boot应用程序,这是一个本地Kubernetes环境.,可能会有所帮助。

In this tutorial, we’ll:

在本教程中,我们将。

  • Install Minikube on our local machine
  • Develop a microservices architecture example with two independent Spring Boot applications communicating through REST
  • Set up the application on a one-node cluster using Minikube
  • Deploy the application using YAML config files

2. Scenario

2.场景

In our example, we’re using the scenario of travel agents offering various deals to clients who will query the travel agents service from time to time. We’ll use it to demonstrate:

在我们的例子中,我们使用的场景是旅行社向客户提供各种交易,客户会不时地查询旅行社的服务。我们将用它来演示。

  • service discovery through Spring Cloud Kubernetes
  • configuration management and injecting Kubernetes ConfigMaps and secrets to application pods using Spring Cloud Kubernetes Config
  • load balancing using Spring Cloud Kubernetes Ribbon

3. Environment Setup

3.环境设置

First and foremost, we need to install Minikube on our local machine and preferably a VM driver such as VirtualBox. It’s also recommended to look at Kubernetes and its main features before following this environment setup.

首先,我们需要在本地机器上安装Minikube,最好是一个虚拟机驱动程序,如VirtualBox。此外,还建议在进行此环境设置之前,先看看Kubernetes及其主要功能。

Let’s start the local single-node Kubernetes cluster:

让我们启动本地单节点Kubernetes集群。

minikube start --vm-driver=virtualbox

This command creates a Virtual Machine that runs a Minikube cluster using the VirtualBox driver. The default context in kubectl will now be minikube. However, to be able to switch between contexts, we use:

这个命令创建了一个虚拟机,使用VirtualBox驱动运行一个Minikube集群。kubectl中的默认上下文现在将是minikube。然而,为了能够在上下文之间切换,我们使用。

kubectl config use-context minikube

After starting Minikube, we can connect to the Kubernetes dashboard to access the logs and monitor our services, pods, ConfigMaps, and Secrets easily:

启动Minikube后,我们可以连接到Kubernetes仪表板,以访问日志并轻松监控我们的服务、pods、ConfigMaps和Secrets。

minikube dashboard

3.1. Deployment

3.1.部署

Firstly, let’s get our example from GitHub.

首先,让我们从GitHub获得我们的例子。

At this point, we can either run the “deployment-travel-client.sh” script from the parent folder, or else execute each instruction one by one to get a good grasp of the procedure:

在这一点上,我们可以从父文件夹中运行 “deployment-travel-client.sh “脚本,或者逐一执行每条指令,以充分掌握程序。

### build the repository
mvn clean install

### set docker env
eval $(minikube docker-env)

### build the docker images on minikube
cd travel-agency-service
docker build -t travel-agency-service .
cd ../client-service
docker build -t client-service .
cd ..

### secret and mongodb
kubectl delete -f travel-agency-service/secret.yaml
kubectl delete -f travel-agency-service/mongo-deployment.yaml

kubectl create -f travel-agency-service/secret.yaml
kubectl create -f travel-agency-service/mongo-deployment.yaml

### travel-agency-service
kubectl delete -f travel-agency-service/travel-agency-deployment.yaml
kubectl create -f travel-agency-service/travel-agency-deployment.yaml

### client-service
kubectl delete configmap client-service
kubectl delete -f client-service/client-service-deployment.yaml

kubectl create -f client-service/client-config.yaml
kubectl create -f client-service/client-service-deployment.yaml

# Check that the pods are running
kubectl get pods

4. Service Discovery

4.服务发现

This project provides us with an implementation for the ServiceDiscovery interface in Kubernetes. In a microservices environment, there are usually multiple pods running the same service. Kubernetes exposes the service as a collection of endpoints that can be fetched and reached from within a Spring Boot Application running in a pod in the same Kubernetes cluster.

该项目为我们提供了Kubernetes中ServiceDiscovery接口的实现。在微服务环境中,通常有多个pod在运行同一个服务。Kubernetes将服务暴露为端点的集合,这些端点可以从运行在同一Kubernetes集群的Pod中的Spring Boot应用程序中获取和到达。

For instance, in our example, we have multiple replicas of the travel agent service, which is accessed from our client service as http://travel-agency-service:8080. However, this internally would translate into accessing different pods such as travel-agency-service-7c9cfff655-4hxnp.

例如,在我们的例子中,我们有多个旅行社服务的副本,它从我们的客户服务中被访问为http://travel-agency-service:8080。然而,这在内部会转化为访问不同的pod,如travel-agency-service-7c9cfff655-4hxnp

Spring Cloud Kubernetes Ribbon uses this feature to load balance between the different endpoints of a service.

Spring Cloud Kubernetes Ribbon使用这一功能在服务的不同端点之间进行负载平衡。

We can easily use Service Discovery by adding the spring-cloud-starter-kubernetes dependency on our client application:

我们可以通过在我们的客户应用程序中添加spring-cloud-starter-kubernetes依赖项来轻松使用服务发现。

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

Also, we should add @EnableDiscoveryClient and inject the DiscoveryClient into the ClientController by using @Autowired in our class:

另外,我们应该添加@EnableDiscoveryClient,并通过在类中使用@AutowiredDiscoveryClient注入ClientController

@SpringBootApplication
@EnableDiscoveryClient
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
@RestController
public class ClientController {
    @Autowired
    private DiscoveryClient discoveryClient;
}

5. ConfigMaps

5.配置地图

Typically, microservices require some kind of configuration management. For instance, in Spring Cloud applications, we would use a Spring Cloud Config Server.

通常情况下,微服务需要某种配置管理。例如,在Spring Cloud应用程序中,我们将使用Spring Cloud配置服务器。

However, we can achieve this by using ConfigMaps provided by Kubernetes – provided that we intend to use it for non-sensitive, unencrypted information only. Alternatively, if the information we want to share is sensitive, then we should opt to use Secrets instead.

但是,我们可以通过使用Kubernetes提供的ConfigMaps来实现这一点–前提是我们打算将其仅用于非敏感的、未加密的信息。另外,如果我们要共享的信息是敏感的,那么我们应该选择使用Secrets来代替。

In our example, we’re using ConfigMaps on the client-service Spring Boot application. Let’s create a client-config.yaml file to define the ConfigMap of the client-service:

在我们的例子中,我们在client-service Spring Boot应用程序上使用ConfigMaps。让我们创建一个client-config.yaml文件来定义client-service的ConfigMap。

apiVersion: v1 by d
kind: ConfigMap
metadata:
  name: client-service
data:
  application.properties: |-
    bean.message=Testing reload! Message from backend is: %s <br/> Services : %s

It’s important that the name of the ConfigMap matches the name of the application as specified in our “application.properties” file. In this case, it’s client-service. Next, we should create the ConfigMap for client-service on Kubernetes:

重要的是,ConfigMap的名称要与我们的 “application.properties “文件中指定的应用程序的名称相匹配。在本例中,它是client-service。接下来,我们应该在Kubernetes上为client-service创建ConfigMap。

kubectl create -f client-config.yaml

Now, let’s create a configuration class ClientConfig with the @Configuration and @ConfigurationProperties and inject into the ClientController:

现在,让我们用@Configuration@ConfigurationProperties创建一个配置类ClientConfig并注入ClientController

@Configuration
@ConfigurationProperties(prefix = "bean")
public class ClientConfig {

    private String message = "Message from backend is: %s <br/> Services : %s";

    // getters and setters
}
@RestController
public class ClientController {

    @Autowired
    private ClientConfig config;

    @GetMapping
    public String load() {
        return String.format(config.getMessage(), "", "");
    }
}

If we don’t specify a ConfigMap, then we should expect to see the default message, which is set in the class. However, when we create the ConfigMap, this default message gets overridden by that property.

如果我们不指定ConfigMap,那么我们应该期望看到默认的消息,这是在类中设置的。然而,当我们创建ConfigMap时,这个默认消息会被该属性覆盖。

Additionally, every time we decide to update the ConfigMap, the message on the page changes accordingly:

此外,每次我们决定更新ConfigMap时,页面上的信息也会相应改变。

kubectl edit configmap client-service

6. Secrets

6.秘密

Let’s look at how Secrets work by looking at the specification of MongoDB connection settings in our example. We’re going to create environment variables on Kubernetes, which will then be injected into the Spring Boot application.

让我们看看秘诀是如何工作的,在我们的例子中,我们要看一下MongoDB连接设置的规范。我们将在Kubernetes上创建环境变量,然后将其注入到Spring Boot应用程序中。

6.1. Create a Secret

6.1.创建一个秘密

The first step is to create a secret.yaml file, encoding the username and password to Base 64:

第一步是创建一个secret.yaml文件,将usernamepassword编码为Base 64

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
data:
  username: dXNlcg==
  password: cDQ1NXcwcmQ=

Let’s apply the Secret configuration on the Kubernetes cluster:

让我们在Kubernetes集群上应用秘密配置。

kubectl apply -f secret.yaml

6.2. Create a MongoDB Service

6.2.创建一个MongoDB服务

We should now create the MongoDB service and the deployment travel-agency-deployment.yaml file. In particular, in the deployment part, we’ll use the Secret username and password that we defined previously:

我们现在应该创建MongoDB服务和部署travel-agency-deployment.yaml文件。特别是在部署部分,我们将使用之前定义的Secret usernamepassword

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: mongo
spec:
  replicas: 1
  template:
    metadata:
      labels:
        service: mongo
      name: mongodb-service
    spec:
      containers:
      - args:
        - mongod
        - --smallfiles
        image: mongo:latest
        name: mongo
        env:
          - name: MONGO_INITDB_ROOT_USERNAME
            valueFrom:
              secretKeyRef:
                name: db-secret
                key: username
          - name: MONGO_INITDB_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:
                name: db-secret
                key: password

By default, the mongo:latest image will create a user with username and password on a database named admin.

默认情况下,mongo:latest镜像将在名为admin.的数据库上创建一个具有usernamepassword的用户。

6.3. Setup MongoDB on Travel Agency Service

6.3.在旅行社服务上设置MongoDB

It’s important to update the application properties to add the database related information. While we can freely specify the database name admin, here we’re hiding the most sensitive information such as the username and the password:

更新应用程序属性以添加数据库相关信息是很重要的。虽然我们可以自由指定数据库名称admin,但在这里我们要隐藏最敏感的信息,如usernamepassword

spring.cloud.kubernetes.reload.enabled=true
spring.cloud.kubernetes.secrets.name=db-secret
spring.data.mongodb.host=mongodb-service
spring.data.mongodb.port=27017
spring.data.mongodb.database=admin
spring.data.mongodb.username=${MONGO_USERNAME}
spring.data.mongodb.password=${MONGO_PASSWORD}

Now, let’s take a look at our travel-agency-deployment property file to update the services and deployments with the username and password information required to connect to the mongodb-service.

现在,让我们看看我们的travel-agency-deployment属性文件,用连接到mongodb-service所需的用户名和密码信息更新服务和部署。

Here’s the relevant section of the file, with the part related to the MongoDB connection:

下面是文件的相关部分,其中与MongoDB连接有关的部分。

env:
  - name: MONGO_USERNAME
    valueFrom:
      secretKeyRef:
        name: db-secret
        key: username
  - name: MONGO_PASSWORD
    valueFrom:
      secretKeyRef:
        name: db-secret
        key: password

7. Communication with Ribbon

7.与Ribbon的沟通

In a microservices environment, we generally need the list of pods where our service is replicated in order to perform load-balancing. This is accomplished by using a mechanism provided by Spring Cloud Kubernetes Ribbon. This mechanism can automatically discover and reach all the endpoints of a specific service, and subsequently, it populates a Ribbon ServerList with information about the endpoints.

在微服务环境中,我们通常需要我们的服务被复制的pod列表,以便执行负载平衡。这可以通过使用Spring Cloud Kubernetes Ribbon提供的机制来实现。该机制可以自动发现并到达特定服务的所有端点,随后,它将端点的信息填充到Ribbon ServerList

Let’s start by adding the spring-cloud-starter-kubernetes-ribbon dependency to our client-service pom.xml file:

我们先把spring-cloud-starter-kubernetes-ribbon依赖性添加到我们的client-service pom.xml文件中。

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

The next step is to add the annotation @RibbonClient to our client-service application:

下一步是将注解@RibbonClient添加到我们的client-service应用程序。

@RibbonClient(name = "travel-agency-service")

When the list of the endpoints is populated, the Kubernetes client will search the registered endpoints living in the current namespace/project matching the service name defined using the @RibbonClient annotation.

当端点列表被填充后,Kubernetes客户端将搜索生活在当前命名空间/项目中的注册端点,这些端点与使用@RibbonClient注释定义的服务名称相匹配。

We also need to enable the ribbon client in the application properties:

我们还需要在应用程序属性中启用Ribbon客户端。

ribbon.http.client.enabled=true

8. Additional Features

8.附加功能

8.1. Hystrix

8.1.Hystrix

Hystrix helps in building a fault-tolerant and resilient application. Its main aims are fail fast and rapid recovery.

Hystrix有助于建立一个容错和弹性的应用程序。其主要目的是快速故障和快速恢复。

In particular, in our example, we’re using Hystrix to implement the circuit breaker pattern on the client-server by annotating the Spring Boot application class with @EnableCircuitBreaker.

特别是在我们的例子中,我们使用Hystrix在client-server上实现断路器模式,方法是用@EnableCircuitBreaker注释Spring Boot应用类。

Additionally, we’re using the fallback functionality by annotating the method TravelAgencyService.getDeals() with @HystrixCommand(). This means that in case of fallback the getFallBackName() will be called and “Fallback” message returned:

此外,我们通过用@HystrixCommand()注释方法TravelAgencyService.getDeals()来使用回退功能。这意味着在回退的情况下,getFallBackName()将被调用并返回 “回退 “消息。

@HystrixCommand(fallbackMethod = "getFallbackName", commandProperties = { 
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") })
public String getDeals() {
    return this.restTemplate.getForObject("http://travel-agency-service:8080/deals", String.class);
}

private String getFallbackName() {
    return "Fallback";
}

8.2. Pod Health Indicator

8.2.Bean荚健康指标

We can take advantage of Spring Boot HealthIndicator and Spring Boot Actuator to expose health-related information to the user.

我们可以利用Spring BootHealthIndicatorSpring Boot Actuator来向用户公开与健康有关的信息。

In particular, the Kubernetes health indicator provides:

特别是,Kubernetes健康指标提供。

  • pod name
  • IP address
  • namespace
  • service account
  • node name
  • a flag that indicates whether the Spring Boot application is internal or external to Kubernetes

9. Conclusion

9.结语

In this article, we provide a thorough overview of the Spring Cloud Kubernetes project.

在这篇文章中,我们对Spring Cloud Kubernetes项目进行了全面介绍。

So why should we use it? If we root for Kubernetes as a microservices platform but still appreciate the features of Spring Cloud, then Spring Cloud Kubernetes gives us the best of both worlds.

那么我们为什么要使用它呢?如果我们把Kubernetes作为一个微服务平台,但仍然欣赏Spring Cloud的功能,那么Spring Cloud Kubernetes给我们提供了两个世界的最佳选择。

The full source code of the example is available over on GitHub.

该示例的完整源代码可在GitHub上获取