第9节 Pod


❤️💕💕新时代拥抱云原生,云原生具有环境统一、按需付费、即开即用、稳定性强特点。Myblog:http://nsddd.topopen in new window


[TOC]

理解Pod

什么是pod?

img

pod是运行中的一组容器,pod是kubernetes中应用的最小单位。

什么是CRI?(container runtime interface)

或许你可以理解是docker,CRI就是容器运行时的环境。我们开发的应用就能以容器化的方式运行~

提示

💡 那么k8s为了管理方便,又封装了pod,所以说pod是容器运行的最小单位~

  • 每一个容器封装成一个pod
  • 每个pod可能有一个或者多个容器,但是也称之为一组容器

pod是可以有多个容器的,而且组成原子,这个是和容器的区别~

⚡ 描述某一个pod是如何运行的

kubectl describe pod my-nginx-7fb96c846b-m9rjp
展开查看详情💡
[root@k8s-master03 ~]# kubectl get pod
NAME                        READY   STATUS    RESTARTS      AGE
my-nginx-7fb96c846b-cnhbz   1/1     Running   2 (92m ago)   38h
my-nginx-7fb96c846b-g55km   1/1     Running   2 (92m ago)   38h
my-nginx-7fb96c846b-m9rjp   1/1     Running   2 (92m ago)   38h
[root@k8s-master03 ~]# kubectl describe pod my-nginx-7fb96c846b-m9rjp
Name:             my-nginx-7fb96c846b-m9rjp
Namespace:        default
Priority:         0
Service Account:  default
Node:             k8s-master03/192.168.0.4
Start Time:       Thu, 20 Oct 2022 22:05:22 +0800
Labels:           app=nginx
                  pod-template-hash=7fb96c846b
Annotations:      cni.projectcalico.org/containerID: 66626e89ebcb580eeef3f2e75d7d860fe14ee213458642f7b25a860e164ea9a3
                  cni.projectcalico.org/podIP: 100.66.195.18/32
                  cni.projectcalico.org/podIPs: 100.66.195.18/32
Status:           Running
IP:               100.66.195.18
IPs:
  IP:           100.66.195.18
