44

我想清除 Kubernetes 命名空间中所有 pod 中的缓存。我想向端点发送一个请求,然后它将向命名空间中的所有 pod 发送 HTTP 调用以清除缓存。目前,我只能使用 Kubernetes 命中一个 pod,而且我无法控制哪个 pod 会被命中。

即使负载均衡器设置为 RR,连续访问 pod(n 次,其中 n 是 pod 的总数)也无济于事,因为其他一些请求可能会悄悄进入。

这里讨论了同样的问题,但我找不到实现的解决方案: https ://github.com/kubernetes/kubernetes/issues/18755

我正在尝试使用 Hazelcast 实现清除缓存部分,其中我将存储所有缓存,Hazelcast 会自动处理缓存更新。

如果有解决此问题的替代方法,或者配置 Kubernetes 以针对某些特定请求命中所有端点的方法,那么在此处分享将有很大帮助。

4

5 回答 5

30

如果你在你的 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)

于 2018-06-11T11:53:55.507 回答
3

对于那些试图寻找替代方案的人,我使用 hazelcast 作为分布式事件侦听器。在 github 上添加了类似的 POC:https ://github.com/vinrar/HazelcastAsEventListener

于 2018-09-23T12:23:57.473 回答
3

我有过类似的情况。这是我解决它的方法(我使用的是“默认”以外的命名空间)。

使用 RBAC 授权设置对集群的访问

对 API 的访问是通过创建一个ServiceAccount来完成的,将其分配给Pod并将一个角色绑定到它。

1.创建服务账户

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 API 访问集群

设置好所有安全方面后,您将有足够的权限访问 Pod 中的 API。与 API Server 通信所需的所有信息都安装/var/run/secrets/kubernetes.io/serviceaccount在您的 Pod 中。您可以使用以下 shell 脚本(可能将其添加到您的命令或 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 参考

于 2020-12-11T14:53:39.570 回答
2

我通过使用这个脚本解决了这个问题。您只需编写等效命令即可进行 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)"
}

例如,要在具有名称和命名空间curl http://google.com的服务的所有 pod 上运行命令,您需要执行.s1n1./kcdo -s s1 -n n1 -- curl http://google.com

于 2018-10-30T06:54:58.550 回答
1

我需要访问所有 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执行它。

不确定这是否是好习惯。

于 2021-06-15T11:31:40.497 回答