Kubernetes进阶 -- pod的生命周期

pod概况

Pod 是 Kubernetes 应用程序的基本执行单元,即它是 Kubernetes 对象模型中创建或部署的最小和最简单的单元。Pod 表示在 集群 上运行的进程。

Pod 封装了应用程序容器(或者在某些情况下封装多个容器)、存储资源、唯一网络 IP 以及控制容器应该如何运行的选项。

Kubernetes 集群中的 Pod 可被用于以下两个主要用途:

运行单个容器的 Pod。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例;在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众,而另一个单独的“挂斗”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。

Pod 为其组成容器提供了两种共享资源:网络 和 存储。
网络

每个 Pod 分配一个唯一的 IP 地址。 Pod 中的每个容器共享网络命名空间,包括 IP 地址和网络端口。 Pod 内的容器 可以使用 localhost 互相通信。 当 Pod 中的容器与 Pod 之外 的实体通信时,它们必须协调如何使用共享的网络资源(例如端口)。
存储

一个 Pod 可以指定一组共享存储卷 。 Pod 中的所有容器都可以访问共享卷,允许这些容器共享数据。 卷还允许 Pod 中的持久数据保留下来,以防其中的容器需要重新启动。

  • 重启策略
    • PodSpec 中有一个 restartPolicy 字段,可能的值为 Always、OnFailure 和Never。默认为 Always。
  • Pod 的生命
    • 一般Pod 不会消失,直到人为销毁他们,这可能是一个人或控制器。
    • 建议创建适当的控制器来创建 Pod,而不是直接自己创建 Pod。因为单独的
      Pod 在机器故障的情况下没有办法自动复原,而控制器却可以。
  • 三种可用的控制器:
    • 使用 Job 运行预期会终止的 Pod,例如批量计算。Job 仅适用于重启策略
      为 OnFailure 或 Never 的 Pod。
    • 对预期不会终止的 Pod 使用 ReplicationController、ReplicaSet 和
      Deployment ,例如 Web 服务器。 ReplicationController 仅适用于具
      有 restartPolicy 为 Always 的 Pod。
    • 提供特定于机器的系统服务,使用 DaemonSet 为每台机器运行一个 Pod 。

pod生命周期

在k8s的每个结点上都有这样一个镜像:

[root@server4 ~]# docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE

reg.caoaoyuan.org/library/pause        3.2                 80d28bedfe5d        4 months ago        683kB
//这是k8s为pod准备的跟镜像,每个pod通过它来启动,它为pod准备了启动的环境(网路,卷)。

Kubernetes进阶 -- pod的生命周期_第1张图片
pod在运行容器之前,会先运行一个或多个init初始化容器,他们一次进行,他们运行完,应用容器才会进行启动。

  • Init容器与普通的容器非常像,除了如下两点:
    • 它们总是运行到完成。
    • Init 容器不支持 Readiness,因为它们必须在 Pod 就绪之前运行完成。
    • 每个 Init 容器必须运行成功,下一个才能够运行。
  • 如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容
    器成功为止。然而,如果 Pod 对应的 restartPolicy 值为 Never,它不会重新
    启动。

初始化容器结束后,普通的容器(main container)开始运行,普通容器的启动和停止通过探针来检测,探针有存活探针和就绪探针,不指定的话默认为成功,liveness探针用来进行存活检测,看容器是否正常的运行着。readness用来检测容器服务是否就绪.

[root@server2 manifest]# kubectl get pod -n kube-system 
NAME                              READY   STATUS    RESTARTS   AGE
coredns-5fd54d7f56-k5jb9          1/1     Running   3          7d8h
coredns-5fd54d7f56-xb5m4          1/1     Running   4          7d19h
etcd-server2                      1/1     Running   7          7d23h

存活探针检测成功才会时running的状态,就绪检测通过才会时ready的状态,用户才可以访问,才可以有流量进来。

init容器

更多详情参考:https://kubernetes.io/zh/docs/concepts/workloads/pods/init-containers/

  • Init 容器能做什么?
    • Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化
      代码。
    • Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性
      降低。
    • 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个
      单独的应用镜像。
    • Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器
      可具有访问 Secrets 的权限,而应用容器不能够访问。
    • 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一
      种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前
      置条件满足,Pod内的所有的应用容器会并行启动。
