標籤:

在 Kubernetes 中使用 SOFABoot 的 Readiness Check 能力

SOFABoot 是螞蟻金服中間件團隊開源的基於 Spring Boot 的一個開發框架,其在 Spring Boot 的健康檢查的基礎上,加上了 Readiness Check 的能力,以更好地適應大規模金融級的服務化場景,防止在應用啟動有問題的情況下讓外部流量進入應用。在本文中,我們將通過 Kubernetes 來演示 SOFABoot 的 Readiness Check 的能力,主要涉及到兩個部分的能力的演示:

  1. SOFABoot 的 Readiness Check 失敗之後,SOFABoot 不會將發布的 RPC 服務的地址註冊到 ZooKeeper 上面,防止 RPC 的流量進入。
  2. Kubernetes 通過 http://localhost:8080/health/readiness 訪問到 SOFABoot 的 Readiness 檢查的結果之後,不會將 Pod 掛到對應的 Service 之上,防止 Kubernetes 上的流量進入。

準備一個 Kubernetes 的環境

為了演示在 Kubernetes 中使用 SOFABoot 的 Readiness Check 的能力,首先需要準備好一個 Kubernetes 的環境,在這個例子中,我們直接選擇在本機安裝一個 minikube,minikube 是 Kubernetes 為了方便研發人員在自己的研發機器上嘗試 Kubernetes 而準備的一個工具,對於學習 Kubernetes 的使用非常方便。關於如何在本機安裝 minikube,大家參考這個官方的安裝教程即可。

安裝完成以後,大家可以直接終端中使用 minikube start來啟動 minikube。

需要?注意的是,由於國內網路環境的問題,直接用 minikube start 可能會無法啟動 minikube,如果遇到無法啟動 minikube 的問題,可以嘗試加上代理的設置,大家可以參考以下的命令來設置代理伺服器的地址:

minikube start --docker-env HTTP_PROXY=http://xxx.xxx.xxx.xxx:6152 --docker-env HTTPS_PROXY=http://xxx.xxx.xxx.xxx:6152

在 Kubernetes 上安裝一個 ZooKeeper

在準備好了 Kubernetes 的環境之後,我們接下來需要在 Kubernetes 上安裝一個 ZooKeeper 作為 SOFARPC 的服務自動發現的組件。首先我們需要有一個 ZooKeeper 的 Deployment:

apiVersion: apps/v1beta1kind: Deploymentmetadata: name: zookeeper-deployment labels: app: zookeeperspec: replicas: 1 selector: matchLabels: app: zookeeper template: metadata: labels: app: zookeeper spec: containers: - name: zookeeper image: zookeeper imagePullPolicy: IfNotPresent ports: - containerPort: 2181

這個 Deployment 會部署一個 ZooKeeper 的實例,並且將 2181 埠暴露出來。

有了這個 YAML 文件之後,我們再部署一個 Service 來作為 ZooKeeper 的負載均衡,這樣我們在應用中就可以直接通過域名來訪問,而不用 IP 來訪問 ZooKeeper 了。這個 Service 的 Yaml 文件如下:

apiVersion: v1kind: Servicemetadata: name: zookeeper-servicespec: selector: app: zookeeper ports: - protocol: TCP port: 2181 targetPort: 2181

這個 Service 直接將 2181 埠映射到 ZooKeeper 的 2181 埠上,這樣,我們就可以在應用中直接通過 zookeeper-service:2181 來訪問了。

準備一個 SOFABoot 的應用

在前面的兩步都 OK 之後,我們需要準備好一個 SOFABoot 的應用,並且在這個應用中發布一個 SOFARPC 的服務。首先,我們需要從 start.spring.io 上生成一個工程,例如 GroupId 設置為 com.alipay.sofa,ArtifactId 設置為 rpcserver。

生成好了之後,接下來,我們需要把 SOFABoot 的依賴加上,將 pom.xml 中的 parent 修改成:

<parent> <groupId>com.alipay.sofa</groupId> <artifactId>sofaboot-dependencies</artifactId> <version>2.3.1</version></parent>

然後,增加一個 SOFARPC 的 Starter 的依賴:

<dependency> <groupId>com.alipay.sofa</groupId> <artifactId>rpc-sofa-boot-starter</artifactId></dependency>

接著,在 application.properties 裡面加上我們的配置,包括應用名和 ZooKeeper 的地址:

# Application Namespring.application.name=SOFABoot Demo# ZooKeeper 的地址com.alipay.sofa.rpc.registry.address=zookeeper://zookeeper-service:2181

