You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

645 lines
28 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 47 | 如何编写Kubernetes资源定义文件
你好,我是孔令飞。
在接下来的48讲我会介绍如何基于腾讯云EKS来部署IAM应用。EKS其实是一个标准的Kubernetes集群在Kubernetes集群中部署应用需要编写Kubernetes资源的YAMLYet Another Markup Language定义文件例如Service、Deployment、ConfigMap、Secret、StatefulSet等。
这些YAML定义文件里面有很多配置项需要我们去配置其中一些也比较难理解。为了你在学习下一讲时更轻松这一讲我们先学习下如何编写Kubernetes YAML文件。
## 为什么选择YAML格式来定义Kubernetes资源
首先解释一下我们为什么使用YAML格式来定义Kubernetes的各类资源呢这是因为YAML格式和其他格式例如XML、JSON等相比不仅能够支持丰富的数据而且结构清晰、层次分明、表达性极强、易于维护非常适合拿来供开发者配置和管理Kubernetes资源。
其实Kubernetes支持YAML和JSON两种格式JSON格式通常用来作为接口之间消息传递的数据格式YAML格式则用于资源的配置和管理。YAML和JSON这两种格式是可以相互转换的你可以通过在线工具[json2yaml](https://www.json2yaml.com/convert-yaml-to-json)来自动转换YAML和JSON数据格式。
例如下面是一个YAML文件中的内容
```yaml
apiVersion: v1
kind: Service
metadata:
name: iam-apiserver
spec:
clusterIP: 192.168.0.231
externalTrafficPolicy: Cluster
ports:
- name: https
nodePort: 30443
port: 8443
protocol: TCP
targetPort: 8443
selector:
app: iam-apiserver
sessionAffinity: None
type: NodePort
```
它对应的JSON格式的文件内容为
```json
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "iam-apiserver"
},
"spec": {
"clusterIP": "192.168.0.231",
"externalTrafficPolicy": "Cluster",
"ports": [
{
"name": "https",
"nodePort": 30443,
"port": 8443,
"protocol": "TCP",
"targetPort": 8443
}
],
"selector": {
"app": "iam-apiserver"
},
"sessionAffinity": "None",
"type": "NodePort"
}
}
```
我就是通过`json2yaml`在线工具来转换YAML和JSON的如下图所示
![图片](https://static001.geekbang.org/resource/image/0f/02/0ffac271b296d1cc407941cfc3139702.png?wh=1920x780)
在编写Kubernetes资源定义文件的过程中如果因为YAML格式文件中的配置项缩进太深导致不容易判断配置项的层级那么你就可以将其转换成JSON格式通过JSON格式来判断配置型的层级。
如果想学习更多关于YAML的知识你可以参考[YAML 1.2 (3rd Edition)](https://yaml.org/spec/1.2/spec.html)。这里可以先看看我整理的YAML基本语法
* 属性和值都是大小写敏感的。
* 使用缩进表示层级关系。
* 禁止使用Tab键缩进只允许使用空格建议两个空格作为一个层级的缩进。元素左对齐就说明对齐的两个元素属于同一个级别。
* 使用 `#` 进行注释,直到行尾。
* `key: value`格式的定义中,冒号后要有一个空格。
* 短横线表示列表项,使用一个短横线加一个空格;多个项使用同样的缩进级别作为同一列表。
* 使用 `---` 表示一个新的YAML文件开始。
现在你知道了Kubernetes支持YAML和JSON两种格式它们是可以相互转换的。但鉴于YAML格式的各项优点我建议你使用YAML格式来定义Kubernetes的各类资源。
## Kubernetes 资源定义概述
Kubernetes中有很多内置的资源常用的资源有Deployment、StatefulSet、ConfigMap、Service、Secret、Nodes、Pods、Events、Jobs、DaemonSets等。除此之外Kubernetes还有其他一些资源。如果你觉得Kubernetes内置的资源满足不了需求还可以自定义资源。
Kubernetes的资源清单可以通过执行以下命令来查看
```bash
$ kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
```
上述输出中,各列的含义如下。
* NAME资源名称。
* SHORTNAMES资源名称简写。
* APIVERSION资源的API版本也称为group。
* NAMESPACED资源是否具有Namespace属性。
* KIND资源类别。
这些资源有一些共同的配置,也有一些特有的配置。这里,我们先来看下这些资源共同的配置。
下面这些配置是Kubernetes各类资源都具备的
```yaml
---
apiVersion: <string> # string类型指定group的名称默认为core。可以使用 `kubectl api-versions` 命令来获取当前kubernetes版本支持的所有group。
kind: <string> # string类型资源类别。
metadata: <Object> # 资源的元数据。
name: <string> # string类型资源名称。
namespace: <string> # string类型资源所属的命名空间。
lables: < map[string]string> # map类型资源的标签。
annotations: < map[string]string> # map类型资源的标注。
selfLink: <string> # 资源的 REST API路径格式为/api/<group>/namespaces/<namespace>/<type>/<name>。例如:/api/v1/namespaces/default/services/iam-apiserver
spec: <Object> # 定义用户期望的资源状态disired state
status: <Object> # 资源当前的状态以只读的方式显示资源的最近状态。这个字段由kubernetes维护用户无法定义。
```
你可以通过`kubectl explain <object>`命令来查看Object资源对象介绍并通过`kubectl explain <object1>.<object2>`来查看`<object1>`的子对象`<object2>`的资源介绍,例如:
```bash
$ kubectl explain service
$ kubectl explain service.spec
$ kubectl explain service.spec.ports
```
Kubernetes资源定义YAML文件支持以下数据类型
* string表示字符串类型。
* object表示一个对象需要嵌套多层字段。
* map\[string\]string表示由key:value组成的映射。
* \[\]string表示字串列表。
* \[\]object表示对象列表。
* boolean表示布尔类型。
* integer表示整型。
## 常用的Kubernetes资源定义
上面说了Kubernetes中有很多资源其中Pod、Deployment、Service、ConfigMap这4类是比较常用的资源我来一个个介绍下。
### Pod资源定义
下面是一个Pod的YAML定义
```yaml
apiVersion: v1 # 必须 版本号, 常用v1 apps/v1
kind: Pod # 必须
metadata: # 必须,元数据
name: string # 必须,名称
namespace: string # 必须命名空间默认上default,生产环境为了安全性建议新建命名空间分类存放
labels: # 非必须,标签,列表值
- name: string
annotations: # 非必须,注解,列表值
- name: string
spec: # 必须,容器的详细定义
containers: #必须,容器列表,
- name: string   #必须容器1的名称
image: string #必须容器1所用的镜像
imagePullPolicy: [Always|Never|IfNotPresent] #非必须镜像拉取策略默认是Always
command: [string] # 非必须 列表值,如果不指定,则是一镜像打包时使用的启动命令
args: [string] # 非必须,启动参数
workingDir: string # 非必须,容器内的工作目录
volumeMounts: # 非必须,挂载到容器内的存储卷配置
- name: string # 非必须,存储卷名字,需与【@1】处定义的名字一致
readOnly: boolean #非必须,定义读写模式,默认是读写
ports: # 非必须,需要暴露的端口
- name: string # 非必须 端口名称
containerPort: int # 非必须 端口号
hostPort: int # 非必须 宿主机需要监听的端口号设置此值时同一台宿主机不能存在同一端口号的pod 建议不要设置此值
proctocol: [tcp|udp] # 非必须 端口使用的协议默认是tcp
env: # 非必须 环境变量
- name: string # 非必须 ,环境变量名称
value: string # 非必须,环境变量键值对
resources: # 非必须,资源限制
limits: # 非必须,限制的容器使用资源的最大值,超过此值容器会推出
cpu: string # 非必须cpu资源单位是core从0.1开始
memory: string 内存限制单位为MiB,GiB
requests: # 非必须,启动时分配的资源
cpu: string
memory: string
livenessProbe: # 非必须,容器健康检查的探针探测方式
exec: # 探测命令
command: [string] # 探测命令或者脚本
httpGet: # httpGet方式
path: string # 探测路径,例如 http://ip:port/path
port: number
host: string
scheme: string
httpHeaders:
- name: string
value: string
tcpSocket: # tcpSocket方式检查端口是否存在
port: number
initialDelaySeconds: 0 #容器启动完成多少秒后的再进行首次探测单位为s
timeoutSeconds: 0 #探测响应超时的时间,默认是1s,如果失败,则认为容器不健康,会重启该容器
periodSeconds: 0 # 探测间隔时间默认是10s
successThreshold: 0 #
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always|Never|OnFailure] # 容器重启的策略,
nodeSelector: object # 指定运行的宿主机
imagePullSecrets: # 容器下载时使用的Secrets名称需要与valumes.secret中定义的一致
- name: string
hostNetwork: false
volumes: ## 挂载的共享存储卷类型
- name: string # 非必须,【@1】
emptyDir: {}
hostPath:
path: string
secret: # 类型为secret的存储卷使用内部的secret内的items值作为环境变量
secrectName: string
items:
- key: string
path: string
configMap: ## 类型为configMap的存储卷
name: string
items:
- key: string
path: string
```
Pod是Kubernetes中最重要的资源我们可以通过Pod YAML定义来创建一个Pod也可以通过DaemonSet、Deployment、ReplicaSet、StatefulSet、Job、CronJob来创建Pod。
### Deployment资源定义
Deployment资源定义YAML文件如下
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels: # 设定资源的标签
app: iam-apiserver
name: iam-apiserver
namespace: default
spec:
progressDeadlineSeconds: 10 # 指定多少时间内不能完成滚动升级就视为失败,滚动升级自动取消
replicas: 1 # 声明副本数,建议 >= 2
revisionHistoryLimit: 5 # 设置保留的历史版本个数默认是10
selector: # 选择器
matchLabels: # 匹配标签
app: iam-apiserver # 标签格式为key: value对
strategy: # 指定部署策略
rollingUpdate:
maxSurge: 1 # 最大额外可以存在的副本数,可以为百分比,也可以为整数
maxUnavailable: 1 # 表示在更新过程中能够进入不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
type: RollingUpdate # 更新策略,包括:重建(Recreate)、RollingUpdate(滚动更新)
template: # 指定Pod创建模板。注意以下定义为Pod的资源定义
metadata: # 指定Pod的元数据
labels: # 指定Pod的标签
app: iam-apiserver
spec:
affinity:
podAntiAffinity: # Pod反亲和性尽量避免同一个应用调度到相同Node
preferredDuringSchedulingIgnoredDuringExecution: # 软需求
- podAffinityTerm:
labelSelector:
matchExpressions: # 有多个选项,只有同时满足这些条件的节点才能运行 Pod
- key: app
operator: In # 设定标签键与一组值的关系In、NotIn、Exists、DoesNotExist
values:
- iam-apiserver
topologyKey: kubernetes.io/hostname
weight: 100 # weight 字段值的范围是1-100。
containers:
- command: # 指定运行命令
- /opt/iam/bin/iam-apiserver # 运行参数
- --config=/etc/iam/iam-apiserver.yaml
image: ccr.ccs.tencentyun.com/lkccc/iam-apiserver-amd64:v1.0.6 # 镜像名,遵守镜像命名规范
imagePullPolicy: Always # 镜像拉取策略。IfNotPresent优先使用本地镜像Never使用本地镜像本地镜像不存在则报错Always默认值每次都重新拉取镜像
# lifecycle: # kubernetes支持postStart和preStop事件。当一个容器启动后Kubernetes将立即发送postStart事件在容器被终结之前Kubernetes将发送一个preStop事件
name: iam-apiserver # 容器名称,与应用名称保持一致
ports: # 端口设置
- containerPort: 8443 # 容器暴露的端口
name: secure # 端口名称
protocol: TCP # 协议TCP和UDP
livenessProbe: # 存活检查,检查容器是否正常,不正常则重启实例
httpGet: # HTTP请求检查方法
path: /healthz # 请求路径
port: 8080 # 检查端口
scheme: HTTP # 检查协议
initialDelaySeconds: 5 # 启动延时,容器延时启动健康检查的时间
periodSeconds: 10 # 间隔时间,进行健康检查的时间间隔
successThreshold: 1 # 健康阈值,表示后端容器从失败到成功的连续健康检查成功次数
failureThreshold: 1 # 不健康阈值,表示后端容器从成功到失败的连续健康检查成功次数
timeoutSeconds: 3 # 响应超时,每次健康检查响应的最大超时时间
readinessProbe: # 就绪检查,检查容器是否就绪,不就绪则停止转发流量到当前实例
httpGet: # HTTP请求检查方法
path: /healthz # 请求路径
port: 8080 # 检查端口
scheme: HTTP # 检查协议
initialDelaySeconds: 5 # 启动延时,容器延时启动健康检查的时间
periodSeconds: 10 # 间隔时间,进行健康检查的时间间隔
successThreshold: 1 # 健康阈值,表示后端容器从失败到成功的连续健康检查成功次数
failureThreshold: 1 # 不健康阈值,表示后端容器从成功到失败的连续健康检查成功次数
timeoutSeconds: 3 # 响应超时,每次健康检查响应的最大超时时间
startupProbe: # 启动探针,可以知道应用程序容器什么时候启动了
failureThreshold: 10
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 3
resources: # 资源管理
limits: # limits用于设置容器使用资源的最大上限,避免异常情况下节点资源消耗过多
cpu: "1" # 设置cpu limit1核心 = 1000m
memory: 1Gi # 设置memory limit1G = 1024Mi
requests: # requests用于预分配资源,当集群中的节点没有request所要求的资源数量时,容器会创建失败
cpu: 250m # 设置cpu request
memory: 500Mi # 设置memory request
terminationMessagePath: /dev/termination-log # 容器终止时消息保存路径
terminationMessagePolicy: File # 仅从终止消息文件中检索终止消息
volumeMounts: # 挂载日志卷
- mountPath: /etc/iam/iam-apiserver.yaml # 容器内挂载镜像路径
name: iam # 引用的卷名称
subPath: iam-apiserver.yaml # 指定所引用的卷内的子路径,而不是其根路径。
- mountPath: /etc/iam/cert
name: iam-cert
dnsPolicy: ClusterFirst
restartPolicy: Always # 重启策略Always、OnFailure、Never
schedulerName: default-scheduler # 指定调度器的名字
imagePullSecrets: # 在Pod中设置ImagePullSecrets只有提供自己密钥的Pod才能访问私有仓库
- name: ccr-registry # 镜像仓库的Secrets需要在集群中手动创建
securityContext: {} # 指定安全上下文
terminationGracePeriodSeconds: 5 # 优雅关闭时间这个时间内优雅关闭未结束k8s 强制 kill
volumes: # 配置数据卷类型详见https://kubernetes.io/zh/docs/concepts/storage/volumes
- configMap: # configMap 类型的数据卷
defaultMode: 420 #权限设置0~0777默认0664
items:
- key: iam-apiserver.yaml
path: iam-apiserver.yaml
name: iam # configmap名称
name: iam # 设置卷名称与volumeMounts名称对应
- configMap:
defaultMode: 420
name: iam-cert
name: iam-cert
```
在部署时,你可以根据需要来配置相应的字段,常见的需要配置的字段为:`labels`、`name`、`namespace`、`replicas`、`command`、`imagePullPolicy`、`container.name`、`livenessProbe`、`readinessProbe`、`resources`、`volumeMounts`、`volumes`、`imagePullSecrets`等。
另外在部署应用时经常需要提供配置文件供容器内的进程加载使用。最常用的方法是挂载ConfigMap到应用容器中。那么如何挂载ConfigMap到容器中呢
引用 ConfigMap 对象时,你可以在 volume 中通过它的名称来引用。你可以自定义 ConfigMap 中特定条目所要使用的路径。下面的配置就显示了如何将名为 `log-config` 的 ConfigMap 挂载到名为 `configmap-pod` 的 Pod 中:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: test
image: busybox
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: log-config
items:
- key: log_level
path: log_level
```
`log-config` ConfigMap 以卷的形式挂载,并且存储在 `log_level` 条目中的所有内容都被挂载到 Pod 的`/etc/config/log_level` 路径下。 请注意,这个路径来源于卷的 `mountPath``log_level` 键对应的`path`。
这里需要注意,在使用 ConfigMap 之前你首先要创建它。接下来我们来看下ConfigMap定义。
### ConfigMap资源定义
下面是一个ConfigMap YAML示例
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config4
data: # 存储配置内容
db.host: 172.168.10.1 # 存储格式为key: value
db.port: 3306
```
可以看到ConfigMap的YAML定义相对简单些。假设我们将上述YAML文件保存在了`iam-configmap.yaml`文件中我们可以执行以下命令来创建ConfigMap
```bash
$ kubectl create -f iam-configmap.yaml
```
除此之外kubectl命令行工具还提供了3种创建ConfigMap的方式。我来分别介绍下。
1通过`--from-literal`参数创建
创建命令如下:
```bash
$ kubectl create configmap iam-configmap --from-literal=db.host=172.168.10.1 --from-literal=db.port='3306'
```
2通过`--from-file=<文件>`参数创建
创建命令如下:
```bash
$ echo -n 172.168.10.1 > ./db.host
$ echo -n 3306 > ./db.port
$ kubectl create cm iam-configmap --from-file=./db.host --from-file=./db.port
```
`--from-file`的值也可以是一个目录。当值是目录时目录中的文件名为key目录的内容为value。
3通过`--from-env-file`参数创建
创建命令如下:
```bash
$ cat << EOF > env.txt
db.host=172.168.10.1
db.port=3306
EOF
$ kubectl create cm iam-configmap --from-env-file=env.txt
```
### Service资源定义
Service 是 Kubernetes 另一个核心资源。通过创建 Service可以为一组具有相同功能的容器应用提供一个统一的入口地址并且将请求负载到后端的各个容器上。Service资源定义YAML文件如下
```yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: iam-apiserver
name: iam-apiserver
namespace: default
spec:
clusterIP: 192.168.0.231 # 虚拟服务地址
externalTrafficPolicy: Cluster # 表示此服务是否希望将外部流量路由到节点本地或集群范围的端点
ports: # service需要暴露的端口列表
- name: https #端口名称
nodePort: 30443 # 当type = NodePort时指定映射到物理机的端口号
port: 8443 # 服务监听的端口号
protocol: TCP # 端口协议支持TCP和UDP默认TCP
targetPort: 8443 # 需要转发到后端Pod的端口号
selector: # label selector配置将选择具有label标签的Pod作为其后端RS
app: iam-apiserver
sessionAffinity: None # 是否支持session
type: NodePort # service的类型指定service的访问方式默认为clusterIp
```
上面我介绍了常用的Kubernetes YAML的内容。我们在部署应用的时候是需要手动编写这些文件的。接下来我就讲解一些在编写过程中常用的编写技巧。
## YAML文件编写技巧
这里我主要介绍三个技巧。
1使用在线的工具来自动生成模板YAML文件。
YAML文件很复杂完全从0开始编写一个YAML定义文件工作量大、容易出错也没必要。我比较推荐的方式是使用一些工具来自动生成所需的YAML。
这里我推荐使用[k8syaml](https://k8syaml.com/)工具。`k8syaml`是一个在线的YAML生成工具当前能够生成Deployment、StatefulSet、DaemonSet类型的YAML文件。`k8syaml`具有默认值,并且有对各字段详细的说明,可以供我们填参时参考。
2使用`kubectl run`命令获取YAML模板
```yaml
$ kubectl run --dry-run=client --image=nginx nginx -o yaml > my-nginx.yaml
$ cat my-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
```
然后我们可以基于这个模板来修改配置形成最终的YAML文件。
3导出集群中已有的资源描述。
有时候如果我们想创建一个Kubernetes资源并且发现该资源跟集群中已经创建的资源描述相近或者一致的时候可以选择导出集群中已经创建资源的YAML描述并基于导出的YAML文件进行修改获得所需的YAML。例如
```bash
$ kubectl get deployment iam-apiserver -o yaml > iam-authz-server.yaml
```
接着,修改`iam-authz-server.yaml`。通常我们需要删除Kubernetes自动添加的字段例如`kubectl.kubernetes.io/last-applied-configuration`、`deployment.kubernetes.io/revision`、`creationTimestamp`、`generation`、`resourceVersion`、`selfLink`、`uid`、`status`。
这些技巧可以帮助我们更好地编写和使用Kubernetes YAML。
## 使用Kubernetes YAML时的一些推荐工具
接下来,我再介绍一些比较流行的工具,你可以根据自己的需要进行选择。
### kubeval
[kubeval](https://github.com/instrumenta/kubeval)可以用来验证Kubernetes YAML是否符合Kubernetes API模式。
安装方法如下:
```bash
$ wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz
$ tar xf kubeval-linux-amd64.tar.gz
$ mv kubeval $HOME/bin
```
安装完成后我们对Kubernetes YAML文件进行验证
```bash
$ kubeval deployments/iam.invalid.yaml
ERR - iam/templates/iam-configmap.yaml: Duplicate 'ConfigMap' resource 'iam' in namespace ''
```
根据提示,查看`iam.yaml`,发现在`iam.yaml`文件中,我们定义了两个同名的`iam` ConfigMap
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: iam
data:
{}
---
# Source: iam/templates/iam-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: iam
data:
iam-: ""
iam-apiserver.yaml: |
...
```
可以看到,使用`kubeval`之类的工具能让我们在部署的早期不用访问集群就能发现YAML文件的错误。
### kube-score
[kube-score](https://github.com/zegl/kube-score)能够对Kubernetes YAML进行分析并根据内置的检查对其评分这些检查是根据安全建议和最佳实践而选择的例如
* 以非Root用户启动容器。
* 为Pods设置健康检查。
* 定义资源请求和限制。
你可以按照这个方法安装:
```bash
$ go get github.com/zegl/kube-score/cmd/kube-score
```
然后我们对Kubernetes YAML进行评分
```bash
$ kube-score score -o ci deployments/iam.invalid.yaml
[OK] iam-apiserver apps/v1/Deployment
[OK] iam-apiserver apps/v1/Deployment
[OK] iam-apiserver apps/v1/Deployment
[OK] iam-apiserver apps/v1/Deployment
[CRITICAL] iam-apiserver apps/v1/Deployment: The pod does not have a matching NetworkPolicy
[CRITICAL] iam-apiserver apps/v1/Deployment: Container has the same readiness and liveness probe
[CRITICAL] iam-apiserver apps/v1/Deployment: (iam-apiserver) The pod has a container with a writable root filesystem
[CRITICAL] iam-apiserver apps/v1/Deployment: (iam-apiserver) The container is running with a low user ID
[CRITICAL] iam-apiserver apps/v1/Deployment: (iam-apiserver) The container running with a low group ID
[OK] iam-apiserver apps/v1/Deployment
...
```
检查的结果有`OK`、`SKIPPED`、`WARNING`和`CRITICAL`。`CRITICAL`是需要你修复的;`WARNING`是需要你关注的;`SKIPPED`是因为某些原因略过的检查;`OK`是验证通过的。
如果你想查看详细的错误原因和解决方案,可以使用`-o human`选项,例如:
```bash
$ kube-score score -o human deployments/iam.invalid.yaml
```
上述命令会检查YAML资源定义文件如果有不合规的地方会报告级别、类别以及错误详情如下图所示
![图片](https://static001.geekbang.org/resource/image/04/f6/0498529693c6d15c9d9d45cbyy866cf6.png?wh=1920x827)
当然除了kubeval、kube-score这两个工具业界还有其他一些Kubernetes检查工具例如[config-lint](https://github.com/stelligent/config-lint)、[copper](https://github.com/cloud66-oss/copper)、[conftest](https://github.com/open-policy-agent/conftest)、[polaris](https://github.com/FairwindsOps/polaris)等。
这些工具我推荐你这么来选择首先使用kubeval工具做最基本的YAML文件验证。验证通过之后我们就可以进行更多的测试。如果你没有特别复杂的YAML验证要求只需要用到一些最常见的检查策略这时候可以使用kube-score。如果你有复杂的验证要求并且希望能够自定义验证策略则可以考虑使用copper。当然`polaris`、`config-lint`、`copper`也值得你去尝试下。
## 总结
今天我主要讲了如何编写Kubernetes YAML文件。
YAML格式具有丰富的数据表达能力、清晰的结构和层次因此被用于Kubernetes资源的定义文件中。如果你要把应用部署在Kubernetes集群中就要创建多个关联的K8s资源如果要创建K8s资源目前比较多的方式还是编写YAML格式的定义文件。
这一讲我介绍了K8s中最常用的四种资源Pod、Deployment、Service、ConfigMap的YAML定义的写法你可以常来温习。
另外在编写YAML文件时也有一些技巧。比如可以通过在线工具[k8syaml](https://k8syaml.com/)来自动生成初版的YAML文件再基于此YAML文件进行二次修改从而形成终版。
最后我还给你分享了编写和使用Kubernetes YAML时社区提供的多种工具。比如kubeval可以校验YAMLkube-score可以给YAML文件打分。了解了如何编写Kubernetes YAML文件下一讲的学习相信你会进行得更顺利。
## 课后练习
1. 思考一下如何将ConfigMap中的Key挂载到同一个目录中文件名为Key名
2. 使用kubeval检查你正在或之前从事过的项目的K8s YAML定义文件查看报错并修改和优化。
欢迎你在留言区和我交流讨论,我们下一讲见。