如何从 pod 容器中访问 Kubernetes api?

How do I access the Kubernetes api from within a pod container?

我以前会卷发

https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1beta3/namespaces/default/

作为我的基础 URL,但在 kubernetes 0.18.0 中它给了我 "unauthorized"。奇怪的是,如果我使用 API 机器(http://172.17.8.101:8080/api/v1beta3/namespaces/default/)的外部 IP 地址,它工作正常。

在官方文档中我发现了这个:

https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod

显然我丢失了一个安全令牌,而在以前的 Kubernetes 版本中我不需要它。由此,我设计了一个我认为比 运行 代理或在我的容器上安装 golang 更简单的解决方案。请参阅此示例,该示例从 api 获取当前容器的信息:

KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" \
      https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME

我还使用包含一个简单的二进制文件 jq (http://stedolan.github.io/jq/download/) 来解析 json 以便在 bash 脚本中使用。

每个 pod 都有一个自动应用的服务帐户,允许它访问 apiserver。服务帐户以不记名令牌的形式提供客户端凭据,以及用于签署 apiserver 提供的证书的证书颁发机构证书。使用这两条信息,您可以创建一个安全的、经过身份验证的到 apiserver 的连接,而无需使用 curl -k(又名 curl --insecure):

curl -v --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/
curl -v -cacert <path to>/ca.crt --cert <path to>/kubernetes-node.crt --key <path to>/kubernetes-node.key https://<ip:port>

我的k8s版本是1.2.0,其他版本应该也可以吧^^

对于使用 Google 容器引擎(由 Kubernetes 提供支持)的任何人:

使用 this kubernetes client for Java 从集群内简单调用 https://kubernetes 即可。

从 pod 内部,可以直接在“https://kubernetes.default”上访问 kubernetes api 服务器。默认情况下,它使用 "default service account" 访问 api 服务器。

因此,我们还需要传递 "ca cert" 和 "default service account token" 以向 api 服务器进行身份验证。

证书文件存储在 pod 内的以下位置: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

默认服务帐户令牌位于: /var/run/secrets/kubernetes.io/serviceaccount/token

您可以使用 nodejs kubbernetes godaddy client.

let getRequestInfo = () => {
    return {
        url: "https://kubernetes.default",
        ca:   fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt').toString(),
        auth: {
            bearer: fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token').toString(),
        },
        timeout: 1500
    };
}

let initK8objs = () =>{
    k8obj = getRequestInfo();
    k8score = new Api.Core(k8obj),
    k8s = new Api.Api(k8obj);
}

使用 Python kubernetes 客户端..

from kubernetes import client, config

config.load_incluster_config()
v1_core = client.CoreV1Api()

wget 版本:

KUBE_TOKEN=$(</var/run/secrets/kubernetes.io/serviceaccount/token)    
wget -vO- --ca-certificate /var/run/secrets/kubernetes.io/serviceaccount/ca.crt  --header "Authorization: Bearer $KUBE_TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME

启用 RBAC 后,默认服务帐户没有任何权限。

最好根据您的需要创建单独的服务帐户并使用它来创建您的广告连播。

spec:
  serviceAccountName: secret-access-sa
  containers:
    ...

这里解释的很好https://developer.ibm.com/recipes/tutorials/service-accounts-and-auditing-in-kubernetes/

我 运行 在尝试使用 Go 代码从 pod 内部访问 API 时遇到了这个问题。如果有人遇到这个问题也想使用 Go,下面是我为使它正常工作而实施的方法。

该示例使用 pod 资源,如果您使用本机 kubernetes 对象,则应使用 client-go 库。该代码对那些使用 CustomResourceDefintions 的人更有帮助。

serviceHost := os.GetEnv("KUBERNETES_SERVICE_HOST")
servicePort := os.GetEnv("KUBERNETES_SERVICE_PORT")
apiVersion := "v1" // For example
namespace := default // For example
resource := "pod" // For example
httpMethod := http.MethodGet // For Example

url := fmt.Sprintf("https://%s:%s/apis/%s/namespaces/%s/%s", serviceHost, servicePort, apiVersion, namespace, resource)

u, err := url.Parse(url)
if err != nil {
  panic(err)
}
req, err := http.NewRequest(httpMethod, u.String(), bytes.NewBuffer(payload))
if err != nil {
    return err
}

caToken, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil {
    panic(err) // cannot find token file
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(caToken)))

caCertPool := x509.NewCertPool()
caCert, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
if err != nil {
    return panic(err) // Can't find cert file
}
caCertPool.AppendCertsFromPEM(caCert)

client := &http.Client{
  Transport: &http.Transport{
    TLSClientConfig: &tls.Config{
        RootCAs: caCertPool,
    },
  },
}

resp, err := client.Do(req)
if err != nil {
    log.Printf("sending helm deploy payload failed: %s", err.Error())
    return err
}
defer resp.Body.Close()

// Check resp.StatusCode
// Check resp.Status

我在 GKE 上遇到了类似的身份验证问题,其中 python 脚本突然抛出异常。对我有用的解决方案是通过角色

授予 pods 权限
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: fabric8-rbac
subjects:
  - kind: ServiceAccount
  # Reference to upper's `metadata.name`
  name: default
  # Reference to upper's `metadata.namespace`
  namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

了解更多信息enter link description here

对上面已经提到的细节最重要的补充是,您尝试从中访问 API 服务器的 pod 应该具有这样做的 RBAC 功能。

k8s 系统中的每个实体都由一个服务帐户标识(例如用于用户的用户帐户)。根据 RBAC 功能,填充服务帐户令牌 (/var/run/secrets/kubernetes.io/serviceaccount/token)。 kube-api 绑定(例如 pykube)可以在创建与 kube-api-servers 的连接时将此令牌作为输入。如果 pod 具有正确的 RBAC 功能,则 pod 将能够与 kube-api 服务器建立连接。

This is from the Kubernetes In Action book.

您需要注意身份验证。 API 服务器本身说您无权访问它,因为 它不知道您是谁

要进行身份验证,您需要一个 身份验证令牌。 幸运的是,令牌是通过前面提到的 default-token Secret 提供的,并且存储在秘密卷中的令牌文件中。

您将使用 令牌 访问 API 服务器。首先,将令牌加载到环境变量中:

root@myhome:/# TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

令牌现在存储在 TOKEN environment variable 中。您可以在向 API 服务器发送请求时使用它:

root@curl:/# curl -H "Authorization: Bearer $TOKEN"  https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME
   {  "paths": 
      [    
        "/api",    
        "/api/v1",   
        "/apis",    
        "/apis/apps",    
        "/apis/apps/v1beta1",    
        "/apis/authorization.k8s.io",        
         ...    
        "/ui/",    
        "/version"  
      ]
  }