你好,我是孔令飞。
在接下来的48讲,我会介绍如何基于腾讯云EKS来部署IAM应用。EKS其实是一个标准的Kubernetes集群,在Kubernetes集群中部署应用,需要编写Kubernetes资源的YAML(Yet 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 ,来自动转换YAML和JSON数据格式。
例如,下面是一个YAML文件中的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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格式的文件内容为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 { "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的,如下图所示:
在编写Kubernetes资源定义文件的过程中,如果因为YAML格式文件中的配置项缩进太深,导致不容易判断配置项的层级,那么,你就可以将其转换成JSON格式,通过JSON格式来判断配置型的层级。
如果想学习更多关于YAML的知识,你可以参考YAML 1.2 (3rd Edition) 。这里,可以先看看我整理的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的资源清单可以通过执行以下命令来查看:
1 2 3 4 5 6 7 $ 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各类资源都具备的:
1 2 3 4 5 6 7 8 9 10 11 --- apiVersion: <string> kind: <string> metadata: <Object> name: <string> namespace: <string> lables: < map[string]string> annotations: < map[string]string> selfLink: <string> spec: <Object> status: <Object>
你可以通过kubectl explain <object>命令来查看Object资源对象介绍,并通过kubectl explain <object1>.<object2>来查看<object1>的子对象<object2>的资源介绍,例如:
1 2 3 $ 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定义:
1 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 apiVersion: v1 kind: Pod metadata: name: string namespace: string labels: - name: string annotations: - name: string spec: containers: - name: string image: string imagePullPolicy: [Always|Never|IfNotPresent ] command: [string ] args: [string ] workingDir: string volumeMounts: - name: string readOnly: boolean ports: - name: string containerPort: int hostPort: int proctocol: [tcp|udp ] env: - name: string value: string resources: limits: cpu: string memory: string 内存限制,单位为MiB,GiB requests: cpu: string memory: string livenessProbe: exec: command: [string ] httpGet: path: string port: number host: string scheme: string httpHeaders: - name: string value: string tcpSocket: port: number initialDelaySeconds: 0 timeoutSeconds: 0 periodSeconds: 0 successThreshold: 0 failureThreshold: 0 securityContext: privileged: false restartPolicy: [Always|Never|OnFailure ] nodeSelector: object imagePullSecrets: - name: string hostNetwork: false volumes: - name: string emptyDir: {} hostPath: path: string secret: secrectName: string items: - key: string path: string configMap: name: string items: - key: string path: string
Pod是Kubernetes中最重要的资源,我们可以通过Pod YAML定义来创建一个Pod,也可以通过DaemonSet、Deployment、ReplicaSet、StatefulSet、Job、CronJob来创建Pod。
Deployment资源定义 Deployment资源定义YAML文件如下:
1 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 apiVersion: apps/v1 kind: Deployment metadata: labels: app: iam-apiserver name: iam-apiserver namespace: default spec: progressDeadlineSeconds: 10 replicas: 1 revisionHistoryLimit: 5 selector: matchLabels: app: iam-apiserver strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 type: RollingUpdate template: metadata: labels: app: iam-apiserver spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - iam-apiserver topologyKey: kubernetes.io/hostname weight: 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 name: iam-apiserver ports: - containerPort: 8443 name: secure protocol: TCP livenessProbe: httpGet: path: /healthz port: 8080 scheme: HTTP initialDelaySeconds: 5 periodSeconds: 10 successThreshold: 1 failureThreshold: 1 timeoutSeconds: 3 readinessProbe: httpGet: 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: cpu: "1" memory: 1Gi requests: cpu: 250m memory: 500Mi 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 schedulerName: default-scheduler imagePullSecrets: - name: ccr-registry securityContext: {} terminationGracePeriodSeconds: 5 volumes: - configMap: defaultMode: 420 items: - key: iam-apiserver.yaml path: iam-apiserver.yaml name: iam name: iam - 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 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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示例:
1 2 3 4 5 6 7 apiVersion: v1 kind: ConfigMap metadata: name: test-config4 data: db.host: 172.168 .10 .1 db.port: 3306
可以看到,ConfigMap的YAML定义相对简单些。假设我们将上述YAML文件保存在了iam-configmap.yaml文件中,我们可以执行以下命令,来创建ConfigMap:
1 $ kubectl create -f iam-configmap.yaml
除此之外,kubectl命令行工具还提供了3种创建ConfigMap的方式。我来分别介绍下。
1)通过--from-literal参数创建
创建命令如下:
1 $ kubectl create configmap iam-configmap --from-literal=db.host=172.168.10.1 --from-literal=db.port='3306'
2)通过--from-file=<文件>参数创建
创建命令如下:
1 2 3 $ 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参数创建
创建命令如下:
1 2 3 4 5 $ 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文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: v1 kind: Service metadata: labels: app: iam-apiserver name: iam-apiserver namespace: default 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
上面,我介绍了常用的Kubernetes YAML的内容。我们在部署应用的时候,是需要手动编写这些文件的。接下来,我就讲解一些在编写过程中常用的编写技巧。
YAML文件编写技巧 这里我主要介绍三个技巧。
1)使用在线的工具来自动生成模板YAML文件。
YAML文件很复杂,完全从0开始编写一个YAML定义文件,工作量大、容易出错,也没必要。我比较推荐的方式是,使用一些工具来自动生成所需的YAML。
这里我推荐使用k8syaml 工具。k8syaml是一个在线的YAML生成工具,当前能够生成Deployment、StatefulSet、DaemonSet类型的YAML文件。k8syaml具有默认值,并且有对各字段详细的说明,可以供我们填参时参考。
2)使用kubectl run命令获取YAML模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ 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。例如:
1 $ 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 可以用来验证Kubernetes YAML是否符合Kubernetes API模式。
安装方法如下:
1 2 3 $ 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文件进行验证:
1 2 $ kubeval deployments/iam.invalid.yaml ERR - iam/templates/iam-configmap.yaml: Duplicate 'ConfigMap' resource 'iam' in namespace ''
根据提示,查看iam.yaml,发现在iam.yaml文件中,我们定义了两个同名的iam ConfigMap:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1 kind: ConfigMap metadata: name: iam data: {} --- apiVersion: v1 kind: ConfigMap metadata: name: iam data: iam-: "" iam-apiserver.yaml: | ...
可以看到,使用kubeval之类的工具,能让我们在部署的早期,不用访问集群就能发现YAML文件的错误。
kube-score kube-score 能够对Kubernetes YAML进行分析,并根据内置的检查对其评分,这些检查是根据安全建议和最佳实践而选择的,例如:
以非Root用户启动容器。 为Pods设置健康检查。 定义资源请求和限制。 你可以按照这个方法安装:
1 $ go get github.com/zegl/kube-score/cmd/kube-score
然后,我们对Kubernetes YAML进行评分:
1 2 3 4 5 6 7 8 9 10 11 12 $ 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选项,例如:
1 $ kube-score score -o human deployments/iam.invalid.yaml
上述命令会检查YAML资源定义文件,如果有不合规的地方会报告级别、类别以及错误详情,如下图所示:
当然,除了kubeval、kube-score这两个工具,业界还有其他一些Kubernetes检查工具,例如config-lint 、copper 、conftest 、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 来自动生成初版的YAML文件,再基于此YAML文件进行二次修改,从而形成终版。
最后,我还给你分享了编写和使用Kubernetes YAML时,社区提供的多种工具。比如,kubeval可以校验YAML,kube-score可以给YAML文件打分。了解了如何编写Kubernetes YAML文件,下一讲的学习相信你会进行得更顺利。
课后练习 思考一下,如何将ConfigMap中的Key挂载到同一个目录中,文件名为Key名? 使用kubeval检查你正在或之前从事过的项目的K8s YAML定义文件,查看报错,并修改和优化。 欢迎你在留言区和我交流讨论,我们下一讲见。