API Server的基本操作

Kubernetes 中的资源访问类型有两种。

  • 一种是由 Pod 提供的服务资源,它可通过Service或Ingress发布以供外部访问,这种访问不需要经过API Server的认证。

  • 另一种是对集群内部资源的操作,它需要通过API Server访问,而且要经过一定的认证授权才能进行操作。

API Server提供了对Kubernetes中各类资源对象进行增删改查等操作的HTTP REST接口。对资源执行的任何操作,都需要由API Server 处理。

在之前所有的演示中,我们是通过命令行工具kubectl客户端来访问API Server的,kubectl客户端将把命令行转换为对API Server的 REST API调用。如果要对Kubernetes的功能进行自定义扩展或二次开发,则需要直接调用API Server的REST API。

我们先在Master节点上打开kubectl反向代理,通过使kubectl反向代理API Server,可以直接使用kubectl命令的认证授权来访问API Server。

$ kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080

API Server支持的操作非常多,可以通过以下命令获取API的Swagger Json定义,它对每个API都进行了详细说明。

$ curl http://localhost:8080/openapi/v2

由于API众多,本节并不打算介绍所有的API,每一个API的具体使用方法可以参见官方文档,或访问API Server的路径/openapi/v2(在 本例中为http://localhost:8080/openapi/v2)来获取Swagger.json格式的详细说明。

1 写操作

1.1 创建资源

创建资源的API调用方式如下。

HTTP请求
    POST
    /{apiVersion}/namespaces/{namespace}/{资源类型}

创建资源的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br />daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |

创建资源的API的请求体只有一个参数——资源类型Json对象,它表示使用Json方式描述的资源对象,等同于之前介绍的yaml模板,只 是这里用Json表现方式传入。

创建资源的API的返回值

状态码

返回消息体

描述

202

创建后的资源类型Json对象

请求已接受(accepted)

200

创建后的资源类型Json对象

请求成功(OK)

201

创建后的资源类型Json对象

请求已创建(created)

例如,要创建一个Pod对象,执行以下命令。

$ curl http://localhost:8080/api/v1/namespaces/default/pods -H "Content-Type:application/json" -X \
        POST -d '{
        "apiVersion": "v1",
        "kind": "Pod",
        "metadata": {
        "name": "examplepod"
        },
    "spec": {
    "containers": [
        {
        "name": "examplepod-container",
        "image": "busybox",
        "imagePullPolicy": "IfNotPresent",
        "command": ["sh","-c"],
        "args": ["echo \"Hello Kubernetes!\"; sleep 3600"]
        }
      ]
    }
}'

本例中使用curl命令来执行http请求,请求地址为http://localhost:8080/api/v1/namespaces/default/pods,命名空间为default。-H参数表示增加请求的Header,在本例中为“Content-Type:application/json”;-X参数表示要使用的HttpMethod,在本例中为POST请求;-d参数表示要传入的请求体,在本例中为Pod模板的Json形式,模板字符串包含在一对单引号当中。

若通过$ kubectl get pod命令查看Pod列表,可以看到Pod已成功创建

$ kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
examplepod   1/1     Running   0          <invalid>

其余资源(如控制器、Service、PVC、ConfigMap等)也可以使用这种方式创建。

1.2 替换资源

替换资源的API调用方式如下。

HTTP请求
    PUT
    /{apiVersion}/namespaces/{namespace}/{资源类型}/{name}

替换资源的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

替换资源的API的请求体只有一个参数——资源类型Json对象,它表示使用Json方式描述的资源对象,等同于之前介绍的yaml模板,只 是这里用Json表现方式传入。

替换资源的API的返回值如表

状态码

返回消息体

描述

200

替换后的资源类型Json对象

请求成功(OK)

201

替换后的资源类型Json对象

请求已创建(created)

