理解Kubernetes中pod是什么

Kubernetes-pod

NO,1:Pod

#Pod 介绍:
每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器

#为什么Kubernetes会设计出一个全新的Pod概念,并且有这样特殊的结构?
原因一:Pause容器作为Pod根容器,以它的状态代表整个容器组的状态 
原因二: Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂接的Volume

Kubernetes为每个Pod分配唯一的IP的地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP。Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP的直接通讯,采用虚拟二层网络技术来实现,一个Pod里的容器与另外主机上的Pod容器能够直接通信。

#静态Pod & 普通Pod
普通的Pod:
普通Pode一旦被创建,就会被放入到etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定(Binding),随后该Pod 被对应的Node上的kubelet进程实例化成一组相关的docker容器运行起来。     当Pod里的某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod (重启Pod里的所有容器),如果Pod所在的Node宕机,则会将这个Node上所偶的Pod从新调度到其他节点上。

静态Pod (STatic Pod)
静态Pod不存放在Kubernetes的etcd存储里,而是存放在某个具体的Node上的文件中,并且只在此Node上启动运行。
静态Pod是由kubelet进行管理的仅存在于特定Node上的Pod。他们不能通过API Server进行管理,无法与ReplicationController(RC)、Deployment、或者DaemonSet进行关联,并且kubelet也无法对它们进行健康检查。静态Pod总是由kubelet进行创建的,并且总是在kubelet所在的Node上运行的

创建静态Pod有两种方式:配置文件方式和HTTP方式
1.配置文件方式
首先,需要设置kubelet的启动参数"config",指定kubelet需要监控的配置文件所在的目录,kubelet会定期扫描该目录,并根据该目录中的*.yaml或*.json文件进行创建操作

部署静态Pod

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    role: nginx
spec:
  containers:
    - name: nginx
      image: nginx:alpine
      ports:
        - name: nginx
          containerPort: 80
          protocol: TCP
部署一下,可以看到nginx的pod
[root@kubernetes-m media]# kubectl create -f nginx.yaml 
pod/nginx created
[root@kubernetes-m media]# kubectl get pod -A
NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE
default       nginx                                  1/1     Running   0          4s
kube-system   coredns-7ff77c879f-6gqsx               1/1     Running   0          47h
kube-system   coredns-7ff77c879f-hhrg5               1/1     Running   0          47h
kube-system   etcd-kubernetes-m                      1/1     Running   0          47h
kube-system   kube-apiserver-kubernetes-m            1/1     Running   0          47h
kube-system   kube-controller-manager-kubernetes-m   1/1     Running   0          47h
kube-system   kube-flannel-ds-amd64-42lg9            1/1     Running   0          47h
kube-system   kube-flannel-ds-amd64-bxr5c            1/1     Running   0          47h
kube-system   kube-flannel-ds-amd64-wvr6d            1/1     Running   0          47h
kube-system   kube-proxy-89plc                       1/1     Running   0          47h
kube-system   kube-proxy-9554v                       1/1     Running   0          47h
kube-system   kube-proxy-n4mrg                       1/1     Running   0          47h
kube-system   kube-scheduler-kubernetes-m            1/1     Running   0          47h

#Endpoint
Pod的IP加上这里的容器端口(container Port),就组成了一个全新的概念---Endpoint 它代表着此Pod里的一个服务进程的对外通讯地址。一个Pod也存在着多个Endpoint的情况,比如我们把Tomcat定义为一个Pod时,可以对外暴露端口与服务端口这两个Endpoint

#Event
Event是一个事件的记录,记录事件的最早生成时间、最后重现时间、重复次数、发起者、类型,以及导致此事件的原因等众多信息。Event通常会关联到某个具体的资源上,是排查故障的重要参考,Node描述信息包含了Event,而Pod同样有Event记录。

当我们发现某个Pod迟迟无法创建时,我们就可以用kubectl describe pod [Pod名称]来查看,定位问题
示例:
[root@kubernetes-m media]# kubectl describe pod nginx 
---
Events:
  Type    Reason     Age    From                     Message
  ----    ------     ----   ----                     -------
  Normal  Scheduled  2m21s  default-scheduler        Successfully assigned default/nginx to kubernetes-w-1
  Normal  Pulled     2m20s  kubelet, kubernetes-w-1  Container image "nginx:alpine" already present on machine
  Normal  Created    2m20s  kubelet, kubernetes-w-1  Created container nginx
  Normal  Started    2m20s  kubelet, kubernetes-w-1  Started container nginx