上面的事情準備好之後,我們可以在應用中發布一個服務,首先,我們需要分別聲明好一個介面和一個實現:

package com.alipay.sofa.rpcserver;public interface SampleService { String hello();}package com.alipay.sofa.rpcserver;public class SampleServiceImpl implements SampleService { @Override public String hello() { return "Hello"; }}

接下來,將這個介面和實現發布成一個 SOFARPC 的服務,我們可以新建一個 src/main/resources/spring/rpc-server.xml 的文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sofa="http://sofastack.io/schema/sofaboot" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://sofastack.io/schema/sofaboot http://sofastack.io/schema/sofaboot.xsd"> <bean class="com.alipay.sofa.rpcserver.SampleServiceImpl" id="sampleService"/> <sofa:service ref="sampleService" interface="com.alipay.sofa.rpcserver.SampleService"> <sofa:binding.bolt/> </sofa:service></beans>

需要注意的是,通過 XML 定義好上面的服務之後,我們還需要在 Main 函數所在的類裡面增加一個 @Import,將 XML Import 進去:

package com.alipay.sofa.rpcserver;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.ImportResource;@SpringBootApplication@ImportResource("classpath*:spring/*.xml")public class RpcServerApplication { public static void main(String[] args) { SpringApplication.run(RpcServerApplication.class, args); }}

然後?,為了演示 Readiness Check 的能力,我們還需要增加一個 HealthIndicator 來控制 Readiness Check 的結果:

package com.alipay.sofa.rpcserver;import org.springframework.boot.actuate.health.Health;import org.springframework.boot.actuate.health.HealthIndicator;import org.springframework.stereotype.Component;@Componentpublic class SampleHealthIndicator implements HealthIndicator { @Override public Health health() { return Health.up().build(); }}

這裡?,我們首先直接返回成功,先演示 Readiness Check 成功的場景。

將應用部署到 Kubernetes 裡面

在前面的步驟完成之後,應用的代碼都已經準備好了,現在可以準備將應用部署到 Kubernetes 裡面。首先,需要將應用打包成一個 Docker 鏡像,需要注意的是,為了讓 Kubernetes 能夠找到這個 Docker 鏡像,在打包鏡像之前,要先將 Docker 環境切成 Minikube 的環境,運行以下的命令即可:

eval $(minikube docker-env)

然後準備一個 Dockerfile:

FROM openjdk:8-jdk-alpineARG JAR_FILEADD ${JAR_FILE} app.jarENTRYPOINT [ "java", "-jar", "/app.jar"]

最後,運行如下的命令來進行打包:

docker build --build-arg JAR_FILE=./target/rpcserver-0.0.1-SNAPSHOT.jar . -t rpc-server-up

其中 JAR_FILE 參數 SOFABoot 應用程序的 JAR 包路徑。鏡像打包出來後,我們就可以準備一個 YAML 來部署應用了:

apiVersion: apps/v1beta1kind: Deploymentmetadata: name: rpc-server-deployment labels: app: rpc-serverspec: replicas: 1 selector: matchLabels: app: rpc-server template: metadata: labels: app: rpc-server spec: containers: - name: rpc-server image: rpc-server-up imagePullPolicy: IfNotPresent ports: - containerPort: 8080 readinessProbe: httpGet: path: /health/readiness port: 8080

注意在上個面的 YAML 中,我們定義了一個 Kubernetes 的 Readiness Probe,訪問 localhost:8080/health/readiness 來獲取 SOFABoot Readiness Check 的結果。

打包完成之後,可以運行如下的命令來將應用部署到 Kubernetes 中:

kubectl apply -f rpcserver.xml

部署完成後,我們再通過一個 Service,將應用的實例掛到一個 Service 下面去,這樣就可以通過查看 Service 下的 EndPoint 節點的數量來看 Readiness Check 是否起作用了:

apiVersion: v1kind: Servicemetadata: name: rpc-server-servicespec: selector: app: rpc-server ports: - protocol: TCP port: 8080 targetPort: 8080

運行如下命令將 Service 部署到 Kubernetes 裡面去:

kubectl apply -f rpc-server-service.yml

Readiness Check 成功的節點掛載情況

由於上面我們寫的 HealthIndicator 直接返回了一個 Up,所以 Readiness Check 應該成功,我們可以分別從 ZooKeeper 和 Service 裡面查看節點的情況。

首先看下 ZooKeeper 裡面,為了查看 ZooKeeper 裡面的節點的情況,需要在本地有一個 ZooKeeper 的程序在,這個可以直接從 ZooKeeper 的官網上下載。

