K8s之Pod学习
1 Pod基本使用1.1 创建一个容器在使用Docker时,可以使用docker run命令创建并启动一个容器。而在Kubernetes系统中对长时间运行容器的要求是:其主程序需要一直在前台执行。对于无法改造为前台执行的应用,可以使用开源工具Supervisor辅助进行前台运行的功能。Pod可以由1个或多个容器组合而成,如下案例Pod只由一个容器组成,配置文件frontend-localredis
1 Pod介绍
1.1 Pod生命周期和重启策略
Pod在整个生命周期中被系统定义为各种状态,熟悉Pod的各种状态对于理解如何设置Pod的调度策略、重启策略是很有必要的。
Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。
当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作。
◎ Always:当容器失效时,由kubelet自动重启该容器。
◎ OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。
◎ Never:不论容器运行状态如何,kubelet都不会重启该容器。
Pod的重启策略与控制方式息息相关,每种控制器对Pod的重启策略要求如下:
◎ RC和DaemonSet:必须设置为Always,需要保证该容器持续运行。
◎ Job:OnFailure或Never,确保容器执行完成后不再重启。
◎ kubelet(管理静态pod):在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查。
1.2 Pod健康检查
Kubernetes 对 Pod 的 健 康 状 态 可 以 通 过 三 类 探 针 来 检 查 :LivenessProbe、ReadinessProbe及StartupProbe。
- LivenessProbe探针:用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。
- ReadinessProbe探针:用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。
- StartupProbe探针:某些应用会遇到启动比较慢的情况,此时ReadinessProbe就不适用了,因为这属于“有且仅有一次”的超长延时,可以通过StartupProbe探针解决该问题。
健康检查实现:
需 要 设 置 initialDelaySeconds 和timeoutSeconds两个参数,它们的含义分别如下:
- initialDelaySeconds:启动容器后进行首次健康检查的等待时间,单位为s。
- timeoutSeconds:健康检查发送请求后等待响应的超时时间,单位为s。当超时发生时,kubelet会认为容器已经无法提供服务,将会重启该容器。
1)ExecAction:在容器内部运行一个命令,如果该命令的返回码为0,则表明容器健康。
在该Pod运行后,将在创建/tmp/health文件10s后删除该文件
2)TCPSocketAction:通过容器的IP地址和端口号执行T?P检查,如果能够建立TCP连接,则表明容器健康。
3)HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。
2 Pod基本使用
2.1 创建容器
在使用Docker时,可以使用docker run命令创建并启动一个容器。而在Kubernetes系统中对长时间运行容器的要求是:其主程序需要一直在前台执行。对于无法改造为前台执行的应用,可以使用开源工具Supervisor辅助进行前台运行的功能。
Pod可以由1个或多个容器组合而成,如下案例Pod只由一个容器组成,配置文件frontend-localredis-pod.yaml的内容如下:
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
另一种场景是,当frontend和redis两个容器应用为紧耦合的关系,并组合成一个整体对外提供服务时,应将这两个容器打包为一个Pod:
apiVersion: v1
kind: Pod
metadata:
name: redis-php
labels:
name: redis-php
spec:
containers:
- name: frontend
image: kubeguide/guestbook-php-frontend:localredis
ports:
- containerPort: 80
- name: redis
image: kubeguide/redis-master
ports:
- containerPort: 6379
kubectl create -f frontend-localredis-pod.yam //创建pod
kubectl get pods // 查看已创建的pod
kubectl describe pod <pod名> //查看具体pod的信息
2.2 静态Pod
静态Pod是由kubelet进行管理的仅存在于特定Node上的Pod。它们不能通过API Server进行管理,无法与ReplicationController、Deployment或者DaemonSet进行关联,并且kubelet无法对它们进行健康检查。
最常见的 Static Pod:
- etcd
- kube-apiserver
- kube-controller-manager
- kube-scheduler
在配置文件/var/lib/kubelet/config.yaml 里找到staticPodPath
在目录 staticPodPath 中放入一个static-web.yaml文件
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
name: static-web
spec:
containers:
- name: static-web
image: nginx
ports:
- name: web
containerPort: 80
重启 kubelet
systemctl stop kubelet
systemctl daemon-reload
systemctl start kubelet
等待一会儿,查看本机中已经启动的容器,可以看到一个Nginx容器已经被kubelet成功创建了出来。
删除该Pod的操作只能将static-web.yaml文件删除。
2.3 Pod配置管理
应用部署的一个最佳实践是将应用所需的配置信息与程序进行分离,这样可以使应用程序被更好地复用。
ConfigMap将应用打包为容器镜像后,可以通过环境变量或者外挂文件的方式在创建容器时进行配置注入。
ConfigMap供容器使用的典型用法如下:
- 生成为容器内的环境变量。
- 设置容器启动命令的启动参数(需设置为环境变量)。
- 以Volume的形式挂载为容器内部的文件或目录。
使用yaml文件创建
cm-appconfigfile.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appconfigfile
data:
key-serverxml: |
<...>
key-logproperity: "..."
kubectl create -f cm-appconfigfile.yaml
kubectl get ConfigMap
kubectl get ConfigMap cm-appconfigfile -o yaml
kubectl describe configmap cm-appconfigfile
通过kubectl命令行方式创建,使用参数--from-file或--from-literal指定内容通过kubectl create configmap创建ConfigMap。
kubectl create configmap -h
kubectl create configmap config-name --from-file=[key-name]=directory或者file
kubectl create configmap config-name --from-literal=key-name=value
kubectl create configmap config-name --from-env-file=envfile
--from-env-file只能跟文件,不能是目录,并且文件里key/value有格式的要求,会做参数的校验。
在Pod“cm-test-pod”的定义中,将ConfigMap“cm-appconfigfile”中的内容以环境变量(APPLOGLEVEL和APPDATADIR)方式设置为容器内部的环境变量,容器的启动命令将显示这两个环境变量的值("env | grep APP"):
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: cm-test
image: busybox
command: [ "/bin/sh", "-c", "env | grep APP" ]
env:
- name: APPLOGLEVEL # 定义环境变量的名称
valueFrom: # key“apploglevel”对应的值
configMapKeyRef:
name: cm-appconfigfile # 环境变量的值取自cm-appconfigfile
key: apploglevel # key为apploglevel
- name: APPDATADIR # 定义环境变量的名称
valueFrom: # key“appdatadir”对应的值
configMapKeyRef:
name: cm-appconfigfile # 环境变量的值取自cm-appconfigfile
key: appdatadir # key为appdatadir
restartPolicy: Never
kubectl create -f cm-test-pod.yaml
kubectl get pods ---show-all
Kubernetes从1.6版本开始,引入了一个新的字段envFrom,实现了在Pod环境中将ConfigMap(也可用于Secret资源对象)中所有定义的key=value自动生成为环境变量:
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: cm-test
image: busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef
name: cm-appconfigfile # 根据cm-appvars中的key=value自动生成环境变量
restartPolicy: Never
2.4 共享Volume
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: logreader
image: logreader
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容器就可以读取其中的文件了。
3 Pod调度
在Kubernetes平台上,我们很少会直接创建一个Pod,在大多数情况下会通过RC、Deployment、DaemonSet、Job等控制器完成对一组Pod副本的创建、调度及全生命周期的自动控制任务。
3.1 Deployment或RC:全自动调度
Deployment或RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量。
3.2 NodeSelector:定向调度
Kubernetes Master上的Scheduler服务(kube-scheduler进程)负责实现Pod的调度,整个调度过程通过执行一系列复杂的算法,最终为每个Pod都计算出一个最佳的目标节点。
而将Pod调度到指定的一些Node上,可以通过Node的标签(Label)和Pod的nodeSelector属性相匹配:
1)首先通过kubectl label命令给目标Node打上一些标签
kubectl label nodes <node-name><label-key>=<label-value>
2)然后,在Pod的定义中加上nodeSelector的设置
apiversion:v2
kind:ReplicationController
metedata:
spec:
replicas:1
spec:
containers:
nodeSelector:
<label-key>=<label-value>
3.3 NodeAffinity:Node亲和性调度
◎ RequiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度Pod到Node上,相当于硬限制。
◎ PreferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上,但并不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。
requiredDuringSchedulingIgnoredDuringExecution:要求只运行在amd64的节点上(beta.kubernetes.io/arch In amd64)。
preferredDuringSchedulingIgnoredDuringExecution:要求尽量运行在磁盘类型为ssd(disk-type In ssd)的节点上。
NodeAffinity语法支持的操作符包括In、NotIn、Exists、DoesNotExist、Gt、Lt;规则设置的注意事项如下:
- 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能最终运行在指定的Node上。
- 如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能匹配成功即可。
- 如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有match?xpressions才能运行该Pod。
3.4 Taints和Tolerations(污点和容忍)
被标记为Taint的节点就是存在问题的节点,比如磁盘要满、资源不足、存在安全隐患要进行升级维护,希望新的Pod不会被调度过来。
kubectl taint nodes <node-name>key=value:NoSchedule
仍需将某些Pod调度到这些节点上时,可以通过使用Toleration属性来实现。
3.5 PodAffinity:Pod亲和与互斥调度策略
相关联的两种或多种Pod是否可以在同一个拓扑域中共存或者互斥,前者被称为Pod Affinity,后者被称为Pod AntiAffinity。
一个拓扑域由一些Node节点组成,这些Node节点通常有相同的地理空间坐标,比如在同一个机架、机房或地区。
1)首先创建一个pod
2)创建一个亲和性pod
3)创建一个互斥pod
3.6 Pod Priority Preemption:Pod优先级调度
Kubernetes会尝试释放目标节点上低优先级的Pod,以腾出空间安置高优先级的Pod,这种调度方式被称为“抢占式调度”。
1)首先,由集群管理员创建PriorityClass,PriorityClass不属于任何命名空间
2)在任意Pod上引用上述Pod优先级类别
3.7 DaemonSet:在每个Node上都调度一个Pod
这种用法适合有这种需求的应用。
◎ 在每个Node上都运行一个GlusterFS存储或者Ceph存储的Daemon进程。
◎ 在每个Node上都运行一个日志采集程序,例如?luentd或者Logstach。
◎ 在每个Node上都运行一个性能监控程序,采集该Node的运行性能数据,例如Prometheus Node Exporter、collectd、New Relic agent或者Ganglia gmond等。
3.8 Cronjob:定时任务
该例子定义了一个名为hello的?ron Job,任务每隔1min执行一次,运行的镜像是busybox,运行的命令是Shell脚本,脚本运行时会在控制台输出当前时间和字符串“Hello from the Kubernetes cluster”。
3.9 自定义调度器
使用自定义的调度器创建pod
附录: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: int
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
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)