#二、Pod基本用法
Pod的基本用法为:Pod 可以创建一个或多个容器组合而成
创建一个名为nginx-deployment的Pod只由一个容器组成
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx   ##容器名称
        image: nginx:alpine  #镜像地址
        imagePullPolicy: IfNotPresent #优先拉取本地
        ports:
        - containerPort: 80
#部署
[root@kubernetes-m media]# kubectl create -f nginx.yaml 
deployment.apps/nginx-deployment created
[root@kubernetes-m media]# kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-97499b967-h4gj6   1/1     Running   0          5s

另一种场景,当nginx容器和tomcat容器应用为紧耦合的关系,应该组合成一个整体对外提供服务时,应将这两个容器打包为一个Pod
配置nginx和tomcat yaml文件如下下

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-tomcat
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-tomcat
  template:
    metadata:
      labels:
        app: nginx-tomcat
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
      - name: tomcat
        image: tomcat
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
部署后看一下pod内的容器
[root@kubernetes-m media]# kubectl describe pod nginx-tomcat-5dffd85c54-vffgl
---
Events:
  Type    Reason     Age    From                     Message
  ----    ------     ----   ----                     -------
  Normal  Scheduled  5m23s  default-scheduler        Successfully assigned default/nginx-tomcat-5dffd85c54-vffgl to kubernetes-w-1
  Normal  Pulled     5m22s  kubelet, kubernetes-w-1  Container image "nginx:alpine" already present on machine
  Normal  Created    5m22s  kubelet, kubernetes-w-1  Created container nginx
  Normal  Started    5m22s  kubelet, kubernetes-w-1  Started container nginx
  Normal  Pulling    5m22s  kubelet, kubernetes-w-1  Pulling image "tomcat"
  Normal  Pulled     95s    kubelet, kubernetes-w-1  Successfully pulled image "tomcat"
  Normal  Created    95s    kubelet, kubernetes-w-1  Created container tomcat
  Normal  Started    94s    kubelet, kubernetes-w-1  Started container tomcat
[root@kubernetes-m media]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-tomcat-5dffd85c54-vffgl   2/2     Running   0          5m29s
我们可以看到READY信息为2/2,表示Pod中的两个容器都成功运行了 (状态Running)

#三、Pod的配置管理 ConfigMap
应用部署的一个最佳实践是讲应用所需的配置信息与程序进行分离,这样可以使得应用程序被更好地复用,通过不同的配置也能实现灵活的功能。将应用打包为容器镜像后,可以通过环境变量或者外挂文件的方式在创建容器时进行配置注入,但在大规模容器集群中,对多个容器进行不同的配置将变得非常复杂。从kubernetes1.2开始提供了一套同意的应用配置管理方案----ConfigMap(资源对象)

#ConfigMap概述
ConfigMap供容器使用的典型用法如下
   ---生成为容器内的环境变量
   ---设置容器的启动命令的启动参数 (需要设置为环境变量)
   ---以Volume的形式挂载为容器内部的文件或目录
   
ConfigMap以一个或多个key:value的形式保存在Kubernetes系统中供应用使用,既可以用于表示一个变量的值(例如apploglevel=info),也可以用于表示一个完整配置文件的内容(server.xml=<?xml..>..)

可以通过yaml配置文件或者直接使用kubectl create configmap来创建ConfigMap

#创建ConfigMap

创建ConfigMap的方式有4种:

   ---通过直接在命令行中指定configmap参数创建,即--from-literal
   ---通过指定文件创建,即将一个配置文件创建为一个ConfigMap--from-file=<文件>
   ---通过指定目录创建,即将一个目录下的所有配置文件创建为一个ConfigMap,--from-file=<目录>
   ---事先写好标准的configmap的yaml文件,然后kubectl create -f 创建
   
1、使用yaml文件创建ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap
data:
  key1: test
  keydir: /var/data

# name: configmap名称
data.key1: key1 对应的值
data.keydir: keydir对应的挂载目录


