kubernetes学习之路(八)资源清单

    技术2022-07-10  91

    文章内容:

    资源类型介绍、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格式语法

    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 会发现是因为端口被占用

     

    Pod生命周

    initC:容器启动时的初始化工作,不止有一个initC,初始化后将丢弃initC,多个initC则必须是前一个initC完成后才执行下一个

    Main C:初始化后运行的主程序

    START:启动时执行一个指令

    STOP:停止时执行一个指令

    readiness:pod启动后假设pod中有个容器运行了一个程序,程序启动即running,而running的pod将可以让外部访问,但是程序                     有可能正在启动而无法提供给用户想要的返回结果,而readiness就是判断服务是否真正启动完成

    Liveness:pod中容器运行期间如果容器中进程出现假死,僵尸进程z,则Liveness可以通过预设检测Main C 判断该pod是否正常

     

    initC

    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

    init C 特殊说明

    pod启动过程中,第一个启动的不是init,而是pause如果init运行失败退出,将导致容器启动失败,它会根据pod的 restartPolicy 指定的策略进行重试。如果pod的 restartPolicy设置为Always,Init 容器失败时会使用 RestartPolicy 策略。在所有init容器没有成功之前,pod不会变成Ready状态,正在初始化的pod处于Pending状态如果pod重启,所有init容器必须重新执行更改init容器的image字段,等价于重启该podInit 容器具有应用容器的所有字段,除了 readinessProbe ,因为 init 容器无法定义不同于完成(completion)的就绪(readiness)之外的其它状态。这回在验证过程中强制执行在pod中的每个app和init容器名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误

     

    探针

    探针概念:

    探针是由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

    以上的检测方式可以合并到一个文件中进行多重条件检测。

     

    start、stop

    启动、退出动作

    定义一个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"]

     

    Processed: 0.010, SQL: 9