使用 Kubernetes API 访问集群

本页展示了如何使用 Kubernetes API 访问集群

准备开始

你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。 如果你还没有集群,你可以通过 Minikube 构建一 个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:

要获知版本信息,请输入 kubectl version.

访问集群 API

使用 kubectl 进行首次访问

首次访问 Kubernetes API 时,请使用 Kubernetes 命令行工具 kubectl

要访问集群,你需要知道集群位置并拥有访问它的凭证。 通常,当你完成入门指南时,这会自动设置完成,或者由其他人设置好集群并将凭证和位置提供给你。

使用此命令检查 kubectl 已知的位置和凭证:

  1. kubectl config view

许多样例 提供了使用 kubectl 的介绍。完整文档请见 kubectl 手册

直接访问 REST API

kubectl 处理对 API 服务器的定位和身份验证。如果你想通过 http 客户端(如 curlwget,或浏览器)直接访问 REST API,你可以通过多种方式对 API 服务器进行定位和身份验证:

  1. 以代理模式运行 kubectl(推荐)。 推荐使用此方法,因为它用存储的 apiserver 位置并使用自签名证书验证 API 服务器的标识。 使用这种方法无法进行中间人(MITM)攻击。
  2. 另外,你可以直接为 HTTP 客户端提供位置和身份认证。 这适用于被代理混淆的客户端代码。 为防止中间人攻击,你需要将根证书导入浏览器。

使用 Go 或 Python 客户端库可以在代理模式下访问 kubectl。

使用 kubectl 代理

下列命令使 kubectl 运行在反向代理模式下。它处理 API 服务器的定位和身份认证。

像这样运行它:

  1. kubectl proxy --port=8080 &

参见 kubectl 代理 获取更多细节。

然后你可以通过 curl,wget,或浏览器浏览 API,像这样:

  1. curl http://localhost:8080/api/

输出类似如下:

  1. {
  2. "versions": [
  3. "v1"
  4. ],
  5. "serverAddressByClientCIDRs": [
  6. {
  7. "clientCIDR": "0.0.0.0/0",
  8. "serverAddress": "10.0.1.149:443"
  9. }
  10. ]
  11. }

不使用 kubectl 代理

通过将身份认证令牌直接传给 API 服务器,可以避免使用 kubectl 代理,像这样:

使用 grep/cut 方式:

  1. # 查看所有的集群,因为你的 .kubeconfig 文件中可能包含多个上下文
  2. kubectl config view -o jsonpath='{"Cluster name\tServer\n"}{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}'
  3. # 从上述命令输出中选择你要与之交互的集群的名称
  4. export CLUSTER_NAME="some_server_name"
  5. # 指向引用该集群名称的 API 服务器
  6. APISERVER=$(kubectl config view -o jsonpath="{.clusters[?(@.name==\"$CLUSTER_NAME\")].cluster.server}")
  7. # 获得令牌
  8. TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}"|base64 -d)
  9. # 使用令牌玩转 API
  10. curl -X GET $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure

输出类似如下:

  1. {
  2. "kind": "APIVersions",
  3. "versions": [
  4. "v1"
  5. ],
  6. "serverAddressByClientCIDRs": [
  7. {
  8. "clientCIDR": "0.0.0.0/0",
  9. "serverAddress": "10.0.1.149:443"
  10. }
  11. ]
  12. }

