简体   繁体   English

Kubenetes:是否可以在 Kubernetes 集群中通过单个请求命中多个 Pod

[英]Kubenetes: Is it possible to hit multiple pods with a single request in Kubernetes cluster

I want to clear cache in all the pods in my Kubernetes namespace.我想清除 Kubernetes 命名空间中所有 pod 中的缓存。 I want to send one request to the end-point which will then send a HTTP call to all the pods in the namespace to clear cache.我想向端点发送一个请求,然后端点将向命名空间中的所有 pod 发送 HTTP 调用以清除缓存。 Currently, I can hit only one pod using Kubernetes and I do not have control over which pod would get hit.目前,我只能使用 Kubernetes 命中一个 Pod,我无法控制哪个 Pod 会被命中。

Even though the load-balancer is set to RR, continuously hitting the pods(n number of times, where n is the total number of pods) doesn't help as some other requests can creep in.即使负载平衡器设置为 RR,连续命中 Pod(n 次,其中 n 是 Pod 的总数)也无济于事,因为其他一些请求可能会蔓延。

The same issue was discussed here, but I couldn't find a solution for the implementation: https://github.com/kubernetes/kubernetes/issues/18755这里讨论了同样的问题,但我找不到实现的解决方案: https : //github.com/kubernetes/kubernetes/issues/18755

I'm trying to implement the clearing cache part using Hazelcast, wherein I will store all the cache and Hazelcast automatically takes care of the cache update.我正在尝试使用 Hazelcast 实现清除缓存部分,其中我将存储所有缓存,Hazelcast 会自动处理缓存更新。

If there is an alternative approach for this problem, or a way to configure kubernetes to hit all end-points for some specific requests, sharing here would be a great help.如果有针对此问题的替代方法,或配置 kubernetes 以针对某些特定请求命中所有端点的方法,那么在此处分享将有很大帮助。

Provided you got kubectl in your pod and have access to the api-server, you can get all endpoint adressess and pass them to curl:如果您的 pod 中有 kubectl 并且可以访问 api-server,您就可以获得所有端点地址并将它们传递给 curl:

kubectl get endpoints <servicename> \
        -o jsonpath="{.subsets[*].addresses[*].ip}" | xargs curl

Alternative without kubectl in pod:在 pod 中没有 kubectl 的替代方案:

the recommended way to access the api server from a pod is by using kubectl proxy: https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod this would of course add at least the same overhead.从 pod 访问 api 服务器的推荐方法是使用 kubectl 代理: https ://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a- pod这当然至少会增加相同的开销。 alternatively you could directly call the REST api, you'd have to provide the token manually.或者,您可以直接调用 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 " ")

if you provide the APISERVER and TOKEN variables, you don't need kubectl in your pod, this way you only need curl to access the api server and "jq" to parse the json output:如果您提供 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

UPDATE (final version)更新(最终版本)

APISERVER usually can be set to kubernetes.default.svc and the token should be available at /var/run/secrets/kubernetes.io/serviceaccount/token in the pod, so no need to provide anything manually: 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 is available here: https://stedolan.github.io/jq/download/ (< 4 MiB, but worth it for easily parsing JSON) jq 可在此处获得: https : //stedolan.github.io/jq/download/ (< 4 MiB,但值得轻松解析 JSON)

I have had the similar situation.我也有过类似的情况。 Here is how I resolved it (I'm using a namespace other than "default").这是我解决它的方法(我使用的是“默认”以外的命名空间)。

Setup access to cluster Using RBAC Authorization 使用 RBAC 授权设置对集群的访问

Access to API is done by creating a ServiceAccount , assign it to the Pod and bind a Role to it. API 的访问是通过创建一个ServiceAccount来完成的,将其分配给Pod并为其绑定一个角色

1.Create a ServiceAccount 1.创建服务账户

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-serviceaccount
  namespace: my-namespace

2.Create a Role : in this section you need to provide the list of resources and the list of actions you'd like to have access to. 2.创建角色:在此部分中,您需要提供资源列表和您想要访问的操作列表。 Here is the example where you'd like to list the endpoints and also get the details of a specific endpoint.这是您想要列出端点并获取特定端点的详细信息的示例。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: my-role
  namespace: my-namespace
rules:
- apiGroups: [""]
  resources: ["endpoints"]
  verbs: ["get", "list"]

3.Bind the role to the service account 3.将角色绑定到服务帐号

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 the service account to the pods in your deployment (it should be under template.spec) 4.将服务帐号分配给部署中的 Pod(应该在 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 使用 Kubernetes API 访问集群

Having all the security aspects set, you will have enough privilege to access the API within your Pod.设置所有安全方面后,您将有足够的权限访问 Pod 中的 API。 All the required information to communicate with API Server is mounted under /var/run/secrets/kubernetes.io/serviceaccount in your Pod.与 API Server 通信所需的所有信息都挂载在 Pod 中的/var/run/secrets/kubernetes.io/serviceaccount下。 You can use the following shell script (probably add it to your COMMAND or ENTRYPOINT of the Docker image).您可以使用以下 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

From this point forward, it is just simple REST API call.从现在开始,它只是简单的 REST API 调用。 You can read these environment variables in any language of your choice and access to API.您可以使用您选择的任何语言读取这些环境变量并访问 API。

Here is an example of listing the endpoint for your use case这是列出用例的端点的示例

# 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"

For more information on available API endpoints and how to call them, refer to API Reference .有关可用 API 端点以及如何调用它们的更多信息,请参阅API 参考

For those of you trying to find an alternative, I have used hazelcast as distributed event listener.对于那些试图寻找替代方案的人,我使用了 hazelcast 作为分布式事件侦听器。 Added a similar POC on github: https://github.com/vinrar/HazelcastAsEventListener在github上添加了一个类似的POC: https : //github.com/vinrar/HazelcastAsEventListener

I fixed this problem by usingthis script .我通过使用这个脚本解决了这个问题。 You just have to write the equivalent command to make the API call.您只需编写等效的命令即可进行 API 调用。 I used curl to do that.我用curl来做到这一点。

Following is the usage of the script:以下是脚本的用法:

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)"
}

For example to run command curl http://google.com on all pods of a service with name s1 and namespace n1 , you need to execute ./kcdo -s s1 -n n1 -- curl http://google.com .例如,要在名称为s1和命名空间n1的服务的所有 pod 上运行curl http://google.com命令,您需要执行./kcdo -s s1 -n n1 -- curl http://google.com

I needed access to all pods so I can change log level on a class so I did from the inside of one of the pods:我需要访问所有 pod 以便我可以更改类的日志级别,所以我从其中一个 pod 内部进行了操作:

// Change level to DEBUG
host <service-name>| awk '{print $4}' | 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 $4}' | while read line; do    
curl --location --request GET "http://$line:9111/actuator/loggers/com.foo.MyClassName"
echo
done

You need host and curl to execute it.您需要hostcurl来执行它。

Not sure if this is good practice.不确定这是否是好的做法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM