k8s工作负载控制器--DaemonSet
一、概述
DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
DaemonSet 的主要作用,是在 Kubernetes 集群里,运行一个 Daemon Pod。 DaemonSet 只管理 Pod 对象,然后通过 nodeAffinity 和 Toleration 这两个调度器参数的功能,保证了每个节点上有且只有一个 Pod
二、适用场景
DaemonSet适用于每个node节点均需要部署一个守护进程的场景
- 日志采集agent,如fluentd或logstash
- 监控采集agent,如Prometheus Node Exporter,Sysdig Agent,Ganglia gmond
- 分布式集群组件,如Ceph MON,Ceph OSD,glusterd,Hadoop Yarn NodeManager等
- k8s必要运行组件,如网络flannel,weave,calico,kube-proxy等
三、基本操作
1、官网的DaemonSet资源清单
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
# 这些容忍度设置是为了让该守护进程集在控制平面节点上运行
# 如果你不希望自己的控制平面节点运行 Pod,可以删除它们
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
# 可能需要设置较高的优先级类以确保 DaemonSet Pod 可以抢占正在运行的 Pod
# priorityClassName: important
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
2、字段解释
apiVersion: apps/v1 #指定YAML文件的API版本,这里是apps/v1
kind: DaemonSet #定义资源类型,这里是DaemonSet
metadata: #包含DaemonSet的元数据
name: fluentd-elasticsearch #此DaemonSet的名称
namespace: kube-system #定义DaemonSet所属的命名空间
labels: #定义标签
k8s-app: fluentd-logging #此标签表示该DaemonSet与日志处理有关
spec: #DaemonSet的规约,包含了DaemonSet的规格和行为的详细配置
selector: #定义了DaemonSet所管理的Pods的标签选择器,即哪些Pods应该被这个DaemonSet管理。这里matchLabels必须与template.metadata.labels相匹配。
matchLabels:
name: fluentd-elasticsearch
template: #Pod的模板,用于创建和管理DaemonSet下的Pods
metadata: #Pod的元数据,这里包含了与spec.selector.matchLabels相匹配的标签。
labels:
name: fluentd-elasticsearch
spec: #Pod的规约
tolerations: #定义了Pod可以容忍的节点污点,允许Pod在带有特定污点的节点上运行。这里配置了两个容忍度,分别针对控制平面节点和标记为master的节点,确保日志采集容器可以在这些特殊节点上运行。
# 这些容忍度设置是为了让该守护进程集在控制平面节点上运行
# 如果你不希望自己的控制平面节点运行 Pod,可以删除它们
- key: node-role.kubernetes.io/control-plane #污点的键,通常表示控制平面节点的标签。
operator: Exists #Exists,表示只要节点上有与key匹配的污点,无论其值是什么,都将被视为匹配
effect: NoSchedule #NoSchedule,表示如果节点上存在与key匹配的污点,则默认情况下不允许Pod被调度到该节点。但是,由于这个Pod声明了对该污点的容忍度,所以Pod可以被调度到带有node-role.kubernetes.io/control-plane污点的节点上。
- key: node-role.kubernetes.io/master #指向标记为master的节点的污点键。
operator: Exists #只要节点上有与key匹配的污点,无论其值是什么,都将被视为匹配。
effect: NoSchedule #表明默认情况下,没有相应容忍度的Pod将不能被调度到带有node-role.kubernetes.io/master污点的节点上。但是,由于这个Pod声明了对该污点的容忍度,所以Pod可以被调度到带有node-role.kubernetes.io/master污点的节点上。
containers: #Pod的容器配置
- name: fluentd-elasticsearch #容器的名称
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2 #指定容器的镜像来源
resources: #定义了容器的资源限制和请求
limits: #容器的最大资源限制
memory: 200Mi
requests: #容器启动时请求的最小资源量
cpu: 100m
memory: 200Mi
volumeMounts: #容器如何挂载卷
- name: varlog #指定了要挂载的卷的名称
mountPath: /var/log #定义了容器内部挂载卷的路径
# 可能需要设置较高的优先级类以确保 DaemonSet Pod 可以抢占正在运行的 Pod
# priorityClassName: important
terminationGracePeriodSeconds: 30 #定义了当Pod被删除时,Kubernetes等待的秒数,以允许容器优雅地关闭。
volumes: #定义Pod可以使用的卷
- name: varlog #定义了一个卷的名称
hostPath: #指定了这个卷的主机路径
path: /var/log
3、编写DaemonSet资源清单
daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: simple-daemonset
namespace: default
spec:
selector:
matchLabels:
app: simple-daemonset-app
template:
metadata:
labels:
app: simple-daemonset-app
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
4、基于yaml创建DaemonSet
kubectl apply -f daemonset.yaml
5、注意点
5.1、必须字段
DaemonSet需要apiVersion、kind 、metadata 和spec字段
以下是DaemonSetYAML定义中最基本的必需字段:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: <daemonset-name>
namespace: <namespace>
spec:
selector:
matchLabels:
<label-key>: <label-value>
template:
metadata:
labels:
<label-key>: <label-value>
spec:
containers:
- name: <container-name>
image: <image-name>
-
apiVersion:指定YAML文件使用的Kubernetes API版本。对于DaemonSet,通常使用apps/v1。
-
kind:指定资源类型,这里应为DaemonSet。
-
metadata:
- name:DaemonSet的名称,必须是唯一的。
- namespace:DaemonSet所在的命名空间,默认为default,但强烈建议明确指定。
-
spec:DaemonSet的规格,定义了它的行为和管理的Pod的模板。
-
selector:选择器,用于标识DaemonSet管理的Pods。
- matchLabels:一个键值对的映射,用于匹配DaemonSet管理的Pods的标签。这是必须的,用于确保DaemonSet管理的Pods与之关联。
-
template:Pod的模板,定义了DaemonSet创建的Pods的结构。
- metadata:Pod的元数据,其中必须包含与spec.selector.matchLabels相匹配的labels字段。
- spec:Pod的规格,定义了容器、卷、网络设置等。
- containers:一个或多个容器的列表,每个容器都需要定义name和image。
-
5.2、DaemonSet 对象的名称
DaemonSet 对象的名称必须是一个合法的 DNS 子域名。
- 不能超过 253 个字符
- 只能包含小写字母、数字,以及 '-' 和 '.'
- 必须以字母数字开头
- 必须以字母数字结尾
5.3、.spec.selector 与 .spec.template.metadata.labels之间的关系
.spec.selector
必须与 .spec.template.metadata.labels
匹配。这意味着 matchLabels
中定义的每个键值对都必须存在于 .spec.template.metadata.labels
中,以确保DaemonSet能够正确地选择它所创建的Pods。如果 .spec.selector
中的标签是 .spec.template.metadata.labels
的子集,则这种匹配是有效的。但如果 .spec.template.metadata.labels
中缺少 .spec.selector
中的任何一个标签,或者标签值不同,那么配置将被视为无效,Kubernetes API将拒绝这个配置。
6、查看DaemonSet
6.1、查看DaemonSet列表
kubectl get ds -n default -o wide
NAME:DaemonSet的名称。在这个例子中,DaemonSet的名称是simple-daemonset。
DESIRED:这是DaemonSet期望在集群中运行的Pod数量。对于DaemonSet而言,这通常是集群中节点的数量,因为DaemonSet的目标是在每个节点上运行至少一个Pod的实例。在这个例子中,DESIRED的值是2,是因为集群有两个节点。
CURRENT:这是DaemonSet当前管理的Pod数量。理想情况下,CURRENT的值应该等于DESIRED的值,这意味着DaemonSet已经达到了其目标状态。在这个例子中,CURRENT的值也是2,与DESIRED相匹配。
READY:这是DaemonSet管理的Pod中处于就绪状态的数量。就绪状态(Ready)意味着Pod中的所有容器都已经启动并且健康检查(如果有的话)已通过。在这个例子中,READY的值是2,表明Pod已经准备好并正在运行。
UP-TO-DATE:这是当前正在运行的Pod中与DaemonSet最新模板匹配的数量。当DaemonSet更新其Pod模板时,这个数字可以帮助你跟踪更新进度。在这个例子中,UP-TO-DATE的值是2,意味着所有运行的Pod都使用了最新的模板。
AVAILABLE:这是DaemonSet管理的Pod中可以服务流量的数量。这个数字通常与READY相同,除非某些Pod由于某种原因被标记为不可用。在这个例子中,AVAILABLE的值是2,与READY一致。
NODE SELECTOR:这是DaemonSet使用的节点选择器,它定义了哪些节点可以运行DaemonSet的Pod。
AGE:这是DaemonSet的创建时间,以持续时间的形式给出。在这个例子中,DaemonSet的AGE是65s,意味着它在65秒前创建。
6.2、查看 DaemonSet 控制器所创建的 Pod 副本信息
kubectl get pods -n default -o wide
7、滚动更新
7.1、查看DaemonSet详情
kubectl get ds -n default
kubectl get daemonset simple-daemonset -n default -o json | jq '.spec.updateStrategy'
可以看到DaemonSet支持RollingUpdate滚动更新策略
- RollingUpdate:这是默认的更新策略。使用 RollingUpdate 更新策略时,在更新 DaemonSet 模板后, 老的 DaemonSet Pod 将被终止,并且将以受控方式自动创建新的 DaemonSet Pod。 更新期间,最多只能有 DaemonSet 的一个 Pod 运行于每个节点上。
- maxSurge:定义了在更新过程中可以超出desiredNumberScheduled(期望的Pod数量)的额外Pod数量。在这个例子中,maxSurge设置为0,意味着在更新过程中不会创建超过当前期望数量的额外Pod。换句话说,DaemonSet在终止一个旧的Pod之前不会创建一个新的Pod。
- maxUnavailable:定义了在更新过程中可以有多少Pod不可用。maxUnavailable设置为1,意味着在更新过程中,可以有最多1个Pod不可用。这通常发生在旧的Pod被终止,而新的Pod尚未完全启动并变得可用时。
- type :为 RollingUpdate 是要启用 DaemonSet 的滚动更新功能必须设置的
7.2、更新nginx镜像版本
kubectl set image daemonsets simple-daemonset nginx-container=nginx:1.14.0 -n default
7.3、查看滚动更新状态
kubectl rollout status ds simple-daemonset -n default
7.4、查看DS滚动更新过程
kubectl describe ds simple-daemonset -n default
7.5、查看DS滚动更新版本
kubectl rollout history ds simple-daemonset -n default
REVERSION1就是初始版本
8、版本回退
8.1、回滚
kubectl rollout undo daemonset -n default simple-daemonset --to-revision=1
8.2、查看版本回退情况
kubectl describe ds simple-daemonset -n default
9、删除DaemonSet
9.1、直接删除DS
kubectl delete ds simple-daemonset -n default
9.2、基于创建的资源清单删除DS
kubectl delete -f daemonset.yaml
四、DaemonSet调度
1、调度方式
DaemonSet通过kubernetes默认的调度器scheduler会在所有的node节点上运行一个Pod副本,可以通过如下三种方式将Pod运行在部分节点上
- 指定
nodeName
节点运行 - 通过标签运行
nodeSelector
- 通过亲和力调度
node Affinity
和node Anti-affinity
- 污点与容忍度(
Tolerations
和Taints
) Priority
和Preemption
(优先级和抢占)
2、指定nodeName节点运行
这种方式通常不用于 DaemonSet,因为 DaemonSet 的目标是在尽可能多的节点上运行 Pod 副本。但是可以通过 .spec.nodeName
来指定特定节点运行 Pod。
2.1、原理机制
- 当为 Pod 指定了具体的
nodeName
后,Kubernetes 调度器将跳过调度过程,直接将 Pod 分配给指定的节点。 - 这种方式通常用于测试目的或者在特殊场景下使用,例如当您需要确保某个 Pod 在特定节点上运行时。
2.2、示例
2.2.1、创建一个DaemonSet资源清单,指定nodeName
cat <<EOF > daemonset-nodename.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-nodename
spec:
selector:
matchLabels:
way: nodename
template:
metadata:
labels:
way: nodename
spec:
nodeName: k8s-node1 # 指定 nodeName
containers:
- name: daemon-nodename-container
image: nginx:latest
EOF
2.2.2、应用 DaemonSet
kubectl apply -f daemonset-nodename.yaml
2.2.3、查看 DaemonSet Pod 的状态
kubectl get pods -l way=nodename -o wide
3、通过标签运行 (nodeSelector)
nodeSelector
是一种简单的方式,用于指定 Pod 应该运行在具有特定标签的节点上。- 当在 Pod 模板中定义了
nodeSelector
,Kubernetes 调度器会将 Pod 分配到具有相应标签的节点上。
3.1、原理机制
- 需要在节点上设置特定的标签。
- 在 DaemonSet 的 Pod 模板中定义
nodeSelector
,指定节点标签。 - Kubernetes 调度器会根据
nodeSelector
将 Pod 分配到符合条件的节点上。
3.2、示例
3.2.1、给 k8s-node1 添加标签
kubectl label nodes k8s-node1 role=worker
3.2.2、创建DaemonSet 资源清单,使用nodeSelector
cat <<EOF > daemonset-nodeselector.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-nodeselector
spec:
selector:
matchLabels:
way: nodeSelector
template:
metadata:
labels:
way: nodeSelector
spec:
nodeSelector: # 使用 nodeSelector
role: worker
containers:
- name: daemonset-nodeselector-container
image: nginx:latest
EOF
3.2.3、应用 DaemonSet
kubectl apply -f daemonset-nodeselector.yaml
3.2.4、查看 DaemonSet Pod 的状态
kubectl get pods -l way=nodeSelector -o wide
3.2.5、删除k8s-node1上的标签
测试完及时删除标签
kubectl label nodes k8s-node1 role-
4、通过亲和力调度 (node Affinity 和 node Anti-affinity)
4.1、Node Affinity (节点亲和性)
4.1.1、原理
- Node Affinity 是一种调度策略,允许定义的 Pod 必须或应该调度到哪些节点上。
- 这种策略分为两类:
requiredDuringSchedulingIgnoredDuringExecution
和preferredDuringSchedulingIgnoredDuringExecution
。 requiredDuringSchedulingIgnoredDuringExecution
表示必须满足的硬性要求。preferredDuringSchedulingIgnoredDuringExecution
表示可选的偏好。
4.1.2、给node-k8s2添加标签
按照节点亲和性原理,pod最终会被调度到k8s-node2这个节点上
kubectl label nodes k8s-node2 role=worker
4.1.3、创建 DaemonSet 资源清单,使用 nodeAffinity
cat <<EOF> daemonset-affinity.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-affinity
spec:
selector:
matchLabels:
way: nodeAffinity
template:
metadata:
labels:
way: nodeAffinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values:
- worker
containers:
- name: daemon-affinity-container
image: nginx:latest
EOF
4.1.4、应用DaemonSet
kubectl apply -f daemonset-affinity.yaml
4.1.5、查看 DaemonSet Pod 的状态
kubectl get pods -l way=nodeAffinity -o wide
4.2、Node Anti-affinity (节点反亲和性)
4.2.1、原理
- Node Anti-affinity 是一种调度策略,允许您定义 Pod 不应该调度到哪些节点上。
- 这种策略也是分为两类:
requiredDuringSchedulingIgnoredDuringExecution
和preferredDuringSchedulingIgnoredDuringExecution
。 requiredDuringSchedulingIgnoredDuringExecution
表示必须满足的硬性要求。preferredDuringSchedulingIgnoredDuringExecution
表示可选的偏好。
4.2.2、给node-k8s2添加标签
按照节点反亲和性原理,节点不会被调度到k8s-node2上
kubectl label node k8s-node2 ROLE=worker2
4.2.3、创建 DaemonSet 资源清单,使用 node Anti-affinity
cat <<EOF > daemonset-Anti-affinity.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-anti-affinity
spec:
selector:
matchLabels:
way: Anti-affinity
template:
metadata:
labels:
way: Anti-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: ROLE
operator: DoesNotExist
- key: ROLE
operator: NotIn
values:
- worker2
containers:
- name: daemonset-anti-affinity-container
image: nginx:latest
EOF
4.2.4、应用DaemonSet
kubectl apply -f daemonset-Anti-affinity.yaml
4.2.5、查看 DaemonSet Pod 的状态
kubectl get pods -l way=Anti-affinity -o wide
5、污点与容忍度(Tolerations
和 Taints
)
- Taints(污点) 是节点上的标记,用于排斥 Pod。
- Tolerations(容忍度) 则是 Pod 上的配置,用于容忍节点上的 taints。
5.1、原理
- 节点可以设置 taints 来排斥 Pod。
- Pod 可以设置 tolerations 来容忍这些 taints。
- Kubernetes 调度器会根据 tolerations 和 taints 的匹配情况来决定 Pod 是否可以被调度到节点上。
5.2、示例
5.2.1、给 k8s-node1 添加 taint
k8s-node1
: 有污点example.com/taint-key=taint-value:NoSchedule
k8s-node2
: 没有污点
kubectl taint nodes k8s-node1 example.com/taint-key=taint-value:NoExecute
5.2.2、创建 DaemonSet 资源清单
省略了
tolerations
部分。这意味着 DaemonSet 的 Pod 不会容忍任何污点,因此它将不会被调度到带有example.com/taint-key=taint-value:NoExecute
污点的节点上。
cat <<EOF > daemonset-no-tolerations.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-no-tolerations
spec:
selector:
matchLabels:
way: no-tolerations
template:
metadata:
labels:
way: no-tolerations
spec:
containers:
- name: daemonset-no-tolerations-container
image: nginx:latest
EOF
5.2.3、应用Daemonset
kubectl apply -f daemonset-no-tolerations.yaml
5.2.4、 查看 DaemonSet Pod 的状态
kubectl get pods -l way=no-tolerations -o wide
五、如何与 DaemonSet 中的 Pod 进行通信
1、 推送(Push)
- 推送模式是指 DaemonSet 中的 Pod 主动将数据发送到其他服务或系统中,如统计数据库或其他后端服务。
- 这种模式不需要外部客户端主动连接到 DaemonSet 中的 Pod。
1.1、实现
- 配置 DaemonSet:
- 需要在 DaemonSet 中的 Pod 规格中配置相应的逻辑,使其能够主动发送数据。
- 通常,这涉及到使用像 HTTP 请求、消息队列或其他通信协议来发送数据。
1.2、示例
日志聚合:
- 可以使用像 Fluentd 或 Logstash 这样的工具,配置它们将日志数据推送到像 Elasticsearch 或 Splunk 这样的后端。
- 在
daemonset-tolerations.yaml
文件中,您需要配置容器以发送日志数据:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-tolerations
spec:
selector:
matchLabels:
way: tolerations
template:
metadata:
labels:
way: tolerations
spec:
containers:
- name: daemonset-tolerations-container
image: nginx:latest
command: ["sh", "-c", "while true; do echo 'Log message'; sleep 10; done | fluentd -t -l /dev/stdin"]
volumeMounts:
- mountPath: /var/log/nginx
name: log-volume
volumes:
- name: log-volume
hostPath:
path: /var/log/nginx
这里我们假设 Fluentd 服务已经配置好,并且 Pod 将日志数据推送给 Fluentd。
2、 NodeIP 和已知端口
- NodeIP 和已知端口是指 DaemonSet 中的 Pod 使用
hostPort
,这意味着它们监听在节点的主机端口上。 - 外部客户端可以通过节点的 IP 地址和预先定义的端口来连接到这些 Pod。
2.1、实现
- 配置 DaemonSet:
- 在 DaemonSet 中的 Pod 规格中暴露
hostPort
。 - 客户端可以通过查询节点列表或通过其他方式获得节点 IP 地址,并使用预先定义的端口进行连接。
- 在 DaemonSet 中的 Pod 规格中暴露
2.2、示例
监控系统:
- 假设有一个监控系统,需要从每个节点收集指标。
- 可以配置 DaemonSet 中的每个 Pod 监听在节点的一个特定端口上,比如 9100。
- 在
daemonset-tolerations.yaml
文件中,配置容器以暴露端口:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-tolerations
spec:
selector:
matchLabels:
way: tolerations
template:
metadata:
labels:
way: tolerations
spec:
containers:
- name: daemonset-tolerations-container
image: nginx:latest
ports:
- containerPort: 80
hostPort: 9100
- 获取节点ip
kubectl get nodes -o jsonpath='{range .items[*]}{.status.addresses[?(@.type=="ExternalIP")].address}{"\n"}{end}'
3、DNS
- DNS 模式是指创建一个无头服务(Headless Service),它使用与 DaemonSet 中的 Pod 相同的选择器。
- 无头服务会创建一个 DNS 记录,该记录解析为 DaemonSet 中所有 Pod 的 IP 地址。
3.1、实现
- 创建无头服务:
- 创建一个无头服务,其选择器与 DaemonSet 的选择器相同。
- 无头服务将自动创建一个 DNS 记录,该记录指向所有匹配的 Pod 的 IP 地址。
- 客户端可以通过查询 DNS 记录来获取所有 Pod 的 IP 地址列表,并进行通信。
3.2、示例
创建一个无头服务 my-daemonset-service
,其选择器与 DaemonSet 相同。
apiVersion: v1
kind: Service
metadata:
name: my-daemonset-service
spec:
clusterIP: None
selector:
way: tolerations
ports:
- name: http
port: 80
targetPort: 80
- 客户端查询 DNS:
- 客户端可以通过查询 DNS 记录
my-daemonset-service.default.svc.cluster.local
来获取所有 Pod 的 IP 地址。 - 可以通过
nslookup
或dig
命令来查询 DNS 记录:
- 客户端可以通过查询 DNS 记录
nslookup my-daemonset-service.default.svc.cluster.local
4、Service
- Service 模式是指创建一个服务,其选择器与 DaemonSet 中的 Pod 相同。
- 客户端可以通过服务名称来访问 DaemonSet 中的任意 Pod。
4.1、实现
- 创建服务:
- 创建一个服务,其选择器与 DaemonSet 的选择器相同。
- 服务将自动创建一个 DNS 记录,该记录解析为当前活动的 Pod 的 IP 地址。
- 客户端可以通过服务名称来访问 Pod。
4.2、示例
- 创建一个服务
my-daemonset-service
,其选择器与 DaemonSet 相同。
apiVersion: v1
kind: Service
metadata:
name: my-daemonset-service
spec:
selector:
way: tolerations
ports:
- name: http
port: 80
targetPort: 80
- 客户端访问服务:
- 客户端可以通过服务名称
my-daemonset-service.default.svc.cluster.local
来访问 DaemonSet 中的任意 Pod。 - 由于服务是负载均衡的,客户端可能会随机连接到不同的 Pod。
- 客户端可以通过服务名称
热门相关:重生后我成了权臣的掌中娇 官仙 寻情仙使 纨绔毒医 功夫圣医