从 Pod 中访问 Kubernetes API
本指南演示了如何从 Pod 中访问 Kubernetes API。
准备开始
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
从 Pod 中访问 API
从 Pod 内部访问 API 时,定位 API 服务器和向服务器认证身份的操作与外部客户端场景不同。
从 Pod 使用 Kubernetes API 的最简单的方法就是使用官方的 客户端库。 这些库可以自动发现 API 服务器并进行身份验证。
使用官方客户端库
从一个 Pod 内部连接到 Kubernetes API 的推荐方式为:
-
对于 Go 语言客户端,使用官方的 Go 客户端库。 函数
rest.InClusterConfig()
自动处理 API 主机发现和身份认证。 参见这里的一个例子。 -
对于 Python 客户端,使用官方的 Python 客户端库。 函数
config.load_incluster_config()
自动处理 API 主机的发现和身份认证。 参见这里的一个例子。 -
还有一些其他可用的客户端库,请参阅客户端库页面。
在以上场景中,客户端库都使用 Pod 的服务账号凭据来与 API 服务器安全地通信。
直接访问 REST API
在运行在 Pod 中时,你的容器可以通过获取 KUBERNETES_SERVICE_HOST
和
KUBERNETES_SERVICE_PORT_HTTPS
环境变量为 Kubernetes API
服务器生成一个 HTTPS URL。
API 服务器的集群内地址也发布到 default
命名空间中名为 kubernetes
的 Service 中,
从而 Pod 可以引用 kubernetes.default.svc
作为本地 API 服务器的 DNS 名称。
说明:
Kubernetes 不保证 API 服务器具有主机名 kubernetes.default.svc
的有效证书;
但是,控制平面应该为 $KUBERNETES_SERVICE_HOST
代表的主机名或 IP 地址提供有效证书。
向 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 命令。 内部的证书机制能够为连接提供保护。
# 指向内部 API 服务器的主机名
APISERVER=https://kubernetes.default.svc
# 服务账号令牌的路径
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
# 读取 Pod 的名字空间
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
# 读取服务账号的持有者令牌
TOKEN=$(cat ${SERVICEACCOUNT}/token)
# 引用内部证书机构(CA)
CACERT=${SERVICEACCOUNT}/ca.crt
# 使用令牌访问 API
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api
输出类似于:
{
"kind": "APIVersions",
"versions": ["v1"],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}