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 "%r" %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 "%r" %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 "%r" %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进行健康检查 |
常见状态转换
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调度