1. 概述
當構建微服務解決方案時,Spring Cloud 和 Kubernetes 都是最佳選擇,因為它們提供瞭解決常見挑戰的組件。但是,如果決定選擇 Kubernetes 作為解決方案的主要容器管理器和部署平台,我們仍然可以通過 Spring Cloud Kubernetes 項目利用 Spring Cloud 的有趣功能。
這個相對較新的項目無疑為 Spring Boot 應用程序提供了與 Kubernetes 的便捷集成。在開始之前,查看如何在 Minikube(本地 Kubernetes 環境)上部署 Spring Boot 應用程序可能是有幫助的。
在本教程中,我們將:
- 在本地機器上安裝 Minikube
- 使用兩個獨立的 Spring Boot 應用程序通過 REST 進行通信,構建微服務架構示例
- 使用 Minikube 設置應用程序在一個節點集羣上
- 使用 YAML 配置文件的方式部署應用程序
2. 場景
在我們的示例中,我們使用旅行社向客户提供各種優惠的場景。客户會不時地查詢旅行社服務。我們將使用它來演示:
- 服務發現通過 Spring Cloud Kubernetes
- 配置管理以及使用 Spring Cloud Kubernetes Config 將 Kubernetes ConfigMaps 和 secrets 注入到應用程序 Pod 中
- 負載均衡使用 Spring Cloud Kubernetes Ribbon
3. 環境搭建
首先,我們需要在本地機器上安裝 Minikube,並最好使用如 VirtualBox 這樣的虛擬機驅動。 建議在按照此環境搭建步驟之前,先了解 Kubernetes 及其主要功能。
接下來,啓動本地單節點 Kubernetes 集羣:
minikube start --vm-driver=virtualbox此命令創建一個使用 VirtualBox 驅動程序運行 Minikube 集羣的虛擬機。 kubectl 的默認上下文現在將是 minikube。 但是,為了能夠在上下文之間切換,我們使用:
kubectl config use-context minikube在啓動 Minikube 後,我們可以連接到 Kubernetes 控制面板,以便輕鬆地訪問日誌並監控我們的服務、Pod、ConfigMap 和 Secret:
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 pods4. 服務發現
本項目提供了一個對 Kubernetes 中 ServiceDiscovery 接口的實現。 在微服務環境中,通常有多個 Pod 運行相同的服務。 Kubernetes 將服務暴露為一個端點的集合, 並且可以從運行在同一 Kubernetes 集羣中的 Spring Boot 應用程序(該應用程序位於 Pod 中)中獲取並訪問。
例如,在我們的示例中,我們有多個旅行代理服務的副本,該服務由我們的客户端服務通過 http://travel-agency-service:8080 訪問。 但是,這內部會轉化為訪問不同的 Pod,例如 travel-agency-service-7c9cfff655-4hxnp。
Spring Cloud Kubernetes Ribbon 利用這一特性來實現服務之間的負載均衡。
可以通過添加 spring-cloud-starter-kubernetes 依賴項到客户端應用程序中來輕鬆使用服務發現。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>此外,我們應該在我們的類中添加 @EnableDiscoveryClient</em/> 並使用 @Autowired</em/> 將 DiscoveryClient</em/> 注入到 ClientController</em/> 中:
@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 用於 client-service Spring Boot 應用程序。讓我們創建一個 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配置映射(ConfigMap)的名稱應與應用程序的名稱相匹配,如我們在“application.properties”文件中所指定的那樣。在這種情況下,它為client-service。接下來,我們需要在 Kubernetes 上創建 client-service 的配置映射:
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 <br/> Services : %s";
// getters and setters
}@RestController
public class ClientController {
@Autowired
private ClientConfig config;
@GetMapping
public String load() {
return String.format(config.getMessage(), "", "");
}
}如果未指定 ConfigMap,我們應該期望看到默認消息,該消息在類中設置。但是,當我們創建 ConfigMap 時,該默認消息會被該屬性覆蓋。
此外,每次我們決定更新 ConfigMap 時,頁面上的消息也會相應地更改:
kubectl edit configmap client-service6. 密鑰(Secrets)
讓我們通過分析 MongoDB 連接設置的規範,來了解 密鑰(Secrets) 的工作原理。我們將會在 Kubernetes 上創建環境變量,這些環境變量隨後會被注入到 Spring Boot 應用程序中。
6.1. 創建密鑰
第一步是創建名為 secret.yaml 的文件,其中編碼了 username 和 password,並使用 Base 64 編碼。
apiVersion: v1
kind: Secret
metadata:
name: db-secret
data:
username: dXNlcg==
password: cDQ1NXcwcmQ=讓我們在 Kubernetes 集羣上應用 Secret 配置:
kubectl apply -f secret.yaml6.2. 創建 MongoDB 服務
現在,我們應該創建 MongoDB 服務以及部署文件 travel-agency-deployment.yaml。 尤其是在部署部分,我們將使用我們之前定義的 Secret username 和 password:
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默認情況下,mongo:latest 鏡像將創建一個名為 username 和 password 的用户,並使用 admin 數據庫。
6.3. 在旅行社服務中設置 MongoDB
重要的是更新應用程序屬性以添加與數據庫相關的信息。雖然我們可以自由指定數據庫名稱 admin,但在這裏我們隱藏了最敏感的信息,例如 用户名 和 密碼。
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}現在,讓我們來查看我們的 travel-agency-deployment 屬性文件,以更新服務和部署信息,其中包含用於連接到 mongodb-service 的用户名和密碼。
以下是文件中與 MongoDB 連接相關的部分:
env:
- name: MONGO_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: MONGO_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password7. 與 Ribbon 進行通信
在微服務環境中,我們通常需要服務實例的 Pod 列表,以便進行負載均衡。這通過使用 Spring Cloud Kubernetes Ribbon 提供的機制來實現。該機制可以自動發現並訪問特定服務的所有端點,並且隨後它會將信息填充到 Ribbon 的 ServerList 中。
讓我們先在 client-service 的 pom.xml 文件中添加 spring-cloud-starter-kubernetes-ribbon 依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>下一步是為我們的 client-service 應用程序添加註釋 @RibbonClient:
@RibbonClient(name = "travel-agency-service")當端點列表被填充後,Kubernetes 客户端將搜索當前命名空間/項目註冊的端點,這些端點與使用 @RibbonClient 註解定義的服務名稱匹配。
還需要在應用程序屬性中啓用 Ribbon 客户端:
ribbon.http.client.enabled=true8. 附加功能
This section details some of the additional features available within the system. These features are designed to enhance the user experience and provide greater flexibility in configuring the system to meet specific needs.
8.1. Real-time Collaboration
The system supports real-time collaboration, allowing multiple users to work on the same document simultaneously. Changes made by one user are instantly reflected for all other users. This feature is facilitated by WebSocket technology and utilizes a shared document model.
8.2. Advanced Search
The advanced search functionality allows users to quickly locate specific content within the system. Users can filter results by keyword, date, author, and other criteria. The search index is built using Elasticsearch for optimal performance.
8.3. Customizable Templates
A library of customizable templates is provided to streamline the creation of new documents. Users can modify existing templates or create their own custom templates to suit their specific requirements. Template definitions are stored in JSON format.
{
"name": "Default Document Template",
"fields": [
{
"name": "Title",
"type": "text"
},
{
"name": "Content",
"type": "textarea"
}
]
}
8.1. Hystrix
Hystrix 幫助構建容錯和彈性應用。其主要目標是快速失敗和快速恢復。
特別是,在我們的示例中,我們使用 Hystrix 來在 客户端-服務器 端實現斷路器模式,通過在 Spring Boot 應用類上註解使用 @EnableCircuitBreaker。
此外,我們還使用回退功能,通過在方法 TravelAgencyService.getDeals() 上註解使用 @HystrixCommand()。這意味着在回退的情況下,getFallBackName() 將被調用並返回“Fallback”消息:
@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 健康指示器
我們可以利用 Spring Boot 的 HealthIndicator 和 Spring Boot Actuator,向用户暴露與健康相關的信息。
特別是,Kubernetes 的健康指示器提供:
- Pod 名稱
- IP 地址
- 命名空間
- 服務賬户
- 節點名稱
- 一個標誌,指示 Spring Boot 應用是內部還是外部的 Kubernetes
9. 結論
在本文中,我們對 Spring Cloud Kubernetes 項目進行了全面的概述。
那麼,我們為什麼應該使用它呢? 如果我們支持 Kubernetes 作為微服務平台,同時又欣賞 Spring Cloud 的特性,那麼 Spring Cloud Kubernetes 就能為我們提供最好的雙贏。