Kubernetes:是否可以在 Kubernetes 集群中通过单个请求命中多个 pods
Kubenetes: Is it possible to hit multiple pods with a single request in Kubernetes cluster
我想清除我的 Kubernetes 命名空间中所有 pods 中的缓存。我想向端点发送一个请求,然后端点将向命名空间中的所有 pods 发送一个 HTTP 调用以清除缓存。目前,我只能使用 Kubernetes 命中一个 pod,而且我无法控制命中哪个 pod。
即使负载均衡器设置为 RR,连续点击 pods(n 次,其中 n 是 pods 的总数)也无济于事请求可能会悄悄出现。
这里讨论了同样的问题,但我找不到实现的解决方案:
https://github.com/kubernetes/kubernetes/issues/18755
我正在尝试使用 Hazelcast 实现清除缓存部分,其中我将存储所有缓存,Hazelcast 会自动处理缓存更新。
如果有解决这个问题的替代方法,或者配置 kubernetes 以针对某些特定请求命中所有端点的方法,在这里分享将是一个很大的帮助。
如果您在 pod 中安装了 kubectl 并且可以访问 api-server,您可以获得所有端点地址并将它们传递给 curl:
kubectl get endpoints <servicename> \
-o jsonpath="{.subsets[*].addresses[*].ip}" | xargs curl
pod 中没有 kubectl 的替代方案:
从 Pod 访问 api 服务器的推荐方法是使用 kubectl 代理:https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod 这当然会增加至少相同的开销。或者您可以直接调用 REST api,您必须手动提供令牌。
APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")
TOKEN=$(kubectl describe secret $(kubectl get secrets \
| grep ^default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d " ")
如果你提供 APISERVER 和 TOKEN 变量,你的 pod 中不需要 kubectl,这样你只需要 curl 访问 api 服务器和 "jq" 解析 json输出:
curl $APISERVER/api/v1/namespaces/default/endpoints --silent \
--header "Authorization: Bearer $TOKEN" --insecure \
| jq -rM ".items[].subsets[].addresses[].ip" | xargs curl
更新(最终版本)
APISERVER 通常可以设置为 kubernetes.default.svc 并且令牌应该在 pod 中的 /var/run/secrets/kubernetes.io/serviceaccount/token 处可用,因此无需手动提供任何内容:
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token); \
curl https://kubernetes.default.svc/api/v1/namespaces/default/endpoints --silent \
--header "Authorization: Bearer $TOKEN" --insecure \
| jq -rM ".items[].subsets[].addresses[].ip" | xargs curl
jq 在此处可用:https://stedolan.github.io/jq/download/(< 4 MiB,但值得轻松解析 JSON)
对于那些试图寻找替代方案的人,我使用了 hazelcast 作为分布式事件侦听器。在 github 上添加了类似的 POC:https://github.com/vinrar/HazelcastAsEventListener
我使用 this script 解决了这个问题。您只需编写等效命令即可进行 API 调用。我用 curl
来做到这一点。
脚本的用法如下:
function usage {
echo "usage: $PROGNAME [-n NAMESPACE] [-m MAX-PODS] -s SERVICE -- COMMAND"
echo " -s SERVICE K8s service, i.e. a pod selector (required)"
echo " COMMAND Command to execute on the pods"
echo " -n NAMESPACE K8s namespace (optional)"
echo " -m MAX-PODS Max number of pods to run on (optional; default=all)"
echo " -q Quiet mode"
echo " -d Dry run (don't actually exec)"
}
例如,要在名称为 s1
和命名空间为 n1
的服务的所有 pods 上 运行 命令 curl http://google.com
,您需要执行 ./kcdo -s s1 -n n1 -- curl http://google.com
.
我也遇到过类似的情况。这是我解决它的方法(我使用的是“默认”以外的名称空间)。
设置集群访问权限Using RBAC Authorization
通过创建 ServiceAccount 来访问 API,将其分配给 Pod 并绑定 对它的作用。
1.Create一个ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-serviceaccount
namespace: my-namespace
2.Create 角色:在本节中,您需要提供您希望访问的资源列表和操作列表。这是您想要列出端点并获取特定端点的详细信息的示例。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role
namespace: my-namespace
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list"]
3.Bind服务帐号的角色
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role-binding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-serviceaccount
roleRef:
kind: Role
name: my-role
apiGroup: rbac.authorization.k8s.io
4.Assign 部署中 pods 的服务帐户(它应该在 template.spec 下)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
namespace: my-namespace
spec:
replicas: 1
selector:
matchLabels:
app: my-pod
template:
metadata:
labels:
app: my-pod
spec:
serviceAccountName: my-serviceaccount
containers:
- name: my-pod
...
Access Clusters Using the Kubernetes API
设置完所有安全方面后,您将有足够的权限访问 Pod 中的 API。与 API 服务器通信所需的所有信息都安装在 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount
下。
您可以使用以下 shell 脚本(可能将其添加到 Docker 图像的 COMMAND 或 ENTRYPOINT 中)。
#!/bin/bash
# Point to the internal API server hostname
API_SERVER=https://kubernetes.default.svc
# Path to ServiceAccount token
SERVICE_ACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
# Read this Pod's namespace
NAMESPACE=$(cat ${SERVICE_ACCOUNT}/namespace)
# Read the ServiceAccount bearer token
TOKEN=$(cat ${SERVICE_ACCOUNT}/token)
# Reference the internal certificate authority (CA)
CA_CERT=${SERVICE_ACCOUNT}/ca.crt
从现在开始,这只是简单的 REST API 调用。您可以使用您选择的任何语言阅读这些环境变量并访问 API.
这是为您的用例列出端点的示例
# List all the endpoints in the namespace that Pod is running
curl --cacert ${CA_CERT} --header "Authorization: Bearer ${TOKEN}" -X GET \
"${API_SERVER}/api/v1/namespaces/${NAMESPACE}/endpoints"
# List all the endpoints in the namespace that Pod is running for a deployment
curl --cacert ${CA_CERT} --header "Authorization: Bearer ${TOKEN}" -X GET \
"${API_SERVER}/api/v1/namespaces/${NAMESPACE}/endpoints/my-deployment"
有关可用 API 端点以及如何调用它们的更多信息,请参阅 API Reference。
我需要访问所有 pods 以便我可以更改 class 上的日志级别所以我从 pods:
之一的内部进行了更改
// Change level to DEBUG
host <service-name>| awk '{print }' | while read line; do
curl --location --request POST "http://$line:9111/actuator/loggers/com.foo.MyClassName" \
--header 'Content-Type: application/json' \
--data-raw '{"configuredLevel": "DEBUG"}'
done
// Query level on all pods
host <service-name>| awk '{print }' | while read line; do
curl --location --request GET "http://$line:9111/actuator/loggers/com.foo.MyClassName"
echo
done
您需要 host
和 curl
才能执行它。
不确定这是否是好的做法。
我想清除我的 Kubernetes 命名空间中所有 pods 中的缓存。我想向端点发送一个请求,然后端点将向命名空间中的所有 pods 发送一个 HTTP 调用以清除缓存。目前,我只能使用 Kubernetes 命中一个 pod,而且我无法控制命中哪个 pod。
即使负载均衡器设置为 RR,连续点击 pods(n 次,其中 n 是 pods 的总数)也无济于事请求可能会悄悄出现。
这里讨论了同样的问题,但我找不到实现的解决方案: https://github.com/kubernetes/kubernetes/issues/18755
我正在尝试使用 Hazelcast 实现清除缓存部分,其中我将存储所有缓存,Hazelcast 会自动处理缓存更新。
如果有解决这个问题的替代方法,或者配置 kubernetes 以针对某些特定请求命中所有端点的方法,在这里分享将是一个很大的帮助。
如果您在 pod 中安装了 kubectl 并且可以访问 api-server,您可以获得所有端点地址并将它们传递给 curl:
kubectl get endpoints <servicename> \
-o jsonpath="{.subsets[*].addresses[*].ip}" | xargs curl
pod 中没有 kubectl 的替代方案:
从 Pod 访问 api 服务器的推荐方法是使用 kubectl 代理:https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod 这当然会增加至少相同的开销。或者您可以直接调用 REST api,您必须手动提供令牌。
APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")
TOKEN=$(kubectl describe secret $(kubectl get secrets \
| grep ^default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d " ")
如果你提供 APISERVER 和 TOKEN 变量,你的 pod 中不需要 kubectl,这样你只需要 curl 访问 api 服务器和 "jq" 解析 json输出:
curl $APISERVER/api/v1/namespaces/default/endpoints --silent \
--header "Authorization: Bearer $TOKEN" --insecure \
| jq -rM ".items[].subsets[].addresses[].ip" | xargs curl
更新(最终版本)
APISERVER 通常可以设置为 kubernetes.default.svc 并且令牌应该在 pod 中的 /var/run/secrets/kubernetes.io/serviceaccount/token 处可用,因此无需手动提供任何内容:
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token); \
curl https://kubernetes.default.svc/api/v1/namespaces/default/endpoints --silent \
--header "Authorization: Bearer $TOKEN" --insecure \
| jq -rM ".items[].subsets[].addresses[].ip" | xargs curl
jq 在此处可用:https://stedolan.github.io/jq/download/(< 4 MiB,但值得轻松解析 JSON)
对于那些试图寻找替代方案的人,我使用了 hazelcast 作为分布式事件侦听器。在 github 上添加了类似的 POC:https://github.com/vinrar/HazelcastAsEventListener
我使用 this script 解决了这个问题。您只需编写等效命令即可进行 API 调用。我用 curl
来做到这一点。
脚本的用法如下:
function usage {
echo "usage: $PROGNAME [-n NAMESPACE] [-m MAX-PODS] -s SERVICE -- COMMAND"
echo " -s SERVICE K8s service, i.e. a pod selector (required)"
echo " COMMAND Command to execute on the pods"
echo " -n NAMESPACE K8s namespace (optional)"
echo " -m MAX-PODS Max number of pods to run on (optional; default=all)"
echo " -q Quiet mode"
echo " -d Dry run (don't actually exec)"
}
例如,要在名称为 s1
和命名空间为 n1
的服务的所有 pods 上 运行 命令 curl http://google.com
,您需要执行 ./kcdo -s s1 -n n1 -- curl http://google.com
.
我也遇到过类似的情况。这是我解决它的方法(我使用的是“默认”以外的名称空间)。
设置集群访问权限Using RBAC Authorization
通过创建 ServiceAccount 来访问 API,将其分配给 Pod 并绑定 对它的作用。
1.Create一个ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-serviceaccount
namespace: my-namespace
2.Create 角色:在本节中,您需要提供您希望访问的资源列表和操作列表。这是您想要列出端点并获取特定端点的详细信息的示例。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role
namespace: my-namespace
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list"]
3.Bind服务帐号的角色
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role-binding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-serviceaccount
roleRef:
kind: Role
name: my-role
apiGroup: rbac.authorization.k8s.io
4.Assign 部署中 pods 的服务帐户(它应该在 template.spec 下)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
namespace: my-namespace
spec:
replicas: 1
selector:
matchLabels:
app: my-pod
template:
metadata:
labels:
app: my-pod
spec:
serviceAccountName: my-serviceaccount
containers:
- name: my-pod
...
Access Clusters Using the Kubernetes API
设置完所有安全方面后,您将有足够的权限访问 Pod 中的 API。与 API 服务器通信所需的所有信息都安装在 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount
下。
您可以使用以下 shell 脚本(可能将其添加到 Docker 图像的 COMMAND 或 ENTRYPOINT 中)。
#!/bin/bash
# Point to the internal API server hostname
API_SERVER=https://kubernetes.default.svc
# Path to ServiceAccount token
SERVICE_ACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
# Read this Pod's namespace
NAMESPACE=$(cat ${SERVICE_ACCOUNT}/namespace)
# Read the ServiceAccount bearer token
TOKEN=$(cat ${SERVICE_ACCOUNT}/token)
# Reference the internal certificate authority (CA)
CA_CERT=${SERVICE_ACCOUNT}/ca.crt
从现在开始,这只是简单的 REST API 调用。您可以使用您选择的任何语言阅读这些环境变量并访问 API.
这是为您的用例列出端点的示例
# List all the endpoints in the namespace that Pod is running
curl --cacert ${CA_CERT} --header "Authorization: Bearer ${TOKEN}" -X GET \
"${API_SERVER}/api/v1/namespaces/${NAMESPACE}/endpoints"
# List all the endpoints in the namespace that Pod is running for a deployment
curl --cacert ${CA_CERT} --header "Authorization: Bearer ${TOKEN}" -X GET \
"${API_SERVER}/api/v1/namespaces/${NAMESPACE}/endpoints/my-deployment"
有关可用 API 端点以及如何调用它们的更多信息,请参阅 API Reference。
我需要访问所有 pods 以便我可以更改 class 上的日志级别所以我从 pods:
之一的内部进行了更改// Change level to DEBUG
host <service-name>| awk '{print }' | while read line; do
curl --location --request POST "http://$line:9111/actuator/loggers/com.foo.MyClassName" \
--header 'Content-Type: application/json' \
--data-raw '{"configuredLevel": "DEBUG"}'
done
// Query level on all pods
host <service-name>| awk '{print }' | while read line; do
curl --location --request GET "http://$line:9111/actuator/loggers/com.foo.MyClassName"
echo
done
您需要 host
和 curl
才能执行它。
不确定这是否是好的做法。