Kubernetes API探索之旅的正确姿势
- - DockOne.io【编者的话】本文带你打开Kubernetes API的探索之旅的正确姿势,快来一睹为快吧. 使用CLI(如curl)或GUI(如postman)HTTP客户端调用Kubernetes API有很多理由. 例如,你可能需要对Kubernetes 对象进行比kubectl提供的更细粒度的控制,或者只是想在尝试从代码访问API之前探索它.
$ curl -sLS https://get.arkade.dev | sudo sh
$ arkade get minikube kubectl
$ minikube start --profile cluster1
curl | sudo sh
模式很吓人。从 Internet 获取软件包并在笔记本电脑上运行它们的想法也是如此。由于我没有时间检查我使用的每一段开源代码,我更喜欢隔离和一次性的开发环境。你可以在 此处阅读有关我的开发程序的更多信息。
kubectl cluster-info
输出。例如,在我的Vagrant盒子上,它会产生以下几行: $ kubectl cluster-info
Kubernetes control plane is running at https://192.168.58.2:8443
...
$ kubectl config view
apiVersion: v1
clusters:
- name: cluster1
cluster:
...
server: https://192.168.58.2:8443
- name: cluster2
cluster:
...
server: https://192.168.59.2:8443
...
因此,从上面的列表中选择正确的集群,让我们尝试向其API服务器发送请求:
默认情况下,kubectl查找目录中命名config的$HOME/.kube
文件。那么,为什么不直接从这个文件中获取API地址呢?
原因是潜在的配置合并。KUBECONFIG通过将env var设置为以冒号分隔的位置列表,可以指定多个kubeconfig文件。kubectl在访问集群之前,会尝试将所有 kubeconfig文件的内容合并到一个配置中。
$ KUBE_API=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')
幸运的是,minikube周到地将CA证书保存到了
默认情况下,curl信任底层操作系统所信任的同一组CA。例如,在Ubuntu或Debian上,受信任的CA列表可以在/etc/ssl/certs/ca-certificates.crt
。 显然,minikube不会将其证书添加到此文件中。
~/.minikube/ca.crt
: $ cat ~/.minikube/ca.crt | openssl x509 -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = minikubeCA
Validity
Not Before: Dec 15 20:46:36 2021 GMT
Not After : Dec 14 20:46:36 2031 GMT
Subject: CN = minikubeCA
Subject Public Key Info:
$ curl --cacert ~/.minikube/ca.crt $KUBE_API/version
{
"major": "1",
"minor": "22",
"gitVersion": "v1.22.3",
"gitCommit": "c92036820499fedefec0f847e2054d824aea6cd1",
"gitTreeState": "clean",
"buildDate": "2021-10-27T18:35:25Z",
"goVersion": "go1.16.9",
"compiler": "gc",
"platform": "linux/amd64"
}
提示 或者,你可以通过使用--insecure
标志或其短别名-k
来使用curl。在安全的环境中,我更喜欢不安全模式——它比试图找到颁发者证书更简单。
用户证书通常可以在我们已经熟悉的
Kubernetes 没有代表用户的对象。即,不能通过API调用将用户添加到集群中。但是,任何提供由集群的证书颁发机构签名的有效证书的用户都被视为已通过身份验证。Kubernetes从证书主题中的通用名称字段中获取用户名(例如,CN = minikube-user)。然后,Kubernetes RBAC子系统判断用户是否有权对资源执行特定操作。
kubectl config view
输出中找到: $ kubectl config view -o jsonpath='{.users[0]}' | python -m json.tool
{
"name": "cluster1",
"user": {
"client-certificate": "/home/vagrant/.minikube/profiles/cluster1/client.crt",
"client-key": "/home/vagrant/.minikube/profiles/cluster1/client.key"
}
}
$ cat ~/.minikube/profiles/cluster1/client.crt | openssl x509 -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = minikubeCA
Validity
Not Before: Dec 26 06:35:56 2021 GMT
Not After : Dec 26 06:35:56 2024 GMT
Subject: O = system:masters, CN = minikube-user
$ curl $KUBE_API/apis/apps/v1/deployments \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key
{
"kind": "DeploymentList",
"apiVersion": "apps/v1",
"metadata": {
"resourceVersion": "654514"
},
"items": [...]
}
$ JWT_TOKEN_DEFAULT_DEFAULT=$(kubectl get secrets \
$(kubectl get serviceaccounts/default -o jsonpath='{.secrets[0].name}') \
-o jsonpath='{.data.token}' | base64 --decode)
$ curl $KUBE_API/apis/apps/v1/ \
--cacert ~/.minikube/ca.crt \
--header "Authorization: Bearer $JWT_TOKEN_DEFAULT_DEFAULT"
{
"kind": "APIResourceList",
"apiVersion": "v1",
"groupVersion": "apps/v1",
"resources": [...]
}
system:serviceaccount:default:default
甚至没有足够的能力在自己的命名空间中列出Kubernetes对象。 $ JWT_TOKEN_KUBESYSTEM_DEFAULT=$(kubectl -n kube-system get secrets \
$(kubectl -n kube-system get serviceaccounts/default -o jsonpath='{.secrets[0].name}') \
-o jsonpath='{.data.token}' | base64 --decode)
$ curl $KUBE_API/apis/apps/v1/deployments \
--cacert ~/.minikube/ca.crt \
--header "Authorization: Bearer $JWT_TOKEN_KUBESYSTEM_DEFAULT"
{
"kind": "DeploymentList",
"apiVersion": "apps/v1",
"metadata": {
"resourceVersion": "656580"
},
"items": [...]
}
$ kubectl run -it --image curlimages/curl --restart=Never mypod -- sh
$ env | grep KUBERNETES
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
/var/run/secrets/kubernetes.io/serviceaccount/
。因此,应用以上部分的知识,curl从 Pod调用Kubernetes API服务器的命令如下所示: $ curl https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/apis/apps/v1 \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
--header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
GET /<resourcePlural> - Retrieve a list of type <resourceName>.
POST /<resourcePlural> - Create a new resource from the JSON
object provided by the client.
GET /<resourcePlural>/<name> - Retrieves a single resource with the
given name.
DELETE /<resourcePlural>/<name> - Delete the single resource with the
given name.
DELETE /<resourcePlural> - Deletes a list of type <resourceName>.
PUT /<resourcePlural>/<name> - Update or create the resource with the given
name with the JSON object provided by client.
PATCH /<resourcePlural>/<name> - Selectively modify the specified fields of
the resource.
GET /<resourcePlural>?watch=true - Receive a stream of JSON objects
corresponding to changes made to any
resource of the given kind over time.
以下是使用curl和YAML清单创建新对象的方法:
即使文档仅提及JSON对象,如果Content-Type标头设置为application/yaml.
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key \
-X POST \
-H 'Content-Type: application/yaml' \
-d '---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
containers:
- name: sleep
image: curlimages/curl
command: ["/bin/sleep", "365d"]
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments?watch=true \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key
以下是更新现有对象的方法:
请注意,只能监视一组资源。但是,你可以通过提供标签或字段选择器将结果集缩小到单个资源。
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key \
-X PUT \
-H 'Content-Type: application/yaml' \
-d '---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
containers:
- name: sleep
image: curlimages/curl
command: ["/bin/sleep", "730d"] # <-- Making it sleep twice longer
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key \
-X PATCH \
-H 'Content-Type: application/merge-patch+json' \
-d '{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "sleep",
"image": "curlimages/curl",
"command": ["/bin/sleep", "1d"]
}
]
}
}
}
}'
最后但同样重要的是 - 以下是如何删除对象集合:
请注意UPDATE和PATCH是相当棘手的操作。第一个受到各种版本冲突的影响,第二个的行为因使用的补丁策略而异。
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key \
-X DELETE
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
--cacert ~/.minikube/ca.crt \
--cert ~/.minikube/profiles/cluster1/client.crt \
--key ~/.minikube/profiles/cluster1/client.key \
-X DELETE
该命令在你的localhost和Kubernetes API服务器kubectl proxy之间创建一个代理服务器(或应用程序级网关)。但它必须不止于此。不然怎么会这么方便?
如果你已经使用可工作的kubectl,为什么还要直接调用Kubernetes API呢?
嗯,原因有很多。例如,你可能正在开发一个控制器并希望在不编写额外代码的情况下使用API查询。或者,你可能对kubectl操纵资源时的幕后操作不满意,这使你希望对Kubernetes对象上的操作进行更细粒度的控制。
$ curl localhost:8080/apis/apps/v1/deployments
{
"kind": "DeploymentList",
"apiVersion": "apps/v1",
"metadata": {
"resourceVersion": "660883"
},
"items": [...]
}
但也有一个缺点——我找不到任何PATCH或WATCH支持,因此curl访问为你提供了更多功能。
原始REST API客户端使用相同的身份验证意味着烘焙命令将使用(在 kubeconfig 文件中配置的任何内容)
-f这些命令通过标志支持传统的基于文件的清单输入。
-v 6
标志添加到任何kubectl命令,日志将变得如此冗长,以至于你将开始看到向Kubernetes API服务器发出的HTTP请求。 kubectl scale deployment
命令是通过对子资源的PATCH请求实现的 /deployments/<name>/scale
: $ kubectl scale deployment sleep --replicas=2 -v 6
I0116 ... loader.go:372] Config loaded from file: /home/vagrant/.kube/config
I0116 ... cert_rotation.go:137] Starting client certificate rotation controller
I0116 ... round_trippers.go:454] GET https://192.168.58.2:8443/apis/apps/v1/namespaces/default/deployments/sleep 200 OK in 14 milliseconds
I0116 ... round_trippers.go:454] PATCH https://192.168.58.2:8443/apis/apps/v1/namespaces/default/deployments/sleep/scale 200 OK in 12 milliseconds deployment.apps/sleep scaled
kubectl apply -v 6
,结果可能非常有见地??
想查看实际的请求和响应主体吗?将日志详细程度增加到8。