Controlled By:  ReplicaSet/my-nginx-7fb96c846b
Containers:
  nginx:
    Container ID:   containerd://85c401a1bca6531519ad09b539ee57bb2b508b370d71053926a1df0b5421597e
    Image:          nginx:1.14.2
    Image ID:       docker.io/library/nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 22 Oct 2022 11:27:59 +0800
    Last State:     Terminated
      Reason:       Unknown
      Exit Code:    255
      Started:      Fri, 21 Oct 2022 11:10:13 +0800
      Finished:     Sat, 22 Oct 2022 11:27:01 +0800
    Ready:          True
    Restart Count:  2
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-x77br (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-x77br:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:                      <none>

我们只要看Events就好了~

可以查看状态和原因,可以去排查事故原因

Pod 状态

状态描述原因
PendingPod已被Kubernetes系统接受,但尚未被调度到节点上运行Pod正在等待调度到节点上运行。可能是由于节点资源不足,或者Pod定义中的控制器正在等待其他Pod先启动。
RunningPod正在正常运行Pod已被调度到节点上,并且容器正在运行。
SucceededPod中的所有容器都已成功运行并已退出所有容器都已成功完成,并且已达到其预期的状态。
FailedPod中的所有容器都已退出,并且至少有一个容器因错误而退出所有容器都已退出,并且至少有一个容器已失败。
Unknown无法确定Pod的状态Kubernetes无法确定Pod的状态。可能是由于与Pod相关的节点(node)失去联系。

一般出现 Failed 的原因都是由于 容器运行异常退出或者是被系统终止掉了。

Pod 的重启策略

在 Kubernetes 中,可以为 pod 设置三种不同的重启策略:

  • Always:无论其中的容器退出代码如何,pod 都将始终重新启动。
  • OnFailure:仅当其中一个或多个容器以非零退出代码退出时,pod 才会重新启动。
  • Never:即使其中一个或多个容器以非零退出代码退出,pod 也永远不会重新启动。

要为 pod 设置重启策略,需要在 pod 的 YAML 文件中指定 spec.restartPolicy 字段。例如,要将重启策略设置为 OnFailure,可以使用以下 YAML:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  restartPolicy: OnFailure
  containers:
  - name: my-container
    image: my-image

Pod 中健康检查

在 Kubernetes 中,可以为 Pod 配置以下三种类型的健康检查:

  • livenessProbe:检查容器是否正在运行。如果容器没有运行,则 kubelet 将根据 Pod 的重启策略重启容器。
  • readinessProbe:检查容器是否已准备好接收流量。如果容器没有准备好,则 kube-proxy 将在其所在的节点上从 Service 的 Endpoint 中删除它。
  • startupProbe:检查容器是否已经完成了启动过程。如果容器已经完成了启动过程,则 kubelet 将开始进行 livenessProbe 和 readinessProbe 检查。

要为容器配置这些检查,需要在 Pod 的 YAML 文件中为容器指定 livenessProbereadinessProbestartupProbe 字段。例如,要为容器 my-container 配置 livenessProbe 和 readinessProbe,可以使用以下 YAML:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: my-image
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20
    readinessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: X-Custom-Header
          value: Awesome
      initialDelaySeconds: 5
      periodSeconds: 10

在平常的使用中,建议对全部的服务同时设置 readiness 和 liveness 的健康检查。

删除pod

由于k8s的概念很多,删除需要指定概念

  • 指定命名空间,不指定是默认
  • 指定删除pod
kubectl delete pod mypodName -n xxxNamespace

管理对象的两种方式

命令行指令

使用 kubectl 命令来创建和管理 kubernetes 对象

简单、高效快速但是功能有限,操作不容易追溯,多用于开发和调试。

声明式配置

kubernetes 使用 yaml 文件来描述 kubernetes 对象

声明式配置就好比申请表,学习难度大而且配置麻烦

好处是操作留痕迹,适合操作复杂的对象,多用于生产

yaml 语法介绍

  • https://yaml.org/

YAML 语言创建于 2001 年,比 XML 晚了三年。XML 你应该知道吧,它是一种类似 HTML 的标签式语言,有很多繁文缛节。而 YAML 虽然在名字上模仿了 XML,但实质上与 XML 完全不同,更适合人类阅读,计算机解析起来也很容易。

YAML 是 JSON 的 超集,支持整数、浮点数、布尔、字符串、数组和对象等数据类型。也就是说,任何合法的 JSON 文档也都是 YAML 文档,如果你了解 JSON,那么学习 YAML 会容易很多。

yaml 语法

  • 缩进代表上下级关系
  • 缩进时使用空格,不要使用tab,通常使用2个空格
  • 使用双引号,不要使用单引号
  • : 键值对的分隔符,前面不要有空格,后面要有空格
  • - 数组的分隔符,前后都要有空格
  • # 注释,后面要有空格
  • | 多行文本,后面要有空格,后面可以有换行
  • > 多行文本,后面要有空格
  • --- yaml文件的分隔符,前后都要有空格

如何编写 yaml

第一个技巧其实前面已经说过了,就是 kubectl api-resources 命令,它会显示出资源对象相应的 API 版本和类型,比如 Pod 的版本是“v1”,Ingress 的版本是“networking.k8s.io/v1”,照着它写绝对不会错。

kubectl api-resources

第二个技巧,是命令 kubectl explain,它相当于是 Kubernetes 自带的 API 文档,会给出对象字段的详细说明,这样我们就不必去网上查找了。比如想要看 Pod 里的字段该怎么写,就可以这样:

kubectl explain pod
kubectl explain pod.metadata
kubectl explain pod.spec
kubectl explain pod.spec.containers

不过我们还可以让 kubectl 为我们“代劳”,生成一份“文档样板”,免去我们打字和对齐格式的工作。这第三个技巧就是 kubectl 的两个特殊参数 --dry-run=client-o yaml,前者是空运行,后者是生成 YAML 格式,结合起来使用就会让 kubectl 不会有实际的创建动作,而只生成 YAML 文件。

例如,想要生成一个 Pod 的 YAML 样板示例,可以在 kubectl run 后面加上这两个参数:

kubectl run ngx --image=nginx:alpine --dry-run=client -o yaml

就会生成一个绝对正确的 YAML 文件:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: ngx
  name: ngx
spec:
  containers:
  - image: nginx:alpine
    name: ngx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

接下来你要做的,就是查阅对象的说明文档,添加或者删除字段来定制这个 YAML 了。

这个小技巧还可以再进化一下,把这段参数定义成 Shell 变量(名字任意,比如$do/$go,这里用的是$out),用起来会更省事,比如:

export out="--dry-run=client -o yaml"
kubectl run ngx --image=nginx:alpine $out

离线任务

我们在后面会知道 Kubernetes 中的离线任务意味着什么。

上次课讲 Pod 的时候我们运行了两个 Pod:Nginx 和 busybox,它们分别代表了 Kubernetes 里的两大类业务。一类是像 Nginx 这样长时间运行的“在线业务”,另一类是像 busybox 这样短时间运行的“离线业务”。

“在线业务”类型的应用有很多,比如 Nginx、Node.js、MySQL、Redis 等等,一旦运行起来基本上不会停,也就是永远在线。

而“离线业务”类型的应用也并不少见,它们一般不直接服务于外部用户,只对内部用户有意义,比如日志分析、数据建模、视频转码等等,虽然计算量很大,但只会运行一段时间。“离线业务”的特点是必定会退出,不会无期限地运行下去,所以它的调度策略也就与“在线业务”存在很大的不同,需要考虑运行超时、状态检查、失败重试、获取计算结果等管理事项。

“离线业务”也可以分为两种。一种是“临时任务”,跑完就完事了,下次有需求了说一声再重新安排;另一种是“定时任务”,可以按时按点周期运行,不需要过多干预。

对应到 Kubernetes 里,“临时任务”就是 API 对象 Job,“定时任务”就是 API 对象 CronJob,使用这两个对象你就能够在 Kubernetes 里调度管理任意的离线业务了。

如何使用 YAML 描述 Job

比如用 busybox 创建一个“echo-job”,命令就是这样的:

export out="--dry-run=client -o yaml"              # 定义Shell变量
kubectl create job echo-job --image=busybox $out

会生成一个基本的 YAML 文件,保存之后做点修改,就有了一个 Job 对象:

apiVersion: batch/v1
kind: Job
metadata:
  name: echo-job

spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
      - image: busybox
        name: echo-job
        imagePullPolicy: IfNotPresent
        command: ["/bin/echo"]
        args: ["hello", "world"]

你会注意到 Job 的描述与 Pod 很像,但又有些不一样,主要的区别就在“spec”字段里,多了一个 template 字段,然后又是一个“spec”,显得有点怪。

如果你理解了刚才说的面向对象设计思想,就会明白这种做法的道理。它其实就是在 Job 对象里应用了组合模式,template 字段定义了一个“应用模板”,里面嵌入了一个 Pod,这样 Job 就可以从这个模板来创建出 Pod。

而这个 Pod 因为受 Job 的管理控制,不直接和 apiserver 打交道,也就没必要重复 apiVersion 等“头字段”,只需要定义好关键的 spec,描述清楚容器相关的信息就可以了,可以说是一个“无头”的 Pod 对象。

为了辅助你理解,我把 Job 对象重新组织了一下,用不同的颜色来区分字段,这样你就能够很容易看出来,其实这个“echo-job”里并没有太多额外的功能,只是把 Pod 做了个简单的包装:

image-20230313231329255

总的来说,这里的 Pod 工作非常简单,在 containers 里写好名字和镜像,command 执行 /bin/echo,输出“hello world”。

不过,因为 Job 业务的特殊性,所以我们还要在 spec 里多加一个字段 restartPolicy,确定 Pod 运行失败时的策略,OnFailure 是失败原地重启容器,而 Never 则是不重启容器,让 Job 去重新调度生成一个新的 Pod。

如何在 Kubernetes 里操作 Job

现在让我们来创建 Job 对象,运行这个简单的离线作业,用的命令还是 kubectl apply:

kubectl apply -f job.yml

查看:

kubectl get job
kubectl get pod
NAME       COMPLETIONS   DURATION   AGE
echo-job   0/1           5s         5s
NAME             READY   STATUS    RESTARTS   AGE
echo-job-tl75m   0/1     Pending   0          5skubectl get job
kubectl get pod
NAME       COMPLETIONS   DURATION   AGE
echo-job   0/1           5s         5s
NAME             READY   STATUS    RESTARTS   AGE
echo-job-tl75m   0/1     Pending   0          5s

可以看到,因为 Pod 被 Job 管理,它就不会反复重启报错了,而是会显示为 Completed 表示任务完成,而 Job 里也会列出运行成功的作业数量,这里只有一个作业,所以就是 1/1。

你还可以看到,Pod 被自动关联了一个名字,用的是 Job 的名字(echo-job)再加上一个随机字符串(pb5gh),这当然也是 Job 管理的“功劳”,免去了我们手工定义的麻烦,这样我们就可以使用命令 kubectl logs 来获取 Pod 的运行结果:

配置对象

在创建 Kubernetes 对象所对应的 yaml 文件中,需要配置的字段:

  • apiVersion :Kubernetes API 版本
  • Kind :对象类别,例如 PodDeployment
  • metadata :描述对象的元数据,包括一个 name 字符串、UID 和 可选的namespace
  • spec :对象的配置

配置文件创建pod

我们或许可以用配置文件的方式去创建一个pod~

[root@k8s-master01 ~]# vim pod.yaml 
[root@k8s-master01 ~]# kubectl apply -f pod.yaml 

yaml创建pod格式

apiVersion: v1
kind: Pod  # 资源类型
metadata:  
  labels:
    run: myapp
  name: myapp  # pod名称
spec: # pod详细配置信息
  containers: # 启动一个容器
  - image: nginx # 启动nginx
    name: mynginx
  - image: tomcat:8.5.68
    name: mytomcat
  - image: redis
    name: myredis

image-20221022153945150

可能会出现pod状态处于ContainerCreating的情况,常见的原因之一是镜像拉取失败。

💡容器的创建详情查看如下:

kubectl describe pod mynginx
⚡ 展开查看详情
[root@k8s-master01 ~]# kubectl describe pod mynginx
Name:             mynginx
Namespace:        default
Priority:         0
Service Account:  default
Node:             k8s-master03/192.168.0.4
Start Time:       Sat, 22 Oct 2022 13:20:17 +0800
Labels:           run=mynginx
Annotations:      cni.projectcalico.org/containerID: 9fc6db4dd24c4816b28be43c1f2907c89adea8fadb36fb49844fea42142671e7
                  cni.projectcalico.org/podIP: 100.66.195.25/32
                  cni.projectcalico.org/podIPs: 100.66.195.25/32
Status:           Running
IP:               100.66.195.25
IPs:
  IP:  100.66.195.25
Containers:
  mynginx:
    Container ID:   containerd://69b25d59d551f94e8f7cc659ef3b740765e23673b60f45de7353cfbc13d52420
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:5ffb682b98b0362b66754387e86b0cd31a5cb7123e49e7f6f6617690900d20b2
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sat, 22 Oct 2022 13:21:13 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-m6rqn (ro)
  myredis:
    Container ID:   containerd://e72e35e2f7dda8d6108a89e98c41da32b4678eab31cf26c8406eeaee5e3ecc3c
    Image:          redis
    Image ID:       docker.io/library/redis@sha256:c95835a74c37b3a784fb55f7b2c211bd20c650d5e55dae422c3caa9c01eb39fa
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sat, 22 Oct 2022 13:21:47 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-m6rqn (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-m6rqn:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  113s  default-scheduler  Successfully assigned default/mynginx to k8s-master03
  Normal  Pulling    112s  kubelet            Pulling image "nginx"
  Normal  Pulled     58s   kubelet            Successfully pulled image "nginx" in 54.707721222s
  Normal  Created    57s   kubelet            Created container mynginx
  Normal  Started    57s   kubelet            Started container mynginx
  Normal  Pulling    57s   kubelet            Pulling image "redis"
  Normal  Pulled     23s   kubelet            Successfully pulled image "redis" in 33.819467112s
  Normal  Created    23s   kubelet            Created container myredis
  Normal  Started    23s   kubelet            Started container myredis

image-20221022132504701

可视化界面创建pod

注意

这个板块待补充~ 欢迎pr

pod日志

好像只有pod有日志把?

和docker的日志一样用法

我们查看pod日志:

kubectl logs mynginx

image-20221022133031267

⚡ 可以加上 -f 追踪式日志

kubectl logs -f  mynginx

image-20221022133159587

pod - IP

⚡ 每个pod – k8s都会分配一个ip,使用下面命令查看:

kubectl get pod -owide

image-20221022150442624

进入pod并修改pod

🗓️ 回忆我们docker修改容器内部

docker exec -it idName #/bin/bash

使用K8s进入pod命令:

和docker命令大致一样,注意后面有

kubectl exec -it mynginx -- /bin/bash

image-20221022151001187

可视化界面

可以直接进去k8s的可视化界面进行修改~

多容器pod细节

提醒⚠️

Kubernetes中部署应用时,都是以pod进行调度的,它们基本上是单个容器的包装或房子。从某种意义上说,容器的容器。 pod是一个逻辑包装实体,用于在K8s集群上执行容器。可以把每个pod想象成一个透明的包装,为容器提供一个插槽。podKubernetes最小的可部署单位。pod是一组一个或多个容器,具有共享的存储/网络资源,以及如何运行容器的规范。因此,最简单地说,pod是一个容器如何在Kubernetes中“用起来”的机制。

  • pod是k8s的最小单元,容器包含在pod中,一个pod中有一个pause容器和若干个业务容器,而容器是单独的一个容器,简而言之,pod是一组容器的集合。

  • pod相当于逻辑主机,每个pod都有自己的ip地址

  • pod内的容器共享相同的ip和端口

  • 默认情况下,每个容器的文件系统与其他容器完全隔离

  • pod是一组容器,一个pod也是可以部署两个甚至是多个容器

更多命令

更多命令:

# 查看全部
kubectl get all

# 重新部署
kubectl rollout restart deployment test-k8s

# 命令修改镜像,--record 表示把这个命令记录到操作历史中
kubectl set image deployment test-k8s test-k8s=ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v2-with-error --record

# 暂停运行,暂停后,对 deployment 的修改不会立刻生效,恢复后才应用设置
kubectl rollout pause deployment test-k8s

# 恢复
kubectl rollout resume deployment test-k8s

# 输出到文件
kubectl get deployment test-k8s -o yaml >> app2.yaml

# 删除全部资源
kubectl delete all --all
遗留问题:
  • 每次只能访问一个 pod,没有负载均衡自动转发到不同 pod
  • 访问还需要端口转发
  • Pod 重创后 IP 变了,名字也变了

END 链接