Kubernetes系统常见运维技巧
mhr18 2025-04-24 04:43 24 浏览 0 评论
本文节选自龚正等编著的《Kubernetes权威指南》,该节主要对常用的Kubernetes系统运维操作和技巧进行详细说明。
Node的隔离和恢复
在硬件升级、硬件维护等情况下,我们需要将某些Node进行隔离,脱离Kubernetes集群的调度范围。Kubernetes提供了一种机制,既可以将Node纳入调度范围,也可以将Node脱离调度范围。
创建配置文件unschedule_node.yaml,在spec部分指定unschedulable为true:
apiVersion: v1kind: Nodemetadata: name: kubernetes-minion1 labels: kubernetes.io/hostname: kubernetes-minion1spec: unschedulable: true
然后,通过kubectl replace命令完成对Node状态的修改:
$ kubectl replace -f unschedule_node.yaml nodes/kubernetes-minion1
查看Node的状态,可以观察到在Node的状态中增加了一项SchedulingDisabled:
$ kubectl get nodes NAME LABELS STATUS kubernetes-minion1 kubernetes.io/hostname=kubernetes-minion1 Ready, SchedulingDisabled
对于后续创建的Pod,系统将不会再向该Node进行调度。
另一种方法是不使用配置文件,直接使用kubectl patch命令完成:
$ kubectl patch node kubernetes-minion1 -p '{"spec":{"unschedulable":true}}'
需要注意的是,将某个Node脱离调度范围时,在其上运行的Pod并不会自动停止,管理员需要手动停止在该Node上运行的Pod。
同样,如果需要将某个Node重新纳入集群调度范围,则将unschedulable设置为false,再次执行kubectl replace或kubectl patch命令就能恢复系统对该Node的调度。
Node的扩容
在实际生产系统中会经常遇到服务器容量不足的情况,这时就需要购买新的服务器,然后将应用系统进行水平扩展来完成对系统的扩容。
在Kubernetes集群中,对于一个新Node的加入是非常简单的。可以在Node节点上安装Docker、Kubelet和kube-proxy服务,然后将Kubelet和kube-proxy的启动参数中的Master URL指定为当前Kubernetes集群Master的地址,最后启动这些服务。基于Kubelet的自动注册机制,新的Node将会自动加入现有的Kubernetes集群中,如图1所示。
图1 新节点自动注册完成扩容
Kubernetes Master在接受了新Node的注册之后,会自动将其纳入当前集群的调度范围内,在之后创建容器时,就可以向新的Node进行调度了。
通过这种机制,Kubernetes实现了集群的扩容。
Pod动态扩容和缩放
在实际生产系统中,我们经常会遇到某个服务需要扩容的场景,也可能会遇到由于资源紧张或者工作负载降低而需要减少服务实例数的场景。此时我们可以利用命令kubectl scale rc来完成这些任务。以redis-slave RC为例,已定义的最初副本数量为2,通过执行下面的命令将redis-slave RC控制的Pod副本数量从初始的2更新为3:
$ kubectl scale rc redis-slave --replicas=3 scaled
执行kubectl get pods命令来验证Pod的副本数量增加到3:
$ kubectl get pods NAME READY STATUS RESTARTS AGE redis-slave-4na2n 1/1 Running 0 1h redis-slave-92u3k 1/1 Running 0 1h redis-slave-palab 1/1 Running 0 2m
将–replicas设置为比当前Pod副本数量更小的数字,系统将会“杀掉”一些运行中的Pod,即可实现应用集群缩容:
$ kubectl scale rc redis-slave --replicas=1scaled$ kubectl get podsNAME READY STATUS RESTARTS AGEredis-slave-4na2n 1/1 Running 0 1h
更新资源对象的Label
Label(标签)作为用户可灵活定义的对象属性,在已创建的对象上,仍然可以随时通过kubectl label命令对其进行增加、修改、删除等操作。
例如,我们要给已创建的Pod“redis-master-bobr0”添加一个标签role=backend:
$ kubectl label pod redis-master-bobr0 role=backend
查看该Pod的Label:
$ kubectl get pods -LroleNAME READY STATUS RESTARTS AGE ROLE redis-master-bobr0 1/1 Running 0 3m backend
删除一个Label,只需在命令行最后指定Label的key名并与一个减号相连即可:
$ kubectl label pod redis-master-bobr0 role-
修改一个Label的值,需要加上–overwrite参数:
$ kubectl label pod redis-master-bobr0 role=master --overwrite
将Pod调度到指定的Node
我们知道,Kubernetes的Scheduler服务(kube-scheduler进程)负责实现Pod的调度,整个调度过程通过执行一系列复杂的算法最终为每个Pod计算出一个最佳的目标节点,这一过程是自动完成的,我们无法知道Pod最终会被调度到哪个节点上。有时我们可能需要将Pod调度到一个指定的Node上,此时,我们可以通过Node的标签(Label)和Pod的nodeSelector属性相匹配,来达到上述目的。
首先,我们可以通过kubectl label命令给目标Node打上一个特定的标签,下面是此命令的完整用法:
kubectl label nodes <node-name> <label-key>=<label-value>
这里,我们为kubernetes-minion1节点打上一个zone=north的标签,表明它是“北方”的一个节点:
$ kubectl label nodes kubernetes-minion1 zone=north NAME LABELS STATUS kubernetes-minion1 kubernetes.io/hostname=kubernetes-minion1,zone=north Ready
上述命令行操作也可以通过修改资源定义文件的方式,并执行kubectl replace -f xxx.yaml命令来完成。
然后,在Pod的配置文件中加入nodeSelector定义,以
redis-master-controller.yaml为例:
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 nodeSelector: zone: north
运行kubectl create -f命令创建Pod,scheduler就会将该Pod调度到拥有zone=north标签的Node上去。
使用kubectl get pods -o wide命令可以验证Pod所在的Node:
# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE NODE redis-master-f0rqj 1/1 Running 0 19s kubernetes-minion1
如果我们给多个Node都定义了相同的标签(例如zone=north),则scheduler将会根据调度算法从这组Node中挑选一个可用的Node进行Pod调度。
这种基于Node标签的调度方式灵活性很高,比如我们可以把一组Node分别贴上“开发环境”“测试验证环境”“用户验收环境”这三组标签中的一种,此时一个Kubernetes集群就承载了3个环境,这将大大提高开发效率。
需要注意的是,如果我们指定了Pod的nodeSelector条件,且集群中不存在包含相应标签的Node时,即使还有其他可供调度的Node,这个Pod也最终会调度失败。
应用的滚动升级
当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有Pod,然后重新拉取镜像并启动。如果集群规模比较大,则这个工作就变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的服务不可用。Kubernetes提供了rolling-update(滚动升级)功能来解决上述问题。
滚动升级通过执行kubectl rolling-update命令一键完成,该命令创建了一个新的RC,然后自动控制旧的RC中的Pod副本数量逐渐减少到0,同时新的RC中的Pod副本数量从0逐步增加到目标值,最终实现了Pod的升级。需要注意的是,系统要求新的RC需要与旧的RC在相同的命名空间(Namespace)内,即不能把别人的资产偷偷转移到自家名下。
以redis-master为例,假设当前运行的redis-master Pod是1.0版本,则现在需要升级到2.0版本。
创建
redis-master-controller-v2.yaml的配置文件如下:
apiVersion: v1 kind: ReplicationController metadata: name: redis-master-v2 labels: name: redis-master version: v2 spec: replicas: 1 selector: name: redis-master version: v2 template: metadata: labels: name: redis-master version: v2 spec: containers: - name: master image: kubeguide/redis-master:2.0 ports: - containerPort: 6379
在配置文件中有几处需要注意:
(1)RC的名字(name)不能与旧的RC的名字相同;
(2)在selector中应至少有一个Label与旧的RC的Label不同,以标识其为新的RC。
本例中新增了一个名为version的Label,以与旧的RC进行区分。
运行kubectl rolling-update命令完成Pod的滚动升级:
kubectl rolling-update redis-master -f redis-master-controller-v2.yaml
Kubectl的执行过程如下:
Creating redis-master-v2At beginning of loop: redis-master replicas: 2, redis-master-v2 replicas: 1Updating redis-master replicas: 2, redis-master-v2 replicas: 1At end of loop: redis-master replicas: 2, redis-master-v2 replicas: 1At beginning of loop: redis-master replicas: 1, redis-master-v2 replicas: 2Updating redis-master replicas: 1, redis-master-v2 replicas: 2At end of loop: redis-master replicas: 1, redis-master-v2 replicas: 2At beginning of loop: redis-master replicas: 0, redis-master-v2 replicas: 3Updating redis-master replicas: 0, redis-master-v2 replicas: 3At end of loop: redis-master replicas: 0, redis-master-v2 replicas: 3Update succeeded. Deleting redis-masterredis-master-v2
等所有新的Pod启动完成后,旧的Pod也被全部销毁,这样就完成了容器集群的更新。
另一种方法是不使用配置文件,直接用kubectl rolling-update命令,加上–image参数指定新版镜像名称来完成Pod的滚动升级:
kubectl rolling-update redis-master --image=redis-master:2.0
与使用配置文件的方式不同,执行的结果是旧的RC被删除,新的RC仍将使用旧的RC的名字。
Kubectl的执行过程如下:
Creating redis-master-ea866a5d2c08588c3375b86fb253db75At beginning of loop: redis-master replicas: 2, redis-master-ea866a5d2c08588c 3375b86fb253db75 replicas: 1Updating redis-master replicas: 2, redis-master-ea866a5d2c08588c3375b86fb253db 75 replicas: 1At end of loop: redis-master replicas: 2, redis-master-ea866a5d2c08588c3375b86fb 253db75 replicas: 1At beginning of loop: redis-master replicas: 1, redis-master-ea866a5d2c08588c 3375b86fb253db75 replicas: 2Updating redis-master replicas: 1, redis-master-ea866a5d2c08588c3375b86fb 253db75 replicas: 2At end of loop: redis-master replicas: 1, redis-master-ea866a5d2c08588c3375b86fb 253db75 replicas: 2At beginning of loop: redis-master replicas: 0, redis-master-ea866a5d2c08588c 3375b86fb253db75 replicas: 3Updating redis-master replicas: 0, redis-master-ea866a5d2c08588c3375b86fb253db 75 replicas: 3At end of loop: redis-master replicas: 0, redis-master-ea866a5d2c08588c3375b86fb 253db75 replicas: 3Update succeeded. Deleting old controller: redis-masterRenaming redis-master-ea866a5d2c08588c3375b86fb253db75 to redis-masterredis-master
可以看到,Kubectl通过新建一个新版本Pod,停掉一个旧版本Pod,逐步迭代来完成整个RC的更新。
更新完成后,查看RC:
$ kubectl get rc CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS redis-master master kubeguide/redis-master:2.0 deployment= ea866a5d2c08588c3375b86fb253db75,name=redis-master,version=v1 3
可以看到,Kubectl给RC增加了一个key为“deployment”的Label(这个key的名字可通过–deployment-label-key参数进行修改),Label的值是RC的内容进行Hash计算后的值,相当于签名,这样就能很方便地比较RC里的Image名字及其他信息是否发生了变化,它的具体作用可以参见第6章的源码分析。
如果在更新过程中发现配置有误,则用户可以中断更新操作,并通过执行Kubectl rolling-update –rollback完成Pod版本的回滚:
$ kubectl rolling-update redis-master --image=kubeguide/redis-master:2.0 --rollback Found existing update in progress (redis-master-fefd9752aa5883ca4d53013a7b 583967), resuming.Found desired replicas.Continuing update with existing controller redis-master.At beginning of loop: redis-master-fefd9752aa5883ca4d53013a7b583967 replicas: 0, redis-master replicas: 3Updating redis-master-fefd9752aa5883ca4d53013a7b583967 replicas: 0, redis-master replicas: 3At end of loop: redis-master-fefd9752aa5883ca4d53013a7b583967 replicas: 0, redis-master replicas: 3Update succeeded. Deleting redis-master-fefd9752aa5883ca4d53013a7b583967redis-master
到此,可以看到Pod恢复到更新前的版本了。
Kubernetes集群高可用方案
Kubernetes作为容器应用的管理中心,通过对Pod的数量进行监控,并且根据主机或容器失效的状态将新的Pod调度到其他Node上,实现了应用层的高可用性。针对Kubernetes集群,高可用性还应包含以下两个层面的考虑:etcd数据存储的高可用性和Kubernetes Master组件的高可用性。
1.etcd高可用性方案
etcd在整个Kubernetes集群中处于中心数据库的地位,为保证Kubernetes集群的高可用性,首先需要保证数据库不是单故障点。一方面,etcd需要以集群的方式进行部署,以实现etcd数据存储的冗余、备份与高可用性;另一方面,etcd存储的数据本身也应考虑使用可靠的存储设备。
etcd集群的部署可以使用静态配置,也可以通过etcd提供的REST API在运行时动态添加、修改或删除集群中的成员。本节将对etcd集群的静态配置进行说明。关于动态修改的操作方法请参考etcd官方文档的说明。
首先,规划一个至少3台服务器(节点)的etcd集群,在每台服务器上安装好etcd。
部署一个由3台服务器组成的etcd集群,其配置如表1所示,其集群部署实例如图2所示。
表1 etcd集群的配置
图2 etcd集群部署实例
# [member]ETCD_NAME=etcd1 #etcd实例名称ETCD_DATA_DIR="/var/lib/etcd/etcd1" #etcd数据保存目录ETCD_LISTEN_PEER_URLS="http://10.0.0.1:2380" #集群内部通信使用的URLETCD_LISTEN_CLIENT_URLS="http://10.0.0.1:2379" #供外部客户端使用的URL……#[cluster]ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.1:2380" #广播给集群内其他成员使用的URLETCD_INITIAL_CLUSTER="etcd1=http://10.0.0.1:2380,etcd2=http://10.0.0.2:2380, etcd3=http://10.0.0.3:2380" #初始集群成员列表ETCD_INITIAL_CLUSTER_STATE="new" #初始集群状态,new为新建集群ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" #集群名称ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.1:2379" #广播给外部客户端使用的URL
启动etcd1服务器上的etcd服务:
$ systemctl restart etcd
启动完成后,就创建了一个名为etcd-cluster的集群。
etcd2和etcd3为加入etcd-cluster集群的实例,需要将其
ETCD_INITIAL_CLUSTER_STATE设置为“exist”。etcd2的完整配置如下(etcd3的配置略):
# [member]ETCD_NAME=etcd2 #etcd实例名称ETCD_DATA_DIR="/var/lib/etcd/etcd2" #etcd数据保存目录ETCD_LISTEN_PEER_URLS="http://10.0.0.2:2380" #集群内部通信使用的URLETCD_LISTEN_CLIENT_URLS="http://10.0.0.2:2379" #供外部客户端使用的URL……#[cluster]ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.2:2380" #广播给集群内其他成员使用的URLETCD_INITIAL_CLUSTER="etcd1=http://10.0.0.1:2380,etcd2=http://10.0.0.2:2380,etcd3=http://10.0.0.3:2380" #初始集群成员列表ETCD_INITIAL_CLUSTER_STATE="exist" # existing表示加入已存在的集群ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" #集群名称ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.2:2379" #广播给外部客户端使用的URL
启动etcd2和etcd3服务器上的etcd服务:
$ systemctl restart etcd
启动完成后,在任意etcd节点执行etcdctl cluster-health命令来查询集群的运行状态:
$ etcdctl cluster-healthcluster is healthy member ce2a822cea30bfca is healthy member acda82ba1cf790fc is healthy member eba209cd0012cd2 is healthy
在任意etcd节点上执行etcdctl member list命令来查询集群的成员列表:
$ etcdctl member list ce2a822cea30bfca: name=default peerURLs=http://10.0.0.1:2380,http://10.0.0.1: 7001 clientURLs=http://10.0.0.1:2379,http://10.0.0.1:4001acda82ba1cf790fc: name=default peerURLs=http://10.0.0.2:2380,http://10.0.0.2: 7001 clientURLs=http://10.0.0.2:2379,http://10.0.0.2:4001eba209cd40012cd2: name=default peerURLs=http://10.0.0.3:2380,http://10.0.0.3: 7001 clientURLs=http://10.0.0.3:2379,http://10.0.0.3:4001
至此,一个etcd集群就创建成功了。
以kube-apiserver为例,将访问etcd集群的参数设置为:
--etcd-servers=http://10.0.0.1:4001,http://10.0.0.2:4001,http://10.0.0.3:4001
在etcd集群成功启动之后,如果需要对集群成员进行修改,则请参考官方文档的详细说明:点击此处
对于etcd中需要保存的数据的可靠性,可以考虑使用RAID磁盘阵列、高性能存储设备、NFS网络文件系统,或者使用云服务商提供的网盘系统等来实现。
2.Kubernetes Master组件的高可用性方案
在Kubernetes体系中,Master服务扮演着总控中心的角色,主要的三个服务kube-apiserver、kube-controller-mansger和kube-scheduler通过不断与工作节点上的Kubelet和kube-proxy进行通信来维护整个集群的健康工作状态。如果Master的服务无法访问到某个Node,则会将该Node标记为不可用,不再向其调度新建的Pod。但对Master自身则需要进行额外的监控,使Master不成为集群的单故障点,所以对Master服务也需要进行高可用方式的部署。
以Master的kube-apiserver、kube-controller-mansger和kube-scheduler三个服务作为一个部署单元,类似于etcd集群的典型部署配置。使用至少三台服务器安装Master服务,并且使用Active-Standby-Standby模式,保证任何时候总有一套Master能够正常工作。
所有工作节点上的Kubelet和kube-proxy服务则需要访问Master集群的统一访问入口地址,例如可以使用pacemaker等工具来实现。图3展示了一种典型的部署方式。
图3 Kubernetes Master高可用部署架构
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)