创建并查看Configmap
[root@kubernetes-m media]# kubectl create -f confingmap.yaml 
configmap/configmap created
[root@kubernetes-m media]# kubectl get configmaps 
NAME        DATA   AGE
configmap   2      4s
[root@kubernetes-m media]# kubectl describe configmaps configmap 
Name:         configmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
key1:
----
test
keydir:
----
/var/data
Events:  <none>
# Data下面是对应的我们上面定义的key和挂载的目录

2、使用--from-file参数创建ConfigMap

通过--from-file参数从文件中进行创建,可以指定key的名称,也可以在一个命令行中创建多个key的ConfigMap==
当前目录下含有配置文件server.xml,可以创建一个包含该文件内容的ConfigMap

[root@kubernetes-m media]# kubectl create configmap test-server.xml --from-file=server.xml
configmap/test-server.xml created
[root@kubernetes-m media]# kubectl get configmaps
NAME              DATA   AGE
test-server.xml   1      11s
[root@kubernetes-m media]# kubectl describe configmaps test-server.xml 
Name:         test-server.xml
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
server.xml:
----
test

Events:  <none>

当前configfiles下有2个配置文件,创建一个configmap包含2个文件内容

[root@kubernetes-m media]# ls configfiles/
server2.xml  server.xml
[root@kubernetes-m media]# kubectl create configmap conf --from-file=configfiles
configmap/two-conf created
[root@kubernetes-m media]# kubectl get configmaps
NAME       DATA   AGE
two-conf   2      11s
[root@kubernetes-m media]# kubectl describe configmaps conf 
Name:         two-conf
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
server.xml:
----
test

server2.xml:
----
test2

Events:  <none>

3、使用--from-literal创建ConfigMap
==使用--from-literal参数进行创建的示例如下:==
kubectl create configmap test-configmap --from-literal=loglevel=info --from-literal=appdatadir=/var/data

[root@kubernetes-m media]# kubectl describe configmaps test-configmap 
Name:         test-configmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
appdatadir:
----
/var/data
loglevel:
----
info
Events:  <none>

容器应用对ConfigMap的使用有以下两种方法
	通过环境变量获取ConfigMap中的内容
	通过Volume挂载的方式将ConfigMap中的内容挂载为容器内部的文件或目录
	
#Pod中使用ConfigMap
(1) 通过环境变量方式使用ConfigMap
首先我们需要创建ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap
data:
  key: test
  dir: /var/data
---
apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
    - name: pod
      image: busybox
      command: [ "/bin/sh", "-c", "env | grep config" ]
      env:
        - name: configmapPod
          valueFrom:
            configMapKeyRef:
              name: configmap
              key: key
        - name: configmapDir
          valueFrom:
            configMapKeyRef:
              name: configmap
              key: dir
  restartPolicy: Never

==================相关参数解释===================
      env:
        - name: configmapPod  ##定义环境变量名称
          valueFrom:           #key "keyinfo对应的值"
            configMapKeyRef:
              name: configmap  ##环境变量的值取自哪(上面创建的configmap名称)
              key: key         #configmap里对应的key
        - name: configmapDir
          valueFrom:
            configMapKeyRef:
              name: configmap  #同上
              key: dir
==================================================
kubectl create -f pod-configmap.yaml

[root@kubernetes-m media]# kubectl logs pod pod 
configmapDir=/var/data
configmapPod=test

从kubernetes1.6开始,引用了一个新的字段envFrom实现Pod环境内将ConfigMap中所有定义的key=value自动生成为环境变量
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap
data:
  key: test
  dir: /var/data
---
apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
    - name: pod
      image: busybox
      command: [ "/bin/sh", "-c", "env" ]
      envFrom:
      - configMapRef:
          name: configmap  ##根据configmap中自动生成key=value环境变量
  restartPolicy: Never
  
[root@kubernetes-m media]# kubectl logs pod pod 
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://100.1.0.1:443
HOSTNAME=pod
SHLVL=1
HOME=/root
dir=/var/data
key=test
KUBERNETES_PORT_443_TCP_ADDR=100.1.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://100.1.0.1:443
KUBERNETES_SERVICE_HOST=100.1.0.1
PWD=/

通过这个定义,在容器内部将会自动生成如下环境配置
需要说明的是,环境变量的名称手POSIX命名规范([a-zA-Z][a-zA-Z0-9])约束,不能以数字开头。如果包含非法字符,则系统将跳过该条环境变量的创建,并记录一个Event来描述环境变量无法生成,但不阻止Pod的启动