然後,我們需要拿到在 Kubernetes 裡面部署的 ZooKeeper 的對外暴露的地址,通過如下命令拿到地址:

kubectl expose deployment zookeeper-deployment --type=NodePort && minikube service zookeeper-deployment --url

在我本機拿到的地址是 192.168.99.100:30180

然後,就可以通過本地的 ZooKeeper 程序裡面的 zkCli.sh 來查看 ZooKeeper 裡面的節點了,運行如下的命令:

./zkCli.sh -server 192.168.99.100:30180......[zk: 192.168.99.100:30180(CONNECTED) 5]ls /sofa-rpc/com.alipay.sofa.rpcserver.SampleService/providers

就可以看到裡面有一個節點的信息,就是我們的 rpcserver 部署在 Kubernetes 裡面的節點。

也可以去看下 rpcserver 的 Service 裡面的節點的信息,運行如下的命令:

kubectl describe service rpc-server-service

也可以看到紅框中有一個節點的信息。

Readiness Check 失敗的節點掛載情況

在上面,我們已經看到了 Readiness Check 成功之後,可以在 ZooKeeper 裡面和 Service 的 EndPoints 裡面都可以看到節點的信息,現在來看下 Readiness Check 失敗後的情況。

為了讓 Readiness Check 失敗,要將之前寫的 SampleHealthIndicator 改成 Down,代碼如下:

package com.alipay.sofa.rpcserver;import org.springframework.boot.actuate.health.Health;import org.springframework.boot.actuate.health.HealthIndicator;import org.springframework.stereotype.Component;@Componentpublic class SampleHealthIndicator implements HealthIndicator { @Override public Health health() { return Health.down().build(); }}

然後使用 mvn clean install 重新打包程序,打包之後,我們需要重新構建鏡像,為了跟前面的 Readiness Check 成功的鏡像以示區分,我們將鏡像的名稱換成 rpc-server-down

docker build --build-arg JAR_FILE=./target/rpcserver-0.0.1-SNAPSHOT.jar . -t rpc-server-down

然後我們再將之前的應用的 Deployment 的 YAML 文件中的鏡像名稱換成新的鏡像名稱,其他保持不變:

apiVersion: apps/v1beta1kind: Deploymentmetadata: name: rpc-server-deployment labels: app: rpc-serverspec: replicas: 1 selector: matchLabels: app: rpc-server template: metadata: labels: app: rpc-server spec: containers: - name: rpc-server image: rpc-server-down imagePullPolicy: IfNotPresent ports: - containerPort: 8080 readinessProbe: httpGet: path: /health/readiness port: 8080

最後,通過 kubectl apply -f rpcserver.yml 來更新 Kubernetes 裡面的 RPCServer 這個應用。

更新之後,我們再去 ZooKeeper 裡面看下服務發布的情況,就只能看到一個空的列表了:

通過 kubectl describe 查看新的 Pod 的情況,也可以看到 Readiness Check 失敗:

通過 kubectl describe service rpc-server-service 也可以看到 Service 下面的 EndPoint 還是之前的那個,新的並沒有掛載上去。

總結

本文中,我們演示了如何通過 Readiness Check 來控制應用的流量,在 Readiness Check 失敗的情況下,讓流量不進入應用,防止業務受損。在上面的例子中,我們通過 Readiness Check 完成了兩個部分的流量的控制,一個是 Readiness Check 失敗之後,SOFARPC 不會將服務的地址上報到對應的服務註冊中心上,控制通過自動服務發現進入的流量,另一個方面,Kubernetes 也不會將 Pod 掛到對應額 Service 之上,防止負載均衡器進入的流量。

雖然 SOFABoot 提供了 Readiness Check 的能力,並且對應的中間件也已經實現了根據 SOFABoot 的 Readiness Check 的結果來控制流量,但是完整的流量控制,還需要外圍的平台進行配合,比如負載均衡的流量就需要 Kubernetes 的 Readiness Check 的能力來一起配合才可以完成控制。

本文中所有涉及到的代碼以及 Kuberentes 的 YAML 配置文件都已經放到了 Github 上,歡迎大家參考下載:github.com/khotyn/sofa-

推薦閱讀:

喪失遲到的關於《小米生態鏈戰地日記》的讀後感,神秘的小米生態鏈終於開始對外界說話了
爭奪classroom,谷歌、蘋果和微軟誰將切下最大的蛋糕?
2017十大突破性科技——神經植入
特斯拉Model 3再次停工!這一次還是因為自動化機器人……

TAG:Kubernetes | 科技 |