K8S Pod 如何实现 Service 切流

前言

在云原生环境中,Pod 是部署应用程序的基本单位,而 Service 将符合指定条件的 Pod 作为可通过网络访问的服务提供给服务调用者。在某些情况下,可能需要将某个 Pod 的流量从 Service 中切走,使其不再接收 Service 的请求。这可能是因为 Pod 出现故障需要保留现场人工排查。

目标

使能够灵活地将 Pod 的流量从 Service 中切走,同时确保在切走流量时,其他 Pod 仍然能够正常工作,并且对用户请求的影响最小化。

概述

  1. 基本概念和原理
    在 Kubernetes 中,Service 通过 Label 选择器来将请求流量分发到对应的 Pod 上。因此,要切走某个 Pod 的流量,可以通过修改 Label 选择器来实现。我们可以为需要切走的 Pod Label 进行修改,使其 Service Label 选择器不再包含该 Pod 的 Label。
# Service 通过 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
  1. 实现流程
    (1)准备阶段:确定需要切走流量的 Pod,并修改成特定 Label,如原 Label:app=test,修改后 Label:app=test-offline。
    (2)修改 Pod 的 Label 后,Deployment 会检测发现同 Label 实例与副本数实例不一致,通过扩容将 Pod 个数与副本数一致。
    (3)验证流量切分:通过 Service 调用时,使用工具或监控系统验证流量是否成功切分,确保其他 Pod 能够正常接收请求和被切流的 Pod 不再接收请求。
    (4)恢复流量:在需要恢复流量时,将切走流量的 Pod 的 Label 恢复为原始状态,Deployment 会检测发现同 Label 实例与副本数实例不一致,通过缩容将 Pod 个数与副本数一致。
    (5)再次验证流量:确认流量是否成功恢复,确保切走流量的 Pod 重新接收请求。

针对于第4、5点,实际情况如排查完问题,没必要恢复该 Pod 流量,而是直接销毁该 Pod,因为第2点已将切流的 Pod 个数扩容了回来,所以无须保留切流的 Pod

具体实现步骤

  1. 准备阶段
  • 确定需要切走流量的 Pod:确定需要切走流量的 Pod 的名称或标识。
  • 修改 Pod Label:使用 K8S API 进行修改
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");
}
  1. 验证流量切分
# 到 Pod 中执行命令安装 arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

# 通过 watch 监控方法是否被调用
watch 包名.类名 方法名 '{params,returnObj,throwExp}'
// 模拟通过 NodePort 进行调用
for (int i = 0; i < 100; i++) {
    CompletableFuture.runAsync(() -> HttpUtil.get("http://测试接口"));
}
ThreadUtil.sleep(10000);
  1. 处理切流的 Pod
    修改了 Label 的 Pod 则脱离了 Deployment 的管理,也无法通过 Deployment 来查看,该 Pod 则无法自动销毁,只能人工销毁。

总结和注意事项

本方案提供了一种将 Pod 的流量从 Service 中切走的方法。通过修改 Pod Label,可以灵活地控制流量的分发,确保在进行维护或升级时,对用户请求的影响最小化。在实际应用中,需要根据具体业务需求和环境进行适当的调整和测试,以确保方案的可行性和稳定性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容