什么是 YAML
YAML(YAML Ain’t Markup Language)是一种可读的数据序列化语言,通常用于配置文件、数据序列化和交换格式。YAML 的设计目标是易读易写,并且能够映射到动态语言中的数据结构
YA加粗样式ML 是 JSON 的超集,支持整数、浮点数、布尔、字符串、数组和对象等数据类型。也就是说,任何合法的 JSON 文档也都是 YAML 文档
和 JSON 比起来,YAML 的语法更简单,形式也更清晰紧凑,比如:
- 使用空白与缩进表示层次(有点类似 Python),可以不使用花括号和方括号。
- 可以使用 # 书写注释,比起 JSON 是很大的改进。
- 对象(字典)的格式与 JSON 基本相同,但 Key 不需要使用双引号。
- 数组(列表)是使用 - 开头的清单形式(有点类似 MarkDown)。
- 表示对象的 : 和表示数组的 - 后面都必须要有空格。
- 可以使用 — 在一个文件里分隔多个 YAML 对象。
示例1
该 YAML 对象,声明了 1 个 Master 节点,3 个 Worker 节点
# YAML对象(字典)
Kubernetes:
master: 1
worker: 3
示例2
Kubernetes,组合数组和对象的yaml
Kubernetes:
master:
- apiserver: running
- etcd: running
node:
- kubelet: running
- kube-proxy: down
- container-runtime: [docker, containerd, cri-o]
什么是 API 对象
使用 kubectl api-resources 来查看当前 Kubernetes 版本支持的所有对象:
kubectl api-resources
在输出的“NAME”一栏,就是对象的名字,比如 ConfigMap、Pod、Service 等等,第二栏“SHORTNAMES”则是这种资源的简写,在我们使用 kubectl 命令的时候很有用,可以少敲几次键盘,比如 Pod 可以简写成 po,Service 可以简写成 svc。
在使用 kubectl 命令的时候,你还可以加上一个参数 --v=9,它会显示出详细的命令执行过程,清楚地看到发出的 HTTP 请求,比如:
kubectl get pod --v=9
从截图里可以看到,kubectl 客户端等价于调用了 curl,向 8443 端口发送了 HTTP GET 请求,URL 是 /api/v1/namespaces/default/pods。
目前的 Kubernetes 1.23 版本有 50 多种 API 对象,全面地描述了集群的节点、应用、配置、服务、账号等等信息,apiserver 会把它们都存储在数据库 etcd 里,然后 kubelet、scheduler、controller-manager 等组件通过 apiserver 来操作它们,就在 API 对象这个抽象层次实现了对整个集群的管理。
如何描述 API 对象
用 YAML 语言,使用“声明式”在 Kubernetes 里描述并创建 API 对象改造之前运行 Nginx 的命令:
kubectl run ngx --image=nginx:alpine
把它改写成“声明式”的 YAML,说清楚我们想要的 Nginx 应用是个什么样子,也就是“目标状态”,让 Kubernetes 自己去决定如何拉取镜像运行:
apiVersion: v1
kind: Pod
metadata:
name: ngx-pod
labels:
env: test
owner: lfgb
spec:
containers:
- image: nginx:alpine
name: ngx
ports:
- containerPort: 80
API 对象采用标准的 HTTP 协议,为了方便理解,我们可以借鉴一下 HTTP 的报文格式,把 API 对象的描述分成“header”和“body”两部分。
API 对象header
header”包含的是 API 对象的基本信息,有三个字段:apiVersion、kind、metadata。
- apiVersion 表示操作这种资源的 API 版本号,由于 Kubernetes 的迭代速度很快,不同的版本创建的对象会有差异,为了区分这些版本就需要使用 apiVersion 这个字段,比如 v1、v1alpha1、v1beta1 等等。
- kind 表示资源对象的类型,这个应该很好理解,比如 Pod、Node、Job、Service 等等。
- metadata 这个字段顾名思义,表示的是资源的一些“元信息”,也就是用来标记对象,方便 Kubernetes 管理的一些信息。
在这个 YAML 示例里就有两个“元信息”,一个是 name,给 Pod 起了个名字叫 ngx-pod,另一个是 labels,给 Pod“贴”上了一些便于查找的标签,分别是 env 和 owner。
apiVersion、kind、metadata 都被 kubectl 用于生成 HTTP 请求发给 apiserver,你可以用 --v=9 参数在请求的 URL 里看到它们,比如:
https://192.168.49.2:8443/api/v1/namespaces/default/pods/ngx-pod
和 HTTP 协议一样,“header”里的 apiVersion、kind、metadata 这三个字段是任何对象都必须有的。
API 对象body
“body”部分则会与对象特定相关,每种对象会有不同的规格定义,在 YAML 里就表现为 spec 字段(即 specification),表示我们对对象的“期望状态”(desired status)。
这个 Pod里,它的 spec 里就是一个 containers 数组,里面的每个元素又是一个对象,指定了名字、镜像、端口等信息:
spec:
containers:
- image: nginx:alpine
name: ngx
ports:
- containerPort: 80
把这些字段综合起来,我们就能够看出,这份 YAML 文档完整地描述了一个类型是 Pod 的 API 对象,要求使用 v1 版本的 API 接口去管理,其他更具体的名称、标签、状态等细节都记录在了 metadata 和 spec 字段等里。
API 生成、删除pod
使用 kubectl apply、kubectl delete,再加上参数 -f,你就可以使用这个 YAML 文件,创建或者删除对象了:
kubectl apply -f ngx-pod.yml
kubectl delete -f ngx-pod.yml
Kubernetes 收到这份“声明式”的数据,再根据 HTTP 请求里的 POST/DELETE 等方法,就会自动操作这个资源对象,至于对象在哪个节点上、怎么创建、怎么删除完全根据内置功能处理。
如何编写 YAML
官方参考文档
API 对象的所有字段都可以在里面找到。不过官方文档内容太多太细,查阅起来有些费劲,下面有几个简单实用的小技巧。
kubectl api-resources 命令
它会显示出资源对象相应的 API 版本和类型,
比如 Pod 的版本是“v1”,
Ingress 的版本是“networking.k8s.io/v1”。
kubectl explain
kubectl explain 相当于是 Kubernetes 自带的 API 文档,会给出对象字段的详细说明,这样我们就不必去网上查找了。比如想要看 Pod 里的字段该怎么写,就可以这样:
kubectl explain pod
kubectl explain pod.metadata
kubectl explain pod.spec
kubectl explain pod.spec.containers
文档样板
可以让 kubectl 为我们“代劳”,生成一份“文档样板”,免去我们打字和对齐格式的工作。
kubectl 的两个特殊参数 –dry-run=client 和 -o yaml,前者是空运行,后者是生成 YAML 格式,结合起来使用就会让 kubectl 不会有实际的创建动作,而只生成 YAML 文件。
例如,想要生成一个 Pod 的 YAML 样板示例,可以在 kubectl run 后面加上这两个参数:
kubectl run ngx --image=nginx:alpine --dry-run=client -o yaml
可以将变量 $out 扩展为其包含的值,而不是作为一个整体。可以使用 ${out} 语法来执行这个操作,像这样:
export out="--dry-run=client -o yaml"
kubectl run ngx --image=nginx:alpine $out
屏幕输出的 YAML 文件内容:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ngx
name: ngx
spec:
containers:
- image: nginx:alpine
name: ngx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
- apiVersion: 指定 Kubernetes API 的版本,这里使用的是 v1 版本。
- kind: 指定资源的类型,这里是一个 Pod。
- metadata: 包含有关 Pod 的元数据,例如名称和标签。
- creationTimestamp: Pod 的创建时间戳。由于这个 Pod 还没有被创建,因此值为 null。
- labels: 包含一个标签,名称为 run,值为 ngx。
- name: 指定 Pod 的名称,这里是 ngx。
- spec: 包含有关 Pod 规范的信息,例如容器配置和资源限制。
- containers: 指定要在 Pod 中运行的容器列表。
- image: 指定容器要使用的镜像,这里是 nginx:alpine。
- name: 指定容器的名称,这里也是 ngx。
- resources: 指定容器的资源限制。在这个示例中,没有定义任何资源限制。
- dnsPolicy: 指定 Pod 的 DNS 解析策略,这里是 ClusterFirst,表示使用集群中的 DNS 服务进行解析。
- restartPolicy: 指定 Pod 终止后的重启策略,这里是 Always,表示总是重启 Pod。
- status: 包含有关 Pod 状态的信息。在这个示例中,没有提供任何状态信息,因为 Pod 还没有被创建。
或者生成到指定文件:
kubectl run ngx --image=ngx:alpine $out > demo.yml
然后查阅对象的说明文档,添加或者删除字段来定制这个 YAML 了。