带你深入学习k8s–(三) pod 管理

  • Post author:
  • Post category:其他



一、简介


1、什么是pod


Pod是可以创建和管理Kubernetes计算的最小可部署单元,一个Pod代表着集群中运行的一个进程,每个pod都有一个唯一的ip。


一个pod类似一个豌豆英,包含一个或多个容器 (通常是docker) ,多个容器间共享IPC、Network和UTC namespace。

2、为什么要有pod

k8s作为集群调度需要解决的一些问题

1、容器建超亲密关系,容器建共享问题如何解决,互通的问题

2、数据间共享问题

每个容器都会有自己的namespace,容器是通过namespace来做的隔离,就是说容器间网络是不通的,有些容器之间我们希望是像localhost这样超亲密容器之间如何互访?

容器中放的就是我们的业务,假设有两个容器,他们的关系非常的亲密,他们之间的通信非常的频繁,而且还需要共享数据,这样就需要pod,在k8s中pod就解决了上述的两个问题,打通了这两个超亲密容器之间的通信和数据共享的问题,pod就给他提供了这样的环境,在同一个pod内的容器共享一个网络栈,pod还可以为pod内的容器提供一个相对持久化的存储也就是卷,不删除pod存储就是在的(pod是怎么来的在我们下载额镜像中reg.westos.org/k8s/pause是汇编语言写的,很小,大概几百kb,永远处于一种暂停的方式,会通过镜像为我们提供一个k8s的环境,这是谷歌为我们准备好的,他的设计理念就是为了解决打通容器间的网络和存储,提供一个相对持久化的存储)

二、pod的分类

Kubernetes 集群中的

Pod 主要有两种用法


  • 运行单个容器的 Pod

    。”每个 Pod 一个容器” 模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。


  • 运行多个协同工作的容器的 Pod

    。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的 “边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。

0、pod常用命令命令

kubectl get pod         ##获取pod

kubectl get ns         ##查看namespace

kubectl get pod -n kube-system         ##查看相应namespace对应的pod,不加namespace就自动选择默认的namespace

kubectl describe pod xxx          ##这条命令来查看pod详细信息

kubectl run -h         ##查看创建pod帮助

kubectl get pod -o wide         ##查看节点的具体信息


kubectl delete pod demo        ##删除pod

1、准备镜像


下载测试镜像


[root@k8s1 docker]# docker pull yakexi007/myapp:v1


[root@k8s1 docker]# docker pull yakexi007/myapp:v2

修改名称


[root@k8s1 docker]# docker tag yakexi007/myapp:v1 reg.westos.org/library/myapp:v1


[root@k8s1 docker]# docker tag yakexi007/myapp:v2 reg.westos.org/library/myapp:v2


上传harbor仓库


[root@k8s1 docker]# docker push reg.westos.org/library/myapp:v1


[root@k8s1 docker]# docker push reg.westos.org/library/myapp:v2


2、自主式pod


(生产不推荐,没有控制器维护的pod就是自主式pod,自主式pod没有自愈性)


[root@k8s2 ~]# kubectl run demo –image=myapp:v1


[root@k8s2 ~]# kubectl get pod -o wide


NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES


demo 1/1 Running 0 35s 10.244.2.2 k8s4 <none> <none>



查看pod详情


[root@k8s2 ~]# kubectl describe pod demo


Name: demo


Namespace: default


Priority: 0


Node: k8s4/192.168.56.174


Start Time: Mon, 09 Jan 2023 15:40:49 +0800


Labels: run=demo


Annotations: <none>


Status: Running


IP: 10.244.2.2


IPs:


IP: 10.244.2.2





删除pod


[root@k8s2 ~]# kubectl delete pod demo

3、控制器创建pod

这里我们先使用deployment控制器,控制器内容会在下一章节讲解

创建


kubectl create deployment myapp –image=myapp:v1

拉伸pod的副本数

kubectl scale deployment myapp –replicas 3


创建时直接设定好副本数:


kubectl create deployment myapp –image=myapp:v1 –replicas=3


控制器会自动维护pod副本数


[root@k8s2 ~]# kubectl get pod


NAME READY STATUS RESTARTS AGE


myapp-678fcbc488-gp6pr 1/1 Running 0 3s


myapp-678fcbc488-gqdgk 1/1 Running 0 3s


myapp-678fcbc488-qqkzx 1/1 Running 0 3s

获取当前

deployment控制器,有3个pod


[root@k8s2 ~]# kubectl get deployments.apps


NAME READY UP-TO-DATE AVAILABLE AGE


myapp 3/3         3                    3                 16s

