深入掌握Pod(上)

深入掌握Pod

对Kubernetes如何发布与管理容器应用进行详细说明和示例,主要包括Pod和容器的使用、应用配置管理、Pod的控制和调度管理、Pod的升级和回滚,以及Pod的扩缩容机制等内容。

| 静态Pod

  • 静态 Pod 直接由特定节点上的kubelet进程来管理,不通过 master 节点上的apiserver。无法与我们常用的控制器Deployment或者DaemonSet进行关联,它由kubelet进程自己来监控,当pod崩溃时重启该pod,kubelete也无法对他们进行健康检查。静态 pod 始终绑定在某一个kubelet,并且始终运行在同一个节点上。 kubelet会自动为每一个静态 pod 在 Kubernetes 的 apiserver 上创建一个镜像 Pod(Mirror Pod),因此我们可以在 apiserver 中查询到该 pod,但是不能通过 apiserver 进行控制(例如不能删除)。
  • 创建静态 Pod 有两种方式:配置文件和 HTTP 两种方式。这里采用配置文件的方式创建

查看配置文件路径

  • kubelet通过 kubelet --pod-manifest-path=<路径>来启动kubelet进程,kubelet 定期的去扫描这个目录,根据这个目录下出现或消失的 YAML/JSON 文件来创建或删除静态 pod。
    如果你的 kubelet 启动参数中没有配置上面的–pod-manifest-path参数的话,那么添加上这个参数然后重启 kubelet 即可。
[root@localhost ~]# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) since Mon 2021-07-26 09:55:46 CST; 7h ago
     Docs: https://kubernetes.io/docs/
 Main PID: 22913 (kubelet)
    Tasks: 17
   Memory: 34.5M
   CGroup: /system.slice/kubelet.service
           └─22913 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig...

Jul 26 16:22:40 localhost.localdomain kubelet[22913]: W0726 16:22:40.758730   22913 conversion.go:110] Coul...ase
Jul 26 16:32:42 localhost.localdomain kubelet[22913]: W0726 16:32:42.195526   22913 conversion.go:110] Coul...ase
Jul 26 16:42:43 localhost.localdomain kubelet[22913]: W0726 16:42:43.687560   22913 conversion.go:110] Coul...ase
Jul 26 16:55:05 localhost.localdomain kubelet[22913]: W0726 16:55:05.486097   22913 conversion.go:110] Coul...ase
Jul 26 16:55:15 localhost.localdomain kubelet[22913]: W0726 16:55:15.517377   22913 conversion.go:110] Coul...ase
Jul 26 17:05:27 localhost.localdomain kubelet[22913]: W0726 17:05:27.041500   22913 conversion.go:110] Coul...ase
Jul 26 17:15:08 localhost.localdomain kubelet[22913]: W0726 17:15:08.447827   22913 conversion.go:110] Coul...ase
Jul 26 17:15:18 localhost.localdomain kubelet[22913]: W0726 17:15:18.469033   22913 conversion.go:110] Coul...ase
Jul 26 17:18:07 localhost.localdomain kubelet[22913]: I0726 17:18:07.183772   22913 topology_manager.go:233...ler
Jul 26 17:18:07 localhost.localdomain kubelet[22913]: E0726 17:18:07.619942   22913 kuberuntime_manager.go:937...
Hint: Some lines were ellipsized, use -l to show in full.

 找到Drop-In 获取其中的环境变量

Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path

 如果没有添加一下

Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true"

注意的是所以如果我们通过kubeadm的方式来安装的集群环境,对应的kubelet已经配置了我们的静态 Pod 文件的路径,那就是/etc/kubernetes/manifests,所以我们只需要在该目录下面创建一个标准的 Pod 的 JSON 或者 YAML 文件即可。

 

 编辑一个Pod nginx.yaml

[root@localhost ~]# cd /etc/kubernetes/manifests/

[root@localhost manifests]# cat nginx.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: web
  name: web
spec:
  containers:
  - image: nginx
    name: web
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

 

 检查Pod状态

查看Pod情况

[root@localhost manifests]# kubectl get pods -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE                    NOMINATED NODE   READINESS GATES
web-localhost.localdomain   1/1     Running   0          30m   10.244.0.6   localhost.localdomain   <none>           <none>

运行Curl

[root@localhost manifests]# curl 10.244.0.6
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

 

静态pod的删除

  • 无法使用kubectl delete删除pods,删掉会马上重启。通过删除/etc/kubernetes/manifests下对应的yaml或JSON文件删除静态POD

补充HTTP方式创建Pods

  • kubelet 周期地从–manifest-url=参数指定的地址下载文件,并且把它翻译成 JSON/YAML 格式的 pod 定义。此后的操作方式与–pod-manifest-path=相同,kubelet 会不时地重新下载该文件,当文件变化时对应地终止或启动静态 pod。

 

| Pod容器共享Volume