我们修改之前示例中定义的Pod,为其增加标签(label),即key1: value1。可以使用API修改之前创建的Pod,但这种更新相对 死板,需要先通过$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod获取当前的Pod信息,然后粘贴status属性之前的所有片段以作为请求体的基础,并添加标签信息。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod -H \
"Content-Type:application/json" -X PUT -d '{
    "kind": "Pod",
    "apiVersion": "v1",
    "metadata": {
        "name": "examplepod",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/examplepod",
        "uid": "17a4a6e2-91ff-43b9-b9bc-ed37e8176a64",
        "resourceVersion": "82851536",
        "creationTimestamp": "2022-04-20T05:40:20Z",
        "labels": {
            "key1": "value1"
        },
        "managedFields": [
            {
                "manager": "curl",
                "operation": "Update",
                "apiVersion": "v1",
                "time": "2022-04-20T05:40:20Z",
                "fieldsType": "FieldsV1",
                "fieldsV1": {
                    "f:spec": {
                        "f:containers": {
                            "k:{\"name\":\"examplepod-container\"}": {
                                ".": {},
                                "f:args": {},
                                "f:command": {},
                                "f:image": {},
                                "f:imagePullPolicy": {},
                                "f:name": {},
                                "f:resources": {},
                                "f:terminationMessagePath": {},
                                "f:terminationMessagePolicy": {}
                            }
                        },
                        "f:dnsPolicy": {},
                        "f:enableServiceLinks": {},
                        "f:restartPolicy": {},
                        "f:schedulerName": {},
                        "f:securityContext": {},
                        "f:terminationGracePeriodSeconds": {}
                    }
                }
            },
            {
                "manager": "kubelet",
                "operation": "Update",
                "apiVersion": "v1",
                "time": "2022-04-20T05:40:22Z",
                "fieldsType": "FieldsV1",
                "fieldsV1": {
                    "f:status": {
                        "f:conditions": {
                            "k:{\"type\":\"ContainersReady\"}": {
                                ".": {},
                                "f:lastProbeTime": {},
                                "f:lastTransitionTime": {},
                                "f:status": {},
                                "f:type": {}
                            },
                            "k:{\"type\":\"Initialized\"}": {
                                ".": {},
                                "f:lastProbeTime": {},
                                "f:lastTransitionTime": {},
                                "f:status": {},
                                "f:type": {}
                            },
                            "k:{\"type\":\"Ready\"}": {
                                ".": {},
                                "f:lastProbeTime": {},
                                "f:lastTransitionTime": {},
                                "f:status": {},
                                "f:type": {}
                            }
                        },
                        "f:containerStatuses": {},
                        "f:hostIP": {},
                        "f:phase": {},
                        "f:podIP": {},
                        "f:podIPs": {
                            ".": {},
                            "k:{\"ip\":\"10.0.6.212\"}": {
                                ".": {},
                                "f:ip": {}
                            }
                        },
                        "f:startTime": {}
                    }
                }
            }
        ]
    },
    "spec": {
        "volumes": [
            {
                "name": "kube-api-access-dzpd6",
                "projected": {
                    "sources": [
                        {
                            "serviceAccountToken": {
                                "expirationSeconds": 3607,
                                "path": "token"
                            }
                        },
                        {
                            "configMap": {
                                "name": "kube-root-ca.crt",
                                "items": [
                                    {
                                        "key": "ca.crt",
                                        "path": "ca.crt"
                                    }
                                ]
                            }
                        },
                        {
                            "downwardAPI": {
                                "items": [
                                    {
                                        "path": "namespace",
                                        "fieldRef": {
                                            "apiVersion": "v1",
                                            "fieldPath": "metadata.namespace"
                                        }
                                    }
                                ]
                            }
                        }
                    ],
                    "defaultMode": 420
                }
            }
        ],
        "containers": [
            {
                "name": "examplepod-container",
                "image": "busybox",
                "command": [
                    "sh",
                    "-c"
                ],
                "args": [
                    "echo \"Hello Kubernetes!\"; sleep 3600"
                ],
                "resources": {},
                "volumeMounts": [
                    {
                        "name": "kube-api-access-dzpd6",
                        "readOnly": true,
                        "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
                    }
                ],
                "terminationMessagePath": "/dev/termination-log",
                "terminationMessagePolicy": "File",
                "imagePullPolicy": "IfNotPresent"
            }
        ],
        "restartPolicy": "Always",
        "terminationGracePeriodSeconds": 30,
        "dnsPolicy": "ClusterFirst",
        "serviceAccountName": "default",
        "serviceAccount": "default",
        "nodeName": "gitee-k8s-w27",
        "securityContext": {},
        "schedulerName": "default-scheduler",
        "tolerations": [
            {
                "key": "node.kubernetes.io/not-ready",
                "operator": "Exists",
                "effect": "NoExecute",
                "tolerationSeconds": 300
            },
            {
                "key": "node.kubernetes.io/unreachable",
                "operator": "Exists",
                "effect": "NoExecute",
                "tolerationSeconds": 300
            }
        ],
        "priority": 0,
        "enableServiceLinks": true,
        "preemptionPolicy": "PreemptLowerPriority"
    }
}'

