前言
在云原生環(huán)境中归薛,Pod 是部署應(yīng)用程序的基本單位羞酗,而 Service 將符合指定條件的 Pod 作為可通過(guò)網(wǎng)絡(luò)訪問(wèn)的服務(wù)提供給服務(wù)調(diào)用者汽抚。在某些情況下易结,可能需要將某個(gè) Pod 的流量從 Service 中切走精算,使其不再接收 Service 的請(qǐng)求瓢宦。這可能是因?yàn)?Pod 出現(xiàn)故障需要保留現(xiàn)場(chǎng)人工排查。
目標(biāo)
使能夠靈活地將 Pod 的流量從 Service 中切走灰羽,同時(shí)確保在切走流量時(shí)驮履,其他 Pod 仍然能夠正常工作,并且對(duì)用戶請(qǐng)求的影響最小化廉嚼。
概述
- 基本概念和原理
在 Kubernetes 中玫镐,Service 通過(guò) Label 選擇器來(lái)將請(qǐng)求流量分發(fā)到對(duì)應(yīng)的 Pod 上。因此怠噪,要切走某個(gè) Pod 的流量恐似,可以通過(guò)修改 Label 選擇器來(lái)實(shí)現(xiàn)。我們可以為需要切走的 Pod Label 進(jìn)行修改傍念,使其 Service Label 選擇器不再包含該 Pod 的 Label矫夷。
# Service 通過(guò) Label 選擇器綁定 Deployment
---
apiVersion: v1
kind: Service
metadata:
name: test
spec:
ports:
- name: port-xxxx
nodePort: xxxxx
port: xxxx
protocol: TCP
targetPort: xxxx
selector:
app: test
type: NodePort
# Deployment Label
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
selector:
matchLabels:
app: test # 與 Pod Label一致
template:
metadata:
labels:
app: test # 與 Service selector 一致
# Pod Label
---
apiVersion: v1
kind: Pod
metadata:
generateName: test-8495787574-
labels:
app: test
name: test-8495787574-rssvq
- 實(shí)現(xiàn)流程
(1)準(zhǔn)備階段:確定需要切走流量的 Pod,并修改成特定 Label捂寿,如原 Label:app=test口四,修改后 Label:app=test-offline。
(2)修改 Pod 的 Label 后秦陋,Deployment 會(huì)檢測(cè)發(fā)現(xiàn)同 Label 實(shí)例與副本數(shù)實(shí)例不一致蔓彩,通過(guò)擴(kuò)容將 Pod 個(gè)數(shù)與副本數(shù)一致。
(3)驗(yàn)證流量切分:通過(guò) Service 調(diào)用時(shí)驳概,使用工具或監(jiān)控系統(tǒng)驗(yàn)證流量是否成功切分赤嚼,確保其他 Pod 能夠正常接收請(qǐng)求和被切流的 Pod 不再接收請(qǐng)求。
(4)恢復(fù)流量:在需要恢復(fù)流量時(shí)顺又,將切走流量的 Pod 的 Label 恢復(fù)為原始狀態(tài)更卒,Deployment 會(huì)檢測(cè)發(fā)現(xiàn)同 Label 實(shí)例與副本數(shù)實(shí)例不一致,通過(guò)縮容將 Pod 個(gè)數(shù)與副本數(shù)一致稚照。
(5)再次驗(yàn)證流量:確認(rèn)流量是否成功恢復(fù)蹂空,確保切走流量的 Pod 重新接收請(qǐng)求俯萌。
針對(duì)于第4、5點(diǎn)上枕,實(shí)際情況如排查完問(wèn)題咐熙,沒(méi)必要恢復(fù)該 Pod 流量,而是直接銷毀該 Pod辨萍,因?yàn)榈?點(diǎn)已將切流的 Pod 個(gè)數(shù)擴(kuò)容了回來(lái)棋恼,所以無(wú)須保留切流的 Pod
具體實(shí)現(xiàn)步驟
- 準(zhǔn)備階段
- 確定需要切走流量的 Pod:確定需要切走流量的 Pod 的名稱或標(biāo)識(shí)。
- 修改 Pod Label:使用 K8S API 進(jìn)行修改
public V1Pod patchPodLabel(String namespace, String name, String key, String value) throws ApiException {
CoreV1Api api = new CoreV1Api(client);
V1Patch v1Patch = new V1Patch(JSONUtil.toJsonStr(CollUtil.newArrayList(new PatchPodLabelsParam(key, value))));
return api.patchNamespacedPod(name, namespace, v1Patch, null, null, null, null);
}
@Getter
public static class PatchPodLabelsParam {
private final String op = "replace";
private final String path;
private final String value;
public PatchPodLabelsParam(String key, String value) {
this.path = StrFormatter.format("/metadata/labels/{}", key);
this.value = value;
}
}
@Test
public void patchPodLabel() throws ApiException {
Kube kube = Kube.init(dev_KubeConfig);
kube.patchPodLabel("default","test-8495787574-nz58d", "app", "test-offline");
}
- 驗(yàn)證流量切分
# 到 Pod 中執(zhí)行命令安裝 arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 通過(guò) watch 監(jiān)控方法是否被調(diào)用
watch 包名.類名 方法名 '{params,returnObj,throwExp}'
// 模擬通過(guò) NodePort 進(jìn)行調(diào)用
for (int i = 0; i < 100; i++) {
CompletableFuture.runAsync(() -> HttpUtil.get("http://測(cè)試接口"));
}
ThreadUtil.sleep(10000);
- 處理切流的 Pod
修改了 Label 的 Pod 則脫離了 Deployment 的管理锈玉,也無(wú)法通過(guò) Deployment 來(lái)查看爪飘,該 Pod 則無(wú)法自動(dòng)銷毀,只能人工銷毀拉背。
總結(jié)和注意事項(xiàng)
本方案提供了一種將 Pod 的流量從 Service 中切走的方法师崎。通過(guò)修改 Pod Label,可以靈活地控制流量的分發(fā)去团,確保在進(jìn)行維護(hù)或升級(jí)時(shí)抡诞,對(duì)用戶請(qǐng)求的影響最小化。在實(shí)際應(yīng)用中土陪,需要根據(jù)具體業(yè)務(wù)需求和環(huán)境進(jìn)行適當(dāng)?shù)恼{(diào)整和測(cè)試昼汗,以確保方案的可行性和穩(wěn)定性。