同一个Pod中的多个容器能够共享Pod级别的存储卷Volume。Volume可以被定义为各种类型,多个容器各自进行挂载操作,将一个Volume挂载为容器内部需要的目录。

 

在下面的例子中,在Pod内包含两个容器:tomcat和busybox,在Pod级别设置Volume“app-logs”,用于tomcat向其中写日志文件,busybox读日志文件。

创建Yaml文件

[root@localhost manifests]# vim  pod-volume.yaml 

apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
spec:
  containers:
  - name: tomact
    image: tomcat
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: app-logs
      mountPath: /usr/local/tomcat/logs
  - name: busybox
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","tail -f /logs/catalina*.log"]
    volumeMounts:										#容器内挂载点
    - name: app-logs									#必须有名称
      mountPath: /logs									#容器内挂在路径
  volumes:												#跟上面的名称对应
  - name: app-logs										#跟上面的名称对应
    emptyDir: {}										#宿主机挂载点

这里设置的Volume名为app-logs,类型为emptyDir,挂载到tomcat容器内的/usr/local/tomcat/logs目录,同时挂载到logreader容器内的/logs目录。tomcat容器在启动后会向/usr/local/tomcat/logs目录写文件,logreader容器就可以读取其中的文件了。

 

检查Pod

有两个在运行的Pod

[root@localhost test]# kubectl get pods -o wide                      
NAME                               READY   STATUS    RESTARTS   AGE     IP           NODE                    NOMINATED NODE   READINESS GATES
volume-pod-localhost.localdomain   2/2     Running   1          4m48s   10.244.0.9   localhost.localdomain   <none>           <none>
web-localhost.localdomain          1/1     Running   0          68m     10.244.0.6   localhost.localdomain   <none>           <none>

 

| ConfigMap概述

ConfigMap供容器使用的典型用法如下。

  1. 生成为容器内的环境变量。
  2. 设置容器启动命令的启动参数(需设置为环境变量)。
  3. 以Volume的形式挂载为容器内部的文件或目录。

ConfigMap以一个或多个key:value的形式保存在Kubernetes系统中供应用使用,既可以用于表示一个变量的值(例如apploglevel=info),也可以用于表示一个完整配置文件的内容(例如server.xml=<?xml...>...)

可以通过YAML配置文件或者直接使用kubectl create configmap命令行的方式来创建ConfigMap。

 

示例

根据文件创建一个名为my-config的configmap

$ kubectl create configmap my-config --from-file=path/to/bar

使用指定的keys创建一个名为my-config的configmap

$ kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt

使用key1 = config1和key2 = config2创建一个名为my-config的configmap

$ kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2

从文件中的key = value对创建一个名为my-config的configmap

$ kubectl create configmap my-config --from-file=path/to/bar

从env文件创建一个名为my-config的configmap

$ kubectl create configmap my-config --from-env-file=path/to/bar.env

 

通过YAML配置文件方式创建

直接通过kubectl create configmap也可以创建ConfigMap,可以使用参数--from-file或--from-literal指定内容,并且可以在一行命令中指定多个参数。然后再转换成yaml文件,

[root@master ~]# kubectl create configmap my-config --from-literal=apploglevel=info --from-literal=appdatadir=/var/data -o yaml --dry-run > configmap.yaml 
W0727 06:29:13.460284   83913 helpers.go:535] --dry-run is deprecated and can be replaced with --dry-run=client.

[root@master ~]# cat  configmap.yaml  
apiVersion: v1
data:
  appdatadir: /var/data
  apploglevel: info
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: my-config

#检查是否正常
[root@master ~]# kubectl apply -f configmap.yaml  
configmap/my-config created

[root@master ~]# kubectl get configmap
NAME        DATA   AGE
my-config   2      5s

容器应用对ConfigMap的使用有以下两种方法。

  • 通过环境变量获取ConfigMap中的内容。
  • 通过Volume挂载的方式将ConfigMap中的内容挂载为容器内部的文件或目录。

 

| 使用ConfigMap的限制条件

使用ConfigMap的限制条件如下。

  • ConfigMap必须在Pod之前创建。
  • ConfigMap受Namespace限制,只有处于相同Namespace中的Pod才可以引用它。
  • ConfigMap中的配额管理还未能实现。
  • kubelet只支持可以被API Server管理的Pod使用ConfigMap。kubelet在本Node上通过 --manifest-url或--config自动创建的静态Pod将无法引用ConfigMap。
  • 在Pod对ConfigMap进行挂载(volumeMount)操作时,在容器内部只能挂载为“目录”,无法挂载为“文件”。在挂载到容器内部后,在目录下将包含ConfigMap定义的每个item,如果在该目录下原来还有其他文件,则容器内的该目录将被挂载的ConfigMap覆盖。如果应用程序需要保留原来的其他文件,则需要进行额外的处理。可以将ConfigMap挂载到容器内部的临时目录,再通过启动脚本将配置文件复制或者链接到(cp或link命令)应用所用的实际配置目录下。

 