删除其中一个pod,控制器会自动创建一个新的,只要不删除控制器,他会自动维护pod


[root@k8s2 ~]# kubectl delete pod myapp-678fcbc488-gp6pr


pod “myapp-678fcbc488-gp6pr” deleted

删除后查看还是3个副本数

在远程pod中执行命令

[root@k8s2 ~]# kubectl exec myapp-fcfbd4477-b2hkm — ls /usr/share/nginx/html

[root@k8s2 ~]# kubectl exec myapp-fcfbd4477-b2hkm — ls /usr/share/nginx/html

50x.html

index.html

4、扩容pod数量

扩容

[root@k8s2 ~]# kubectl  scale deployment myapp –replicas=6

[root@k8s2 ~]# kubectl get pod

NAME                     READY   STATUS    RESTARTS   AGE

myapp-678fcbc488-gqdgk   1/1     Running   0          11m

myapp-678fcbc488-jb5dw   1/1     Running   0          7s

myapp-678fcbc488-qqkzx   1/1     Running   0          11m

myapp-678fcbc488-tm55k   1/1     Running   0          7s

myapp-678fcbc488-v7ftf   1/1     Running   0          11m

myapp-678fcbc488-wrjt7   1/1     Running   0          7s

缩容

[root@k8s2 ~]# kubectl  scale deployment myapp –replicas=3

deployment.apps/myapp scaled

[root@k8s2 ~]# kubectl get pod

NAME                     READY   STATUS    RESTARTS   AGE

myapp-678fcbc488-gqdgk   1/1     Running   0          12m

myapp-678fcbc488-qqkzx   1/1     Running   0          12m

myapp-678fcbc488-v7ftf   1/1     Running   0          11m

5、通过service暴露pod(负载均衡,自动发起)

指定暴露端口和目标端口,目标端口相当于做了一个映射

[root@k8s2 ~]# kubectl expose deployment myapp –port=80 –target-port=80



查看svc详情

describe查看命令详情

有3个Endpoints,这个就是三个pod的ip地址


[root@k8s2 ~]# kubectl describe  svc myapp

Name:              myapp

Namespace:         default

Labels:            app=myapp

Annotations:       <none>

Selector:          app=myapp

Type:              ClusterIP

IP Family Policy:  SingleStack

IP Families:       IPv4

IP:                10.106.225.101

IPs:               10.106.225.101

Port:              <unset>  80/TCP

TargetPort:        80/TCP

Endpoints:         10.244.1.2:80,10.244.1.3:80,10.244.2.4:80

Session Affinity:  None

Events:            <none>


访问时默认是iptable的负载均衡算法,不是特别的均匀但是会提供一个健康的


[root@k8s2 ~]# curl 10.106.225.101


Hello MyApp | Version: v1 | <a href=”hostname.html”>Pod Name</a>

[root@k8s2 ~]# curl 10.106.225.101/hostname.html

myapp-678fcbc488-v7ftf


service自动发现pod扩容与缩容,自动更新endpoints,实现对应用的负载均衡


service默认使用clusterip类型,只能在集群中访问


nodeport类型,可以在集群外部访问


[root@k8s2 ~]# kubectl edit svc myapp


[root@k8s2 ~]# kubectl get svc


NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE


kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 120m


myapp


NodePort


10.106.225.101 <none> 80:


30280


/TCP 23m

6、更新应用版本

更新镜像版本


[root@k8s2 ~]# kubectl set image deployment/myapp myapp=myapp:v2


[root@k8s1 docker]# curl 192.168.18.14:30840



查看应用历史版本


[root@k8s2 ~]# kubectl rollout history deployment myapp

回滚


[root@k8s2 ~]# kubectl rollout undo deployment myapp –to-revision=1


[root@k8s2 ~]# curl 192.168.18.14:30840


删除应用


[root@k8s2 ~]# kubectl delete deployments.apps myapp


[root@k8s2 ~]# kubectl delete svc myapp


[root@k8s2 ~]# kubectl get pod


以上操作我们都是在默认的namespace中进行,在k8s中通过namespace进行逻辑隔离,只要不指定就是在default中


[root@k8s2 ~]# kubectl get ns

三、编写yaml文件

在实际中我们更常用yaml文件的方式创建pod



资源清单



获取帮助

[root@k8s2 pod]# kubectl explain pod.spec.containers

获取yaml模板

[root@k8s2 pod]# kubectl run demo –image nginx –dry-run=client  -o yaml > pod.yaml

编写yaml文件

[root@k8s2 pod]# vim pod.yaml

apiVersion: v1

kind: Pod

metadata:

labels:

run: demo

name: demo

spec:

containers:

– image: nginx

