1. 引言
在本教程中,我們將討論 Kubernetes 的 探測器(probes)及其如何利用 Actuator 的 HealthIndicator 來準確瞭解應用程序的狀態。
為了方便本教程,我們假設您已經具備了對 Spring Boot Actuator、Kubernetes 和 Docker 的一定經驗。
2. Kubernetes 探針
Kubernetes 定義了兩種不同的探針,我們可以定期檢查它們是否按預期工作:就緒探測 和 就緒狀態探測。
2.1. 活躍性與就緒性
通過使用和探針,Kubelet 可以在檢測到問題後立即啓動,從而最大限度地減少應用程序停機時間。
兩者配置方式相同,但具有不同的語義,並且Kubelet 根據觸發的不同探針執行不同的操作。
- Readiness – Readiness 驗證我們的Pod 是否準備好接收流量。當所有容器都已準備好時,我們的Pod 就可以接收流量。
- Liveness – 與Readiness 探針相反,Liveness 檢查我們的Pod 是否應該重啓。它適用於應用程序正在運行但無法繼續前進的情況,例如進入死鎖狀態。
我們以容器級別配置這兩種探針類型。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 1
successThreshold: 1
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 2
failureThreshold: 1
successThreshold: 1我們可以配置若干字段以更精確地控制探測器的行為:
- initialDelaySeconds – 創建容器後,等待 n 秒,然後啓動探測器
- periodSeconds – 此探測器運行的頻率,默認值為 10 秒;最小值為 1 秒
- timeoutSeconds – 我們等待的時間,超時探測器,默認值為 1 秒;最小值為 1 秒
- failureThreshold – 嘗試 n 次,在失敗後放棄。對於 readiness ,我們的 Pod 將被標記為不可準備就緒;而對於 liveness ,放棄意味着重啓 Pod 。 默認值為 3 次失敗,最小值為 1
- successThreshold – 這是探測器被認為是成功的最小連續成功次數,在已失敗後。 默認值為 1 次成功,最小值為 1
在這種情況下,我們選擇了 tcp 探測器,但我們還可以使用其他類型的探測器。
2.2. 探測類型
根據我們的使用場景,一種探測類型可能比另一種更實用。例如,如果我們的容器是一個 Web 服務器,使用一個 http 探測可能比使用一個 tcp 探測更可靠。
幸運的是,Kubernetes 提供了三種不同的探測類型供我們使用:
- `exec` – 在我們的容器中執行 `bash` 指令。例如,檢查是否存在特定文件。如果指令返回失敗代碼,探測將失敗
- `tcpSocket` – 嘗試使用指定的端口建立到容器的 `tcp` 連接。如果無法建立連接,探測將失敗
- `httpGet` – 向容器中運行並監聽指定端口的服務器發送 HTTP GET 請求。任何 200 到 400 之間的代碼都表示成功
需要注意的是,<em>HTTP</em> 探測具有除了我們之前提到的之外的額外字段:
- `host` – 連接的 Hostname,默認值為 Pod 的 IP
- `scheme` – 應該使用的 Scheme,`HTTP` 或 `HTTPS`,默認值為 `HTTP`
- `path` – 用於訪問 Web 服務器的路徑
- `httpHeaders` – 用於在請求中設置的自定義 Header
- `port` – 用於訪問容器的端口名稱或數字
3. Spring Actuator 和 Kubernetes 自愈能力
現在我們對 Kubernetes 如何檢測應用程序是否處於故障狀態有了初步瞭解,接下來讓我們看看我們如何利用 Spring 的 Actuator 來更密切地關注應用程序及其依賴項。
為了便於這些示例,我們將依賴 Minikube。
3.1. Actuator及其HealthIndicators
考慮到Spring提供了多種HealthIndicator,將應用程序的依賴項狀態反映到Kubernetes的探測器中,只需將Actuator依賴項添加到我們的pom.xml中即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>3.2. 活體檢測示例
讓我們從一個正常啓動並將在 30 秒 後 切換到異常狀態的應用開始。
我們將通過創建一條 HealthIndicator 來模擬異常狀態,該指標會驗證一個 boolean 變量是否為 true。 我們將初始化該變量為 true,然後安排一個任務在 30 秒 後將其更改為 false:
@Component
public class CustomHealthIndicator implements HealthIndicator {
private boolean isHealthy = true;
public CustomHealthIndicator() {
ScheduledExecutorService scheduled =
Executors.newSingleThreadScheduledExecutor();
scheduled.schedule(() -> {
isHealthy = false;
}, 30, TimeUnit.SECONDS);
}
@Override
public Health health() {
return isHealthy ? Health.up().build() : Health.down().build();
}
}有了我們的HealthIndicator,我們需要將我們的應用程序進行容器化:
FROM openjdk:8-jdk-alpine
RUN mkdir -p /usr/opt/service
COPY target/*.jar /usr/opt/service/service.jar
EXPOSE 8080
ENTRYPOINT exec java -jar /usr/opt/service/service.jar接下來,我們創建我們的 Kubernetes 模板:
apiVersion: apps/v1
kind: Deployment
metadata:
name: liveness-example
spec:
...
spec:
containers:
- name: liveness-example
image: dbdock/liveness-example:1.0.0
...
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
timeoutSeconds: 2
periodSeconds: 3
failureThreshold: 1
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 20
timeoutSeconds: 2
periodSeconds: 8
failureThreshold: 1我們正在使用一個 httpGet 探測器,指向 Actuator 的健康端點。 應用程序狀態(及其依賴項)的任何更改都將反映在部署的健康狀況上。
將我們的應用程序部署到 Kubernetes 後,我們可以看到這兩個探測器在行動:大約 30 秒後,我們的 Pod 將被標記為未就緒並從輪換中移除;幾秒鐘後, Pod 會被重新啓動。
我們可以查看我們的 Pod 執行 kubectl describe pod liveness-example 的事件:
Warning Unhealthy 3s (x2 over 7s) kubelet, minikube Readiness probe failed: HTTP probe failed ...
Warning Unhealthy 1s kubelet, minikube Liveness probe failed: HTTP probe failed ...
Normal Killing 0s kubelet, minikube Killing container with id ...3.3. 示例:就緒狀態
在之前的示例中,我們看到了如何使用 HealthIndicator 來反映應用程序在 Kubernetes 部署健康狀況上的狀態。
讓我們在另一個用例中使用它:假設我們的應用程序 需要 一些 時間 來 在 能夠 接收 流量。例如,它需要將文件加載到內存中並驗證其內容。
這是一個很好的例子,説明我們如何利用 就緒探測。
讓我們修改 HealthIndicator 和 Kubernetes 模板,並將其調整為該用例:
@Component
public class CustomHealthIndicator implements HealthIndicator {
private boolean isHealthy = false;
public CustomHealthIndicator() {
ScheduledExecutorService scheduled =
Executors.newSingleThreadScheduledExecutor();
scheduled.schedule(() -> {
isHealthy = true;
}, 40, TimeUnit.SECONDS);
}
@Override
public Health health() {
return isHealthy ? Health.up().build() : Health.down().build();
}
}我們初始化變量為false,並在40秒後,一個任務將執行並將其設置為true。
接下來,我們使用以下模板通過Docker化和部署應用程序:
apiVersion: apps/v1
kind: Deployment
metadata:
name: readiness-example
spec:
...
spec:
containers:
- name: readiness-example
image: dbdock/readiness-example:1.0.0
...
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 40
timeoutSeconds: 2
periodSeconds: 3
failureThreshold: 2
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 100
timeoutSeconds: 2
periodSeconds: 8
failureThreshold: 1雖然兩者相似,但我們需要指出一些探測器配置上的變更:
- 由於我們知道應用程序需要大約40秒才能準備好接收流量,因此我們增加了 initialDelaySeconds 的值,將我們的 就緒 探測器設置為40秒。
- 同樣,我們增加了 initialDelaySeconds 的值,將我們的 活躍性 探測器設置為100秒,以避免被 Kubernetes 提前終止。
如果40秒後仍未完成,它仍有大約60秒的時間完成。之後,我們的 活躍性 探測器將啓動並重啓 Pod。
4. 結論
在本文中,我們討論了 Kubernetes 探測器以及如何使用 Spring 的 Actuator 來改進我們應用程序的健康監控。