Kubenetes:是否可以在Kubernetes集群中一次请求命中多个示例

rkttyhzu  于 2022-10-23  发布在  Kubernetes
关注(0)|答案(5)|浏览(142)

我想清除Kubernetes命名空间中所有Pod中的缓存。我想向端点发送一个请求,然后该端点将向命名空间中的所有Pod发送一个HTTP调用以清除缓存。目前,我只能用Kubernetes命中一个吊舱,而且我无法控制哪个吊舱会被击中。
即使将负载均衡器设置为RR,连续命中Pod(n次,其中n是Pod的总数)也没有帮助,因为其他一些请求可能会悄悄进入。
这里讨论了相同的问题,但我找不到实现的解决方案:https://github.com/kubernetes/kubernetes/issues/18755
我正在尝试使用Hazelcast来实现清除缓存部分,其中我将存储所有的缓存,而Hazelcast会自动处理缓存更新。
如果有替代方法来解决这个问题,或者有一种方法可以配置Kubernetes以针对某些特定请求命中所有端点,那么这里的共享将是一个很大的帮助。

but5z9lq

but5z9lq1#

假设您的pod中有kubectl并有权访问API服务器,您就可以获取所有端点地址并将它们传递给cURL:

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

示例中没有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)

lsmepo6l

lsmepo6l2#

更新我为该方法发布了this article

我也遇到过类似的情况。下面是我如何解析它的(我使用的名称空间不是“Default”)。

使用RBAC授权设置集群访问权限

访问API的方法是创建一个ServiceAccount,将其分配给Pod,并绑定一个角色
创建ServiceAccount

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

2.创建角色:在此部分中,您需要提供您希望访问的资源列表和操作列表。以下是您想要列出端点并获取特定端点的详细信息的示例。

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

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.将服务帐户分配给部署中的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
        ...

使用Kubernetes接口访问集群

设置了所有安全方面后,您将有足够的权限访问Pod中的API。与API服务器通信所需的所有信息都安装在Pod的/var/run/secrets/kubernetes.io/serviceaccount下。您可以使用以下外壳脚本(可能将其添加到您的命令或Docker映像的入口点)。


# !/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参考。

csbfibhn

csbfibhn3#

对于那些试图找到替代方案的人,我已经使用了Hazelcast作为分布式事件监听器。在GitHub上添加了类似的PoC:https://github.com/vinrar/HazelcastAsEventListener

zengzsys

zengzsys4#

我使用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的服务的所有Pod上运行命令curl http://google.com,您需要执行./kcdo -s s1 -n n1 -- curl http://google.com

7d7tgy0s

7d7tgy0s5#

我需要访问所有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

您需要hostcurl来执行它。
我不确定这是不是很好的做法。

相关问题