name: demo

imagePullPolicy: IfNotPresent


imagePullPolicy: IfNotPresent


镜像拉取策略,有3种,always总是拉取、Never不拉取、IfNotPresent如果本地有就不拉取镜像,1.25版本默认就是 IfNotPresent


创建pod


[root@k8s2 pod]# kubectl create -f pod.yaml


查看详情


[root@k8s2 pod]# kubectl get pod -o wide


[root@k8s2 pod]# kubectl describe pod demo


[root@k8s2 pod]# kubectl get pod demo -o yaml


示例

[root@k8s2 pod]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: demo
  name: demo
spec:
  hostNetwork: true
  nodeSelector:				#nodeSelector调动策略,是以标签的形式写的 kubectl getnode --show-labels
    kubernetes.io/hostname: k8s3
  containers:
  - image: myapp:v1		
    name: demo
    imagePullPolicy: IfNotPresent
    #ports:							#端口映射
    #- name: http
    #  containerPort: 80
    #  hostPort: 80
    #resources:						#资源限制
    #  limits:
    #    cpu: 1
    #    memory: 200Mi
    #  requests:
    #    cpu: 0.5
    #    memory: 100Mi

  #- name: demo2					#定义多个容器
  #  image: busyboxplus
  #  command: ["/bin/sh", "-c", "sleep 3600"]


资源敏感型业务:


resources


这里会有一个资源敏感型业务,最小requests和最大上限limits是一样的,并且cpu和内存都需要设置。如果不是资源敏感型业务,在这个pod上如果资源不够时会把一些资源要求比较宽容的pod踢出去,从而保证资源敏感型pod正常运行。(Mi是1024换算,M是1000换算),在k8s中QoS Class不可以直接赋值,必须要通过resources来赋值

k8s根据Pod中Containers Resource的request和limit的值来定义Pod的QoS Class。其中,指定容器request,代表系统确保能够提供的资源下限值。指定容器limit,代表系统允许提供的资源上限值。

Pods需要保证长期稳定运行需要设定“确保运行的最少资源”,然而pod能够使用的资源经常是不能确保的。

通常,Kubernetes通过设置request和limit的值来指定超卖比例,进而提升资源利用率。K8S的调度基于request,而不是limit。Borg通过使用“non-guranteed”的资源,提升了20%的资源利用率。

在一个资源被“超卖”的系统(总limits > machine capacity),容器在资源被耗尽的情况下会被kill。理想情况是那些“不重要”的容器先被kill。

对于每一种Resource都可以将容器分为3中QoS Classes:Guaranteed敏感型, Burstable次敏感型, and Best-Effort宽容型,它们的QoS级别依次递减。K8S底层实际上是通过 limit和request值来实现不同等级QoS的划分。

Guaranteed 如果Pod中所有Container的所有Resource的limit和request都相等且不为0,则这个Pod的QoS Class就是Guaranteed。

注意,如果一个容器只指明了limit,而未指明request,则表明request的值等于limit的值。

Best-Effort 如果Pod中所有容器的所有Resource的request和limit都没有赋值,则这个Pod的QoS Class就是Best-Effort

Burstable 除了符合Guaranteed和Best-Effort的场景,其他场景的Pod QoS Class都属于Burstable。 当limit值未指定时,其有效值其实是对应Node Resource的Capacity

应用


[root@k8s2 pod]# kubectl apply -f


pod.yml

删除


[root@k8s2 pod]# kubectl delete -f pod.yml

四、Pod生命周期

官方文档:



Pod 的生命周期 | Kubernetes



https://v1-25.docs.kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/



1、init容器


为什么要用初始化容器,Init 容器能做什么?


Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。


应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。


Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。由于Init 容器必须在应用容器启动之前运行完成,因此 lnit 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。

案例:需要service解析,没有解析init容器启动失败,主容器不会运行,

初始化容器运行成功后主容器才能运行


[root@k8s2 pod]# vim init-pod.yaml


apiVersion: v1


kind: Pod


metadata:


name: myapp-pod


labels:


app.kubernetes.io/name: MyApp


spec:


containers:


– name: myapp-container


image: busybox


command: [‘sh’, ‘-c’, ‘echo The app is running! && sleep 3600’]


initContainers:


– name: init-myservice


image: busybox


command: [‘sh’, ‘-c’, “until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done”]


[root@k8s2 pod]# kubectl apply -f init-pod.yaml


[root@k8s2 pod]# kubectl get pod


NAME READY STATUS RESTARTS AGE


myapp-pod 0/1 Init:0/1 0 41s


在init容器没有成功运行之前,主容器不会被运行


添加svc定义