可以看到,整个请求体里面包含了非常多不相关的文本,这就是直接使用PUT请求的弊端。

1.3 更新资源

上述方式使用的是完全更新,还可以实现局部更新,其调用方式如下。

HTTP请求
    PATCH
    /{apiVersion}/namespaces/{namespace}/{资源类型}/{name}

更新资源的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

更新资源的API的请求体只有一个参数——局部更新的对象,这表示使用Json方式描述的对象,相当于Json模板中的某个片段对象。

更新资源的API的返回值只有一个状态码200,表示请求成功(OK),返回的消息体表示更新资源类型后完整的Json对象。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod -H \
    "Content-Type:application/merge-patch+json" -X PATCH -d '{
    "metadata": {
        "labels": {
            "key1": "value2"
        }
    }
}'

本例中的局部更新效果和之前全局更新的效果一致。区别在于,在局部更新时,Header的Content-Type为application/merge- patch+json,同时请求体中只需要传入模板片段,只写需要添加或更新的部分即可。

1.4 删除资源

删除资源的API调用方式如下。

HTTP请求
    删除单个指定资源:DELETE
    /{apiVersion}/namespaces/{namespace}/{资源类型}/{name}

    删除命名空间下的整类资源对象:DELETE
    /{apiVersion}/namespaces/{namespace}/{资源类型}

删除资源的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

删除资源的API的请求体只有一个参数——DeleteOption对象,它表示删除时的一些参数设置,默认可以不传入。

删除资源的API的返回值

状态码

返回消息体

描述

200

Status对象

请求成功(OK)

202

Status对象

请求已接受(accepted)

在本例中,删除单个Pod的命令如下。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod -X DELETE

此时再使用$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod命令查询Pod,可以发现对应Pod已删除,并将会返回查询失败的信息。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "pods \"examplepod\" not found",
  "reason": "NotFound",
  "details": {
    "name": "examplepod",
    "kind": "pods"
  },
  "code": 404
$ kubectl get pod
NAME         READY   STATUS        RESTARTS   AGE
examplepod   1/1     Terminating   0          34m

2 读操作

可以对各个资源执行单个查询或列表查询,以及监控等操作。

除了部分极其特殊的资源之外,其他资源具备该操作类型。主要的读操作方式有以下几种。

2.1 查询资源

查询资源的API调用方式如下。

HTTP请求
    查询命名空间下的资源列表:GET
    /{apiVersion}/namespaces/{namespace}/{资源类型}

    查询单个指定资源:GET
    /{apiVersion}/namespaces/{namespace}/{资源类型}/{name}

查询资源的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

查询资源的 API 的返回值是状态码 200,这表示请求成功(OK)。

对于/api/v1/ namespaces/{namespace}/{资源类型}来说,返回的消息体是使用Json方式描述的资源对象列表。

而对于/api/v1/namespaces/{namespace}/{资源类型}/{name}来说,返回的消息体是使用Json方式描述的资源对象,等同于之前介绍 的yaml模板,只是这里使用Json表现方式。

在本例中,查询Pod列表的命令如下。