使用 jsonpath 方式:

  1. APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
  2. TOKEN=$(kubectl get secret $(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 --decode )
  3. curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
  1. {
  2. "kind": "APIVersions",
  3. "versions": [
  4. "v1"
  5. ],
  6. "serverAddressByClientCIDRs": [
  7. {
  8. "clientCIDR": "0.0.0.0/0",
  9. "serverAddress": "10.0.1.149:443"
  10. }
  11. ]
  12. }

上面例子使用了 --insecure 标志位。这使它易受到 MITM 攻击。 当 kubectl 访问集群时,它使用存储的根证书和客户端证书访问服务器。 (已安装在 ~/.kube 目录下)。 由于集群认证通常是自签名的,因此可能需要特殊设置才能让你的 http 客户端使用根证书。

在一些集群中,API 服务器不需要身份认证;它运行在本地,或由防火墙保护着。 对此并没有一个标准。 配置对 API 的访问 阐述了一个集群管理员如何对此进行配置。这种方法可能与未来的高可用性支持发生冲突。

编程方式访问 API

Kubernetes 官方支持 GoPythonJavadotnetJavascriptHaskell 语言的客户端库。还有一些其他客户端库由对应作者而非 Kubernetes 团队提供并维护。 参考客户端库了解如何使用其他语言 来访问 API 以及如何执行身份认证。

Go 客户端

  • 要获取库,运行下列命令:go get k8s.io/client-go/<版本号>/kubernetes, 参见 https://github.com/kubernetes/client-go 查看受支持的版本。
  • 基于 client-go 客户端编写应用程序。

说明: 注意 client-go 定义了自己的 API 对象,因此如果需要,请从 client-go 而不是主仓库导入 API 定义,例如 import "k8s.io/client-go/kubernetes" 是正确做法。

Go 客户端可以使用与 kubectl 命令行工具相同的 kubeconfig 文件 定位和验证 API 服务器。参见这个 例子

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "k8s.io/apimachinery/pkg/apis/meta/v1"
  6. "k8s.io/client-go/kubernetes"
  7. "k8s.io/client-go/tools/clientcmd"
  8. )
  9. func main() {
  10. // uses the current context in kubeconfig
  11. // path-to-kubeconfig -- for example, /root/.kube/config
  12. config, _ := clientcmd.BuildConfigFromFlags("", "<path-to-kubeconfig>")
  13. // creates the clientset
  14. clientset, _ := kubernetes.NewForConfig(config)
  15. // access the API to list pods
  16. pods, _ := clientset.CoreV1().Pods("").List(context.TODO(), v1.ListOptions{})
  17. fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
  18. }

如果该应用程序部署为集群中的一个 Pod,请参阅下一节

Python 客户端

要使用 Python 客户端,运行下列命令: pip install kubernetes。 参见 Python 客户端库主页 了解更多安装选项。

Python 客户端可以使用与 kubectl 命令行工具相同的 kubeconfig 文件 定位和验证 API 服务器。参见这个 例子

  1. from kubernetes import client, config
  2. config.load_kube_config()
  3. v1=client.CoreV1Api()
  4. print("Listing pods with their IPs:")
  5. ret = v1.list_pod_for_all_namespaces(watch=False)
  6. for i in ret.items:
  7. print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name))

Java 客户端

  1. # 克隆 Java 库
  2. git clone --recursive https://github.com/kubernetes-client/java
  3. # 安装项目文件、POM 等
  4. cd java
  5. mvn install

参阅https://github.com/kubernetes-client/java/releases 了解当前支持的版本。

Java 客户端可以使用 kubectl 命令行所使用的 kubeconfig 文件 以定位 API 服务器并向其认证身份。 参看此示例

  1. package io.kubernetes.client.examples;
  2. import io.kubernetes.client.ApiClient;
  3. import io.kubernetes.client.ApiException;
  4. import io.kubernetes.client.Configuration;
  5. import io.kubernetes.client.apis.CoreV1Api;
  6. import io.kubernetes.client.models.V1Pod;
  7. import io.kubernetes.client.models.V1PodList;
  8. import io.kubernetes.client.util.ClientBuilder;
  9. import io.kubernetes.client.util.KubeConfig;
  10. import java.io.FileReader;
  11. import java.io.IOException;
  12. /**
  13. * A simple example of how to use the Java API from an application outside a kubernetes cluster
  14. *
  15. * <p>Easiest way to run this: mvn exec:java
  16. * -Dexec.mainClass="io.kubernetes.client.examples.KubeConfigFileClientExample"
  17. *
  18. */
  19. public class KubeConfigFileClientExample {
  20. public static void main(String[] args) throws IOException, ApiException {
  21. // file path to your KubeConfig
  22. String kubeConfigPath = "~/.kube/config";
  23. // loading the out-of-cluster config, a kubeconfig from file-system
  24. ApiClient client =
  25. ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build();
  26. // set the global default api-client to the in-cluster one from above
  27. Configuration.setDefaultApiClient(client);
  28. // the CoreV1Api loads default api-client from global configuration.
  29. CoreV1Api api = new CoreV1Api();
  30. // invokes the CoreV1Api client
  31. V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
  32. System.out.println("Listing all pods: ");
  33. for (V1Pod item : list.getItems()) {
  34. System.out.println(item.getMetadata().getName());
  35. }
  36. }
  37. }

.Net 客户端

要使用 .Net 客户端,运行下面的命令: dotnet add package KubernetesClient --version 1.6.1。 参见 .Net 客户端库页面了解更多安装选项。 关于可支持的版本,参见https://github.com/kubernetes-client/csharp/releases

  1. using System;
  2. using k8s;
  3. namespace simple
  4. {
  5. internal class PodList
  6. {
  7. private static void Main(string[] args)
  8. {
  9. var config = KubernetesClientConfiguration.BuildDefaultConfig();
  10. IKubernetes client = new Kubernetes(config);
  11. Console.WriteLine("Starting Request!");
  12. var list = client.ListNamespacedPod("default");
  13. foreach (var item in list.Items)
  14. {
  15. Console.WriteLine(item.Metadata.Name);
  16. }
  17. if (list.Items.Count == 0)
  18. {
  19. Console.WriteLine("Empty!");
  20. }
  21. }
  22. }
  23. }