[root@k8s2 pod]# vim myservice.yaml




apiVersion: v1


kind: Service


metadata:


name: myservice


spec:


ports:


– protocol: TCP


port: 80


targetPort: 80


[root@k8s2 pod]# kubectl apply -f myservice.yaml


[root@k8s2 pod]# kubectl get svc


NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE


kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d1h


myservice ClusterIP 10.103.221.131 <none> 80/TCP 2s


svc解析成功后,init容器退出,主容器运行


[root@k8s2 pod]# yum install -y bind-utils


[root@k8s2 pod]# dig -t A myservice.default.svc.cluster.local. @10.96.0.10



[root@k8s2 pod]# kubectl get pod


NAME READY STATUS RESTARTS AGE


myapp-pod 1/1 Running 0 3m35s


回收资源


[root@k8s2 pod]# kubectl delete -f


init-pod.yml


[root@k8s2 pod]# kubectl delete -f myservice.yml

2、探针



共三种探针:分别是存活探针,就绪探针,启动探针,前两个使用居多。


1、存活探针

[root@k8s2 pod]# vim liveness-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: nginx
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 3	#容器启动多少秒后开始检测
      periodSeconds: 3	#检测频率,间隔
      timeoutSeconds: 1	#超时时间

[root@k8s2 pod]# kubectl apply -f liveness-pod.yaml

在存活探针检测失败导致容器不断被重启

[root@k8s2 pod]# kubectl get pod -w

NAME            READY   STATUS    RESTARTS   AGE

liveness-http   1/1     Running   0          5s

liveness-http   1/1     Running   1 (0s ago)   13s

liveness-http   1/1     Running   2 (0s ago)   22s

[root@k8s2 pod]# kubectl describe  pod liveness-http


释放资源


[root@k8s2 pod]# kubectl delete -f liveness-pod.yaml

2、就绪探针

[root@k8s2 pod]# vim liveness-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: nginx
    livenessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 3
    readinessProbe:
      httpGet:
        path: /test.html
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5

[root@k8s2 pod]# kubectl apply -f liveness-pod.yaml


就绪探针失败导致容器一直未就绪

[root@k8s2 pod]# kubectl get pod

NAME            READY   STATUS    RESTARTS   AGE

liveness-http   0/1     Running   0          34s

查看详情


[root@k8s2 pod]# kubectl describe pod liveness-http


创建测试页面

[root@k8s2 pod]# kubectl exec  liveness-http — touch /usr/share/nginx/html/test.html

就绪探针成功

[root@k8s2 pod]# kubectl get pod

NAME            READY   STATUS    RESTARTS   AGE

liveness-http   1/1     Running   0          100s



创建svc


[root@k8s2 pod]# kubectl expose pod liveness-http –port 80 –target-port 80


svc通过就绪探针判断这个应用是否正常,能否上线


就绪容器自动上线


[root@k8s2 pod]# kubectl describe svc liveness-http


Name: liveness-http


Namespace: default


Labels: test=liveness


Annotations: <none>


Selector: test=liveness


Type: ClusterIP


IP Family Policy: SingleStack


IP Families: IPv4


IP: 10.108.21.178


IPs: 10.108.21.178


Port: <unset> 80/TCP


TargetPort: 80/TCP


Endpoints:


10.244.1.33:80


Session Affinity: None


Events: <none>



删除测试页面


[root@k8s2 pod]# kubectl exec liveness-http — rm /usr/share/nginx/html/test.html


就绪探针失败,容器未就绪,svc发现不了服务,就没有Endpoints


[root@k8s2 pod]# kubectl get pod


NAME READY STATUS RESTARTS AGE


liveness-http 0/1 Running 0 6m15s


在svc中容器自动下线


[root@k8s2 pod]# kubectl describe svc liveness-http


Name: liveness-http


Namespace: default


Labels: test=liveness


Annotations: <none>


Selector: test=liveness


Type: ClusterIP


IP Family Policy: SingleStack


IP Families: IPv4


IP: 10.108.21.178


IPs: 10.108.21.178


Port: <unset> 80/TCP


TargetPort: 80/TCP


Endpoints:


Session Affinity: None


Events: <none>


回收

[root@k8s2 pod]# kubectl delete  -f liveness-pod.yaml

总结:


存活探针如果启动失败,他会不断的重启这个容器,让他达到一个自愈的功能,就绪探针和


svc自动发现相关联,就绪我们就可以认为这个业务可以正常对外发布,正常才让他出现在svc的负载均衡列表中,就相当于健康检测,这是k8s对我们应用上线和下线的一个优雅操作。



版权声明:本文为weixin_43975532原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。