| 在Pod中使用ConfigMap

通过环境变量方式使用ConfigMap

在Pod“cm-test-pod”的定义中,将ConfigMap“cm-appvars”中的内容以环境变量(APPLOGLEVEL和APPDATADIR)方式设置为容器内部的环境变量,容器的启动命令将显示这两个环境变量的值("env | grep APP")

使用kubectl create -f命令创建该Pod,由于是测试Pod,所以该Pod在执行完启动命

令后将会退出,并且不会被系统自动重启(restartPolicy=Never)

使用kubectl get pods --show-all查看已经停止的Pod:

查看该Pod的日志,可以看到启动命令“env | grep APP”的执行结果如下:

说明容器内部的环境变量使用ConfigMap cm-appvars中的值进行了正确设置。

Kubernetes从1.6版本开始,引入了一个新的字段envFrom,实现了在Pod环境中将ConfigMap(也可用于Secret资源对象)中所有定义的key=value自动生成为环境变量:

 

| Pod生命周期和重启策略

Pod在整个生命周期中被系统定义为各种状态,熟悉Pod的各种状态对于理解如何设置Pod的调度策略、重启策略是很有必要的。

Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。当某个容器异常退出或者健康检查(详见下节)失败时,kubelet将根据RestartPolicy的设置来进行相应的操作。

Pod的重启策略包括Always、OnFailure和Never,默认值为Always。

  • 🥩    Always:当容器失效时,由kubelet自动重启该容器。
  • 🥩 OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。
  • 🥩 Never:不论容器运行状态如何,kubelet都不会重启该容器。

Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下。

  • RC和DaemonSet:必须设置为Always,需要保证该容器持续运行。
  • Job:OnFailure或Never,确保容器执行完成后不再重启。
  • kubelet:在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查。

在Pod的yaml编排使用重启策略。

spec:
  containers:
  - image: nginx
    name: web
    ports:
    - containerPort: 80
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always              #重启策略

 

Pod健康检查

Kubernetes 对 Pod 的健康状态可以通过两类探针来检查:LivenessProbe 和ReadinessProbe,kubelet定期执行这两类探针来诊断容器的健康状况。

  • LivenessProbe探针:用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。
  • ReadinessProbe探针:用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上。

 

LivenessProbe和ReadinessProbe均可配置以下三种实现方式。

ExecAction

  • ExecAction:在容器内部执行一个命令,如果该命令的返回码为0,则表明容器健康。

通过执行“cat /tmp/health”命令来判断一个容器运行是否正常。在该Pod运行后,将在创建/tmp/health文件10s后删除该文件,而LivenessProbe健康检查的初始探测时间(initialDelaySeconds)为15s,探测结果是Fail,将导致kubelet杀掉该容器并重启它

[root@master ~]# vim pod.yaml               
 dd   resources: {}
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
  name: web
spec:
  containers:
  - image: nginx
    name: web
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
    livenessProbe:                  "健康检查"
      exec:
        command:
        - cat
        - /tmp/health
      initialDelaySeconds: 15        "初始探测时间"
      timeoutSeconds: 1              "超时时间"
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

查看状态正常

[root@master ~]# kubectl apply -f pod.yaml  
pod/web created

[root@master ~]# kubectl get pods 
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          4s

 

TCPSocketAction

  • TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。

在下面的例子中,通过与容器内的localhost:80建立TCP连接进行健康检查:

[root@master ~]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
  name: web
spec:
  containers:
  - image: nginx
    name: web
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
    livenessProbe:                        "健康检查"
      tcpSocket:                          "TCP连接进行健康检查"
        port: 80
      initialDelaySeconds: 30
      timeoutSeconds: 1 
  dnsPolicy: ClusterFirst
  restartPolicy: Always
  
  
[root@master ~]# kubectl apply -f pod.yaml    
pod/web created
status: {}

 

HTTPGetAction

  • HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。

在下面的例子中,kubelet定时发送HTTP请求到localhost:80/_status/healthz来进行容器应用的健康检查:

[root@master ~]# cat pod.yaml  
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
  name: web
spec:
  containers:
  - image: nginx
    name: web
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
    livenessProbe:                        "健康检查"
      httpGet:                            "HTTP Get方法"
        path: /_status/healthz
        port: 80 
      initialDelaySeconds: 30
      timeoutSeconds: 1 
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

对于每种探测方式,都需要设置initialDelaySeconds和timeoutSeconds两个参数,它们的含义分别如下。

  •  initialDelaySeconds:启动容器后进行首次健康检查的等待时间,单位为s。
  •  timeoutSeconds:健康检查发送请求后等待响应的超时时间,单位为s。当超时发生时,kubelet会认为容器已经无法提供服务,将会重启该容器。
posted @ 2021-07-26 17:53  isicman  阅读(213)  评论(0编辑  收藏  举报