(2) 通过volumeMount使用ConfigMap

在本例子中包含了1个配置文件的定义 server.xml

apiVersion: v1
kind: ConfigMap
metadata:
  name: tomcat-server-config
data:
  server.xml: |
    <?xml version='1.0' encoding='utf-8'?>
      <Server port="8005" shutdown="SHUTDOWN">
      <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
      <!--APR library loader. Documentation at /docs/apr.html -->
      <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
      <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
      <Listener className="org.apache.catalina.core.JasperListener" />
      <!-- Prevent memory leaks due to use of particular java/javax APIs-->
      <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
      <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
      <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
      <GlobalNamingResources>
        <Resource name="UserDatabase" auth="Container"
                  type="org.apache.catalina.UserDatabase"
                  description="User database that can be updated and saved"
                  factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
                  pathname="conf/tomcat-users.xml" />
      </GlobalNamingResources>
      <Service name="Catalina">
        <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
            maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true" />
        <Connector executor="tomcatThreadPool" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
                   connectionTimeout="20000"
                   redirectPort="8443"
                   enableLookups="false"
                   maxPostSize="10485760"
                   URIEncoding="UTF-8"
                   disableUploadTimeout="true"
                   maxConnections="10000"
                   SSLEnabled="false"/>
        <Engine name="Catalina" defaultHost="localhost">
          <Realm className="org.apache.catalina.realm.LockOutRealm">
            <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                   resourceName="UserDatabase"/>
          </Realm>
          <Host name="localhost"  appBase="webapps"
                unpackWARs="true" autoDeploy="true">
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                   prefix="localhost_access_log." suffix=".txt"
                   pattern="%h %l %u %t &quot;%r&quot; %s %b" />
          </Host>
          <Context path="" docBase="/tomcat/webapps" debug="0" reloadable="true" crossContext="true"/>
        </Engine>
       </Service>
     </Server>
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tomcat
  template:
    metadata:
      labels:
        app: tomcat
    spec:
      containers:
      - image: busybox
        imagePullPolicy: IfNotPresent
        name: tomcatpod
        volumeMounts:
        - mountPath: /tmp/server.xml
          name: serverxml
          subPath: server.xml
        ports:
        - containerPort: 8080
        command: ["tail", "-f", "/dev/null"]
      volumes:
      - name: serverxml
        configMap:
          name: tomcat-server-config
          items:
          - key: server.xml
            path: server.xml

[root@kubernetes-m media]# kubectl exec -it pod-85dbb9989-jndn8 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/ # cd /tmp/
/tmp # ls
server.xml
/tmp # cat server.xml 
<?xml version='1.0' encoding='utf-8'?>
  <Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true" />
    <Connector executor="tomcatThreadPool" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
               connectionTimeout="20000"
               redirectPort="8443"
               enableLookups="false"
               maxPostSize="10485760"
               URIEncoding="UTF-8"
               disableUploadTimeout="true"
               maxConnections="10000"
               SSLEnabled="false"/>
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
      <Context path="" docBase="/tomcat/webapps" debug="0" reloadable="true" crossContext="true"/>
    </Engine>
   </Service>
 </Server>

需要注意的是,不可以光mount挂载,需要执行命令让容器在前台运行!

如果在引用ConfigMap时不指定items,则使用volumeMount方式在容器内的目录中为每个item生成一个文件夹为key的文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tomcat
  template:
    metadata:
      labels:
        app: tomcat
    spec:
      containers:
      - image: busybox
        imagePullPolicy: IfNotPresent
        name: tomcatpod
        volumeMounts:
        - mountPath: /tmp/server.xml
          name: serverxml
          subPath: server.xml
        ports:
        - containerPort: 8080
        command: ["tail", "-f", "/dev/null"]
      volumes:
      - name: serverxml
        configMap:
          name: tomcat-server-config
#验证
[root@kubernetes-m media]# kubectl exec -it pod-75fd94d7c5-ls84q /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
/ # ls /tmp/
server.xml
/ # cat /tmp/server.xml 
<?xml version='1.0' encoding='utf-8'?>
  <Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true" />
    <Connector executor="tomcatThreadPool" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
               connectionTimeout="20000"
               redirectPort="8443"
               enableLookups="false"
               maxPostSize="10485760"
               URIEncoding="UTF-8"
               disableUploadTimeout="true"
               maxConnections="10000"
               SSLEnabled="false"/>
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
      <Context path="" docBase="/tomcat/webapps" debug="0" reloadable="true" crossContext="true"/>
    </Engine>
   </Service>
 </Server>
 
