K8s 配置详解:如何编写和使用 YAML 文件
引言:基础设施即代码与 Kubernetes
在现代云原生应用开发的浪潮中,Kubernetes (K8s) 已成为容器编排的事实标准。它提供了一个强大、灵活的平台来自动化部署、扩展和管理容器化应用。而要驯服 Kubernetes 这个强大的野兽,理解其配置方式至关重要。
传统的IT运维中,应用的部署和管理往往涉及大量的手动操作和脚本,这不仅效率低下,而且难以维护和复现。云原生时代倡导“基础设施即代码”(Infrastructure as Code, IaC)理念,这意味着基础设施的配置和管理应该像应用代码一样被处理:使用文本文件定义状态,通过版本控制进行管理,并通过自动化工具进行部署。
Kubernetes 完美契合了 IaC 的思想。在 K8s 中,我们不是直接告诉集群“运行一个 Nginx”,而是通过声明式 API 向 K8s 提交一个描述期望状态的配置清单,比如“我想要一个 Nginx Pod,它应该有 3 个副本,对外暴露 80 端口”。Kubernetes 控制平面会持续监控当前集群的状态,并努力使其达到你在配置清单中声明的期望状态。
那么,这些“配置清单”通常是什么格式呢?在 Kubernetes 中,最常用也是事实上的标准格式就是 YAML。
本文将深入探讨 Kubernetes 配置的基石——YAML 文件,详细解释其结构、如何编写不同类型的 K8s 资源配置,以及如何使用 kubectl
工具来应用和管理这些配置。
第一部分:为什么选择 YAML?YAML 的基础语法
在了解 Kubernetes 配置之前,我们首先需要理解为什么 Kubernetes 青睐 YAML,以及 YAML 的基本语法。
1.1 YAML vs. JSON:可读性与互操作性
虽然 Kubernetes API 本质上可以使用 JSON 或 YAML 进行通信,但在编写和管理配置文件时,YAML 凭借其出色的可读性成为了首选。
- JSON (JavaScript Object Notation): 是一种轻量级的数据交换格式,广泛用于网络传输。它的结构清晰,易于机器解析。
- YAML (YAML Ain’t Markup Language / Yet Another Markup Language): 是一种人类友好的数据序列化标准,设计目标是易于阅读和编写。
对比两者的一个简单例子:
JSON:
json
{
"name": "my-app",
"ports": [
{"containerPort": 80},
{"containerPort": 443}
]
}
YAML:
yaml
name: my-app
ports:
- containerPort: 80
- containerPort: 443
显而易见,YAML 使用更少的符号(没有大括号、方括号、逗号和引号,在很多情况下)和更自然的缩进,使得配置文件看起来更像结构化的文本,而不是代码。这对于需要人工编写、阅读和维护大量配置文件的场景(比如 Kubernetes 应用部署)来说是一个巨大的优势。
尽管 YAML 更易读,但它在功能上与 JSON 基本等价,可以轻松地相互转换。Kubernetes API 内部也是 JSON 驱动的,但它提供了对 YAML 输入的良好支持。
1.2 YAML 的核心语法要素
掌握 Kubernetes 配置的第一步是掌握 YAML 的基础语法。YAML 主要基于以下几种结构:
1.2.1 键值对 (Key-Value Pairs)
这是 YAML 最基本的组成单元,表示一个属性及其对应的值。使用冒号 :
分隔键和值,冒号后面通常有一个空格,以增强可读性。
yaml
key1: value1
key2: value2
值可以是字符串、数字、布尔值等。字符串通常不需要引号,除非包含特殊字符或需要保留前导/后导空格。
yaml
name: my-container # 字符串
port: 80 # 数字
enabled: true # 布尔值
description: "This is a string with spaces and special characters: !" # 带引号的字符串
1.2.2 列表 (Lists / Sequences)
列表表示一组有序的项。列表的每一项都以短横线 -
开头,并且与父元素有相同的缩进。
yaml
fruits:
- Apple
- Banana
- Cherry
ports:
- protocol: TCP
number: 80
- protocol: UDP
number: 53
注意,列表中的项可以是简单的值,也可以是嵌套的键值对(即一个对象)。
1.2.3 对象 / 映射 (Objects / Maps / Dictionaries)
对象表示一组无序的键值对集合。在 YAML 中,通过缩进来表示一个键的值是一个嵌套的对象。
yaml
person:
name: Alice
age: 30
address:
street: 123 Main St
city: Anytown
这里的 person
的值是一个对象,包含 name
、age
和 address
。而 address
的值又是一个嵌套的对象。
1.2.4 缩进 (Indentation)
缩进是 YAML 中最重要的语法元素,它定义了结构的层级关系。 YAML 不使用大括号或方括号来表示结构,而是完全依赖于一致的缩进。
- 必须使用空格进行缩进,而不是 Tab 键。 不同的 Tab 宽度在不同的编辑器中可能导致解析错误。
- 同一层级的元素必须具有相同的缩进量。
- 通常使用 2 个或 4 个空格作为缩进单位。 推荐使用 2 个空格,这是 Kubernetes 文档中最常见的风格。
错误的缩进示例:
“`yaml
错误:name 和 age 缩进不一致
person:
name: Alice
age: 30
错误:list 项缩进与父元素不同
fruits:
– Apple
– Banana # Banana 缩进错误
错误:address 缩进错误
person:
name: Alice
address:
street: 123 Main St # street 缩进错误
“`
YAML 解析器对缩进非常敏感,即使一个空格的差异也可能导致解析失败或配置错误。务必确保缩进的正确性和一致性。
1.2.5 注释 (Comments)
使用井号 #
开头表示注释。注释可以出现在行尾或独立一行,它们会被解析器忽略,用于提高配置文件的可读性和解释性。
“`yaml
这是一个顶级注释
name: my-application # 应用程序名称
ports: # 定义端口列表
– containerPort: 80 # HTTP 端口
“`
1.2.6 多个文档在一个文件 (---
)
YAML 支持在同一个文件中包含多个独立的 YAML 文档,使用 ---
分隔符。这在 Kubernetes 中非常常见,例如将一个应用的 Deployment 和 Service 定义放在同一个文件里。
“`yaml
— 表示第一个文档的开始或结束
apiVersion: apps/v1
kind: Deployment
… Deployment 配置 …
— # 分隔符
apiVersion: v1
kind: Service
… Service 配置 …
“`
1.3 YAML 小结
掌握了键值对、列表、对象、缩进和分隔符这几个基本概念,你就掌握了编写 Kubernetes YAML 配置所需的核心语法。记住:缩进是王道! 务必保持缩进的正确和一致。
第二部分:Kubernetes YAML 配置的解剖刀
一个典型的 Kubernetes 配置清单(无论是 Pod、Deployment、Service 还是其他资源)都遵循一个标准的顶层结构。理解这个结构是编写有效 K8s 配置的关键。
一个 Kubernetes 对象的 YAML 表示通常包含以下四个(或五个)顶层字段:
apiVersion
: 定义创建该对象所使用的 Kubernetes API 版本。kind
: 定义对象的类型(例如 Pod, Deployment, Service, ConfigMap 等)。metadata
: 定义对象的元数据,包括名称、命名空间、标签、注解等。spec
: 定义对象的期望状态(Declaration of the desired state)。这是配置的核心部分,不同的对象类型有不同的spec
字段。status
: 定义对象的当前状态。这个字段通常由 Kubernetes 集群自动填充和管理,用户在编写配置文件时不会设置status
字段。但在查看对象状态时,kubectl get <resource> -o yaml
会显示这个字段。
让我们逐一详细解释这些字段。
2.1 apiVersion
这个字段指定了用来创建或修改对象的 API 版本。Kubernetes 的 API 是不断演进的,不同的版本提供不同的功能和稳定性保证。API 版本通常由 API 组和版本号组成,例如 apps/v1
、v1
、networking.k8s.io/v1
等。
v1
: 核心 API 组,包含 Pods, Services, Namespaces, PersistentVolumes 等基本对象。apps/v1
: 用于管理有状态应用的 API 组,包含 Deployments, ReplicaSets, StatefulSets, DaemonSets 等。networking.k8s.io/v1
: 用于网络策略相关的 API 组,包含 NetworkPolicy。storage.k8s.io/v1
: 用于存储相关的 API 组,包含 StorageClass, VolumeAttachment 等。
选择正确的 apiVersion
非常重要,因为它决定了后续 spec
字段的结构和可用的选项。通常,你应该使用最新且稳定的 API 版本。可以在 Kubernetes 官方文档中查找特定资源类型对应的 API 版本。
2.2 kind
这个字段指定了你想要创建的 Kubernetes 对象的类型。例如:
Pod
: K8s 的最小可部署单元。Deployment
: 管理无状态 Pod 的部署和扩展。Service
: 定义访问 Pods 的策略,提供稳定的网络端点。ConfigMap
: 存储非敏感配置数据。Secret
: 存储敏感配置数据(如密码、密钥)。Namespace
: 隔离资源的分区。Ingress
: 暴露 HTTP 和 HTTPS 路由到集群内服务。- 等等。
kind
和 apiVersion
共同确定了配置文件的类型和版本,从而决定了 spec
字段的结构。
2.3 metadata
metadata
字段是一个对象,用于包含对象的元数据,即描述对象自身的信息。这是 Kubernetes 中一个非常重要的部分,因为它提供了组织、识别和管理对象的机制。常见的元数据字段包括:
name
(string, Required): 对象的名称,在同一类型的对象和同一命名空间下必须唯一。遵循 DNS 子域名的命名规范(小写字母、数字、中划线,必须以字母开头和结尾)。namespace
(string): 对象所在的命名空间。如果不指定,通常默认为default
命名空间。命名空间提供了资源的逻辑隔离。labels
(map[string]string): 一组附加到对象上的键值对标签。标签用于组织和选择对象,是 Kubernetes 中进行资源分组和筛选的核心机制。例如,你可以使用app: my-app
和tier: frontend
来标记属于某个应用前端部分的 Pods。annotations
(map[string]string): 一组附加到对象上的键值对注解。注解用于存储非标识性的元数据,通常用于工具或库的内部使用,不像标签那样用于选择对象。例如,部署工具可能会在这里记录部署信息。uid
(string): 由 Kubernetes 系统生成的唯一标识符,用于区分历史上的对象。resourceVersion
(string): 表示对象在内部数据库中的特定版本,用于实现乐观并发控制。
在编写配置时,name
是必需的(除了少数资源类型如 Namespace),namespace
是可选的(但强烈推荐使用),labels
是非常常用且重要的,annotations
则根据需要使用。
示例 metadata
:
yaml
metadata:
name: my-nginx-deployment
namespace: default # 可选,通常省略或明确指定
labels:
app: my-app
tier: frontend
annotations:
description: "This is a sample nginx deployment"
2.4 spec
spec
字段是 Kubernetes 配置清单中最复杂、内容最丰富的部分,因为它包含了你想要创建的对象的期望状态的详细描述。spec
的结构完全取决于 kind
字段指定的对象类型。 不同的对象类型有完全不同的 spec
结构和字段。
例如:
- Pod 的
spec
包含容器列表、卷、重启策略等。 - Deployment 的
spec
包含 Pod 模板 (template
)、副本数量 (replicas
)、选择器 (selector
) 等。 - Service 的
spec
包含服务类型 (type
)、端口映射 (ports
)、选择器 (selector
) 等。 - ConfigMap 的
spec
包含要存储的数据 (data
或binaryData
)。
理解各种 Kubernetes 资源的 spec
字段是掌握 Kubernetes 配置的关键。这需要查阅 Kubernetes 官方文档,或者使用 kubectl explain <resource_type>
命令来获取详细的字段说明。
示例 spec
(以 Deployment 为例):
yaml
spec:
replicas: 3 # 期望运行的 Pod 副本数量
selector: # 选择器,用于确定哪些 Pod 由此 Deployment 管理
matchLabels:
app: my-app
tier: frontend
template: # Pod 模板,定义了 Deployment 将创建的 Pod 的 spec
metadata:
labels: # Pod 模板中的标签必须与 selector.matchLabels 匹配
app: my-app
tier: frontend
spec:
containers: # Pod 包含的容器列表
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
2.5 status
(了解即可)
status
字段描述了对象的当前状态。这个字段是由 Kubernetes 系统和控制器自动更新的,用户在编写 YAML 文件时不需要(也不能)设置它。当你使用 kubectl get <resource> <name> -o yaml
命令查看一个正在运行或已经创建的对象时,你会看到 status
字段,它包含了诸如 Pod 的 IP 地址、Deployment 的当前副本数、Service 的 ClusterIP 等信息。
示例 status
(以 Pod 为例):
yaml
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2023-10-26T10:00:00Z"
status: "True"
type: Initialized
# ... 其他条件 ...
containerStatuses:
- containerID: containerd://...
image: nginx:latest
imageID: docker.io/library/nginx@sha256:...
lastState: {}
name: nginx
ready: true # 容器是否就绪
restartCount: 0
started: true
state:
running: # 容器当前状态
startedAt: "2023-10-26T10:00:10Z"
hostIP: 192.168.1.100
podIP: 10.10.0.5
podIPs:
- ip: 10.10.0.5
phase: Running # Pod 当前阶段 (Pending, Running, Succeeded, Failed, Unknown)
qosClass: Burstable
startTime: "2023-10-26T10:00:00Z"
第三部分:编写常见的 Kubernetes 资源 YAML
现在我们来编写一些最常见和重要的 Kubernetes 资源的 YAML 配置。
3.1 Pod
Pod 是 Kubernetes 中最小的可部署计算单元。一个 Pod 包含一个或多个紧密相关的容器、存储卷、网络配置以及如何运行容器的规范。
基本 Pod YAML 示例 (运行一个 Nginx 容器):
“`yaml
pod-nginx.yaml
apiVersion: v1 # 使用核心 API v1
kind: Pod # 类型为 Pod
metadata:
name: nginx-pod # Pod 名称
labels: # 标签用于识别和分组
app: nginx
spec: # Pod 的期望状态
containers: # 容器列表
– name: nginx # 容器名称
image: nginx:latest # 使用的镜像
ports: # 暴露的端口
– containerPort: 80 # 容器内部监听的端口
“`
这个 Pod 定义非常简单,它告诉 Kubernetes 创建一个名为 nginx-pod
的 Pod,其中包含一个基于 nginx:latest
镜像的容器,该容器暴露 80 端口。
3.2 Deployment
Deployment 是 Kubernetes 中用于管理无状态应用的核心控制器。它可以定义 Pod 的模板、期望的副本数量,并提供滚动更新、回滚等功能。Deployment 会管理 ReplicaSet,而 ReplicaSet 则确保运行指定数量的 Pod 副本。
基本 Deployment YAML 示例 (运行 3 个 Nginx Pod 副本):
“`yaml
deployment-nginx.yaml
apiVersion: apps/v1 # 使用 apps API v1
kind: Deployment # 类型为 Deployment
metadata:
name: nginx-deployment # Deployment 名称
labels:
app: nginx
spec:
replicas: 3 # 期望的 Pod 副本数量
selector: # 选择器,用于匹配 Deployment 管理的 Pods
matchLabels:
app: nginx # 匹配带有 app: nginx 标签的 Pods
template: # Pod 模板
metadata:
labels: # Pod 模板的标签,必须与 selector 匹配
app: nginx
spec:
containers:
– name: nginx
image: nginx:latest
ports:
– containerPort: 80
“`
这个 Deployment 告诉 Kubernetes:
1. 创建一个名为 nginx-deployment
的 Deployment。
2. 始终保持 3 个带有 app: nginx
标签的 Pod 运行。
3. 这些 Pod 的创建基于 template
中定义的规范:一个名为 nginx-container
的容器,使用 nginx:latest
镜像,并暴露 80 端口。
注意 selector.matchLabels
和 template.metadata.labels
必须一致。这是 Deployment 知道哪些 Pod 属于它的关键。
3.3 Service
Pod 是有生命周期的,它们的 IP 地址不是固定的。Service 提供了一种抽象,为一组 Pods 提供一个稳定的网络端点(ClusterIP、DNS 名称等),并将请求负载均衡到这组 Pods 上。Service 通过 selector
字段来选择提供服务的 Pods。
基本 Service YAML 示例 (暴露 Nginx Deployment):
“`yaml
service-nginx.yaml
apiVersion: v1 # 使用核心 API v1
kind: Service # 类型为 Service
metadata:
name: nginx-service # Service 名称
spec:
selector: # 选择器,用于匹配 Service 服务的 Pods
app: nginx # 匹配带有 app: nginx 标签的 Pods
ports: # 定义服务的端口映射
– protocol: TCP
port: 80 # Service 监听的端口 (集群内访问)
targetPort: 80 # Pod 中容器监听的端口
type: ClusterIP # 服务类型 (ClusterIP, NodePort, LoadBalancer)
“`
这个 Service 告诉 Kubernetes:
1. 创建一个名为 nginx-service
的 Service。
2. 它将把流量路由到带有 app: nginx
标签的 Pods 上(这些 Pods 正是由上面定义的 Deployment 管理的)。
3. 服务在集群内部的 80 端口监听请求 (port: 80
)。
4. 接收到的请求将被转发到被选中 Pods 的 80 端口 (targetPort: 80
)。
5. 服务的类型是 ClusterIP
,这意味着它只在集群内部可访问,分配一个集群内部 IP。
常见的 Service 类型:
* ClusterIP
: 默认类型,分配一个集群内部 IP,只在集群内可访问。
* NodePort
: 在集群中每个节点上开放一个静态端口,外部可以通过 <NodeIP>:<NodePort>
访问服务。用于开发或测试。
* LoadBalancer
: 在支持的云提供商上,会自动创建一个外部负载均衡器,将流量导入服务。用于生产环境暴露服务。
* ExternalName
: 将服务映射到外部的 DNS 名称,不做代理。
3.4 ConfigMap 和 Secret
ConfigMap 用于存储非敏感的配置数据,如配置文件、命令行参数、环境变量等。Secret 用于存储敏感数据,如密码、OAuth Token、SSH Key 等。它们都以键值对的形式存储数据,可以作为文件或环境变量注入到 Pod 中。
基本 ConfigMap YAML 示例:
“`yaml
configmap-app.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data: # 非敏感数据
app.properties: | # 可以存储多行文本
database.url=jdbc:mysql://mysql:3306/mydb
database.username=myuser
config.json: |
{
“logLevel”: “INFO”,
“timeout”: 30
}
api_key: abcdef12345 # 也可以是单行键值对
“`
基本 Secret YAML 示例:
Secret 的 data
字段的值必须是 Base64 编码的。这是为了确保数据在传输和存储时是“可打印”的,但这不是加密。任何人都可以轻松解码 Base64。因此,Secret 只是为了管理敏感数据而设计的,而不是为了保护数据不被知道。真正的数据安全需要依赖于底层的 etcd 加密和 RBAC 访问控制。
“`yaml
secret-db-credentials.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque # 默认类型,表示通用的用户定义 Secret
data:
# 数据库用户名 (Base64 编码的 ‘admin’)
username: YWRtaW4=
# 数据库密码 (Base64 编码的 ‘password123’)
password: cGFzc3dvcmQxMjM=
“`
你可以使用在线工具或命令行工具(如 echo -n 'your_string' | base64
)来对字符串进行 Base64 编码。
第四部分:使用 kubectl
应用和管理 YAML 文件
编写好 YAML 文件后,就需要使用 Kubernetes 的命令行工具 kubectl
来与集群交互,创建、更新或删除资源。
4.1 创建资源 (kubectl apply
或 kubectl create
)
有两种主要的方式使用 YAML 文件创建资源:
kubectl create -f <filename.yaml>
: 基于 YAML 文件创建一个或多个资源。如果资源已经存在,会报错。kubectl apply -f <filename.yaml>
: 基于 YAML 文件创建或更新资源。这是更推荐的方式,尤其是用于持续部署。apply
命令是幂等的,你可以反复运行它,它只会根据 YAML 文件中的定义创建新资源或更新现有资源。
使用 apply
创建/更新资源:
“`bash
kubectl apply -f pod-nginx.yaml # 应用单个文件
kubectl apply -f deployment-nginx.yaml
kubectl apply -f service-nginx.yaml
kubectl apply -f configmap-app.yaml
kubectl apply -f secret-db-credentials.yaml
应用包含多个 YAML 文档的文件
kubectl apply -f app.yaml # app.yaml 可能包含 Deployment 和 Service
应用一个目录下的所有 YAML 文件
kubectl apply -f ./config/ # 应用 config 目录下的所有 .yaml, .yml, .json 文件
“`
kubectl apply
的工作原理是计算当前集群中对象的状态与 YAML 文件中定义的状态之间的差异,然后只发送必要的补丁请求来更新对象。
4.2 查看资源 (kubectl get
和 kubectl describe
)
创建资源后,可以使用 kubectl get
查看资源列表或特定资源的状态概要,使用 kubectl describe
查看资源的详细信息。
“`bash
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get configmaps
kubectl get secrets
查看特定资源的 YAML 配置
kubectl get deployment nginx-deployment -o yaml
查看特定资源的详细信息
kubectl describe pod nginx-pod
kubectl describe service nginx-service
“`
kubectl get -o yaml
是一个非常有用的命令,可以用来查看 Kubernetes 为你的对象自动添加的字段(如 status
、uid
、resourceVersion
等),以及验证你的配置是否被正确应用。
4.3 删除资源 (kubectl delete
)
使用 kubectl delete
命令可以根据 YAML 文件或资源名称删除资源。
根据文件删除:
bash
kubectl delete -f pod-nginx.yaml
kubectl delete -f deployment-nginx.yaml
kubectl delete -f service-nginx.yaml
kubectl delete -f app.yaml # 删除 app.yaml 中定义的所有资源
kubectl delete -f ./config/ # 删除目录下的所有资源
根据类型和名称删除:
bash
kubectl delete pod nginx-pod
kubectl delete deployment nginx-deployment
kubectl delete service nginx-service
4.4 验证 YAML (kubectl apply --validate
)
从 Kubernetes 1.20 版本开始,kubectl apply
默认启用客户端侧验证。这意味着在你将 YAML 发送给 API Server 之前,kubectl
会检查你的 YAML 文件结构和字段是否符合 Kubernetes 资源的模式定义。
如果想手动验证而不应用:
bash
kubectl apply -f app.yaml --dry-run=client --validate
--dry-run=client
表示只在客户端模拟操作,不实际发送请求到集群。结合 --validate
可以用来检查 YAML 的语法和结构有效性。
4.5 学习资源的 YAML 结构 (kubectl explain
)
如果你不确定某个资源类型或字段的正确 YAML 结构,kubectl explain
命令是一个非常有用的工具。
bash
kubectl explain pod # 查看 Pod 的顶级字段说明
kubectl explain pod.spec # 查看 Pod spec 字段的说明
kubectl explain deployment.spec.template.spec.containers # 查看 Deployment Pod 模板中容器字段的说明
kubectl explain service.spec.ports # 查看 Service 端口字段的说明
这个命令会打印出字段的描述、类型以及是否必需,对于编写和调试 YAML 文件非常有帮助。
第五部分:编写 K8s YAML 的最佳实践和技巧
编写清晰、可维护的 Kubernetes YAML 配置需要遵循一些最佳实践。
- 保持文件小而专注: 将不同类型的资源(如 Deployment 和 Service)定义在不同的文件中,除非它们紧密相关且逻辑上属于同一单元(此时可以使用
---
分隔符)。这样可以提高文件的可读性和可维护性。 - 使用有意义的名称和标签: 为资源选择清晰、描述性的名称。广泛使用标签来标记应用、组件、环境、版本等,这是 Kubernetes 中组织和选择资源的基石。标签的一致性对于 Service、Deployment、ConfigMap Volume 挂载等都非常重要。
- 利用命名空间: 使用命名空间来对不同环境(开发、测试、生产)或不同团队/应用进行逻辑隔离,避免资源名称冲突和提高安全性。在
metadata
中明确指定namespace
。 - 添加注释: 使用注释解释复杂的配置段落、决策原因或注意事项,帮助自己和他人理解配置。
- 使用版本控制: 将你的 YAML 配置文件存储在 Git 等版本控制系统中。这使得你可以跟踪配置变更历史、回滚到早期版本,并进行团队协作。基础设施即代码的核心优势之一就是版本控制。
- 模板化和参数化: 对于需要在不同环境或不同部署中使用略有差异的配置(如镜像标签、副本数、配置值等),避免手动修改 YAML 文件。考虑使用模板工具,如 Helm 或 Kustomize。
- Helm: 是 Kubernetes 的包管理器,使用 Chart 定义应用。Chart 中包含参数化的 YAML 模板,通过 values 文件注入具体值。
- Kustomize: 是一个原生的 Kubernetes 配置管理工具,通过 overlay 的方式对基础 YAML 进行修改和定制,而无需修改原始文件。
这些工具在管理复杂的应用或在多个环境中部署时非常有用。
- 定义资源请求和限制 (
resources
): 在 Pod 的容器定义中,为 CPU 和内存设置resources.requests
和resources.limits
。这有助于调度器更合理地分配资源,并防止单个 Pod 耗尽节点资源影响其他 Pod。 - 配置健康检查 (
livenessProbe
,readinessProbe
): 为容器配置存活探针 (livenessProbe
) 和就绪探针 (readinessProbe
)。这让 Kubernetes 知道何时重启不健康的容器,以及何时将流量路由到就绪的 Pod。 - 使用配置映射和秘密进行外部化配置: 将应用的配置数据从容器镜像中分离出来,存储在 ConfigMap 和 Secret 中。这样可以在不重建镜像的情况下修改应用配置,并且更安全地管理敏感信息。
- 从小处着手,逐步迭代: 从一个简单的 Pod 开始,然后是 Deployment 和 Service,再添加 ConfigMap、Secret、Ingress 等。逐步增加配置的复杂性,每次修改后都进行测试。
第六部分:常见的 YAML 编写错误和故障排除
即使有经验,编写 YAML 文件时也容易出错。以下是一些常见的错误及其排除方法:
- 缩进错误: 这是最常见也是最令人沮丧的错误。YAML 解析器对缩进非常敏感。
- 错误信息: YAML 解析错误,通常指示缩进不一致或无效。
- 排除方法: 使用支持 YAML 语法的代码编辑器(如 VS Code、Sublime Text 等),它们通常有缩进指南和语法高亮,能帮你发现问题。确保只使用空格,并且同一层级的元素缩进一致。可以使用在线 YAML 校验器或
kubectl apply --dry-run=client --validate
进行初步检查。
- 键名或值拼写错误: Kubernetes 的字段名称是固定的,拼写错误会导致字段无法识别。
- 错误信息: 可能是
error: error validating... unknown field "<wrong_field>" in <object_type>.spec
。 - 排除方法: 仔细检查字段名称。使用
kubectl explain <resource_type>.<field>
来查找正确的字段名和结构。
- 错误信息: 可能是
- API 版本或类型错误: 指定了错误的
apiVersion
或kind
。- 错误信息:
error: unable to recognize "<filename.yaml>": no matches for kind "<kind>" in version "<api_version>"
. - 排除方法: 确认你使用的 Kubernetes 版本支持该
apiVersion
和kind
的组合。查阅 Kubernetes 文档或使用kubectl api-versions
查看集群支持的 API 版本。
- 错误信息:
- 必需字段缺失: 某些字段是必需的,如果遗漏会导致创建失败。
- 错误信息:
error: error validating... missing required field "<required_field>" in <object_type>.spec
。 - 排除方法: 查看错误信息,它会明确指出缺失的字段。使用
kubectl explain <resource_type>.<parent_field>
查看哪些字段是必需的。
- 错误信息:
- 选择器不匹配: Deployment 或 Service 的
selector
没有正确匹配 Pod 模板的标签。- 症状: Deployment 创建了 ReplicaSet 但没有 Pods 运行,或者 Service 没有 endpoints。
- 排除方法: 检查 Deployment/Service 的
selector.matchLabels
是否与 Pod 模板template.metadata.labels
完全一致。标签的键和值都必须匹配。
- 配置值不正确: 字段值格式错误或不在允许范围内。
- 错误信息: 可能因字段而异,例如端口号超出范围,镜像名称格式错误等。
- 排除方法: 查阅相关字段的文档说明。对于镜像问题,使用
docker pull <image>
在本地尝试拉取镜像,检查名称是否正确。
- 多个文档分隔符 (
---
) 使用错误: 如果在同一个文件中定义了多个资源但忘记使用---
分隔,解析器可能只会识别第一个文档。
排除 K8s 配置问题时,kubectl describe
命令是你的好朋友。它会提供资源的状态、事件以及相关的控制器信息,这些信息对于诊断问题非常有价值。例如,kubectl describe pod <pod-name>
可以看到 Pod 的调度情况、容器创建日志、错误事件等。
结论
Kubernetes 的配置是其强大能力的核心所在,而 YAML 文件则是承载这些配置的标准格式。通过本文的学习,你应该已经:
- 理解了为什么 YAML 是 Kubernetes 配置的首选。
- 掌握了 YAML 的基本语法:键值对、列表、对象、缩进和分隔符。
- 了解了 Kubernetes YAML 对象的标准结构:
apiVersion
,kind
,metadata
,spec
,status
。 - 学会了编写常见的 Kubernetes 资源(Pod, Deployment, Service, ConfigMap, Secret)的 YAML 配置。
- 掌握了使用
kubectl apply
,get
,describe
,delete
,explain
等命令来管理和调试配置。 - 了解了编写高质量 K8s YAML 的最佳实践和常见错误排除方法。
编写和管理 Kubernetes 配置是一个不断学习和实践的过程。从简单的应用开始,逐步引入更复杂的资源和概念。善用 kubectl explain
和 Kubernetes 官方文档,它们是学习和解决问题的重要资源。将基础设施视为代码,将 YAML 文件纳入版本控制,采纳自动化工具和最佳实践,将极大地提高你在 Kubernetes 上管理应用的效率和可靠性。
继续练习,你会越来越熟练地运用 YAML 来构建和管理你的云原生应用世界!