Ръководство за пролетния облак Kubernetes

1. Общ преглед

Когато изграждаме решение за микроуслуги, Spring Cloud и Kubernetes са оптимални решения, тъй като осигуряват компоненти за разрешаване на най-често срещаните предизвикателства. Ако обаче решим да изберем Kubernetes като основен мениджър на контейнери и платформа за внедряване на нашето решение, все пак можем да използваме интересните функции на Spring Cloud главно чрез проекта Spring Cloud Kubernetes.

Този относително нов проект несъмнено осигурява лесна интеграция с Kubernetes за приложенията Spring Boot. Преди да започнете, може да е полезно да разгледате как да разположите приложението Spring Boot в Minikube, локална среда на Kubernetes .

В този урок ще:

  • Инсталирайте Minikube на нашата локална машина
  • Разработете пример за архитектура на микроуслуги с две независими приложения Spring Boot, комуникиращи чрез REST
  • Настройте приложението на клъстер с един възел, като използвате Minikube
  • Разгърнете приложението с помощта на YAML конфигурационни файлове

2. Сценарий

В нашия пример използваме сценария на туристически агенти, предлагащи различни сделки на клиенти, които от време на време ще заявяват услугата на туристическите агенти. Ще го използваме, за да демонстрираме:

  • откриване на услуги чрез Spring Cloud Kubernetes
  • управление на конфигурацията и инжектиране на Kubernetes Config Карти и тайни на подсистеми на приложения с помощта на Spring Cloud Kubernetes Config
  • балансиране на натоварването с помощта на Spring Cloud Kubernetes Ribbon

3. Настройка на околната среда

Първо и най-важно, трябва да инсталираме Minikube на нашата локална машина и за предпочитане VM драйвер като VirtualBox. Също така се препоръчва да разгледате Kubernetes и основните му характеристики, преди да следвате тази настройка на средата.

Нека започнем локалния клъстер Kubernetes с един възел:

minikube start --vm-driver=virtualbox

Тази команда създава виртуална машина, която изпълнява клъстер Minikube, използвайки драйвера VirtualBox. Контекстът по подразбиране в kubectl сега ще бъде minikube . Въпреки това, за да можем да превключваме между контексти, използваме:

kubectl config use-context minikube

След стартирането на Minikube можем да се свържем с таблото за управление на Kubernetes, за да осъществим достъп до дневниците и да наблюдаваме лесно нашите услуги, подсистеми, ConfigMaps и Secrets:

minikube dashboard 

3.1. Разгръщане

Първо, нека вземем нашия пример от GitHub.

На този етап можем или да стартираме скрипта “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. Откриване на услугата

Този проект ни предоставя внедряване на интерфейса ServiceDiscovery в Kubernetes. В среда на микроуслуги обикновено има множество подсистеми, изпълняващи една и съща услуга. Kubernetes излага услугата като колекция от крайни точки, които могат да бъдат извлечени и достигнати от приложението Spring Boot, работещо в под в същия клъстер на Kubernetes.

Например, в нашия пример имаме множество копия на услугата за туристически агент, която е достъпна от нашата услуга за клиенти като // travel-agency-service: 8080 . Това обаче би се превърнало в достъп до различни подгрупи като travel-agency-service-7c9cfff655-4hxnp .

Spring Cloud Kubernetes Ribbon използва тази функция, за да зареди баланса между различните крайни точки на услугата.

Лесно можем да използваме Service Discovery, като добавим зависимостта spring-cloud-starter-kubernetes към нашето клиентско приложение:

 org.springframework.cloud spring-cloud-starter-kubernetes 

Също така трябва да добавим @EnableDiscoveryClient и да инжектираме DiscoveryClient в ClientController, като използваме @Autowired в нашия клас:

@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

Обикновено микроуслугите изискват някакъв вид управление на конфигурацията . Например в приложенията на Spring Cloud бихме използвали Spring Cloud Config Server.

Можем обаче да постигнем това, като използваме ConfigMaps, предоставени от Kubernetes - при условие, че възнамеряваме да го използваме само за нечувствителна, некриптирана информация. Като алтернатива, ако информацията, която искаме да споделим, е чувствителна, тогава вместо това трябва да изберем да използваме Secrets.

В нашия пример използваме ConfigMaps в приложението Spring Boot на клиентската услуга . Нека създадем клиентска конфигурация. yaml файл за дефиниране на ConfigMap на клиентската услуга :

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

Services : %s

Важно е името на ConfigMap да съвпада с името на приложението, както е посочено в нашия файл „application.properties“. В този случай това е услуга за клиенти . След това трябва да създадем ConfigMap за клиентска услуга на Kubernetes:

kubectl create -f client-config.yaml

Сега, нека създадем конфигурационен клас ClientConfig с @Configuration и @ConfigurationProperties и инжектираме в ClientController :

@Configuration @ConfigurationProperties(prefix = "bean") public class ClientConfig { private String message = "Message from backend is: %s

Services : %s"; // getters and setters }

@RestController public class ClientController { @Autowired private ClientConfig config; @GetMapping public String load() { return String.format(config.getMessage(), "", ""); } }

Ако не посочим ConfigMap, трябва да очакваме да видим съобщението по подразбиране, което е зададено в класа. Когато обаче създаваме ConfigMap, това съобщение по подразбиране се заменя от това свойство.

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

kubectl edit configmap client-service

6. Secrets

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.

6.1. Create a Secret

The first step is to create a secret.yaml file, encoding the username and password to 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:

kubectl apply -f secret.yaml

6.2. Create a MongoDB Service

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:

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.

6.3. Setup MongoDB on Travel Agency Service

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:

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.

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

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

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.

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

 org.springframework.cloud spring-cloud-starter-kubernetes-ribbon 

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

@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.

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

ribbon.http.client.enabled=true

8. Additional Features

8.1. Hystrix

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

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.

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(fallbackMethod = "getFallbackName", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") }) public String getDeals() { return this.restTemplate.getForObject("//travel-agency-service:8080/deals", String.class); } private String getFallbackName() { return "Fallback"; }

8.2. Pod Health Indicator

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

In particular, the Kubernetes health indicator provides:

  • pod name
  • IP address
  • namespace
  • service account
  • node name
  • флаг, който показва дали приложението Spring Boot е вътрешно или външно за Kubernetes

9. Заключение

В тази статия предоставяме задълбочен преглед на проекта Spring Cloud Kubernetes.

И така, защо да го използваме? Ако корен за Kubernetes като платформа за микроуслуги, но все пак оценяваме характеристиките на Spring Cloud, тогава Spring Cloud Kubernetes ни дава най-доброто от двата свята.

Пълният изходен код на примера е достъпен в GitHub.