#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)应用所用的实际配置目录下
需要注意的是,容器不可以光mount挂载,需要执行命令让容器在前台运行!
需要在挂载下面添加subPath,否则将会替换整个目录

深入Pod

Pod声明周期和重启策略
Pod在整个生命周期过程中被系统定义为各种状态
状态值 描 述
Pending API Server已经创建该Pod,但Pod内还有一个或多个容器的镜像没有创建成功,包括正在下载的镜像的过程
Running Pod内所有容器均已创建,且至少有一个容器处于运行状态、正在启动或正在重启状态
Succeeded Pod内所有容器均已成功执行退出,且不会再重启
Failed Pod内所有容器均已退出,但至少有一个容器退出为失败状态
Unknown 由于某种原因无法获取该Pod的状态,可能由于网络通信不畅导致
Pod重启策略 Pod重启策略RestartPolicy应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作。

Pod的重启策略包括Always、OnFailure和Never,默认值为Always
Always 当容器失效时,由kubelet自动重启该容器
OnFailure 当容器终止运行切退出代码不为0时,由kubelet自动重启该容器
Never 不论容器运行状态如何,kubelet都不会重启该容器
kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算,例如1、2、4、8倍等,最长延时5min,并且在成功重启后的10min后重置该时间

Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下
RC和DaemonSet 必须设置为Always,需要保证该容器持续运行
Job OnFailure或Never,确保容器执行完成后不再重启。
Kubelet 在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查
常见状态转换

-w726

Pod 健康检查
对Pod的健康状态检查可以通过两类探针来检查:LivenessProbe和ReadinessProbe

1.LivenessProbe探针
用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含你LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是 "Success"

2.ReadinessProbe探针
用于判断容器是否完成(Ready状态),可以接收请求。如果ReadinessProbe探针检测到失败,则Pod的状态将被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在的Pod的Endpoint

探针配置参数说明
探针参数 说明
initialDelaySeconds 启动活动或准备就绪探测之前容器启动后的秒数
periodSeconds 执行探测的频率(以秒为单位)。默认为10秒。最小值为1
timeoutSeconds 探测超时的秒数。默认为1秒。最小值为1
successThreshold 失败后探测成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。
failureThreshold Pod启动并且探测器失败时,Kubernetes会failureThreshold在放弃之前尝试一次。在活动探测的情况下放弃意味着重新启动Pod。如果准备好探测,Pod将被标记为未准备好。默认为3.最小值为1
Http探针配置
Http Get 说明
host 要连接的主机名,默认为pod IP。您可能希望在httpHeaders中设置“主机”
scheme 用于连接主机(HTTP或HTTPS)的方案。默认为HTTP
path HTTP服务器上的访问路径
httpHeaders 要在请求中设置的自定义标头。HTTP允许重复标头
port 容器上要访问的端口的名称或编号。数字必须在1到65535的范围内
对于HTTP探测,kubelet将HTTP请求发送到指定的路径和端口以执行检查。kubelet将探测器发送到pod的IP地址,除非地址被可选host字段覆盖httpGet。如果 scheme字段设置为HTTPS,则kubelet会发送跳过证书验证的HTTPS请求。在大多数情况下,您不希望设置该host字段。这是您设置它的一个场景。假设Container侦听127.0.0.1并且Pod的hostNetwork字段为true。然后host,在httpGet,应设置为127.0.0.1。如果你的pod依赖虚拟主机,这可能是更常见的情况,你不应该使用host,而是设置Host标头httpHeaders

详情请参考官方文档

kubelet定期执行LivenessProbe探针来诊断容器的健康状况。LivenessProbe有以下三种方式
(1) ExecAction
在容器内执行一个命令,如果该命令的返回码为0,则表示容器健康
通过执行"cat /tmp/health" 命令来判断一个容器运行是否正常。而该pod运行之后,在创建/tmp/health文件的10s之后将删除该文件,而LivenessProbe健康检查的初始探测时间(initialDelaySeconds)为15s,探测结果将是Fail,将导致kubelet杀掉该容器并重启它

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        command: ["/bin/sh", "-c", "echo ok >/tmp/health; sleep 60;rm -rf /tmp/health; sleep 600"]
        livenessProbe:
          exec:
            command:
            - cat
            - /tmp/health
          initialDelaySeconds: 15
          timeoutSeconds: 1



