本节将对kubernetes如何发布和管理应用进行说明和示例,主要包括Pod和容器的使用、Pod的控制和调度、应用配置管理等内容。
1.Pod定义详解
yaml格式的Pod定义文件的完整内容:
apiVersion: v1
kind: Pod
metadata:
name: string
namespace: string
labels:
- name: string
annotations:
- name: string
spec:
containers:
- name: string
image: string
imagePullPolicy: [Always | Never | IfNotPresent]
command: [string]
args: [string]
workingDir: string
volumeMounts:
- name: string
mountPath: string
readOnly: boolean
ports:
- name: string
containerPort: int
hostPort: ing
protocol: string
env:
- name: string
value: string
resources:
limits:
cpu: string
memory: string
requests:
cpu: string
memory: string
livenessProbe:
exec:
command: [string]
httpGet:
path: string
port: number
host: string
scheme: string
httpHeaders:
- name: string
value: string
tcpSocket:
port: number
initialDelaySeconds: 0
timeoutSeconds: 0
periodSeconds: 0
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure]
nodeSelector: object
imagePullSecrets:
- name: string
hostNetwork: false
volumes:
- name: string
emptyDir: {}
hostPath:
path: string
secret:
secretName: string
items:
- key: string
path: string
configMap:
name: string
items:
- key: string
path: string
2. Pod的基本用法
Pod可用由1个或多个容器组合而成。
例如名为frontend的Pod只由一个容器组成:
apiVersion: v1
kind: Pod
metadata:
name: frontend
labels:
name: frontend
spec:
containers:
- name: frontend
image: kubeguide/guestbook-php-frontend
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 80
这个Pod启动后,将启动1个Docker容器
另一种场景是,当两个容器为紧耦合关系,应将两个容器打包为一个Pod,如下:
配置文件frontend-localredis-pod.yaml如下:
apiVersion: v1
kind: Pod
metadata:
name: redis-php
labels:
name: redis-php
spec:
containers:
- name: frontend
image: kubeguide/guestbook-frontend:localredis
ports:
- containerPort: 80
- name: redis
image: kubeguide/redis-master
ports:
- containerPort: 6379
运行命令创建Pod:
#kubectl create -f frontend-localredis-pod.yaml
#kubectl get pods
NAME |Ready |status |Restarts |Age
redis-php |2/2 |Running |0 |10m
可以看到Ready信息为2/2,表示Pod中有两个容器在运行
查看这个Pod的详细信息,可以看到两个容器的定义及创建过程(Event事件信息)
#kubectl describe pod redis-php
3.静态Pod
静态Pod是由kubectl进行管理的仅存于特定Node上的Pod。他们不能通过API Server惊醒管理,无法与ReplicationController、Deployment或者DaemonSet进行关联,并且kubelet也无法对他们进行健康检查。静态Pod总是由kubectl进行创建,并且总是在kubelet所在的Node上运行。
创建Pod有两种方式:配置文件或HTTP方式,这里只说常用的配置文件方式
配置文件方式
在目录/etc/kubelet.d中放入static-web.yaml文件,内容:
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
name: static-web
spce:
containers:
- name: static-web
image: nginx
ports:
- name: web
containerPort: 80
等一会,查看本机中已经启动的容器:
#docker ps
就可以看到一个Nginx容器已经被Kubelet成功创建了出来。
到Master节点查看Pod列表,可以看到这个static pod:
#kubectl get pods
由于静态Pod无法通过API Server直接管理,所以在Master节点尝试删除这个Pod,将会使其标为Pending状态,且不会被删除。
#kubectl delete pod static-web-node1
删除该Pod的操作只能是到其所在Node上,将其自定义文件static-web.yaml从/etc/kubelet.d目录下删除
#rm /etc/kubelet.d/static-web.yaml
#docker ps
容器已经删除了
4 Pod容器共享Volume
在同一个Pod中多个容器能够共享Pod级别的存储卷Volume,如图:
在下面的例子中,Pod内包含两个容器:tomcat和busybox,在Pod级别设置Volume“app-logs”,用于tomcat向其中写日志文件,busybox读取日志文件
配置文件pod-volume-applogs.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: tomcat
image: tomcat
ports:
- containerPort: 8080
volumeMounts:
- name: app-logs
mountPath: /usr/local/tomcat/logs
- name: busybox
image: busybox
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目录。
通过kubectl logs命令查看logreader容器的输出内容:
#kubectl logs Volume-pod -c busybox
这个文件即为tomcat生成的日志文件/usr/local/tomcat/logs/catalina.
.log的内容,登录tomcat
容器进行查看:
#kubectl exec -it volume-pod -c tomcat -- ls /usr/local/tomcat/logs
#lubectl exec -it volume-pod -c tomcat -- tail /usr/local/tomcat/logs/ctalima.2017-07-30.log
5. Pod的配置管理
在大规模容器集群的环境中,对多个容器进行不同的配置将变得非常复杂,kubernetes1.2版本后提供一种同一的集群配置管理方案--ConfigMap
1)ConfigMap:容器应用的配置管理
ConfigMap典型用法如下:
a)生成为容器内的环境变量
b)设置容器启动命令的启动参数(需要设置为环境变量)
c)以volume的形式挂载为容器内部的文件或者目录
可以通过yaml配置文件或者直接使用kubectl create configmap命令的方式来创建ConfigMap
2)ConfigMap的创建:yaml文件方式
文件cm-appvars.yaml描述了将几个应用所需的变量定义为ConfigMap的用法:
cm-appvars.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appvars
data:
apploglevel: info
appdatadir: /var/data
执行kubectl create创建:
#kubectl create -f cm-appvars.yaml
查看Configmap
#kubectl get configmap
NAME |DATA |AGE
cm-appvars |2 |3s
#kubectl describe configmap cm-appvars
#kubectl get configmap cm-appvars -o yaml
3)ConfigMap的创建:kubectl命令行方式
其他方式参考
http://www.cnblogs.com/ilinuxer/p/6629228.html
http://www.cnblogs.com/breezey/p/6582082.html
http://rootsongjc.github.io/blogs/kubernetes-configmap-introduction/?utm_source=tuicool&utm_medium=referral
4)ConfigMap的创建:环境变量方式
5)ConfigMap的创建:volumeMount模式
6)使用ConfigMap的限制条件
configMap必须在Pod之前创建
ConfigMap也可以定义为属于某个Namespace,只有处于相同Namespaces中的Pod可以引用它
ConfigMap中的配额管理还未能实现
kubectl只支持可以被API Server管理的Pod使用。
在Pod对ConfigMap进行挂载操作时,目录中将包含ConfigMap定义的每个item,如果目录下原先还有其他文件,则容器内的该目录将会被挂载的ConfigMap进行覆盖。如果应用程序需要保留原来的其他文件,则需要进行额外的处理。通过将ConfigMap挂载到容器内部的临时目录,在通过启动脚本将配置文件复制或者链接(cp或link)到应用所用的实际配置目录下。
6. Pod生命周期和重启策略
Pod在整个生命周期过程中被系统定义为各种状态,熟悉Pod的各种状态对于我们理解如何设置Pod的调度策略、重启策略是很有必要的。
Pod的重启策略包括Always、OnFailure和Never,默认值为Always
Always:当容器失效时,由kubelet自动重启该容器
OnFailure:当容器终止运行且退出不为0时,由kubelet自动重启该容器
Never:无论容器运行状态如何,kubelet都不会重启该容器
kubelet重启失效容器的时间间隔以sync-frequency乘以2n计算,例如1、2、4、8倍等,最长延时5分钟,并且在成功重启后的10分钟后重置该时间。
Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、
job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下:
RC和DaemonSet:必须设置为Always,需要保证该容器持续运行
Job:OnFailure或Never,确保容器执行完成后不再重启
kubelet:在Pod失效时自动重启它,无论RestartPolicy设置什么值,并且也不会对Pod进行健康检查
7.Pod健康检查
对Pod的健康状态检查可以通过两类探针来检查:LivenessProbe和ReadinessProbe
LivenessProbe探针:用于判断容器是否存活(running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做响应的处理。如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivemessProbe探针返回的值永远是“Success”
ReadinessProbe:用于判断容器是否启动完成(ready状态),可以接收请求,如果ReadinessProbe探针检测到失败,则Pod的状态将被修改,Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的Endpoint。
kubelet定期执行LivenessProbe探针来诊断容器的健康状态。LivenessProbe有一下三种实现方式。
(1)ExecAction
(2)TCPSocketAction
(3)HTTPGetAction
8. Pod调度
在kubernetes系统中,Pod在大部分场景下都只是容器的载体而已,通常需要通过RC、Deployment、
DaemonSet、Job等对象完成Pod的调度和自动控制功能。
1)RC、Deployment:全自动调度
RC的主要功能之一就是自动部署一个容器应用的多份副本,以及继续监控副本的数量,在集群内始终维持用户指定的副本数量。
a)NodeSelector:定向调度
b)NodeAffinity:亲和性调度
2)DaemonSet:特定场景调度
DaemonSet是kubernetes1.2版本新增的一种资源对象,用于管理在集群中每个Node上仅运行一份Pod的副本实例。
DaemonSet的Pod调度策略与RC类似,除了使用系统内置的算法在每台Node上进行调度,也可以在Pod的定义中使用NodeSelector或NodeAffinity来指定满足条件的Node范围进行调度。
3)Job:批处理调度
kubernetes从1.2版本开始支持批处理类型的应用,我们可以通过kubernetes Job资源对象来定义并启动一个批处理任务。批处理任务通常并行启动多个计算进程去处理一批工作项,处理完成后,整个批处理任务结束。
按照批处理任务实现方式的不同,分为:
Job Template Expansion模式
Queue with Pod Per Work Item模式
Queue with Variable Pod Count模式
kubernetes将Job分以下三种类型。
1)Non-parallel Jobs
2)Parallel Jobs with a fixed completion count
3)Parallel Jobs with a work queue
9. Pod的扩容和缩容
在实际生产系统中,我们经常会遇到某个服务需要扩容的场景,也可能会遇到由于资源紧张或者工作负载降低而需要减少服务实例数量的场景。此时我们可以利用RC的Scale机制来完成这些工作。以redis-slave RC为例,已定义的最初副本数量为2,通过kubectl scale命令可以将redis-slave RC控制的Pod副本数量从初始的2更新为3:
#kubectl scale rc redis-slave --replicas=3
将--replicas设置为比当前Pod副本数量更小的数字,系统将会“kill掉”一些运行中的容器,以实现应用集群缩容:
#kubectl scale rc redis-slave --replicas=1
除了scale方式,还有一种Horizontal Pod Autoscaler(HPA)方式
10. Pod滚动升级
当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有Pod,然后重新拉取镜像并启动,如果集群规模比较大,则这个工作就变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的服务不可用。
滚动升级通过执行kubectl rolling-updata命令一键完成,该命令创建一个新的RC,然后自动控制就得RC中的Pod副本的数量逐渐减少到0,同时新的RC中的Pod副本的数量从0逐步增加到目标值,最终实现了Pod的升级。需要注意的是,系统要求新的RC需要与旧的RC在相同的命名空间(Namespace)内,不能吧别人的资产偷偷的转移到自家名下。
需要注意:
(1)RC的名字不能与旧的RC名字相同
(2)在Selector中应至少有一个Label与旧的RC的label不同,以标示其为新的RC。
运行kubectl rolling-update redis-master -f redis-masterController-v2.yaml等所有新的Pod启动完成后,旧的Pod也被全部销毁,这样就完成了容器集群的更新工作。
另一种方法,不用配置文件,直接用kubectl rolling-update命令,加上--image参数指定新版镜像名称来完成Pod的滚动升级:
#kubectl rolling-update redis-master --image=redis-master:2.0
更新后查看RC
#kubectl get rc
如果在更新的过程中发现配置有误,用户可以中断更新操作,并通过执行kubectl rolling-update-rollback完成Pod版本的回滚:
#kubectl rolling-update redis-master --image=kubeguide/redis-master:2.0 --rollback
就可以恢复到更新前的版本了。