Kubernetes之yaml文件详解原创
Kubernetes的YAML文件是用于定义Kubernetes对象(如Pod、Service、Deployment等)的一种格式化文件。这些文件通常由开发人员和运维人员使用,并通过kubectl工具进行部署和管理。
版本说明
本文写于 2022-03,基于 Kubernetes 1.20 左右。
在 1.31 上的差异:本文若涉及 PodSecurityPolicy(policy/v1beta1),该资源已在 1.21 弃用、1.25 彻底移除,需改用 Pod Security Admission(命名空间级 pod-security.kubernetes.io 标签);Ingress 资源自 1.22 起仅支持 networking.k8s.io/v1(不再支持 extensions/v1beta1/networking.k8s.io/v1beta1),使用时请核对 apiVersion 是否已更新;Deployment/Service/ConfigMap 等基础资源的 YAML 结构未变。
以下是一个基本的Kubernetes YAML文件的示例:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx:latest
2
3
4
5
6
7
8
9
10
11
Kubernetes YAML文件的主要结构由以下几个部分组成:
apiVersion:用于指定该对象的Kubernetes API版本。该版本必须与所使用的Kubernetes版本兼容。
为什么有的写
v1、有的写apps/v1:Kubernetes 的 API 按「组 / 版本」组织。Pod、Service、ConfigMap、Secret 这些最早的资源属于核心组(core group),它的组名是空字符串,所以只写版本号v1;后来加入的资源都归到具名组里,写法是<组名>/<版本>——Deployment 属于apps组,写apps/v1;Ingress 属于networking.k8s.io组,写networking.k8s.io/v1。不用背,随时能查:
kubectl api-resources | grep -i deployment # NAME SHORTNAMES APIVERSION NAMESPACED KIND # deployments deploy apps/v1 true Deployment1
2
3APIVERSION那一列就是该集群当前该写的值。要查某个字段怎么填,用kubectl explain:kubectl explain deployment.spec.strategy # 看这个字段有哪些子字段、各自什么含义 kubectl explain deployment.spec --recursive # 一次性列出整棵字段树1
2这两条命令的好处是答案直接来自你这个集群的 API Server,不会像搜到的博客那样给你一个已经被移除的字段。
kind:用于指定该对象的类型。常见的类型有Pod、Service、Deployment、ConfigMap、Secret等。
metadata:用于指定该对象的元数据,包括名称、标签、注释等信息。
spec:用于指定该对象的规范,包括容器、服务端口、存储卷等配置信息。
在一个Kubernetes YAML文件中,可以定义多个Kubernetes对象,每个对象之间用 --- 分隔开来。例如:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx:latest
---
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- name: http
port: 80
targetPort: 80
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在上面的示例中,定义了一个Pod和一个Service对象。
Kubernetes YAML文件的定义格式是相对灵活的,开发人员和运维人员可以根据需要灵活定义和组织它们。在定义时,可以使用一些基本的Kubernetes YAML文件的语法和结构元素,例如注释、缩进、序列和映射等。
总的来说,Kubernetes YAML文件是定义Kubernetes对象的一种简单但强大的方式。熟练掌握Kubernetes YAML文件的语法和结构可以更好地帮助开发人员和运维人员管理和部署Kubernetes对象。
除了上述基本结构外,Kubernetes YAML文件还支持许多其他功能和特性。下面列举了一些常用的Kubernetes YAML文件的功能和技巧:
- 注释:使用 # 符号来添加注释。注释可以添加在任何位置,以提高代码的可读性。
apiVersion: v1
kind: Pod
metadata:
name: my-pod # 定义Pod名称
spec:
containers:
- name: my-container # 定义容器名称
image: nginx:latest # 定义容器镜像
2
3
4
5
6
7
8
9
- 多行字符串:使用 | 符号来定义多行字符串。这在定义大块的配置文件时非常有用。
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
data:
my-conf.yaml: |
key1: value1
key2: value2
key3: value3
2
3
4
5
6
7
8
9
10
- 环境变量:可以通过 env 属性来定义容器的环境变量。
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx:latest
env:
- name: ENV_VAR1
value: "value1"
- name: ENV_VAR2
value: "value2"
2
3
4
5
6
7
8
9
10
11
12
13
- 存储卷:可以使用 volumes 属性来定义Pod中的存储卷。
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx:latest
volumeMounts:
- name: my-volume
mountPath: /data
volumes:
- name: my-volume
configMap:
name: my-config
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 配置文件:可以使用 configMap 和 secret 属性来定义Pod中的配置文件。
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx:latest
volumeMounts:
- name: my-config
mountPath: /etc/my-app
env:
- name: ENV_VAR1
valueFrom:
configMapKeyRef:
name: my-config
key: env-var1
- name: ENV_VAR2
valueFrom:
secretKeyRef:
name: my-secret
key: env-var2
volumes:
- name: my-config
configMap:
name: my-config
- name: my-secret
secret:
name: my-secret
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 部署:可以使用 Deployment 对象来定义Pod的部署和升级策略。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deploy
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx:latest
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 写完怎么确认它是对的
YAML 的问题分两层:格式对不对(缩进、引号),字段对不对(拼写、层级、该集群支不支持)。分别有对应的验证手段,都不需要真的创建资源。
# 1. 只做客户端校验:格式和已知字段
kubectl apply --dry-run=client -f pod.yaml
2
期望输出 pod/my-pod created (dry run)。这一步能查出缩进错误和明显的字段拼写错误,但它用的是 kubectl 内置的 schema,不认识 CRD。
# 2. 送到 API Server 做完整校验,但不落盘
kubectl apply --dry-run=server -f pod.yaml
2
这一步才是真正可靠的:API Server 会跑完整的字段校验、准入控制(admission webhook)和默认值填充,只是不写进 etcd。CRD、Operator 自定义资源、准入策略拦截,全都能在这里暴露出来。
# 3. 看看服务端最终会把它变成什么样(默认值都填上之后)
kubectl apply --dry-run=server -o yaml -f pod.yaml
2
输出里会多出一大堆你没写的字段——imagePullPolicy、restartPolicy、terminationGracePeriodSeconds、各种默认的 resources。排查「我没配这个东西为什么会有这个行为」时,先看这份补全后的 YAML,答案通常就在里面。
# 4. 已经创建的资源,看实际生效的完整定义
kubectl get deployment my-deploy -o yaml
2
# 坑与边界
1. YAML 里绝对不能用 Tab 缩进。 YAML 规范只接受空格,一个 Tab 就会报 error converting YAML to JSON: yaml: found character that cannot start any token——这条报错信息完全没提 Tab,第一次遇到很难猜。编辑器里把「插入 Tab 时转换为空格」打开,能省掉大量时间。
2. | 和 > 是两种不同的多行字符串。 | 保留换行(literal),> 会把换行折叠成空格(folded)。配置文件内容(如上文的 my-conf.yaml、Nginx 配置、脚本)必须用 |,用 > 会把整个配置压成一行,程序读进去就是语法错误。带 - 后缀(|-)表示去掉结尾多余的换行,通常更符合预期。
3. 版本号、端口、布尔值必须加引号。 YAML 会自作主张地推断类型:version: 1.20 解析成浮点数 1.2(末尾的 0 被吃掉),on / yes / no 解析成布尔值,08 可能被当成非法八进制。ConfigMap 的 data 字段只接受字符串,写数字会直接报错。规则很简单:data: 下面的值一律加引号。
4. 挂载 Secret 时注意文件权限。 volumes.secret 挂进去的文件默认权限是 0644,同 Pod 内的任何进程都能读。SSH 私钥、证书这类要求严格权限的文件需要显式设 defaultMode: 0400,否则 ssh 会直接拒绝使用并报 Permissions are too open。
5. 把 volume 挂到一个已有内容的目录上,会遮盖原有文件。 例如把 ConfigMap 挂到 /etc/nginx/,镜像里原本的 nginx.conf 就消失了,容器起不来。正确做法是挂到子目录(/etc/nginx/conf.d/),或者用 subPath 只覆盖单个文件——但要注意 subPath 挂载的文件不会随 ConfigMap 更新自动刷新,改完配置必须重启 Pod。
6. 本文示例里的 nginx:latest 只是占位,生产环境别照抄。 为了让示例聚焦在 YAML 结构上,下面统一写了 image: nginx:latest。真实环境必须把 tag 锁到具体小版本(如 nginx:1.27.3):latest 是可变引用,某次重建就可能撞上大版本跳变、配置不兼容、容器起不来,而且回滚时无法确定上一次跑的到底是哪个镜像。同样的口径见 k8s 部署 MySQL 与 Docker 使用笔记。
7. 一个文件里用 --- 分隔多个对象时,顺序不重要但依赖关系重要。 kubectl apply 会按顺序提交,但 Kubernetes 是最终一致的——Deployment 先于它引用的 ConfigMap 创建也不会报错,只是 Pod 会短暂停在 ContainerCreating 直到 ConfigMap 出现。真正会失败的是引用不存在的 Namespace,那会直接被拒绝。