=======================分割线======================

initialDelaySeconds   #执行第一次探测之前等待15秒
periodSeconds       #每5秒执行一次活跃度探测

结果演示

kubelet将cat /tmp/healthy在Container中执行命令。如果命令成功,则返回0,并且kubelet认为Container是活动且健康的。如果该命令返回非零值,则kubelet会终止Container并重新启动它。

当Container启动时,它会执行以下命令:

/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600" 对于Container的生命的前30秒,有一个/tmp/healthy文件。因此,在前30秒内,该命令cat /tmp/healthy返回成功代码。30秒后,cat /tmp/healthy返回失败代码。kubelet会将容器杀死并重新创建

[root@kubernetes-m media]# kubectl describe pod pod-b8df6db6c-zf87b kubectl describe pod pod-b8df6db6c-zf87b
Events:
  Type     Reason     Age               From                     Message
  ----     ------     ----              ----                     -------
  Normal   Scheduled  98s               default-scheduler        Successfully assigned default/pod-b8df6db6c-zf87b to kubernetes-w-1
  Normal   Pulled     97s               kubelet, kubernetes-w-1  Container image "nginx:alpine" already present on machine
  Normal   Created    97s               kubelet, kubernetes-w-1  Created container nginx
  Normal   Started    97s               kubelet, kubernetes-w-1  Started container nginx
  Warning  Unhealthy  8s (x3 over 28s)  kubelet, kubernetes-w-1  Liveness probe failed: cat: can't open '/tmp/health': No such file or directory
  Normal   Killing    8s                kubelet, kubernetes-w-1  Container nginx failed liveness probe, will be restarted


(2) TCPSocketAction
通过容器的IP地址和端口号执行TCP检查,如果能联立TCP连接,则表示容器健康
TCP检查的配置与HTTP检查非常相似。在容器启动10秒后,kubelet将发送第一个就绪探测器。这将尝试连接到容器端口80上的容器。如果探测成功,则该pod将标记为就绪。kubelet将每10秒继续运行此检查。如果重启探测失败将会新建容器并重新启动

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10
          timeoutSeconds: 1

#参数解释请往上翻阅
测试 因为使用nginx镜像,默认端口80,所以8080一直无法探测成功

Events:
  Type     Reason     Age   From                     Message
  ----     ------     ----  ----                     -------
  Normal   Scheduled  24s   default-scheduler        Successfully assigned default/pod-7c7df6cf45-5nhtd to kubernetes-w-1
  Normal   Pulled     23s   kubelet, kubernetes-w-1  Container image "nginx:alpine" already present on machine
  Normal   Created    23s   kubelet, kubernetes-w-1  Created container nginx
  Normal   Started    23s   kubelet, kubernetes-w-1  Started container nginx
  Warning  Unhealthy  6s    kubelet, kubernetes-w-1  Liveness probe failed: dial tcp 200.1.1.55:8080: connect: connection refused

(3) HTTPGetAction
通过容器的IP地址、端口号及路径调用HTTP Get方法,如果影响的状态码大于等于200且小于400,则认为容器状态健康.
为了执行探测,kubelet向在Container中运行的服务器发送HTTP GET请求并侦听端口80.如果服务器abcdicjer路径的处理程序返回成功代码,则kubelet认为Container是活动且健康的。如果处理程序返回失败代码,则kubelet会终止Container并重新启动它。

任何大于或等于200且小于400的代码表示成功。任何其他代码表示失败

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        livenessProbe:
          httpGet:
            path: /abcdocker/
            port: 80
          initialDelaySeconds: 15
          periodSeconds: 10
          timeoutSeconds: 1
 因为请求的nginx路径不存在,所以容器报错404并进行重启
 Events:
  Type     Reason     Age                   From                     Message
  ----     ------     ----                  ----                     -------
  Normal   Scheduled  20m                   default-scheduler        Successfully assigned default/pod-7c7df6cf45-5nhtd to kubernetes-w-1
  Normal   Pulled     18m (x4 over 20m)     kubelet, kubernetes-w-1  Container image "nginx:alpine" already present on machine
  Normal   Killing    18m (x3 over 19m)     kubelet, kubernetes-w-1  Container nginx failed liveness probe, will be restarted
  Normal   Created    18m (x4 over 20m)     kubelet, kubernetes-w-1  Created container nginx
  Normal   Started    18m (x4 over 20m)     kubelet, kubernetes-w-1  Started container nginx
  Warning  BackOff    9m53s (x26 over 16m)  kubelet, kubernetes-w-1  Back-off restarting failed container
  Warning  Unhealthy  4m53s (x25 over 19m)  kubelet, kubernetes-w-1  Liveness probe failed: dial tcp 200.1.1.55:8080: connect: connection refused
  
  