JavaScript 客户端

要安装 JavaScript 客户端,运行下面的命令: npm install @kubernetes/client-node。 参考https://github.com/kubernetes-client/javascript/releases了解可支持的版本。

JavaScript 客户端可以使用 kubectl 命令行所使用的 kubeconfig 文件 以定位 API 服务器并向其认证身份。 参见此例

  1. const k8s = require('@kubernetes/client-node');
  2. const kc = new k8s.KubeConfig();
  3. kc.loadFromDefault();
  4. const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
  5. k8sApi.listNamespacedPod('default').then((res) => {
  6. console.log(res.body);
  7. });

Haskell 客户端

参考 https://github.com/kubernetes-client/haskell/releases 了解支持的版本。

Haskell 客户端 可以使用 kubectl 命令行所使用的 kubeconfig 文件 以定位 API 服务器并向其认证身份。 参见此例

  1. exampleWithKubeConfig :: IO ()
  2. exampleWithKubeConfig = do
  3. oidcCache <- atomically $ newTVar $ Map.fromList []
  4. (mgr, kcfg) <- mkKubeClientConfig oidcCache $ KubeConfigFile "/path/to/kubeconfig"
  5. dispatchMime
  6. mgr
  7. kcfg
  8. (CoreV1.listPodForAllNamespaces (Accept MimeJSON))
  9. >>= print

从 Pod 中访问 API

从 Pod 内部访问 API 时,定位 API 服务器和向服务器认证身份的操作 与上面描述的外部客户场景不同。

从 Pod 使用 Kubernetes API 的最简单的方法就是使用官方的 客户端库。 这些库可以自动发现 API 服务器并进行身份验证。

使用官方客户端库

从一个 Pod 内部连接到 Kubernetes API 的推荐方式为:

在以上场景中,客户端库都使用 Pod 的服务账号凭据来与 API 服务器安全地通信。

直接访问 REST API

在运行在 Pod 中时,可以通过 default 命名空间中的名为 kubernetes 的服务访问 Kubernetes API 服务器。也就是说,Pod 可以使用 kubernetes.default.svc 主机名 来查询 API 服务器。官方客户端库自动完成这个工作。

向 API 服务器进行身份认证的推荐做法是使用 服务账号凭据。 默认情况下,每个 Pod 与一个服务账号关联,该服务账户的凭证(令牌)放置在此 Pod 中 每个容器的文件系统树中的 /var/run/secrets/kubernetes.io/serviceaccount/token 处。

如果由证书包可用,则凭证包被放入每个容器的文件系统树中的 /var/run/secrets/kubernetes.io/serviceaccount/ca.crt 处, 且将被用于验证 API 服务器的服务证书。

最后,用于命名空间域 API 操作的默认命名空间放置在每个容器中的 /var/run/secrets/kubernetes.io/serviceaccount/namespace 文件中。

使用 kubectl proxy

如果你希望不实用官方客户端库就完成 API 查询,可以将 kubectl proxy 作为 command 在 Pod 启动一个边车(Sidecar)容器。这样,kubectl proxy 自动完成对 API 的身份认证,并将其暴露到 Pod 的 localhost 接口,从而 Pod 中的其他容器可以 直接使用 API。

不使用代理

通过将认证令牌直接发送到 API 服务器,也可以避免运行 kubectl proxy 命令。 内部的证书机制能够为链接提供保护。

  1. # 指向内部 API 服务器的主机名
  2. APISERVER=https://kubernetes.default.svc
  3. # 服务账号令牌的路径
  4. SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
  5. # 读取 Pod 的名字空间
  6. NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
  7. # 读取服务账号的持有者令牌
  8. TOKEN=$(cat ${SERVICEACCOUNT}/token)
  9. # 引用内部整数机构(CA)
  10. CACERT=${SERVICEACCOUNT}/ca.crt
  11. # 使用令牌访问 API
  12. curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api

输出类似于:

  1. {
  2. "kind": "APIVersions",
  3. "versions": [
  4. "v1"
  5. ],
  6. "serverAddressByClientCIDRs": [
  7. {
  8. "clientCIDR": "0.0.0.0/0",
  9. "serverAddress": "10.0.1.149:443"
  10. }
  11. ]
  12. }