4.3 常用运维技巧集锦
4.3.1 Node的隔离和恢复
有些情况下我们需要将某些Node进行隔离,脱离K8S的调度范围,在spec中可以指定参数unschedulable: true
来实现。
apiVersion: v1
kind: Node
metadata:
name: kubernetes-minion1
lables:
kubernetes.io/hostname: kubernetes-minion1
spec:
unschedulable
使用kubectl replace命令完成对Node状态的修改:
kubectl replace -f unschedule_node.yaml
需要注意的是,将某个Node脱离调度范围时,在该节点运行的Pod不会自动停止。
4.3.2 Node的扩容
在K8S集群中,在需要新加入的节点上安装Docker、Kubelet和kube-proxy服务,然后将Kubelet和kube-proxy的启动参数中的Master URL指定为当前K8S集群Master的地址,最后启动这些服务。基于Kubelet的自动注册机制,新的Node将会自动加入现有的K8S集群中。K8S Master在接受了新的Node的注册后,会自动将其纳入当前集群的调度范围内。
4.3.3 Pod动态扩容和缩放
通过kubectl scale rc <name> --replicas=<number>
来实现。如果运行的Pod小于number,则会增加Pod,如果运行的Pod大于number,则会终止一些运行中的Pod。
[root@hdss7-21 redis]# kubectl get po
NAME READY STATUS RESTARTS AGE
redis-slave-qfrk5 1/1 Running 0 97s
redis-slave-vbft8 1/1 Running 0 97s
Pod扩容
[root@hdss7-21 redis]# kubectl scale rc redis-slave --replicas=3
replicationcontroller/redis-slave scaled
[root@hdss7-21 redis]# kubectl get po
NAME READY STATUS RESTARTS AGE
redis-slave-lpsgm 0/1 ContainerCreating 0 3s
redis-slave-qfrk5 1/1 Running 0 2m49s
redis-slave-vbft8 1/1 Running 0 2m49s
pod缩容
[root@hdss7-21 redis]# kubectl scale rc redis-slave --replicas=1
replicationcontroller/redis-slave scaled
[root@hdss7-21 redis]# kubectl get po
NAME READY STATUS RESTARTS AGE
redis-slave-lpsgm 1/1 Terminating 0 78s
redis-slave-qfrk5 1/1 Terminating 0 4m4s
redis-slave-vbft8 1/1 Running 0 4m4s
[root@hdss7-21 redis]# kubectl get po
NAME READY STATUS RESTARTS AGE
redis-slave-vbft8 1/1 Running 0 4m55s
4.3.4 更新资源对象的Lable
Lable作为用户可灵活定义的对象属性,在对已创建的对象上,仍然可以随时通过kubectl label命令对其进行增删改查等操作。
[root@hdss7-21 redis]# kubectl label pod redis-slave-vbft8 role=backend
pod/redis-slave-vbft8 labeled
查看pod标签
[root@hdss7-21 redis]# kubectl get po -Lrole
NAME READY STATUS RESTARTS AGE ROLE
redis-slave-vbft8 1/1 Running 0 16m backend
删除pod标签
[root@hdss7-21 redis]# kubectl label pod redis-slave-vbft8 role-
pod/redis-slave-vbft8 labeled
[root@hdss7-21 redis]# kubectl get po -Lrole
NAME READY STATUS RESTARTS AGE ROLE
redis-slave-vbft8 1/1 Running 0 18m
4.3.5 将Pod调度到指定的Node
首先,我们可以kubectl给node打上一个特定的标签:
kubectl label nodes <node-name> <label-key>=<label-value>
kubectl label nodes kubernetes-minimon1 zone=north
然后以redis-master-controller.yaml为例,在配置文件中加入nodeSelector定义
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 2
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: redis
ports:
- containerPort: 6379
# 看这里
nodeSelector:
zone: north
通过这样,可以将不同的node贴上不同的标签,比如开发环境、测试环境和生产环境等。
注意:如果在pod中设置了nodeSelector,但是所有node中都不存在有这个标签的节点,即使有其他可用的node,也会调度失败。
4.3.6 应用滚动升级
K8S提供了rolling-update来实现滚动升级。
使用配置文件
使用命令:
kubectl rolling-update
该命令创建了一个新的RC,然后自动将旧的RC中的Pod副本数减少到0,同时新的RC中的Pod副本数从0逐步增加到目标值。
在这个过程中需要注意的是:
- 新的RC需要与旧的RC在相同Namespace中。
- RC的名字不能与旧的RC名字相同。
- 在selector中应至少有一个Label与旧的Label不同,以标识其为新的RC。
直接使用命令
使用kubectl rolling-update
再加上--image
参数指定新版镜像名称来完成Pod的滚动升级。
4.3.7 K8S集群高可用方案
主要包括两方面的高可用:
- etcd
- K8S Master组件
1、etcd高可用性方案
etcd在整个集群中处于中心数据库的地位,为保证K8S集群的高可用性,首先需要保证数据库不是单点,另一方面,etcd存储的数据本身也应该考虑使用可靠的存储设备。
2、K8S Master组件高可用性方案
在K8S集群中,Master服务扮演着总控中心的角色,主要的三个服务kube-apiserver、kube-controller-manager和kube-scheduler通过不断与工作节点上的Kubelet和kube-proxy进行通信,来维护整个集群的健康工作状态。如果Master的服务无法访问到某个Node,则会将该Node标记为不可用,不再向其调度新建的Pod。但对Master自身则需要进行额外的监控,使Master不成为集群的单故障点,所以对Master服务也需要进行高可用方式的部署。
4.4 资源配额管理
目前容器支持CPU和内存两类资源的配额限制。
4.4.1 指定容器配额
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 1
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: kubeguide/redis-master
ports:
- containerPort: 6379
# 资源配额限制
resources:
limits:
cpu: 0.5
memory: 128Mi
CPU限制计算方法可参考官网解释,不是通过单纯的字面意思来计算。
如果一个容器在运行过程中超出了内存配额,那么容器可能会被“杀掉”然后重新启动,因此,需要准确评估容器所需内存大小。而超出CPU限制而不会被强行“杀掉”。
更多底层知识请查看Linux cgroup方面的内容。
4.2.2 全局默认配额
除了通过RC文件中给指定的容器增加配额参数,还可以通过创建LimitRange对象来定义一个全局默认的配额模板。这个默认配额模板回加载到集群中的每个Pod及容器上。
LimitRange对象可以同时在Pod和Container两个级别上对资源配额进行管理。
apiVersion: v1
kind: LimitRange
metadata:
name: limit-range-1
spec:
limits:
- type: "Pod"
max:
cpu: "2"
memory: 1Gi
min:
cpu: 250m
memory: 32Mi
- type: "Container"
max:
cpu: "2"
memory: 1Gi
min:
cpu: 250m
memory: 32Mi
default:
cpu: 250m
memory: 64Mi
LimitRange是与Namespace捆绑的,每个Namespace都可以关联一个不同的LimitRange作为其全局默认配额配置。在创建LimitRange时可以在命令行以指定--namespace=命名空间
的方式关联到指定的Namespace上,也可以在定义文件中直接指定namespace:
apiVersion: v1
kind: LimitRange
metadata:
name: limit-range-1
# 指定名称空间
namespace: development
spec:
limits:
- type: "Container"
default:
cpu: 250m
memory: 64Mi
4.4.3 多租户配额管理
多租户在K8S中以Namespace来体现,这里的多租户可以是多个用户、多个业务系统或者相互隔离的多种作业环境。一个集群中的资源总是有限的,当这个集群被多个租户的应用同时使用时,就需要将资源配额的管理单元提升到租户级别,只需要在不同租户对应的Namespace上加载对应的ResourceQuota配置即可达到目的。
以开发组和测试组为例,首先创建开发组对应的namespace:
apiVersion: v1
kind: Namespace
metadata:
name: devlopment
然后创建ResourceQuota对象,并指定Namespace:
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-development
namespace: devlopment
spec:
hard:
cpu: "32"
memory: 256Gi
persistentvolumeclaims: "10"
pods: "100"
replicationcontrollers: "50"
resourcequotas: "1"
secrets: "20"
services: "50"
测试组操作同上,只是namespace需要设置为test
。
在创建完ResourceQuota之后,对于所有需要创建的Pod都必须指定具体的资源配额设置,否则,创建Pod回失败。
然后可以使用命令来查看某个租户的配额使用情况:
# kubectl describe resourcequota <quota name> --namespace=<namespace>
kubectl describe resourcequota quota-development --namespace=development
4.5 K8S网络配置方案详解
- 4.5.1 直接路由
- 4.5.2 使用flannel
- 4.5.3 使用Open vSwitch
4.6 K8S集群监控
- kube-ui
- cAdvisor
4.7 Trouble Shooting指导
- 查看K8S对象的当前运行时信息,特别是与对象关联的Event事件。
- 查看对象运行时的数据,排查是否有参数错误、关联错误、状态异常等问题。可能会涉及到多个相关对象的排查。
- 服务/容器的问题,则需要先查看容器和服务的日志,然后再深入容器内部进行排查。
- 对于某些复杂的问题,可能需要结合集群中每个节点上的K8S服务日志来排查。比如Master上的组件日志、节点上的Kubelet、kube-proxy服务日志。
常见问题汇总
Pod Pending状态
- 没有可用的Node以供调度
- 开启了资源配额管理并且当前Pod的目标节点上刚好没有可用资源
Pod状态不是Ready,且重启次数持续增加
- 通常是因为容器的启动命令不能保持在前台运行
4.7.1 对象的Event事件
# kubectl describe po <pod name>
[root@hdss7-21 redis]# kubectl describe po redis-master-qtczc
Name: redis-master-qtczc
Namespace: default
Priority: 0
Node: hdss7-21.host.com/192.168.50.21
Start Time: Wed, 29 Dec 2021 10:13:44 +0800
Labels: name=redis-master
Annotations: <none>
Status: Running
IP: 172.7.21.7
IPs:
IP: 172.7.21.7
Controlled By: ReplicationController/redis-master
# 省略.................
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events: <none>
可以看到有Event相关事件,可以从Event相关事件中查看到某些异常是因何导致的。
4.7.2 容器日志
如果一个Pod中包含多个容器,则需要通过-c
参数指定容器名称进行查看:
kubectl logs <pod name> -c <container name>
4.7.3 K8S系统日志
如果在Linux系统上进行安装,并使用systemd来管理K8S服务,那么systemd的journal就会接管服务程序的输出日志,那么就可以通过使用systemd status或journalctl工具来查看系统服务的日志。
如果不使用systemd系统接管K8S的标准输出,则可以通过其他一些服务的启动参数来指定日志存放目录:
--logtostderr=false # 不输出到stderr
--log-dir=/var/log/kubernetes # 日志存放目录
--v=0 # glog日志级别