Pod 调度
在Kubernetes系统中,Pod在大部分场景下都只是容器的载体而已,通常需要Deployment、DaemonSet、RC、Job等对象来完成一组Pod的调度和自动控制功能

1.Deployment/RC:全自动调度
Deployment或RC的主要功能之一就是自动部署一个容器应用的多个副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量
下面是创建一个Deployment配置的例子,使用这个配置文件创建一个ReplicaSet,ReplicasSet (与Replication Controller同名)会创建3个nginx应用的pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
[root@kubernetes-m media]# vim pod.yaml 
[root@kubernetes-m media]# kubectl create -f pod.yaml 
deployment.apps/pod created
[root@kubernetes-m media]# kubectl get pod -owide | grep pod
pod-85676947d7-t2xw2   1/1     Running   0          16s   200.1.2.44   kubernetes-w-2   <none>           <none>
pod-85676947d7-xnlps   1/1     Running   0          16s   200.1.1.57   kubernetes-w-1   <none>           <none>
pod-85676947d7-zghp4   1/1     Running   0          16s   200.1.1.56   kubernetes-w-1   <none>           <none>

从调度策略来说,这三个nginx Pod由系统全自动完成调度,它们各自最终运行在哪个节点上,完全由master的schedulet经过一系列的算法得出,用户无法干预调度过程和结果。

除了使用系统自动调度算法完成一组Pod的部署,Kubernetes也提供了丰富的调度策略,用户只需要在Pod的定义中使用NodeSelector NodeAffinity PodAffinity Pod 驱逐等更加细粒的调度策略设置,就能完成对Pod的精准调度。


2.NodeSelector:定向调度
Kubernetes Master上的Scheduler服务(kube-scheduler进程) 负责实现Pod的调度,这个调度过程通过一系列复杂的算法,最终为每个Pod计算出一个最佳的目标节点,这一过程是自动完成的,通常我们无法指定Pod最终会被调度在哪个节点上,在实际强开中,也可以需要将pod调度到指定的一些Node上,可以通过Node的标签(Label)和Pod的nodeSelector属性相匹配,来达到目的。

(1) 首先通过kubectl label命令给目标Node打赏一些标签
kubectl label nodes [node-name] <label-key>=<label-value>

这里我们使用node节点打上一个key=aaa的标签
[root@kubernetes-m media]# kubectl label nodes kubernetes-w-1 key=aaa

上述命令操作也可以通过修改资源定义文件的方式,并执行kubectl replace -f xxx.yaml命令来完成
(2)需要在Pod中定义nodeSelector的配置,我们以Nginx为例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
      nodeSelector:
        key: aaa

###nodeSelector是配置绑定node
abcdocker:aaa 是我们之前创建的标签

[root@kubernetes-m media]# kubectl create -f pod.yaml 
deployment.apps/pod created
[root@kubernetes-m media]# kubectl get pod -A -owide | grep pod
default       pod-8548d48db-887mr                    1/1     Running   0          11s    200.1.1.60   kubernetes-w-1   <none>           <none>
default       pod-8548d48db-bhmzs                    1/1     Running   0          11s    200.1.1.59   kubernetes-w-1   <none>           <none>
default       pod-8548d48db-jc98f                    1/1     Running   0          11s    200.1.1.58   kubernetes-w-1   <none>           <none>

我们可以看到现在所有的Pod都在对应的kubernetes-w-1节点上

如果我们给多个Node都定义了相同的标签(例如:key=aaa),则scheduler将会根据调度算法从这组Node中挑选一个可用的Node进行pod调度
posted @ 2021-12-17 10:28  Layzer  阅读(162)  评论(1编辑  收藏  举报