[root@server2 manifest]# vim init.yml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  initContainers:
  - name: init-myservice
    image: busybox:latest
    command: ['sh', '-c', "until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:latest
    command: ['sh', '-c', "until nslookup mydb.default.svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
  containers:
  - name: myapp-container
    image: busybox:latest
~                                                                                                                      

“until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done”]
的意思是,执行nslookup指令解析myservice.default.svc.cluster.local这个地址,如果解析成功则继续,不成功则一直处于初始化状态,循环do里面的内容。

[root@server2 manifest]# kubectl get pod -w
NAME        READY   STATUS     RESTARTS   AGE
myapp-pod   0/2     Init:0/1   0          5s

//正在进行初始化容器,但是卡在这里了,一直在进行init


Init Containers:
  init-myservice:
    Container ID:  docker://3b83c7896675f49dab5b8c103e52b5f5e4b62bf6ce6d3659267267ebddc0978e
    Image:         busyboxplus
    Image ID:      docker-pullable://busyboxplus@sha256:9d1c242c1fd588a1b8ec4461d33a9ba08071f0cc5bb2d50d4ca49e430014ab06
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done
    State:          Running			//一直在运行
      Started:      Fri, 26 Jun 2020 18:56:21 +0800
    Ready:          False

但是当前这个容器时无法运行的,因为没有创建myservice这个服务,不能完成解析。
注意要关闭外网,不然会通过主机的dns解析出去。

为两个初始化容器创建服务:

[root@server2 manifest]# vim service.yml
kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
  name: mydb
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9377
[root@server2 manifest]# kubectl apply -f service.yml 
service/myservice created
service/mydb created
[root@server2 manifest]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   8d
mydb         ClusterIP   10.100.111.80   <none>        80/TCP    7s
myservice    ClusterIP   10.107.87.62    <none>        80/TCP    7s
[root@server2 manifest]# kubectl get pod -w		//再次查看
NAME        READY   STATUS     RESTARTS   AGE
myapp-pod   0/1     Init:1/2   0          9s
myapp-pod   0/1     PodInitializing   0          13s	//pod初始化
myapp-pod   1/1     Running   0          52s	//就运行了

此时我们在关闭service,这个容器也不会在受影响了,因为init时运行在容器之前的,运行完就结束了。不会在对后面的容器产生影响了。
进入到应用容器的运行后,接下来我们就可以去布置探针了。用来检测服务和运行状态了。

探针

  • 探针 是由 kubelet 对容器执行的定期诊断:
    • ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认
      为诊断成功。
    • TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果
      端口打开,则诊断被认为是成功的。
    • HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP
      Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是
      成功的。
  • 每次探测都将获得以下三种结果之一:
    • 成功:容器通过了诊断。
    • 失败:容器未通过诊断。
    • 未知:诊断失败,因此不会采取任何行动。
  • Kubelet 可以选择是否执行在容器上运行的三种探针执行和做出反应:
    • livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet
      会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探
      针,则默认状态为 Success。
    • readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端
      点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。
      初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默
      认状态为 Success。
    • startupProbe: 指示容器中的应用是否已经启动。如果提供了启动探测
      (startup probe),则禁用所有其他探测,直到它成功为止。如果启动探测
      失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有

startupProbe 存在时就会忽略上面的存活探针就绪探针,所以我们只对存活探针和就绪探针进行实验.

liveness

[root@server2 manifest]# vim init.yml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  initContainers:
  - name: init-myservice
    image: busyboxplus
    command: ['sh', '-c', "until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  containers:
  - name: myapp-container
    image: myapp:v1
    imagePullPolicy: IfNotPresent
    livenessProbe:		//存活探针
      tcpSocket:
        port: 80		//检测80端口,打开则正常运行
      initialDelaySeconds: 1	//容器开启后延迟1秒
      periodSeconds: 2			//每2秒检测一次
      timeoutSeconds: 1			//超时

[root@server2 manifest]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1               443/TCP   8d
myservice    ClusterIP   10.99.245.243           80/TCP    15h	//我们的svc开启着
[root@server2 manifest]# kubectl apply -f init.yml 
pod/myapp-pod created
[root@server2 manifest]# kubectl get pod -w
NAME        READY   STATUS            RESTARTS   AGE
myapp-pod   0/1     PodInitializing   0          4s
myapp-pod   1/1     Running           0          4s
[root@server2 manifest]# kubectl exec -it myapp-pod  -- sh
/ # nginx -s stop			//进入同期内部,关闭nginx服务
2020/06/27 02:51:21 [notice] 12#12: signal process started
/ # command terminated with exit code 137
[root@server2 manifest]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   1          3m42s	//自动重启了。

[root@server2 manifest]# kubectl describe pod myapp-pod
Liveness:       tcp-socket :80 delay=1s timeout=1s period=2s #success=1 #failure=3		//成功检测一次,失败检测三次

存活探针和容器的生命周期保持一直,会不断的进行容器的存活检测,当检测到端口关闭的时候,会让kubelet 去重启这个容器,但是前提时重启策略不是Never。

此时我们的service无法识别pod的ip地址,只是做了一个解析,我们应该:

kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  selector:			//加上选择器,选择我们的pod的标签加入到service的服务中
    app: myapp		//service就是作一个端口的暴露
[root@server2 manifest]# kubectl apply -f service.yml 
service/myservice created
[root@server2 manifest]# kubectl describe svc myservice 
Name:              myservice
Namespace:         default
Labels:            <none>
Annotations:       Selector:  app=myapp
Type:              ClusterIP
IP:                10.100.34.244
Port:              <unset>  80/TCP
TargetPort:        9376/TCP
Endpoints:         10.244.1.60:9376		//pod的资源就到了service上了,这是在就绪探针完成的状态下,
Session Affinity:  None
Events:            <none>
[root@server2 manifest]# kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP            NODE      NOMINATED NODE   READINESS GATES
myapp-pod   1/1     Running   1          22m   10.244.1.60   server3   <none>           <none>

readiness

上面我们只加了存活探针,就绪探针不加的话是默认成功,所以我们才能看到pod的ip加到svc上,可以访问。下面我们加上就绪探针进行检测。

[root@server2 manifest]# vim init.yml
...
    livenessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 1
      periodSeconds: 2
      timeoutSeconds: 1
    readinessProbe:		//把就绪探针加进去
      httpGet:
        path: /hostname.html		//让它检测这个页面
        port: 80					//和80端口
      initialDelaySeconds: 1
      periodSeconds: 2
      timeoutSeconds: 1
[root@server2 manifest]# kubectl apply -f init.yml 
pod/myapp-pod created
[root@server2 manifest]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   0          2m9s	
//当前的ready状态是正常的,因为检测的两个东西都正常

[root@server2 manifest]# kubectl exec -it myapp-pod  -- sh		//做一些更改
/ # vi /etc/nginx/conf.d/default.conf 
    #location = /hostname.html {
    #   alias /etc/hostname; 		//注释掉着两行
    #}
    
/ # nginx -s reload
2020/06/27 03:23:53 [notice] 23#23: signal process started
/ # ps ax
PID   USER     TIME   COMMAND
    1 root       0:00 nginx: master process nginx -g daemon off;
   14 root       0:00 sh
   24 nginx      0:00 nginx: worker process
   25 root       0:00 ps ax
/ # [root@server2 manifest]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   0/1     Running   0          6m50s			//容器运行,但是没准备好
//就绪状态就关闭了,因为就绪探针生效,它找不到  path: /hostname.html	这个路径了。
[root@server2 manifest]# kubectl describe svc myservice 
Name:              myservice
Namespace:         default
Labels:            
Annotations:       Selector:  app=myapp
Type:              ClusterIP
IP:                10.100.34.244
Port:                80/TCP
TargetPort:        9376/TCP
Endpoints:                 		//就不会把pod的地址接入到这里了。

[root@server2 manifest]# kubectl exec -it myapp-pod  -- sh
/ # vi /etc/nginx/conf.d/default.conf 		//我们在进入容器打开哪几个参数
/ # nginx -s reload
2020/06/27 04:03:16 [notice] 32#32: signal process started          
/ # [root@server2 manifest]# kubectl describe svc myservice 
Name:              myservice
Namespace:         default
Labels:            
Annotations:       Selector:  app=myapp
Type:              ClusterIP
IP:                10.100.34.244
Port:                80/TCP
TargetPort:        9376/TCP
Endpoints:         10.244.1.61:9376		//加近来了
Session Affinity:  None
Events:            
[root@server2 manifest]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
myapp-pod   1/1     Running   0          46m
[root@server2 manifest]# kubectl run demo  --image=busyboxplus -it --restart=Never
cuelIf you don't see a command prompt, try pressing enter.
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
// 然后通过svc的ip地址就可以访问容器了,svc通过标签把容器的接入近来。

我们在多加一个pod:

[root@server2 manifest]# vim pod2.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-example
spec:
  replicas: 2		//有两个副本
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp		//设置标签相同。
    spec:
      containers:
      - name: nginx
        image: myapp:v2		//使用v2镜像

[root@server2 manifest]# kubectl  apply  -f  pod2.yml 
kubec	deployment.apps/deployment-example created
[root@server2 manifest]# kubectl get pod
NAME                                  READY   STATUS      RESTARTS   AGE
demo                                  0/1     Completed   0          10m
deployment-example-5c9fb4c54c-4f9dj   1/1     Running     0          5s
deployment-example-5c9fb4c54c-pnfzb   1/1     Running     0          5s
myapp-pod                             1/1     Running     0          64m
[root@server2 manifest]# kubectl describe svc myservice 
Name:              myservice
Namespace:         default
Labels:            <none>
Annotations:       Selector:  app=myapp
Type:              ClusterIP
IP:                10.102.77.37
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.61:80,10.244.2.36:80,10.244.2.37:80	 //把新开的两个容器页加进去了
Session Affinity:  None
Events:            <none>

这样我们就可以做负载均衡了。

[root@server2 manifest]# kubectl run demo  --image=busyboxplus -it --restart=Never
If you don't see a command prompt, try pressing enter.
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

你可能感兴趣的:(k8s)