文章内容:
资源类型介绍、YAML格式介绍、常用字段说明、Pod生命周期、initC、initC特殊说明、探针-1、探针-2、start、stop、相位
资源清单,简单来说就是通过资源清单中的资源项编写剧本yaml文件,实现服务pod化、service、volume等等。
工作负载型资源(workload)
Pod
ReplicaSet 用于通过标签创建pod
Deployment 用于通过ReplicaSet创建pod
StatefulSet 无状态服务管理器
DaemonSet 用于在每个节点都创建一个组件,例如部署监控
Job 任务
CronJob 计划任务
服务发现及负载均衡型资源(ServiceDiscovery LoadBalance)
Service
Ingress
配置与存储型资源
Volume(存储卷)
CSI (容器存储接口,可以扩展各种各样的第三方存储卷)
特殊类型的存储卷
ConfigMap (配置资源类型,部分应用的配置文件管理,达到热提交)
Secret (保存敏感数据)
DownwardAPI (吧外部环境中的信息输出给容器,下载或上传文件的接口)
Namespace 命名空间
Node 节点
Role 角色
ClusterRole 集群角色
RoleBinding
ClusterRoleBinding
根据指标进行操作
HPA 根据cpu 内存占用情况自动扩展缩减节点
PodTemplate pod模板
LimitRange 资源限制
yaml语言是一种可读性高,用来表达数据序列的格式语言。其意思是:仍是一种标记型语言,但为了强调这种语言一数据作为中心,而不是以标记语言为重点。
基本语法:
缩进时不允许使用Tab键,只允许使用空格缩进的空格数目不重要,但要相同层级的元素左对齐#表示注释yaml支持的数据结构
对象:键值对的集合,又称为映射/哈希/字典数组:一组按次序排列的值,又称为序列/列表纯量:单个的,不可再分的值对象类型:对象的一组键值对,使用冒号结构表示
name: Steve
age: 18
另一种写法
hash: { name: Steve, age: 18 }
数组类型:一组连词线开头的行,构成一个数组
animal
- Cat
- Dog
数组也可以采用行内表示法
animal: [Cat, Dog]
复合结构:对象和数组可以结合使用,形成复合结构
languages:
- Ruby
- Perl
- Python
websites:
YAML: yaml.org
Ruby: ruby-lang.org
Python: python.org
纯量:纯量是最基本的、不可再分的值。一下数据类型都属于纯量
字符串、布尔值、整数、浮点数、null
时间、日期
数值直接以字面量的形式表示:
number: 12.13
布尔值用true和false表示:
isSet: true
null用 ~ 表示,不写也是null:
parent: ~
时间采用ISO8601格式:
iso8601: 2020-06-30t11:20:40.10-05:00
日期采用复合 iso8601 格式的年、月、日表示
date: 1999-06-30
YAML允许使用两个感叹号,强制转换数据类型:
e: !!str 123 转换为字符类型
f: !!str true 转换为字符类型
字符串
字符串默认不使用引号表示:
str: 这是一行字符串
如果字符串之中包含空格或特殊字符,需要放在引号之中:
str: '这是 一行字符串'
单引号和双引号都可以使用,双引号不会对特殊字符进行转义:
s1: '这是\n字符串‘
s2: "这是\n字符串"
单引号之中如果还有单引号,必须连续使用两个单引号转义:
str: 'labor ''s day'
字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符挥别转为空格:
str: 这是一段
多行
字符串
多行字符串可以使用 | 保留换行符,也可以使用 > 折叠换行:
this: |
Foo
Bar
thar: >
Foo
Bar
+ 表示保留文字块末尾的换行,-表示删除字符串末尾的换行:
s1: |
Foo
s2: |+
Foo
s3: |-
Foo
必须存在的属性表
参数名字段类型说明versionString这里指的是K8S API的版本,目前基本上是V1,可以用kubectl api-versions命令查询kindString这里指的是yaml文件定义的资源类型和角色,比如:PodmetadataObject 元数据对象,固定值就写metadatametadata.nameString元数据对象的名字,这里由我们编写,比如命名Pod的名字metadata.namespaceString元数据对象的命名空间,由我们自身定义SpecObject详细定义对象,固定值就写Specspec.containers[]list这里是Spec对象的容器列表定义,是个列表spec.containers[].nameString这里定义容器的名字spec.containers[].imageString这里定义要用到的镜像名称主要对象
参数名字段类型说明spec.containers[].nameString定义容器的名字spec.containers[].imageString定义要用到的镜像名称spec.containers[].imagePullPolicyString定义镜像拉取策略,有Always、Never、ifNotPresent三个值可选
Always:意思是每次都尝试重新拉取镜像
Never:表示仅使用本地镜像
ifNotPresent:如果本地有镜像就使用本地镜像,没有就拉取镜像
默认值:Always
最佳选择是:ifNotPresent
spec.containers[].command[]List指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令spec.containers[].args[]List指定容器启动命令参数,因为是数组可以指定多个spec.containers[].workingDirString指定容器的工作目录spec.containers[].env[].nameString指定环境变量名称spec.containers[].env[].valueString指定环境变量值spec.containers[].resourcesObject指定资源限制和资源请求的值(这里开始就是设置容器的资源上限)spec.containers[].resources.limitsObject指定设置容器运行时的资源使用上限spec.containers[].resources.limits.cpuString指定CPU的限制,单位为core,将用于docker run --cpu-shares参数spec.containers[].resources.limits.memoryString指定MEM内存的限制,单位为MIB、GiBspec.containers[].resources.requestsObject指定容器启动和调度是的限制设置spec.containers[].resources.requests.cpuStringCPU请求,单位为core数,容器启动是初始化可用数量spec.containers[].resources.requests.memoryString内存请求,单位为MIB、GiB,容器启动时初始化可用数量额外的参数项
参数名字段类型说明spec.restartPolicyString定义Pod的重启策略,可选值为Always、OnFailure,默认值为Always
Always:Pod一旦终止运行,则无论容器是如何终止的,kubelet服务都会将其重启
OnFailure:只要Pod以非0退出码终止时,kubelet才会重启该容器
Never:Pod终止后,kubelete将退出码报告给Master,不会重启该Pod
spec.nodeSelectorObject定义Node的Label过了标签,以key:value格式指定spec.imagePullSecretsObject定义pull镜像时使用secret名称,以name:secretkey格式指定spec.hostNetworkBoolean定义是否使用主机网络模式,默认值为false
设置true表示使用苏主机网络,不实用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本
除了上面常用的以外还有很多,可以通过命令查看
查看pod的字段
kubectl create pod
FIELDS下面就是创建pod的一些模板字段
继续查看字段的详细描述信息
例如查看apiVersion
kubectl create pod.apiVersion
pod yaml文件示例:
apiVersion: v1 kind: Pod metadata: name: myapp-pod namespace: default labels: app: myapp spec: containers: - name: app image: docker.harbor.com/library/myapp:v1 - name: test image: docker.harbor.com/library/myapp:v1注意,上面的示例代码创建出来的pod实际上是个故障pod,原因是个pod中两个容器没有问题,问题是两个容器使用了同一个镜像,同一个镜像使用的端口一样,所以会造成端口冲突。
故障排查:
根据上面的文件创建出来的pod通过 kubectl get pod 会发现pod状态不断改变并重启,RESTARTS下的重启数值会增加
查看pod信息
kubectl describe pod myapp-pod 会发现是第二个容器 test 在重启
查看test容器日志报错信息
kubectl log myapp-pod -c test 会发现是因为端口被占用
initC:容器启动时的初始化工作,不止有一个initC,初始化后将丢弃initC,多个initC则必须是前一个initC完成后才执行下一个
Main C:初始化后运行的主程序
START:启动时执行一个指令
STOP:停止时执行一个指令
readiness:pod启动后假设pod中有个容器运行了一个程序,程序启动即running,而running的pod将可以让外部访问,但是程序 有可能正在启动而无法提供给用户想要的返回结果,而readiness就是判断服务是否真正启动完成
Liveness:pod中容器运行期间如果容器中进程出现假死,僵尸进程z,则Liveness可以通过预设检测Main C 判断该pod是否正常
pod能够具有多个容器,应用运行在容器中,但是他也可能有一个或多个先于应用容器启动的 init 容器
init 容器与普通的容器非常像,除了如下亮点:
init 容器总是运行到成功完成为止每个 init 容器都必须在下一个init容器启动之前成功完成如果 pod 的 init 容器失败,kubernetes 会不断的重启该pod,直到 init 容器成功为止,除非 pod 对应的 restartPolicy 为 Never。
举例说明:
有下面一个文件 init-pod.yaml
首先运行一个容器 myapp-container,运行一条命令,等待6分钟
然后initContainers运行init,执行一条命令,解析域名myservice,每两秒循环一次,直到解析成功才退出
前一个 init-myservice init执行完成后执行 init-mydb的init
解析域名mydb,同样解析成功退出
apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: docker.harbor.com/library/busybox:v1 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: docker.harbor.com/library/busybox:v1 command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;'] - name: init-mydb image: docker.harbor.com/library/busybox:v1 command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']运行:
kubectl create -f init-pod.yaml此时因为没有创建 myservice 和 mydb 这两个 service,所以会出现下面的状态
[root@m1 ymal]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6s
查看故障原因
可以看到在 init-myservice 处 ready 为False
[root@m1 ymal]# kubectl describe pod myapp-pod Name: myapp-pod Namespace: default Priority: 0 Node: m3-n2/172.26.220.94 Start Time: Wed, 01 Jul 2020 18:03:46 +0800 Labels: app=myapp Annotations: <none> Status: Pending IP: 10.244.2.2 Init Containers: init-myservice: Container ID: docker://b2d3ffc1b3fc6309c2ee1ca2f268eb03638d97f8b18dfe26c787ba1045481e5f Image: docker.harbor.com/library/busybox:v1 Image ID: docker-pullable://docker.harbor.com/library/busybox@sha256:2131f09e4044327fd101ca1fd4043e6f3ad921ae7ee901e9142e6e36b354a907 Port: <none> Host Port: <none> Command: sh -c until nslookup myservice; do echo waiting for myservice; sleep 2; done; State: Running Started: Wed, 01 Jul 2020 18:03:47 +0800 Ready: False Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-wprng (ro) init-mydb: Container ID: Image: docker.harbor.com/library/busybox:v1 Image ID: Port: <none> Host Port: <none> Command: sh -c until nslookup mydb; do echo waiting for mydb; sleep 2; done; State: Waiting Reason: PodInitializing Ready: False Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-wprng (ro)查看故障故障点
可以看到是因为域名解析失败了
[root@m1 ymal]# kubectl log myapp-pod -c init-myservice log is DEPRECATED and will be removed in a future version. Use logs instead. Server: 10.96.0.10 Address: 10.96.0.10:53 ** server can't find myservice.default.svc.cluster.local: NXDOMAIN *** Can't find myservice.svc.cluster.local: No answer *** Can't find myservice.cluster.local: No answer *** Can't find myservice.default.svc.cluster.local: No answer *** Can't find myservice.svc.cluster.local: No answer *** Can't find myservice.cluster.local: No answer好的我们创建 myservice.yaml 并启动
kind: Service apiVersion: v1 metadata: name: myservice spec: ports: - protocol: TCP port: 80 # 容器内部端口 targetPort: 9376 # 映射到外部的端口 运行 # kubectl create -f myservice.yaml稍微等待一会再次查看 pod 会发现变成了下面的状态, Init 变成了 1/2,表示第一个init已经运行成功了
[root@m1 ymal]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 10m
我们再继续创建下一个 service, mydb.yaml
kind: Service apiVersion: v1 metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 运行 # kubectl create -f mydb.yaml等待一会再次查看 pod
成功运行
[root@m1 ymal]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 10m
探针概念:
探针是由kubelet 对容器执行的定期诊断,要执行诊断,kubelet调用由容器实现的Handler。
有三种类型的处理程序:
ExecAction:在容器内执行指定的命令,退出码为 0 表示诊断成功TCPSocketAction:对指定端口上的容器IP地址进行TCP检查,端口通则表示诊断成功HTTPGetAction:对指定容器的ip和端口执行HTTP Get请求,状态吗返回结果大于等于200 小于400,表示诊断成功每次探测都将获得一下三种结果之一:
成功:容器通过诊断失败:容器未通过诊断未知:诊断失败,因此不会采取任何行动探测方式:
readinessProbe:指示容器是否做好服务请求,如果就绪探测失败,端点控制器将从Pod匹配的所有Service的端点中删除该Pod的IP地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。。简单来说就是如果配置此探针但是诊断失败,Main C网络不会对外开放访问。
livenessProbe:指示容器是否正在运行。如果存活探测失败,则kubelet会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为Success。
探针检测-就绪检测
执行 get 检测,因为根本就没有index1.html这个文件,所以这个剧本执行一定失败
initialDelaySeconds: 1 表示启动后一秒执行检测 periodSeconds: 3 重试间隔3秒
[root@m1 yaml]# cat readiness-httpget-pod.yaml apiVersion: v1 kind: Pod metadata: name: readiness-httpget-pod namespace: default spec: containers: - name: readiness-httpget-container image: docker.harbor.com/library/nginx:v1 imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 80 path: /index1.html initialDelaySeconds: 1 periodSeconds: 3 [root@m1 yaml]# kubectl create -f readiness-httpget-pod.yaml启动后查看pod状态
会发现状态为Running,但是READY状态显示为成功
[root@m1 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget-pod 0/1 Running 0 5s
查看pod详细信息
[root@m1 yaml]# kubectl describe pod readiness-httpget-pod
会发现最后显示为:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m33s default-scheduler Successfully assigned default/readiness-httpget-pod to m3-n2
Normal Pulling 3m33s kubelet, m3-n2 Pulling image "docker.harbor.com/library/nginx:v1"
Normal Pulled 3m30s kubelet, m3-n2 Successfully pulled image "docker.harbor.com/library/nginx:v1"
Normal Created 3m30s kubelet, m3-n2 Created container readiness-httpget-container
Normal Started 3m29s kubelet, m3-n2 Started container readiness-httpget-container
Warning Unhealthy 2m27s (x21 over 3m27s) kubelet, m3-n2 Readiness probe failed: HTTP probe failed with statuscode: 404
状态码为 404
我们进入容器创建一个 index1.html
[root@m1 yaml]# kubectl exec readiness-httpget-pod -it -- /bin/sh
# cd /usr/share/nginx/html
# echo '123' >> index1.html
# exit
再次查看pod,发现已经就绪
[root@m1 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget-pod 1/1 Running 0 6m5s
探针检测-存活检测-ExecAction命令探测
检测意思就是,启动后会创建一个文件 /tmp/live ,60秒后删除这个文件
然后存活检测是查看这个文件是否存在,存在即存活,然而60秒后因为删除了这个文件,所以会检测失败
[root@m1 yaml]# cat live-exec.yaml apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: default spec: containers: - name: liveness-exec-container image: docker.harbor.com/library/busybox:v1 imagePullPolicy: IfNotPresent command: ["/bin/sh", "-c", "touch /tmp/live ; sleep 60; rm -rf /tmp/live; sleep 3600"] livenessProbe: exec: command: ["test", "-e", "/tmp/live"] initialDelaySeconds: 1 periodSeconds: 3 [root@m1 yaml]# kubectl create -f live-exec.yaml启动后持续观察这个pod状态
会发现每隔一段时间就会重启一次,因为检测失败就会触发重启策略,重启后文件又重新创建,检测也就能成功,如此循环。
[root@m1 yaml]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
liveness-exec-pod 1/1 Running 5 8m14s
liveness-exec-pod 1/1 Running 6 9m54s
探针检测-存活检测-HTTPGetAction
检测访问index.html
timeoutSeconds: 10 超时时间10秒
[root@m1 yaml]# cat liveness-httpget-pod.yaml apiVersion: v1 kind: Pod metadata: name: liveness-httpget-pod namespace: default spec: containers: - name: liveness-httpget-container image: docker.harbor.com/library/nginx:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 livenessProbe: httpGet: port: http path: /index.html initialDelaySeconds: 1 periodSeconds: 3 timeoutSeconds: 10 [root@m1 yaml]# kubectl create -f liveness-httpget-pod.yaml删除 index.html文件
[root@m1 yaml]# kubectl exec liveness-httpget-pod -it -- /bin/sh
# cd /usr/share/nginx/html
# ls
50x.html index.html
# rm -rf index.html
# ls
50x.html
# exit
查看pod状态,发生重启,重启后容器会自动建立index.html所以会成功
[root@m1 yaml]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
liveness-httpget-pod 1/1 Running 0 4m44s
liveness-httpget-pod 1/1 Running 1 4m46s
探针检测-存活检测-TCPSocketAction
初始化后五秒开始检测 80 端口,超时时间 1 秒,检测失败重启三秒
# cat livenessProbe-tcp.yaml apiVersion: v1 kind: Pod metadata: name: probe-tcp spec: containers: - name: nginx image: docker.huarbor.com/library/nginx:v1 livenessProbe: initialDelaySeconds: 5 timeoutSeconds: 1 tcpSocket: port: 80 periodSeconds: 3 # kubectl create -f livenessProbe-tcp.yaml以上的检测方式可以合并到一个文件中进行多重条件检测。
启动、退出动作
定义一个pod启动时想要做什么,和退出时要做什么
apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: nginx lifecycle: postStart: exec: command: ['/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: exec: command: ["/usr/sbin/nginx", "-s", "quit"]