$ curl http://localhost:8080/api/v1/namespaces/default/pods
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/default/pods",
    "resourceVersion": "82851741"
  },
  "items": [
    {
      "metadata": {
        "name": "examplepod",
......

返回值中的kind字段为PodList,表示Pod列表;刚才创建的examplepod已显示在列表中,位于items数组中。

在本例中,查询单个Pod的命令如下。

API直接返回了单个Pod的信息。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "examplepod",
    "namespace": "default",
    "selfLink": "/api/v1/namespaces/default/pods/examplepod",
    "uid": "17a4a6e2-91ff-43b9-b9bc-ed37e8176a64",
    "resourceVersion": "82851536",
    "creationTimestamp": "2022-04-20T05:40:20Z",
......

2.2 监控资源

通过以下方式监控资源的API。当使用监控API时,将会与服务器建立长连接,持续刷新Pod的当前动态。

HTTP请求
    监控命名空间下的资源列表:GET
    /{apiVersion}/watch/namespaces/{namespace}/{资源类型}

    监控单个指定资源:GET
    /{apiVersion}/watch/namespaces/{namespace}/{资源类型}/{name}

查询资源的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

查询资源的 API 的返回值是状态码 200,它表示请求成功(OK)。

返回的消息体是WatchEvent对象,WatchEvent对象的格式如下。

{
    "type": "操作类型,例如ADDED",
    "object": {
        资源类型的Json对象,等同于之前介绍的yaml模板,只是这里用Json表
        现方式
    }
}

在本例中,监控Pod的命令如下。

$ curl http://localhost:8080/api/v1/watch/namespaces/default/pods/examplepod
{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"examplepod","namespace":"default","selfLink":"/api/v1/namespaces/default/pods/examplepod","uid":"17a4a6e2-91ff-43b9-b9bc-ed37e8176a64","resourceVersion":"82851536","creationTimestamp":"2022-04-20T05:40:20Z","managedFields":[{"manager":"curl","operation":"Update","apiVersion":"v1","time":"2022-04-20T05:40:20Z","fieldsType":"FieldsV1","fieldsV1":{"f:spec":{"f:containers":{"k:{\"name\":\"examplepod-container\"}":{".":{},"f:args":{},"f:command":{},"f:image":{},"f:imagePullPolicy":{},"f:name":{},"f:resources":{},"f:terminationMessagePath":{},....

可以发现第一个操作为ADDED,这表示添加Pod,目前它的标签键值(key1)为value1。

因为现在curl命令已经与API建立了长连接,所以命令的执行不会结束。

此时若通过其他命令窗口修改Pod的标签,将标签键值key1修改为value2,可以发现正在监控的命令窗口中的内容已经发生变化,出现 了第二条操作信息,其类型为MODIFIED,如图9-11所示,表示通过API已经成功监控到Pod所发生的变化。

将标签键值key1修改为value3

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod -H \
    "Content-Type:application/merge-patch+json" -X PATCH -d '{
    "metadata": {
        "labels": {
            "key1": "value3"
        }
    }
}'

出现了第二条操作信息,其类型为MODIFIED,如下图所示,表示通过API已经成功监控到Pod所发生的变化。

../../_images/image-20220420141028630.png

3 独有操作

独有操作表示某类资源独有的操作。例如,Pod 可以读取日志,而 Deployment/StatefulSet控制器可以通过设置Scale控制伸缩。接 下来将分别介绍相关内容。

3.1 Pod的日志读取操作

对于之前示例中创建的Pod,在容器配置中有一行启动命令echo “Hello Kubernetes!”,该命令会输出一行文本“Hello Kubernetes!”。可以通过日志API查询Pod的输出。

查询Pod日志的API调用方式如下。

HTTP请求
    GET
    /api/v1/namespaces/{namespace}/pods/{name}/log

查询Pod日志的API的URL参数如表

参数

描述

namespace

命名空间,如果没有特定命名空间,可使用default

name

Pod名称

查询Pod日志的API的返回值是状态码200,它表示请求成功(OK)。返回的消息体是字符串。 在本例中,查询日志的命令如下。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod/log
Hello Kubernetes!

3.2 Deployment/StatefulSet的伸缩操作

在开始介绍API之前,先创建一个基本的Deployment控制器,用它来执行伸缩操作。

$ curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments -H \
    "Content-Type:application/json" -X POST -d '{
    "apiVersion": "apps/v1",
    "kind": "Deployment",
    "metadata": {
        "name": "exampledeployment"
    },
    "spec": {
    "replicas": 3,
    "selector": {
        "matchLabels": {
        "example": "deploymentfornginx"
        }
    },
    "template": {
        "metadata": {
            "labels": {
            "example": "deploymentfornginx"
            }
        },
    "spec": {
        "containers": [
        {
            "name": "nginx",
            "image": "nginx:1.7.9",
        "ports": [
            {
                "containerPort": 80
            }
            ]
          }
        ]
      }
    }
  }
}'

本例中创建了一个名为exampledeployment的Deployment控制器,它拥有3个Pod。命令执行后可以查到对应的Deployment控制器

$ kubectl get deployment
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
exampledeployment   3/3     3            3           81s

读取伸缩信息

可以通过API读取Deployment控制器的当前伸缩信息,其调用方式如下。

HTTP请求
    GET
    /apis/apps/v1/namespaces/{namespace}/deployments/{name}/scale

读取伸缩信息的API的URL参数如表

参数

描述

namespace

命名空间,如果没有特定命名空间,可使用default

name

Pod名称

读取伸缩信息的API的返回值是状态码200,它表示请求成功(OK)。返回的消息体是使用Json方式描述的伸缩对象。

在本例中,查询伸缩信息的命令如下。

$ curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments/exampledeployment/scale
{
  "kind": "Scale",
  "apiVersion": "autoscaling/v1",
  "metadata": {
    "name": "exampledeployment",
    "namespace": "default",
    "selfLink": "/apis/apps/v1/namespaces/default/deployments/exampledeployment/scale",
    "uid": "f20edd07-dd69-43b5-85d3-a664d656bd4d",
    "resourceVersion": "82868258",
    "creationTimestamp": "2022-04-20T06:17:54Z"
  },
  "spec": {
    "replicas": 3
  },
  "status": {
    "replicas": 3,
    "selector": "example=deploymentfornginx"
  }

查询结果如上所示,API返回了Deployment控制器的当前伸缩信息。

更新伸缩信息

可以通过API更新Deployment的伸缩信息,其调用方式如下。

HTTP请求
    PATCH
    /apis/apps/v1/namespaces/{namespace}/deployments/{name}/scale

更新伸缩信息的API的URL参数如表

参数

描述

namespace

命名空间,如果没有特定命名空间,可使用default

name

Pod名称

更新伸缩信息的API的请求体参数是局部更新对象,它表示使用Json方式描述的对象,相当于Json模板中的某个片段对象。

更新伸缩信息的API的返回值是状态码200,它表示请求成功(OK)。返回的消息体是更新后伸缩类型的完整Json对象。

现在我们使用API修改之前的伸缩信息,将其设置为4,需要执行以下命令。

本例中Header的Content-Type为application/merge-patch+json,同时请求体中只需要传入模板片段,填写需要更新的部分即可。命令执行后,结果如下所示,API返回了更新后的Scale类型的Json对象。

$ curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments/exampledeployment/scale -H  "Content-Type:application/merge-patch+json" -X PATCH -d \
    '{
    "spec": {
        "replicas": 4
    }
}'

{
  "kind": "Scale",
  "apiVersion": "autoscaling/v1",
  "metadata": {
    "name": "exampledeployment",
    "namespace": "default",
    "selfLink": "/apis/apps/v1/namespaces/default/deployments/exampledeployment/scale",
    "uid": "f20edd07-dd69-43b5-85d3-a664d656bd4d",
    "resourceVersion": "82870725",
    "creationTimestamp": "2022-04-20T06:17:54Z"
  },
  "spec": {
    "replicas": 4
  },
  "status": {
    "replicas": 3,
    "selector": "example=deploymentfornginx"
  }
}

此时再查看Deployment的基本信息,可以看到已经发生变化,如下

$ kubectl get deployment
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
exampledeployment   4/4     4            4           8m36s

伸缩信息还可以使用 API 来执行替换操作。因为伸缩信息可设置的有意义的属性只有replicas一个,所以下面的API没有必要。

PUT
/apis/apps/v1/namespaces/{namespace}/deployments/{name}/scale

4 状态操作

状态类API可以更新或读取资源的状态。工作负载对象(Pod和控制器)、服务对象(Service和Ingress)、存储对象(PVC和PV)、主 机对象(Node)、管理类型对象(Namespace、ResourceQuota)都具有这类操作,其他类型对象只有少部分拥有该类操作。

一般来说,状态应该只用来查询,由Kubernetes自行控制各个资源的状态,只有在极特殊情况下,才会查询、替换、更新资源的状 态。

4.1 查询状态

查询状态的 API 调用方式如下。它和查询资源的命令很相似,都返回整个资源的 Json描述。

HTTP请求
    GET
    /{apiVersion}/namespaces/{namespace}/{资源类型}/{name}/status

查询状态的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

查询状态的API的返回值是状态码200,它表示成功(OK)。返回的消息体是使用Json方式描述的资源对象,等同于之前介绍的yaml模 板,只是这里使用Json表现方式。

在本例中,查询Pod状态的命令如下。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod/status

查询结果如下所示,API直接返回了Pod的状态信息。

[root@gitee-k8s-m1 ~]# curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod/status
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "examplepod",
    "namespace": "default",
    "selfLink": "/api/v1/namespaces/default/pods/examplepod/status",
    "uid": "4b7276a3-9724-4ac3-8378-92de72c350b7",
    "resourceVersion": "82873324",
    "creationTimestamp": "2022-04-20T06:30:47Z",
    "managedFields": [
      {
        "manager": "curl",
        "operation": "Update",
        "apiVersion": "v1",
        "time": "2022-04-20T06:30:47Z",
        "fieldsType": "FieldsV1",
        "fieldsV1": {"f:spec":{"f:containers":{"k:{\"name\":\"examplepod-container\"}":{".":{},"f:args":{},"f:command":{},"f:image":{},"f:imagePullPolicy":{},"f:name":{},"f:resources":{},"f:terminationMessagePath":{},"f:terminationMessagePolicy":{}}},"f:dnsPolicy":{},"f:enableServiceLinks":{},"f:restartPolicy":{},"f:schedulerName":{},"f:securityContext":{},"f:terminationGracePeriodSeconds":{}}}
      },
      {
        "manager": "kubelet",
        "operation": "Update",
        .......

4.2 替换状态

替换状态的API调用方式如下。 HTTP请求

PUT
/{apiVersion}/namespaces/{namespace}/{资源类型}/{name}/status

替换状态的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

替换状态的API的请求体参数是资源类型Json对象,它表示使用Json方式描述的资源对象,等同于之前介绍的yaml模板,只是这里使 用Json表现方式传入。

替换状态的API的返回值如表

状态码

返回消息体

描述

200

替换后的资源类型Json对象

请求成功(OK)

201

替换后的资源类型Json对象

请求已创建(created)

这种更新相对死板,我们修改之前示例中定义的 Pod 状态。需要 先通过$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod/status获取当前Pod的状态信息,然后粘贴整个status属性片段以作为请求体的基础,之后在此基础上修改。

在本例中,我们将其restartCount属性修改为999,具体命令如下所示。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod/status -H \
"Content-Type:application/json" -X PUT -d '{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "examplepod",
    "namespace": "default",
    "selfLink": "/api/v1/namespaces/default/pods/examplepod/status",
    "uid": "4b7276a3-9724-4ac3-8378-92de72c350b7",
    "resourceVersion": "82876375",
    "creationTimestamp": "2022-04-20T06:30:47Z",
    "managedFields": [
      {
        "manager": "curl",
        "operation": "Update",
        "apiVersion": "v1",
        "time": "2022-04-20T06:36:13Z",
        "fieldsType": "FieldsV1",
        "fieldsV1": {"f:spec":{"f:containers":{"k:{\"name\":\"examplepod-container\"}":{".":{},"f:args":{},"f:command":{},"f:image":{},"f:imagePullPolicy":{},"f:name":{},"f:resources":{},"f:terminationMessagePath":{},"f:terminationMessagePolicy":{}}},"f:dnsPolicy":{},"f:enableServiceLinks":{},"f:restartPolicy":{},"f:schedulerName":{},"f:securityContext":{},"f:terminationGracePeriodSeconds":{}}}
      },
      {
        "manager": "kubelet",
        "operation": "Update",
        "apiVersion": "v1",
        "time": "2022-04-20T06:37:50Z",
        "fieldsType": "FieldsV1",
        "fieldsV1": {"f:status":{"f:conditions":{"k:{\"type\":\"ContainersReady\"}":{".":{},"f:lastProbeTime":{},"f:lastTransitionTime":{},"f:status":{},"f:type":{}},"k:{\"type\":\"Initialized\"}":{".":{},"f:lastProbeTime":{},"f:lastTransitionTime":{},"f:status":{},"f:type":{}},"k:{\"type\":\"Ready\"}":{".":{},"f:lastProbeTime":{},"f:lastTransitionTime":{},"f:status":{},"f:type":{}}},"f:containerStatuses":{},"f:hostIP":{},"f:phase":{},"f:podIP":{},"f:podIPs":{".":{},"k:{\"ip\":\"10.0.25.238\"}":{".":{},"f:ip":{}}},"f:startTime":{}}}
      }
    ]
  },
  "spec": {
    "volumes": [
      {
        "name": "kube-api-access-hcfqq",
        "projected": {
          "sources": [
            {
              "serviceAccountToken": {
                "expirationSeconds": 3607,
                "path": "token"
              }
            },
            {
              "configMap": {
                "name": "kube-root-ca.crt",
                "items": [
                  {
                    "key": "ca.crt",
                    "path": "ca.crt"
                  }
                ]
              }
            },
            {
              "downwardAPI": {
                "items": [
                  {
                    "path": "namespace",
                    "fieldRef": {
                      "apiVersion": "v1",
                      "fieldPath": "metadata.namespace"
                    }
                  }
                ]
              }
            }
          ],
          "defaultMode": 420
        }
      }
    ],
    "containers": [
      {
        "name": "examplepod-container",
        "image": "busybox",
        "command": [
          "sh",
          "-c"
        ],
        "args": [
          "echo \"Hello Kubernetes!\"; sleep 3600"
        ],
        "resources": {

        },
        "volumeMounts": [
          {
            "name": "kube-api-access-hcfqq",
            "readOnly": true,
            "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
          }
        ],
        "terminationMessagePath": "/dev/termination-log",
        "terminationMessagePolicy": "File",
        "imagePullPolicy": "IfNotPresent"
      }
    ],
    "restartPolicy": "Always",
    "terminationGracePeriodSeconds": 30,
    "dnsPolicy": "ClusterFirst",
    "serviceAccountName": "default",
    "serviceAccount": "default",
    "nodeName": "gitee-k8s-w17",
    "securityContext": {

    },
    "schedulerName": "default-scheduler",
    "tolerations": [
      {
        "key": "node.kubernetes.io/not-ready",
        "operator": "Exists",
        "effect": "NoExecute",
        "tolerationSeconds": 300
      },
      {
        "key": "node.kubernetes.io/unreachable",
        "operator": "Exists",
        "effect": "NoExecute",
        "tolerationSeconds": 300
      }
    ],
    "priority": 0,
    "enableServiceLinks": true,
    "preemptionPolicy": "PreemptLowerPriority"
  },
  "status": {
    "phase": "Running",
    "conditions": [
      {
        "type": "Initialized",
        "status": "True",
        "lastProbeTime": null,
        "lastTransitionTime": "2022-04-20T06:30:45Z"
      },
      {
        "type": "Ready",
        "status": "True",
        "lastProbeTime": null,
        "lastTransitionTime": "2022-04-20T06:30:47Z"
      },
      {
        "type": "ContainersReady",
        "status": "True",
        "lastProbeTime": null,
        "lastTransitionTime": "2022-04-20T06:30:47Z"
      },
      {
        "type": "PodScheduled",
        "status": "True",
        "lastProbeTime": null,
        "lastTransitionTime": "2022-04-20T06:29:12Z"
      }
    ],
    "hostIP": "192.168.1.126",
    "podIP": "10.0.25.238",
    "podIPs": [
      {
        "ip": "10.0.25.238"
      }
    ],
    "startTime": "2022-04-20T06:30:45Z",
    "containerStatuses": [
      {
        "name": "examplepod-container",
        "state": {
          "running": {
            "startedAt": "2022-04-20T06:30:46Z"
          }
        },
        "lastState": {

        },
        "ready": true,
        "restartCount": 999,
        "image": "docker.io/library/busybox:latest",
        "imageID": "docker.io/library/busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678",
        "containerID": "containerd://7f49bba436afa5cc194aa10c208f200c0eea1d318c7b58782be21ba84371435d",
        "started": true
      }
    ],
    "qosClass": "BestEffort"
  }
}'

可以看到,整个请求体里面包含了非常多不相关的文本,这就是直接使用PUT请求的弊端。

执行结果如下所示,可以看到重启次数已修改为999。

.....
        "lastState": {

        },
        "ready": true,
        "restartCount": 999,
        "image": "docker.io/library/busybox:latest",
        "imageID": "docker.io/library/busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678",
        "containerID": "containerd://7f49bba436afa5cc194aa10c208f200c0eea1d318c7b58782be21ba84371435d",
        "started": true
      }
    ],
    "qosClass": "BestEffort"
  }
}

这种替换方式并不推荐,一般使用PATCH进行局部更新,除非要对状态进行大量更新。

4.3 更新状态

通过API,可以实现局部状态更新,其调用方式如下。

HTTP请求
    PATCH
    /{apiVersion}/namespaces/{namespace}/{资源类型}/{name}/status

更新状态的API的URL参数如表

| 参数       | 描述                                                         |
| ---------- | ------------------------------------------------------------ |
| apiVersion | 与yaml模板中填写的apiVersion属性类似,区别在于加了api或<br/>apis前缀。 例如,Pod的apiVersion为api/v1,Deployment控制<br/>器的apiVersion为apis/apps/v1,Job控制器的apiVersion为<br/>apis/batch/v1等 |
| namespace  | 命名空间,如果没有特定命名空间可使用“default”                |
| 资源类型   | 资源类型使用复数形式,例如,pods、deployments、<br/>daemonsets、services、ingresses、configmaps、<br/>limitranges、nodes等 |
| name       | 资源名称                                                     |

更新状态的API的请求体参数是局部更新对象,它表示使用Json方式描述的对象,相当于Json模板中的某个片段对象。 更新状态的API的返回值是状态码200,这表示请求成功(OK)。返回的消息体表示更新后的资源类型的完整Json对象。

在对示例进行操作之前,我们先看看当前 Pod 的状态,如下所示,其 IP 地址为10.0.25.238,状态为Running。

$ kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE            NOMINATED NODE   READINESS GATES
examplepod   1/1     Running   0          18m   10.0.25.238   gitee-k8s-w17   <none>           <none>

为了使用API修改之前创建的Pod的状态,执行以下命令。

$ curl http://localhost:8080/api/v1/namespaces/default/pods/examplepod/status -H \
    "Content-Type:application/merge-patch+json" -X PATCH -d '{
    "status": {
        "podIP": "10.0.25.239",
        "phase": "Pending"
    }
}'

本例中Header的Content-Type为application/merge-patch+json,同时请求体中只需要传入模板片段,写入需要更新的 部分即可。我们将Pod的IP地址修改为10.0.25.239,状态修改为Pending。

此时再查看Pod的状态,可以看到已经发生变化。

$ kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE            NOMINATED NODE   READINESS GATES
examplepod   1/1     Pending   0          21m   10.0.25.239   gitee-k8s-w17   <none>           <none>

参考文献

利用curl命令访问Kubernetes API server