pod是k8s集群中的最小调度单元,一个pod中可以有多个容器。k8s引入pod,而不直接对容器进行调度的原因有如下两个:
使用yaml定义一个pod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| apiVersion: v1 kind: pod metadata: name: namespace: labels: key1: value1 key2: value2 spec: volumes: containers: - name: image: ports: - containerPort: env: - name: value: - name: value:
- name: image: ports: - containerPort: env: - name: value: - name: value:
|
定义好一个pod描述之后,就可以使用kubectl create -f xxx.yaml
来创建一个pod
pod的常用操作
查看pod被调度的节点已经pod ip
1
| kubectl -n <namespace> get pod -o wide
|
查看pod的配置
1
| kubectl -n <namespace> get pod <pod name> -o <yaml|json>
|
查看pod的信息及事件
1
| kubectl -n <namespace> describe pod <pod name>
|
进入pod内的容器
1
| kubectl -n <namespace> exec <pod name> -c <container name> -it /bin/bash
|
查看pod内容器日志,显示标准或者错误输出日志
1
| kubectl -n <namespace> logs -f <pod name> -c <container name>
|
更新pod
1
| kubectl apply -f <pod yaml file> # 更新pod是使用更新yaml文件的形式
|
删除pod
1 2
| kubectl delete -f <pod yaml file> # 根据配置文件删除 kubectl -n <namespace> delete pod <pod name> # 根据pod name删除
|
Pod健康检查
pod的健康检查由kubelet来进行,pod健康检查有两种机制:
LivenessProbe:存活性探测,用于判断容器是否存活,即pod是否为running状态。如果LivenessProbe探针探测到容器不健康,则kubelet将kill掉容器,并根据容器的重启策略是否重启(如果不配置,默认会进行重启),如果一个容器不包含LivenessProbe探针,则kubelet认为容器的LivenessProbe探针的返回值永远成功,即任务容器是健康的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ... containers: - name: image: livenessProbe: httpGet: path: port: scheme: initialDelaySeconds: periodSeconds: timeoutSeconds: successThreshold: failureThreshold:
|
ReadinessProbe:可用性探测,用于判断容器是否正常提供服务,即容器的Ready是否为True,是否可以接收请求。如果ReadinessProbe探测失败,则容器的ready将为False,Endpoint Controller控制器会将此Pod的Endpoint从对应的service的Endpoint列表中移除,不再将任何请求调度到此Pod上,直到下次探测成功。
1 2 3 4 5 6 7 8 9 10 11 12 13
| ... containers: - name: image: readinessProbe: httpGet: path: port: scheme: initialDelaySeconds: periodSeconds: timeoutSeconds: ...
|
对于同一个容器,两种健康检查可以同时设置。
重启策略
Pod的重启策略应用于Pod内的所有容器,并且仅在Pod所处的Node上由Kubelet进行判断和重启操作。当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作。Pod的重启策略包括Always、OnFailure和Never,默认值为Always。
* Always:当容器进程退出后,由kubelet自动重启该容器
* OnFailure:当容器进程终止运行且退出码不为0时,由kubelet自动重启该容器
* Never:不论容器运行状态如何,kubelet都不会重启该容器
1 2 3 4
| ... spec: restartPolicy: OnFailure containers:
|
# 镜像拉取策略
有如下几种镜像拉取策略:
* Always:总是拉取镜像,即使本地有镜像也从镜像仓库拉取
* IfNotPresent:本地有则使用本地镜像,本地没有则去仓库拉取,默认的镜像拉取策略
* Never:只使用本地镜像,本地没有则报错
1 2 3 4 5 6
| ... spec: containers: - name: myblog image: imagePullPolicy: IfNotPresent
|
# Pod资源限制
为了保证充分利用集群资源,且确保重要容器在运行周期内能够分配到足够的资源稳定运行,因此平台需要具备Pod的资源限制的能力。对于一个Pod来说,资源最基础的2个指标就是CPU和内存。资源限制有两种类型:
* requests:容器使用的最小资源要求,作用于schedule阶段,作为容器调度时分配的判断依赖,只有当节点上可分配的资源量>=request时,才允许将容器调度到该节点。requests参数不限制容器的最大可用资源。requests.cpu被转成docker的--cpu-shares参数,与cgroup.cpu.shared功能相同。requests.memory没有对应的docker参数,仅作为k8s调度的依据
* limits:容器使用的最大资源限制,不设置或者设置为0表示对使用的资源不做限制。当pod内存超过limit时,会被oom,当cpu超过limit时,不会被kill,但会被限制不超过limit值(因为cpu的时间片是动态调度)。limits.cpu会被转换成docker的-cpu-quota参数,与cgroup.cpu.cfs\_quota_us功能相同。limits.memory会被转换成docker的-memory参数,用来限制容器使用的最大内存。
1 2 3 4 5 6 7 8 9 10 11 12
| ... spec: containers: - name: image: resources: requests: memory: 100Mi cpu: 500m limits: memory: 500Mi cpu: 2
|
# configMap和secret
configMap和Secret是k8s提供的两种资源类型,它们可以用来实现业务配置的统一管理。一般来说会使用configMap存储一些不包含敏感信息的基本配置,secret用于管理敏感信息配置,例如密码、密钥等。
使用yaml定义一个configMap资源:
1 2 3 4 5 6 7 8
| apiVersion: v1 kind: ConfigMap metadata: name: namespace: data: key1: value1 key2: value2
|
secret有三种类型:
* Service Accout:用来访问k8s API,由k8s 自动创建,并且会自动挂载到pod的/run/secrets/kubernetes.io/serveraccount目录中;
* Opaque:base64编码的Secret,用来存储密码,密钥等
* kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息
1 2 3 4 5 6 7 8 9
| apiVersion: v1 kind: Secret metadata: name: namespace: type: Opaque data: key1: base64_encoded_value1 key2: base64_encoded_value2
|
configMap和secret的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| spec: containers: - name: image: env: - name: env_name_1 valueFrom: secretKeyRef: name: <secret resouce name> key: <secret resouce key> - name: env_name_2 valueFrom: configMapKeyRef: name: <config map resource name> key: <config map resource key>
|
# pod生命周期
一个pod可能处于如下的几种状态
| 状态值 | 描述 |
| ---------------------- | ---------------------------------------- |
| Pending | API Server已经创建该Pod,等待调度器调度 |
| ContainerCreating | 拉取镜像启动容器中 |
| Runing | Pod内容器均已创建,且至少有一个容器处于运行状态、正在启动状态或者正在重启状态 |
| Succeeded \| Completed | 容器内所有容器均已成功执行退出,且不再重启 |
| Failed \| Error | Pod内所有容器均已退出,但至少有一个容器退出为失败状态 |
| CrashLoopBackOff | Pod内容器启动失败,比如配置文件丢失导致进程启动失败 |
| Unknown | 由于某种原因无法获取该Pod的状态,可能由于网络通信不畅导致 |
pod支持两种hook,post-start hook 和pre-stop hook
1 2 3 4 5 6 7 8 9 10 11 12
| ... spec: containers: - name: image: lifecycle: postStart: exec: command: preStop: exec: command:
|
pre-stop hook只有在手动kill掉pod才会触发,如果是Pod自己down掉,则不会触发pre-stop hook
# Pod控制器(workload工作负载)
workload是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试进行重启,当根据重启策略无效时,则会重新新建pod资源。workload有以下几种类型:
* ReplicaSet:pod副本数量,确保pod副本数量符合预期状态,并且支持滚动式自动阔缩容
* Deployment:工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器,支持滚动更新和回滚功能
* DaemonSet:用于确保集群中的每一个节点只运行特定的pod服务,通常用于实现系统级后台服务
* Job:只要完成就立即退出,不需要重启或重建
* Cronjob:周期性任务控制,不需要持续后台运行
* StatefulSet:管理有状态应用
## Deployment
使用yaml定义一个deployment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: apps/v1 kind: Deployment metadata: name: namespace: spec: replicas: 2 selector: matchLabels: podLabelKey1: podLabelValue template: metadata: labels: podLabelKey1: podLabelValue spec: nodeSelector: nodeLabelKey: nodeLabelValue containers: - name: image: env:
|
deployment阔缩容命令:
1
| kubectl -n <namespace> scale deployment <deployment name> --replicas=<n>
|
deployment服务更新(镜像更新)
* 通过yaml配置文件的方式(建议)
1
| kubectl -n <namespace> apply -f <xxx.yaml>
|
* 通过命令行直接更新
1
| kubectl -n <namespace> set image deployment <deployment name> <container name>=<image>
|
deploy服务回滚
回滚只能通过命令行进行回滚,不能通过配置文件进行回滚
* 查看可回滚的历史记录
1
| kubectl -n <namespace> rollout history deployment <deployment name>
|
* 回滚
1
| kubectl -n <namespace> rollout undo deployment <deployment name> --to-revision=<revsion number>
|
### deployment更新(回滚)策略配置
deployment的更新(回滚)是滚动更新(回滚)的,即一次只进行一部分pod更新(回滚),直到所有的pod都完成更新(回滚),deployment的更新(回滚)策略有以下几种可配置项:
* maxSurge:最大激增数,指更新过程中,最多可以比replicas预先设定值多出的pod数量,可以为固定值或百分比,默认为25%,计算时向上取整
* maxUnavailable:指更新过程中,最多有几个pod处于无法服务状态,可以为固定值或百分比,默认为25%,计算时向下取整
deployment更新的底层实现其实是新建了一个ReplicaSet,这个ReplicaSet使用的最新版本的镜像,然后通过调整新ReplicaSet和老ReplicaSet的副本数来实现滚动升级。同时老的ReplicaSet不会立即删除,目的是为了方便回滚。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| apiVersion: apps/v1 kind: Deployment metadata: name: namespace: spec: replicas: 2 selector: matchLabels: podLabelKey1: podLabelValue strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% template: metadata: labels: podLabelKey1: podLabelValue spec: nodeSelector: nodeLabelKey: nodeLabelValue containers: - name: image: env:
|
Service负载均衡之Cluster IP
通过deployment,我们已经可以创建一组Pod来提供具有高可用性的服务,虽然每个Pod都会分配一个单独的Pod IP, 然而却存在如下两个问题:
Services是一组pod服务的抽象,相当于一组pod的load balancer,负责将请求分发到对应的pod。service会有一个IP,一般称为cluster ip,service对象通过selector进行标签选择,找到到对应的pod
使用yaml定义一个service
1 2 3 4 5 6 7 8 9 10 11 12 13
| apiVersion: v1 kind: Service metadata: name: namespace: spec: ports: - port: 80 protocol: TCP targetPort: 8002 selector: podLabelName: podLabelValue type: ClusterIP
|
创建好service后,在集群内部就可以直接使用service name + pod对服务进行访问,因为集群内部的dns会记录相关解析规则
Service负载均衡之NodePort
Cluster IP也是一个虚拟地址,其目的是为了方便集群内部服务直接的通信,只能在k8s集群内部进行访问,如果需要集群外部访问集群内部服务,实现方式之一为使用NodePort方式。NodePort会默认在30000—32767之间,不指定会随机使用其中的一个。
1 2 3 4 5 6 7 8 9 10 11 12 13
| apiVersion: v1 kind: Service metadata: name: namespace: spec: ports: - port: 80 protocol: TCP targetPort: 8002 selector: podLabelName: podLabelValue type: NodePort
|
kube-proxy
kube-proxy运行在每个节点上,监听API Server中服务对象的变化,再通过创建流量路由规则来实现网络的转发。kube-proxy支持三种模式:
User space:让kube-proxy 在用户空间监听一个端口,所有的service都转发到这个端口,然后kube-proxy在内部应用层对其进行转发,所有报文都走一遍用户态,性能不高,在k8s v1.2版本后废弃
Iptables:当前默认模式,完全由iptables来实现,通过各个节点上的iptable规则来实现service的负载均衡,但是随着service数量增大,iptables模式由于线性查找匹配、全量更新等特点,其性能会显著下降
IPVS:与iptables同样基于Netfilter,但是采用的hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能。k8s 1.8版本开始引入,1.11版本开始稳定,需要开启宿主机的ipvs模块
Ingress
对于k8s的service,无论是Cluster-IP还是NodePort的形式,都是四层的负载,集群内的服务如果实现7层的负载均衡,这就需要借助与Ingress。Ingress控制器的实现方式有很多,例如nginx、contour、haproxy,trafik,istio。
ingress-nginx是7层的负载均衡器,根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件。
1 2 3 4 5 6 7 8 9 10 11 12
| apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: spec: rules: - host: http: - paths: / backend: serviceName: <service name> servicePort: <service port>
|
ingress实现逻辑
ingress controller通过api server,监听集群中ingress规则变化
然后读取ingress规则(规则就是写明了哪个域名对应哪个service),按照自定义的规则,生成一段nginx配置
再写到nginx-ingress-contoller的pod里,nginx-ingress-controller的pod里运行着Nginx服务