k8s 声明式 API 简介
k8s 声明式 API
下面举个例子简单说明下什么是声明式:
我们知道,docker 的编排是基于命令行的:
$ docker run --name nginx --replicas 2 nginx
对于这种使用方式,我们称为之为:命令式命令行操作。
那么在k8s 中呢,你一定也已经很熟悉了:我们先要编写一个 deployment 的yaml文件:
nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
然后,再执行下面的命令:
$ kubectl create -f nginx.yaml
这样这个nginx 容器就跑起来了。
而如果要更新这两个 Pod 使用的 Nginx 镜像,该怎么办呢?
可以使用 kubectl set image
和 kubectl edit
命令,来直接修改 Kubernetes 里的 API 对象。不过,现在我们很多人都通过修改本地 YAML 文件来完成这个操作,这样我的改动就会体现在这个本地 YAML 文件里了:
...
spec:
containers:
- name: nginx
image: nginx:1.7.9
而接下来,我们就可以执行一句 kubectl replace
操作,来完成这个 Deployment 的更新:
$ kubectl replace -f nginx.yaml
可是,上面这种基于 YAML 文件的操作方式,是“声明式 API”吗 ?
并不是。
对于上面这种先 kubectl create,再 replace 的操作,我们称为命令式配置文件操作。
也就是说,它的处理方式,其实跟前面 Docker 的命令,没什么本质上的区别。只不过,它是把 Docker 命令行里的参数,写在了配置文件里而已。
那么,到底什么才是“声明式 API”呢?
答案是,kubectl apply
命令。
在之前我跟很多同事说过使用这个 kubectl apply
命令,代替 kubectl create 命令:
$ kubectl apply -f nginx.yaml
这样,Nginx 的 Deployment 就被创建了出来,这看起来跟 kubectl create
的效果一样.
然后,我再修改一下 nginx.yaml 里定义的镜像:
...
spec:
containers:
- name: nginx
image: nginx:1.7.9
这时候,关键来了。
在修改完这个 YAML 文件之后,我不再使用 kubectl replace
命令进行更新,而是继续执行一条 kubectl apply
命令,即:
$ kubectl apply -f nginx.yaml
这时,Kubernetes 就会立即触发这个 Deployment 的“滚动更新”。
可是,它跟 kubectl replace
命令有什么本质区别吗?
实际上,你可以简单地理解为,kubectl replace
的执行过程,是使用新的 YAML 文件中的 API 对象,替换原有的 API 对象;而 kubectl apply
,则是执行了一个对原有 API 对象的 PATCH 操作。类似,kubectl set image
和 kubectl edit
也是对已有 API 对象的修改。
更进一步地,这意味着 kube-apiserver
在响应命令式请求(比如,kubectl replace
)的时候,一次只能处理一个写请求,否则会有产生冲突的可能。而对于声明式请求(比如:kubectl apply
),一次能处理多个写操作,并且具备 Merge 能力。
这种区别,可能听起来没那么重要。而且,正是由于要照顾到这样的 API 设计,做同样一件事情,Kubernetes 需要的步骤往往要比其他项目多不少。
但是,如果你仔细思考一下 Kubernetes 项目的工作流程,就不难体会到这种声明式 API 的独到之处。
TODO add example
- 首先,所谓“声明式”,指的就是我只需要提交一个定义好的 API 对象来“声明”,我所期望的状态是什么样子。
- 其次,“声明式 API”允许有多个 API 写端,以 PATCH 的方式对 API 对象进行修改,而无需关心本地原始 YAML 文件的内容。
- 最后,也是最重要的,有了上述两个能力,Kubernetes 项目才可以基于对 API 对象的增、删、改、查,在完全无需外界干预的情况下,完成对“实际状态”和“期望状态”的调谐(Reconcile)过程。
声明式 API,才是 Kubernetes 项目编排能力“赖以生存”的核心所在。