k8s各资源介绍应用部署
本文系统地介绍了Kubernetes的核心概念和运维实践,全文提供了大量YAML配置示例和命令行操作,既涵盖了Kubernetes的基础知识,又包含了生产环境中的高级实践,如网络策略、定时任务等,是一份全面的Kubernetes技术参考指南
一、namespace
1、管理namespace资源
namespace资源的名称仅能由字母、数字、下划线、连接线等字符组成。删除namespace资源会级联删除其包含的所有其他资源对象。
2 、切换默认查看命名空间
kubectl config set-context --current --namespace=buke-system
![]()
3、创建
3.1、命令行创建
kubectl create ns test
kubectl create namespace test

3.2、文件创建
apiVersion: v1
kind: Namespace
metadata:
name: test

4、资源限额
requests 是 “调度时的最小需求总和”
limits 是 “运行时的最大使用总和”
单个容器的 requests ≤ limits 且 整体总和不超各自限额
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota
namespace: test
spec:
hard:
limits.cpu: "3"
limits.memory: "2048Mi"
requests.cpu: "1.2"
requests.memory: "1024Mi"


4.1、pod限额


4.2、不限额


二、configmap
1、作用
ConfigMap 的主要作用就是为了让镜像和配置文件解耦,以便实现镜像的可移植性和可复用性
2、应用场景
一种将 configMap 做为存储卷,一种是将configMap 通过 env 中 configMapKeyRef 注入到容器中
3、限制条件
-
ConfigMap 需要在 Pod 启动前创建出来;
-
并且只有当 ConfigMap 和 Pod 处于同一命名空间时,才可以被 Pod 引用;
-
当 Pod 挂载 ConfigMap 绑定的目录时,目录下的目录并不会挂载到 Pod 内,只有目录下的文件会被挂载。
-
ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1MiB。如果你需要保存超出此尺寸限制的数据,可以考虑挂载存储卷或者使用独立的数据库或者文件服务。
4、创建
4.1、文件创建
apiVersion: v1
kind: ConfigMap
metadata:
name: con-env
namespace: test
data:
k1: "v1"
a1: "b1"

4.2、命令行创建
kubectl create configmap test-map --from-literal=q1=12 --from-literal=w1=45 -n test

5、使用案例
5.1、创建configmap
5.2、pod中引用
apiVersion: v1
kind: Pod
metadata:
name: nginx-test
namespace: test
labels:
app: nginx-pod ##标签
spec:
containers:
- name: nginx #容器名称
ports:
- containerPort: 83
hostPort: 83
image: nginx
imagePullPolicy: IfNotPresent #拉取策略
volumeMounts: ##存储挂载
- name: nginx-config ##对应卷名
mountPath: /etc/nginx/conf.d/default.conf #挂载文件
subPath: default.conf #指定键名
volumes: ## 卷定义
- name: nginx-config
configMap:
name: nginx-83

5.3、结果

三、 ingress
1、工作原理
-
用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service
-
Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置
-
Ingress控制器会将生成的Nginx配置写入到一个运行着的Nginx服务中的pod,并动态更新
-
到此为止,其实真正在工作的就是一个Nginx了,内部配置了用户定义的请求转发规则
2、创建
获取ingress-nginx,此使用的是1.12.0版本
主要镜像版本 验证


2.1、NodePort 模式
kubectl -n ingress-nginx edit svc ingress-nginx-controller


创建service与pod
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
spec:
replicas: 1
selector:
matchLabels:
app: nginx-deploy
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:latest
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-deploy
name: nginx-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-deploy
type: ClusterIP

设置 http代理
apiVersion: networking.k8s.io/v1
kind: Ingress # 创建一个类型为Ingress的资源
metadata:
name: nginx-ingress # 这个资源的名字为 nginx-ingress
spec:
ingressClassName: nginx # 使用nginx
rules:
- host: nginx.jx.com # 访问此内容的域名
http:
paths:
- backend:
service:
name: nginx-svc # 对应nginx的服务名字,该规则的namespace必须与service的一致
port:
number: 80 # 访问的端口
path: / # 匹配规则
pathType: Prefix # 匹配类型,这里为前缀匹配


修改hosts文件
针对 ingress 创建在哪个节点上的pod 填写相应的IP



2.2、LoadBalancer模式
kubectl -n ingress-nginx edit svc ingress-nginx-controller

2.2.1、修改ARP模式,启用严格ARP模式 (可选)
# 执行修改操作
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system
#或者
kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f - -n kube-system
#查看修改结果
kubectl edit configmap -n kube-system kube-proxy
-
避免 ARP 冲突
-
确保流量正确分配
-
增强网络安全性和稳定
2.2.2、metallb

kubectl apply -f metallb-native.yaml

2.2.3、创建IP池
cat >IPAddressPool.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: planip-pool #这里与下面的L2Advertisement的ip池名称需要一样
namespace: metallb-system
spec:
addresses:
- 192.168.111.140-192.168.11.170 #自定义ip段
EOF

2.2.4、关联IP池
cat >L2Advertisement.yaml<<EOF
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: planip-pool
namespace: metallb-system
spec:
ipAddressPools:
- planip-pool #这里需要跟上面ip池的名称保持一致
EOF

2.2.5、提交
kubectl apply -f IPAddressPool.yaml
kubectl apply -f L2Advertisement.yaml

2.2.6、添加新规则
kubectl edit ingress


2.2.7、查看分配IP

2.2.8、修改hosts文件

2.2.9、访问



不同域名访问不同应用




四、kube-proxy
4.1、userspace模式
userspace模式下,kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB(LoadBalance,负载均衡)算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。该模式下,kube-proxy充当了一个四层负载均衡器的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低。
4.2、iptables模式
iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。 该模式下kube-proxy不承担四层负载均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。(默认)
4.3、ipvs模式
ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。除此以外,ipvs支持更多的LB算法。 
添加模块
modprobe ip_vs
lsmod | grep ip_vs



修改ipvs模式
kubectl edit cm kube-proxy -n kube-system
kubectl delete pod -l k8s-app=kube-proxy -n kube-system
##删除之前的pod


下载ipvs命令
yum install -y ipvsadm



五 、service资源对象
1、Service类型
| 类型 | 含义 |
|---|---|
| ClusterIP | 意味着服务仅在集群内部可用,只能通过集群IP访问。 |
| ExternalName | 意味着服务仅包含一个对外部名称的引用,Kubedns或等价物将返回作为CNAME记录,不会涉及任何容器的暴露或代理。 |
| LoadBalancer | 意味着服务将通过外部负载均衡器(如果云提供商支持的话)进行暴露,除了NodePort类型之外。 |
| NodePort | 意味着服务将在每个节点的一个端口上进行暴露,除了ClusterIP类型之外。 |
2、Service中的三类IP地址
| IP类型 | 作用 |
|---|---|
| Node IP | 节点IP是Kubernetes集群中每个节点的唯一标识符。它代表了节点的网络接口,用于在集群内部进行通信。节点IP通常是一个私有IP地址范围,用于在集群内部进行通信。节点IP是Service在集群内部提供服务的唯一标识,用于路由流量到指定的Pod。 |
| Pod IP | Pod IP是Kubernetes中每个Pod的唯一标识符。它代表了Pod的网络接口,用于在集群内部进行通信。Pod IP通常是一个私有IP地址范围,用于在集群内部进行通信。Pod IP是Service在集群内部提供服务的唯一标识,用于路由流量到指定的Pod。 |
| Cluster IP | Cluster IP是Kubernetes集群中Service的IP地址。它代表了Service在集群内部提供的服务,用于在集群内部进行通信。Cluster IP通常是一个私有IP地址范围,用于在集群内部进行通信。Cluster IP是Service在集群内部提供服务的唯一标识,用于路由流量到指定的Pod。 |
3、案例
准备

区别访问页面

3.1、ClusterIP类型的Service
对Service的访问被分发到了后端的Pod上去,目前kubernetes提供了两种负载分发策略:
-
如果不定义,默认使用kube-proxy的策略,比如随机、轮询
-
基于客户端地址的会话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个Pod上
创建
在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口

ipvs映射

访问结果

还原
kubectl delete service service-clusterip

3.2 HeadLiness类型的Service
在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询
创建

查看结果
[service-name].[namespace].svc.cluster.local (默认dns生成)
apt update && apt install -y dnsutils
nslookup service-headliness.wezzer.svc.cluster.local

dig @10.96.0.10 service-headliness.wezzer.svc.cluster.local

还原
kubectl delete svc service-headliness

3.3、NodePort类型的Service
在之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上,然后就可以通过NodeIp:NodePort来访问service了。
创建
查看
NodePort 类型的核心特性:在所有节点开放相同端口
NodePort 类型的 Service 会在 Kubernetes 集群的 所有节点(包括 master 和 worker 节点) 上开放一个指定的端口(即 nodePort 字段定义的端口,这里是 30722)。
无论客户端访问集群中的 任意一个节点的 IP:nodePort,Kubernetes 都会通过负载均衡将请求转发到后端关联的 Pod 上(配合 kube-proxy 的转发规则,确保无论访问哪个节点的该端口,都能路由到后端 Pod)。这一设计的目的是 保证外部客户端可以通过集群中任意节点的 IP 访问服务,无需关心具体哪个节点运行着目标 Pod,提高了服务的可用性(例如某个节点故障时,可通过其他节点访问)



访问(伪轮询)



删除
kubectl delete svc service-nodeport

3.4、LoadBalancer类型的Service
LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中
参考 ingress的LoadBalancer模式
3.5、ExternalName类型的Service
ExternalName类型的Service用于引入集群外部的服务,它通过externalName属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了
其他几个都是由外部访问内部 ,只有这个是 内部访问外部
创建

验证
pod中验证

百度服务器的 Host 头校验机制
curl -v -H "Host: www.baidu.com" http://service-externalname.wezzer.svc.cluster.local

六、Deployment资源对象
1、介绍
Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。
典型的应用场景包括:
-
定义Deployment来创建Pod和ReplicaSet
-
滚动升级和回滚应用
-
扩容和缩容
-
暂停和继续Deployment更新
Deployment表示用户对K8S集群的一次更新操作。Deployment是一个比RS( Replica Set, RS) 应用模型更广的 API 对象,可以是创建一个新的服务,更新一个新的服务,也可以是滚动升级一个服务。滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新 RS 中副本数增加到理想状态,将旧RS中的副本数减少到0的复合操作。
这样一个复合操作用一个RS是不好描述的,所以用一个更通用的Deployment来描述。以K8S的发展方向,未来对所有长期伺服型的业务的管理,都会通过Deployment来管理
2、文件详解
apiVersion: apps/v1 #接口版本
kind: Deployment #接口类型
metadata:
name: cango-demo #Deployment名称
namespace: cango-prd #命名空间
labels:
app: cango-demo #标签
spec:
replicas: 3
selector:
matchLabels:
app: cango-demo #匹配模板中label
strategy:
rollingUpdate: ##由于replicas为3,则整个升级,pod个数在2-4个之间
maxSurge: 1 #滚动升级时会先启动1个pod
maxUnavailable: 1 #滚动升级时允许的最大Unavailable的pod个数
template:
metadata:
labels:
app: cango-demo #模板名称必填
sepc: #定义容器模板,该模板可以包含多个容器
containers:
- name: cango-demo1 #镜像名称
image: swr.cn-east-2.myhuaweicloud.com/cango-prd/cango-demo:0.0.1-SNAPSHOT #镜像地址
command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ] #启动命令
args: #启动参数
- '-storage.local.retention=$(STORAGE_RETENTION)'
- '-storage.local.memory-chunks=$(STORAGE_MEMORY_CHUNKS)'
- '-config.file=/etc/prometheus/prometheus.yml'
- '-alertmanager.url=http://alertmanager:9093/alertmanager'
- '-web.external-url=$(EXTERNAL_URL)'
#如果command和args均没有写,那么用Docker默认的配置。
#如果command写了,但args没有写,那么Docker默认的配置会被忽略而且仅仅执行.yaml文件的command(不带任何参数的)。
#如果command没写,但args写了,那么Docker默认配置的ENTRYPOINT的命令行会被执行,但是调用的参数是.yaml中的args。
#如果如果command和args都写了,那么Docker默认的配置被忽略,使用.yaml的配置。
imagePullPolicy: IfNotPresent #如果不存在则拉取
livenessProbe: #表示container是否处于live状态。如果LivenessProbe失败,LivenessProbe将会通知kubelet对应的container不健康了。随后kubelet将kill掉container,并根据RestarPolicy进行进一步的操作。默认情况下LivenessProbe在第一次检测之前初始化值为Success,如果container没有提供LivenessProbe,则也认为是Success;
httpGet:
path: /health #如果没有心跳检测接口就为/
port: 8080
scheme: HTTP
initialDelaySeconds: 60 ##启动后延时多久开始运行检测
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /health #如果没有心跳检测接口就为/
port: 8080
scheme: HTTP
initialDelaySeconds: 30 ##启动后延时多久开始运行检测
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
resources: ##CPU内存限制
requests:
cpu: 2
memory: 2048Mi
limits:
cpu: 2
memory: 2048Mi
env: ##通过环境变量的方式,直接传递pod=自定义Linux OS环境变量
- name: LOCAL_KEY #本地Key
value: value
- name: CONFIG_MAP_KEY #局策略可使用configMap的配置Key,
valueFrom:
configMapKeyRef:
name: special-config #configmap中找到name为special-config
key: special.type #找到name为special-config里data下的key
ports:
- name: http
containerPort: 8080 #对service暴露端口
volumeMounts: #挂载volumes中定义的磁盘
- name: log-cache
mountPath: /tmp/log
- name: sdb #普通用法,该卷跟随容器销毁,挂载一个目录
mountPath: /data/media
- name: nfs-client-root #直接挂载硬盘方法,如挂载下面的nfs目录到/mnt/nfs
mountPath: /mnt/nfs
- name: example-volume-config #高级用法第1种,将ConfigMap的log-script,backup-script分别挂载到/etc/config目录下的一个相对路径path/to/...下,如果存在同名文件,直接覆盖。
mountPath: /etc/config
- name: rbd-pvc #高级用法第2中,挂载PVC(PresistentVolumeClaim)#使用volume将ConfigMap作为文件或目录直接挂载,其中每一个key-value键值对都会生成一个文件,key为文件名,value为内容,
volumes: # 定义磁盘给上面volumeMounts挂载
- name: log-cache
emptyDir: {}
- name: sdb #挂载宿主机上面的目录
hostPath:
path: /any/path/it/will/be/replaced
- name: example-volume-config # 供ConfigMap文件内容到指定路径使用
configMap:
name: example-volume-config #ConfigMap中名称
items:
- key: log-script #ConfigMap中的Key
path: path/to/log-script #指定目录下的一个相对路径path/to/log-script
- key: backup-script #ConfigMap中的Key
path: path/to/backup-script #指定目录下的一个相对路径path/to/backup-script
- name: nfs-client-root #供挂载NFS存储类型
nfs:
server: 10.42.0.55 #NFS服务器地址
path: /opt/public #showmount -e 看一下路径
- name: rbd-pvc #挂载PVC磁盘
persistentVolumeClaim:
claimName: rbd-pvc1 #挂载已经申请的pvc磁盘
3、回滚
3.1、查看历史版本
kubectl rollout history deployment name
3.2、回滚操作
kubectl rollout undo deployment name --to-revision=(对应版本编号)
4、更新策略
4.1、类型
-
maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。
-
maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;
4.2、设置方式
-
按数量
-
maxUnavailable: [0, 副本数]
-
maxSurge: [0, 副本数]
-
注两者不能同时为0。
-
按比例
-
maxUnavailable: [0%, 100%] 向下取整,比如10个副本,5%的话==0.5个,但计算按照0个;
-
maxSurge: [0%, 100%] 向上取整,比如10个副本,5%的话==0.5个,但计算按照1个;
-
两者不能同时为0。
4.3、案例
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v1
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: v1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp
image: janakiramm/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
七、daemonset控制器
1、概述
1.1、DaemonSet
DaemonSet 控制器能够确保 k8s 集群所有的节点都运行一个相同的 pod 副本,当向 k8s 集群中增加 node 节点时,这个 node 节点也会自动创建一个 pod 副本,当 node 节点从 集群移除,这些 pod 也会自动删除;删除 Daemonset 也会删除它们创建的 pod
1.2、DaemonSet 工作原理
daemonset 的控制器会监听 kuberntes 的 daemonset 对象、pod 对象、node 对象,这些被监听的对象之变动,就会触发 syncLoop 循环让 kubernetes 集群朝着 daemonset 对象描述的状态进行演进。
1.3、Daemonset 典型的应用场景
在集群的每个节点上运行存储,比如:glusterd 或 ceph。 在每个节点上运行日志收集组件,比如:flunentd 、 logstash、filebeat 等。 在每个节点上运行监控组件,比如:Prometheus、 Node Exporter 、collectd 等。
1.4、DaemonSet 与 Deployment 的区别
Deployment 部署的副本 Pod 会分布在各个 Node 上,每个 Node 都可能运行好几个副本。
DaemonSet 的不同之处在于:每个 Node 上最多只能运行一个副本。
2、模板
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: pod-controller # ds名称
labels: # 给ds打标签
controller: daemonset
spec:
revisionHistoryLimit: 3 # 保留历史版本数量,默认为10
updateStrategy: # Pod更新策略,默认是RollingUpdate
type: RollingUpdate # 滚动更新策略。另一种是OnDelete,其没有子属性配置参数
rollingUpdate: # 当type为RollingUpdate的时候生效,为其配置参数
maxSurge: 25% # 升级过程中可以超过期望的Pod的最大数量,可以为百分比,也可以为整数。默认是25%
maxUnavailable: 25% # 升级过程中最大不可用状态的Pod数量,可以为百分比,也可以为整数。默认是25%
selector: # 选择器,通过该控制器管理哪些pod
matchLabels: # Labels匹配规则。和matchExpressions类似
app: nginx-pod ###或者
matchExpressions: # Expressions匹配规则。和matchLabels类似
- {key: app, operator: 'In', values: ["nginx-pod"]}
template: # pod副本创建模板。属性和Pod的属性一样
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
八、Statefulset控制器
1、Statefulset控制器:概念、原理解读
StatefulSet是为了管理有状态服务的问题而设计的。
1.1、有状态服务
StatefulSet是有状态的集合,管理有状态的服务,它所管理的Pod的名称不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数据持久化存储目录。比如MySQL主从、redis集群等。
1.2、无状态服务
RC、Deployment、DaemonSet都是管理无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的。个体对整体无影响,所有pod都是共用一个数据卷的,部署的tomcat就是无状态的服务,tomcat被删除,在启动一个新的tomcat,加入到集群即可,跟tomcat的名字无关。
1.3、StatefulSet部分组成
-
Headless Service:用来定义pod网路标识,生成可解析的DNS记录
-
volumeClaimTemplates:存储卷申请模板,创建pvc,指定pvc名称大小,自动创建pvc,且pvc由存储类供应。
-
StatefulSet:管理pod的
1.3.1、Headless service
Headless service不分配clusterIP,headless service可以通过解析service的DNS,返回所有Pod的dns和ip地址 (只有statefulSet部署的Pod才有DNS地址),普通的service,只能通过解析service的DNS返回service的ClusterIP。
为什么要用headless service(没有service ip的service)?
在使用Deployment时,创建的Pod名称是没有顺序的,是随机字符串,在用statefulset管理pod时要求pod名称必须是有序的 ,每一个pod不能被随意取代,pod重建后pod名称还是一样的。因为pod IP是变化的,所以要用Pod名称来识别。pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称。
1.3.2、域名分配
headless service会为service分配一个域名
<service name>.<namespace name>.svc.cluster.local
StatefulSet会为关联的Pod保持一个不变的Pod Name
statefulset中Pod的名字格式为 【 $(StatefulSet name)-$(pod序号) 】
StatefulSet会为关联的Pod分配一个dnsName
<Pod Name>.<service name>.<namespace name>.svc.cluster.local
2、编写技巧
#查看定义Statefulset资源需要的字段
[root@k8s-master01~]# kubectl explain statefulset
FIELDS:
apiVersion <string> #定义statefulset资源需要使用的api版本
kind <string> #定义的资源类型
metadata <Object> #元数据
spec <Object> #定义容器相关的信息
#查看statefulset.spec字段如何定义
[root@k8s-master01~]# kubectl explain statefulset.spec
FIELDS:
podManagementPolicy <string> #pod管理策略
replicas <integer> #副本数
revisionHistoryLimit <integer> #保留的历史版本
selector <Object> -required- #标签选择器,选择它所关联的pod
serviceName <string> -required- #headless service的名字
template <Object> -required- #生成pod的模板
updateStrategy <Object> #更新策略
volumeClaimTemplates <[]Object> #存储卷申请模板
#查看statefulset的spec.template字段如何定义?
#对于template而言,其内部定义的就是pod,pod模板是一个独立的对象
[root@k8s-master01~]# kubectl explain statefulset.spec.template
FIELDS:
metadata <Object>
spec <Object> #定义容器属性的
九、NetworkPolicy
1、什么是NetworkPolicy?
NetworkPolicy是Kubernetes中用于定义Pod之间网络通信规则的资源对象。通过NetworkPolicy,开发者可以控制哪些Pod可以与另外哪些Pod通信,以及使用何种方式进行通信。这种细粒度的网络控制有助于提高集群的安全性,防止未经授权的访问和通信。
2、NetworkPolicy的基本原理
NetworkPolicy的工作原理基于以下几个核心概念:
-
Pod选择器(PodSelector)& namespaceSelector:NetworkPolicy使用标签选择器来选择特定的Pod。通过标签,可以将网络策略应用于特定的Pod群体。
-
Ingress规则:定义了允许从其他Pod进入被选中Pod的规则,包括允许的协议、端口范围等。
-
Egress规则:定义了允许被选中Pod访问其他Pod或外部网络的规则。
-
Peer Pod:NetworkPolicy中的规则是基于Peer Pod(对等Pod)的。通过选择Peer Pod,可以精确定义通信策略。
3、NetworkPolicy资源清单
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: backend #选择带有 app=backend 标签的 Pod 作为目标 Pod
ingress: #入站
- from:
- podSelector:
matchLabels:
app: frontend # 允许带有 app=frontend 标签的 Pod 访问目标 Pod
- ipBlock:
cidr: 192.168.1.0/24 # 允许来自 192.168.1.0/24 网段的流量访问目标 Pod
ports:
- protocol: TCP
port: 8080 # 只允许访问目标 Pod 的 8080 端口
egress: #出站
- to:
- podSelector:
matchLabels:
app: database # 允许目标 Pod 访问带有 app=database 标签的 Pod
ports:
- protocol: TCP
port: 3306 #目标 Pod 访问其他 Pod 时只允许使用 3306 端口
十、Job & Cronjob
1、介绍
1.1、Job
Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止。 随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。 删除 Job 的操作会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。
一种简单的使用场景下,你会创建一个 Job 对象以便以一种可靠的方式运行某 Pod 直到完成。 当第一个 Pod 失败或者被删除(比如因为节点硬件失效或者重启)时,Job 对象会启动一个新的 Pod。
你也可以使用 Job 以并行的方式运行多个 Pod。
1.2、Cronjob
CronJob 创建基于时隔重复调度的 Job。
CronJob 用于执行排期操作,例如备份、生成报告等。 一个 CronJob 对象就像 Unix 系统上的 crontab(cron table)文件中的一行。 它用 Cron 格式进行编写, 并周期性地在给定的调度时间执行 Job。
2、配置解读
1、job
apiVersion: batch/v1 ## api版本
kind: Job ## 资源类型
metadata: ## 元数据
name: pi ## 资源名称
namespace: default ## 命名空间
spec: ## 详情
backoffLimit: 4 ## 最大失败次数
completions: 1 ## 要求完成的次数
parallelism: 1 ## 并发数量
activeDeadlineSeconds: 100 ## 最大运行时间
ttlSecondsAfterFinished: 20 ## ttl时间
template: ## Pod配置模板
spec: ## 规约
containers: ## 容器信息
- name: pi ## 容器名称
image: perl:5.34.0 ## 镜像
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] ## 容器运行命令
imagePullPolicy: IfNotPresent
restartPolicy: Never ## 重启策略
2、Cronjob
apiVersion: batch/v1 ## api版本
kind: CronJob ## 资源类型
metadata: ## 元数据
name: hello ## 资源名称
namespace: default ## 命名空间
spec: ## 详情
schedule: "* * * * *" ## 定时配置
successfulJobsHistoryLimit: 3 ## 保留运行完成pod的历史数量
jobTemplate: ## job配置模板
spec: ## job详细配置
template: ## pod配置模板
spec: ## pod详细配置
containers: ## 容器配置
- name: hello ## 容器名称
image: busybox:1.28 ## 容器镜像
imagePullPolicy: IfNotPresent ## 镜像拉取策略
command: ## 镜像启动运行命令
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure ## 重启策略
###################################################################
imagePullSecrets: ## 镜像下载秘钥
- name: harbor-secret
重启策略 restartPolicy
Never:当 Pod 失败时,Job 控制器会启动一个新的 Pod
OnFailure:Pod 继续留在当前节点,但容器会被重新运行
十一、RBAC认证中心
1、k8s安全管理:认证、授权、准入控制概述
k8s对我们整个系统的认证,授权,访问控制做了精密的设置;对于k8s集群来说,apiserver是整个集群访问控制的唯一入口,我们在k8s集群之上部署应用程序的时候,也可以通过宿主机的NodePort暴露的端口访问里面的程序,用户访问kubernetes集群需要经历如下认证过程:
认证->授权->准入控制(admination controller)
1.认证(Authenticating)是对客户端的认证,通俗点就是用户名密码验证
2.授权(Authorization)是对资源的授权,k8s中的资源无非是容器,最终其实就是容器的计算,网络,存储资源,当一个请求经过认证后,需要访问某一个资源(比如创建一个pod),授权检查会根据授权规则判定该资源(比如某namespace下的pod)是否是该客户可访问的。
3.准入(Admission Control)机制:
准入控制器(Admission Controller)位于 API Server中,在对象被持久化之前,准入控制器拦截对 API Server 的请求,一般用来做身份验证和授权。其中包含两个特殊的控制器:
Mutating Admission Webhook 和 Validating Admission Webhook。分别作为配置的变更和验证准入控制 webhook。
变更(Mutating)准入控制:修改请求的对象
验证(Validating)准入控制:验证请求的对象
准入控制器是在 API Server 的启动参数配置的。一个准入控制器可能属于以上两者中的一种,也可能两者都属于。当请求到达 API Server 的时候首先执行变更准入控制,然后再执行验证准入控制。
我们在部署 Kubernetes 集群的时候都会默认开启一系列准入控制器,如果没有设置这些准入控制器的话可以说你的 Kubernetes 集群就是在裸奔,应该只有集群管理员可以修改集群的准入控制器。
例如:会默认开启如下的准入控制器。
--admission-control=ServiceAccount,NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota,MutatingAdmissionWebhook,ValidatingAdmissionWebhook
k8s的整体架构也是一个微服务的架构,所有的请求都是通过一个GateWay,也就是kube-apiserver这个组件(对外提供REST服务),k8s中客户端有两类,一种是普通用户,一种是集群内的Pod,这两种客户端的认证机制略有不同,但无论是哪一种,都需要依次经过认证,授权,准入这三个机制。
1.1 认证
1、认证支持多种插件
(1)令牌(token)认证:
双方有一个共享密钥,服务器上来先创建一个密码下来,客户端登陆的时候拿这个密码登陆即可,这个就是对称密钥认证方式;k8s提供了一个restful风格的接口,它的所有服务都是通过http协议提供的,因此认证信息只能经由http协议的认证首部进行传递,这种认证首部进行传递通常叫做令牌;
(2)ssl认证:
对于k8s访问来讲,ssl认证能让客户端确认服务器的认证身份,我们在跟服务器通信的时候,需要服务器发过来一个证书,我们需要确认这个证书是不是ca签署的,如果是我们认可的ca签署的,里面的subj信息与我们访问的目标主机信息保持一致,没有问题,那么我们就认为服务器的身份得到认证了,k8s中最重要的是服务器还需要认证客户端的信息,kubectl也应该有一个证书,这个证书也是server所认可的ca签署的证书,双方需要互相认证,实现加密通信,这就是ssl认证。
2、kubernetes上的账号
客户端对apiserver发起请求,apiserver要识别这个用户是否有请求的权限,要识别用户本身能否通过apiserver执行相应的操作,那么需要哪些信息才能识别用户信息来完成对用户的相关的访问控制呢?
kubectl explain pods.spec可以看到有一个字段serviceAccountName(服务账号名称),这个就是我们pod连接apiserver时使用的账号,因此整个kubernetes集群中的账号有两类,ServiceAccount(服务账号),User account(用户账号)
User account:实实在在现实中的人,人可以登陆的账号,客户端想要对apiserver发起请求,apiserver要识别这个客户端是否有请求的权限,那么不同的用户就会有不同的权限,靠用户账号表示,叫做username
ServiceAccount:方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的,是kubernetes中的一种资源
sa账号:登陆dashboard使用的账号
user account:这个是登陆k8s物理机器的用户(系统用户)
1.ServiceAccount
Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。它与User account不同,User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;User account是跨namespace的,而service account则是仅局限它所在的namespace;每个namespace都会自动创建一个default service account;
开启ServiceAccount Admission Controller后
1)每个Pod在创建后都会自动设置spec.serviceAccount为default(除非指定了其他ServiceAccout)
2)验证Pod引用的service account已经存在,否则拒绝创建;
当创建 pod 的时候,如果没有指定一个 serviceaccount,系统会自动在与该pod 相同的 namespace 下为其指派一个default service account。这是pod和apiserver之间进行通信的账号,如下:
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-pod-volume 1/1 Running 0 43m
nfs-provisioner-cd5589cfc-c8vc5 1/1 Running 0 13h
pod-secret 1/1 Running 0 18m
web-0 1/1 Running 0 13h
web-1 1/1 Running 0 13h
1.2 授权
如果用户通过认证,什么权限都没有,需要一些后续的授权操作,如对资源的增删该查等,kubernetes1.6之后开始有RBAC(基于角色的访问控制机制)授权检查机制。(role basic access control)
Kubernetes的授权是基于插件形成的,其常用的授权插件有以下几种:
-
Node(节点认证)
-
ABAC(基于属性的访问控制)
-
RBAC(基于角色的访问控制)(Role Basic Access Control)
-
Webhook(基于http回调机制的访问控制)
什么是RBAC(基于角色的访问控制)?
让一个用户(Users)扮演一个角色(Role),角色拥有权限,从而让用户拥有这样的权限,随后在授权机制当中,只需要将权限授予某个角色,此时用户将获取对应角色的权限,从而实现角色的访问控制,如图:

在k8s的授权机制当中,采用RBAC的方式进行授权,其工作逻辑是,把对对象的操作权限定义到一个角色当中,再将用户绑定到该角色,从而使用户得到对应角色的权限。
如果通过rolebinding绑定role,只能对rolebingding所在的名称空间的资源有权限,上图user1这个用户绑定到role1上,只对role1这个名称空间的资源有权限,对其他名称空间资源没有权限,属于名称空间级别的;
另外,k8s为此还有一种集群级别的授权机制,就是定义一个集群角色(ClusterRole),对集群内的所有资源都有可操作的权限,从而将User2通过ClusterRoleBinding到ClusterRole,从而使User2拥有集群的操作权限。
Role、RoleBinding、ClusterRole和ClusterRoleBinding的关系如下图:

通过上图可以看到,可以通过rolebinding绑定role,rolebinding绑定clusterrole,clusterrolebinding绑定clusterrole。
上面我们说了两个角色绑定:
(1)用户通过rolebinding绑定role
(2)用户通过clusterrolebinding绑定clusterrole
还有一种:rolebinding绑定clusterrole
rolebinding绑定clusterrole的好处:
假如有6个名称空间,每个名称空间的用户都需要对自己的名称空间有管理员权限,那么需要定义6个role和rolebinding,然后依次绑定,如果名称空间更多,我们需要定义更多的role,这个是很麻烦的,所以我们引入clusterrole,定义一个clusterrole,对clusterrole授予所有权限,然后用户通过rolebinding绑定到clusterrole,就会拥有自己名称空间的管理员权限了
注:RoleBinding仅仅对当前名称空间有对应的权限。
2、RBAC认证授权策略
RBAC介绍
在Kubernetes中,所有资源对象都是通过API进行操作,他们保存在etcd里。而对etcd的操作我们需要通过访问 kube-apiserver 来实现,上面的Service Account其实就是APIServer的认证过程,而授权的机制是通过RBAC:基于角色的访问控制实现。
RBAC有四个资源对象,分别是Role、ClusterRole、RoleBinding、ClusterRoleBinding
2.1、Role:角色
一组权限的集合,在一个命名空间中,可以用其来定义一个角色,只能对命名空间内的资源进行授权。如果是集群级别的资源,则需要使用ClusterRole。例如:定义一个角色用来读取Pod的权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: rbac
name: pod-read
rules:
- apiGroups: [""]
resources: ["pods"]
resourceNames: []
verbs: ["get","watch","list"]
rules中的参数说明:
-
apiGroups:支持的API组列表,例如:"apiVersion: batch/v1"等
-
resources:支持的资源对象列表,例如pods、deplayments、jobs等
-
resourceNames: 指定resource的名称
-
verbs:对资源对象的操作方法列表。
2.2、ClusterRole:集群角色
具有和角色一致的命名空间资源的管理能力,还可用于以下特殊元素的授权
-
集群范围的资源,例如Node
-
非资源型的路径,例如:/healthz
-
包含全部命名空间的资源,例如Pods
例如:定义一个集群角色可让用户访问任意secrets
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secrets-clusterrole
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get","watch","list"]
2.3、RoleBinding:角色绑定、ClusterRolebinding:集群角色绑定
角色绑定和集群角色绑定用于把一个角色绑定在一个目标上,可以是User,Group,Service Account,使用RoleBinding为某个命名空间授权,使用ClusterRoleBinding为集群范围内授权。
例如:将在rbac命名空间中把pod-read角色授予用户es
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-read-bind
namespace: rbac
subjects:
- kind: User
name: es
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-read
apiGroup: rbac.authorization.k8s.io
RoleBinding也可以引用ClusterRole,对属于同一命名空间内的ClusterRole定义的资源主体进行授权, 例如:es能获取到集群中所有的资源信息
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: es-allresource
namespace: rbac
subjects:
- kind: User
name: es
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
集群角色绑定的角色只能是集群角色,用于进行集群级别或对所有命名空间都生效的授权
例如:允许manager组的用户读取所有namaspace的secrets
apiVersion: rabc.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secret-global
subjects:
- kind: Group
name: manager
apiGroup: rabc.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-read
apiGroup: rabc.authorization.k8s.io
3、限制不同的用户操作k8s集群
ssl认证
生成一个证书
(1)生成一个私钥
cd /etc/kubernetes/pki/ umask 077; openssl genrsa -out lucky.key 2048
(2)生成一个证书请求
openssl req -new -key lucky.key -out lucky.csr -subj "/CN=lucky"
(3)生成一个证书
openssl x509 -req -in lucky.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out lucky.crt -days 3650
在kubeconfig下新增加一个lucky这个用户
(1)把lucky这个用户添加到kubernetes集群中,可以用来认证apiserver的连接
[root@xianchaomaster1 pki]# kubectl config set-credentials lucky --client-certificate=./lucky.crt --client-key=./lucky.key --embed-certs=true
(2)在kubeconfig下新增加一个lucky这个账号
kubectl config set-context lucky@kubernetes --cluster=kubernetes --user=lucky
(3)切换账号到lucky,默认没有任何权限
[root@k8s-master01 pki]# kubectl config use-context lucky@kubernetes [root@k8s-master01 pki]# kubectl get pod Error from server (Forbidden): pods is forbidden: User "lucky" cannot list resource "pods" in API group "" in the namespace "default" ###切换到有权限的管理账户 [root@k8s-master01 pki]# kubectl config use-context kubernetes-admin@kubernetes
这个是集群用户,有任何权限;把lucky这个用户通过rolebinding绑定到clusterrole上,授予权限,权限只是在lucky这个名称空间有效
(1)把lucky这个用户通过rolebinding绑定到clusterrole上
[root@k8s-master01 pki]# kubectl create ns lucky [root@k8s-master01 pki]# kubectl create rolebinding lucky -n lucky --clusterrole=cluster-admin --user=lucky
(2)切换到lucky这个用户
[root@k8s-master01 pki]# kubectl config use-context lucky@kubernetes
(3)测试是否有权限
kubectl get pods -n lucky [root@k8s-master01 pki]# kubectl get pod -n lucky No resources found in lucky namespace. [root@k8s-master01 pki]# kubectl get sa -n lucky NAME SECRETS AGE default 0 2m10s #有权限操作这个名称空间 kubectl get pods [root@k8s-master01 pki]# kubectl get pod Error from server (Forbidden): pods is forbidden: User "lucky" cannot list resource "pods" in API group "" in the namespace "default" #没有权限操作其他名称空间
添加一个lucky的普通用户
useradd lucky cp -ar /root/.kube/ /home/lucky/ chown -R lucky.lucky /home/lucky/ su - lucky vim .kube/config ....... server: https://192.168.158.15:6443 name: kubernetes contexts: - context: cluster: kubernetes user: lucky name: lucky@kubernetes current-context: lucky@kubernetes .... su - root chattr +i /home/lucky/.kube/config exit kubectl get pods -n lucky
验证创建pod:
[lucky@k8s-master ~]$ cat nginx.txt apiVersion: v1 kind: Pod metadata: name: nginx-pod spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent [lucky@k8s-master ~]$ kubectl apply -f nginx.txt ##发现报错 Error from server (Forbidden): error when retrieving current configuration of: Resource: "/v1, Resource=pods", GroupVersionKind: "/v1, Kind=Pod" Name: "nginx-pod", Namespace: "default" from server for: "nginx.txt": pods "nginx-pod" is forbidden: User "lucky" cannot get resource "pods" in API group "" in the namespace "default" [lucky@k8s-master ~]$ cat nginx.txt apiVersion: v1 kind: Pod metadata: name: nginx-pod namespace: lucky spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent [lucky@k8s-master ~]$ kubectl apply -f nginx.txt ##发现成功创建 pod/nginx-pod created [lucky@k8s-master ~]$ kubectl -n lucky get po NAME READY STATUS RESTARTS AGE nginx-pod 1/1 Running 0 28s
十二、调度管理
1、node节点选择器
我们在创建pod资源的时候,pod会根据schduler进行调度,那么默认会调度到随机的一个工作节点,如果我们想要pod调度到指定节点或者调度到一些具有相同特点的node节点,可以使用pod中的nodeName或者nodeSelector字段指定要调度到的node节点
1.1、nodeName
指定pod节点运行在哪个具体node上 
1.2、nodeSelector
指定pod调度到具有哪些标签的node节点上
kubectl get nodes --show-labels
## 查看标签
kubectl label nodes k8s-node1 node-type=k8s-node1
## 为node 节点打上新标签

apiVersion: v1
kind: Pod
metadata:
name: pod
namespace: wezzer
labels:
app: myapp
env: dev
spec:
nodeSelector:
node-type: k8s-node2 (键/值 都要写对)
containers:
- name: pod
ports:
- containerPort: 80
image: nginx
imagePullPolicy: IfNotPresentapiVersion: v1

2、 pod亲和性
Pod 的亲和性与反亲和性有两种类型:
requiredDuringSchedulingIgnoredDuringExecution ##一定满足
preferredDuringSchedulingIgnoredDuringExecution ##尽量满足
亲和性
与 psec.containers(同级)
affinity: # 亲和性配置的顶层关键字,用于定义Pod与节点、Pod与Pod之间的调度关联规则
# 包含三大类配置:nodeAffinity(Pod与节点亲和)、podAffinity(Pod与Pod亲和)、podAntiAffinity(Pod与Pod反亲和)
podAffinity: # Pod亲和性规则:控制当前Pod调度到哪些节点,取决于「目标节点上已运行的其他Pod的标签」
# 核心逻辑:让当前Pod和满足条件的已有Pod调度到「同一拓扑域」(如同一节点、同一机房等)
requiredDuringSchedulingIgnoredDuringExecution: # 亲和性规则的「强制调度策略」
# requiredDuringScheduling:调度阶段必须满足该规则,否则Pod无法调度(不满足则Pending)
# IgnoredDuringExecution:Pod调度成功后,即使后续目标Pod被删除/标签变更,当前Pod也不会被驱逐
# 对比其他策略:preferredDuringScheduling...(非强制,满足最好,不满足也可能调度)
- labelSelector: # 标签选择器:定义需要匹配的「目标Pod的标签条件」(即当前Pod要亲和的Pod必须满足这些标签规则)
matchExpressions: # 标签匹配表达式:支持更灵活的标签匹配逻辑(比matchLabels更灵活,可多条件组合)
- {key: app2, operator: 'In', values: ["myapp2"]} # 具体的匹配表达式,由3个部分组成:
# key: app2 → 要匹配的目标Pod的「标签键」(必须检查目标Pod是否有app2这个标签)
# operator: 'In' → 匹配运算符,这里表示「目标Pod的标签值必须在values列表中」
# 常用运算符:In(在列表中)、NotIn(不在列表中)、Exists(存在该key即可,忽略value)、DoesNotExist(不存在该key)
# values: ["myapp2"] → 标签值列表,结合In运算符,即目标Pod的app2标签值必须是myapp2
topologyKey: kubernetes.io/hostname # 拓扑域关键字:定义「什么是同一个调度域」,即满足标签条件的Pod和当前Pod要处于「同一拓扑域」
# kubernetes.io/hostname → 内置节点标签,值为节点主机名(如k8s-node2)
# 含义:当前Pod必须调度到「已运行有app2=myapp2标签的Pod的节点上」(同一节点即同一拓扑域)
# 其他常用topologyKey:
# topology.kubernetes.io/zone(同一可用区)、topology.kubernetes.io/region(同一地域)
# 自定义标签(如env=prod,同一环境的节点为一个拓扑域)
反亲和性
与 psec.containers(同级)
affinity: # 亲和性配置顶层关键字,用于定义Pod与节点、Pod与Pod之间的调度关联规则
# 包含三大类子配置:nodeAffinity(Pod与节点亲和)、podAffinity(Pod与Pod亲和)、podAntiAffinity(Pod与Pod反亲和)
podAntiAffinity: # Pod反亲和性规则:控制当前Pod「避免」调度到某些节点,取决于「目标节点上已运行的其他Pod的标签」
# 核心逻辑:让当前Pod和满足条件的已有Pod「远离彼此」,不处于同一拓扑域(如避免同一节点、同一机房等)
# 对比podAffinity(亲和):反亲和是「排斥」,亲和是「吸引」
preferredDuringSchedulingIgnoredDuringExecution: # 反亲和性规则的「非强制调度策略」(优先满足,不满足也可调度)
# preferredDuringScheduling:调度阶段会「优先尝试满足」该规则,提升调度合理性
# IgnoredDuringExecution:Pod调度成功后,即使后续目标Pod被添加/标签变更,当前Pod也不会被驱逐
# 对比其他策略:requiredDuringScheduling...(强制满足,不满足则PodPending)
- weight: 100 # 权重值(范围1-100):当存在多个preferred规则时,权重越高的规则优先级越高
# 作用:调度器会计算所有满足条件的节点得分,权重值影响节点的最终调度优先级(权重越高,越优先避免符合条件的节点)
# 示例:若同时有2个preferred反亲和规则,权重100的规则会比权重50的规则优先被满足
podAffinityTerm: # 反亲和性的「核心匹配条件」:定义需要「排斥」的目标Pod特征和拓扑范围
labelSelector: # 标签选择器:定义需要匹配的「目标Pod的标签条件」(即当前Pod要排斥的Pod必须满足这些标签规则)
matchExpressions: # 标签匹配表达式:支持灵活的多条件标签匹配(比matchLabels更灵活,可组合多种匹配逻辑)
- key: app1 # 要匹配的目标Pod的「标签键」:必须检查目标节点上的Pod是否有「app1」这个标签
operator: 'In' # 标签匹配运算符:表示「目标Pod的标签值必须在values列表中」
# 常用运算符说明:
# - In:值在values列表内(如这里要求app1的值是myapp1)
# - NotIn:值不在values列表内
# - Exists:只要目标Pod有该key的标签,不管值是什么(忽略values)
# - DoesNotExist:目标Pod没有该key的标签(忽略values)
values: # 标签值列表:结合operator: In,即目标Pod的app1标签值必须是myapp1
- myapp1
topologyKey: kubernetes.io/hostname # 拓扑域关键字:定义「什么是同一个排斥域」,即当前Pod要避免和满足条件的Pod处于「同一拓扑域」
# kubernetes.io/hostname:K8s内置节点标签,值为节点主机名(如k8s-node1、k8s-node2)
# 本配置含义:当前Pod会「优先避免」调度到「已运行有app1=myapp1标签Pod的节点」(同一节点即同一拓扑域)
# 其他常用topologyKey场景:
# - topology.kubernetes.io/zone:避免同一可用区(适合高可用,分散跨机房)
# - topology.kubernetes.io/region:避免同一地域(适合跨区域容灾)
# - 自定义标签(如env=prod:避免同一环境节点)
3、污点与容忍
前面介绍了节点亲和性调度,它可以使得我们的Pod调度到指定的Node节点上,而污点(Taints)与之相反,它可以让Node拒绝Pod的运行,甚至驱逐已经在该Node上运行的Pod
污点是Node上设置的一个属性,通常设置污点表示该节点有问题,比如磁盘要满了,资源不足,或者该Node正在升级暂时不能提供使用等情况,这时不希望再有新的Pod进来,这个时候就可以给该节点设置一个污点。
但是有的时候其实Node节点并没有故障,只是不想让一些Pod调度进来,比如这台节点磁盘空间比较大,希望是像Elasticsearch、Minio这样需要较大磁盘空间的Pod才调度进来,那么就可以给节点设置一个污点,给Pod设置容忍(Tolerations)对应污点,如果再配合节点亲和性功能还可以达到独占节点的效果
一般时候 Taints 总是与 Tolerations配合使用
3.1、污点(Taints)
设置污点后,一般Pod将不会调度到该节点上来。每次Pod都不会调度到master节点,那是因为搭建K8s集群的时候,K8s给master自带了一个污点。
kubectl describe node k8s-master
...
Taints: node-role.kubernetes.io/control-plane:NoSchedule
...
查看master上是否有污点,通过describe命令可以看到master节点上的所有污点
kubectl get nodes k8s-master -o go-template={{.spec.taints}}
[map[effect:NoSchedule key:node-role.kubernetes.io/control-plane]]
3.2、污点类别
上面我们看到了污点有一个effect 属性为NoSchedule,其实还有其它两种类别分别是 PreferNoSchedule与 NoExecute
-
NoSchedule: 如果没有容忍该污点就不能调度进来。
-
PreferNoSchedule: 相当于NoExecute的一个软限制,如果没有容忍该污点,尽量不要把Pod调度进来,但也不是强制的。
-
NoExecute: 如果没有设置容忍该污点,新的Pod肯定不会调度进来, 并且已经在运行的Pod没有容忍该污点也会被驱逐。
# 设置污点并不允许Pod调度到该节点
$ kubectl taint node k8s-node1 key=value:NoSchedule
# 设置污点尽量不要让Pod调度到该节点
$ kubectl taint node k8s-node1 key=value:PreferNoSchedule
# 设置污点,不允许Pod调度到该节点,并且且将该节点上没有容忍该污点的Pod将进行驱逐
$ kubectl taint node k8s-node1 key=value:NoExecute
3.3、删除污点
# 删除该key的所有污点
$ kubectl taint node k8s-node1 key-
# 删除该key的某一个污点
$ kubectl taint node k8s-node1 key=value:NoSchedule-
# 删除该key的某一个污点可以不写value
$ kubectl taint node k8s-node1 key:NoSchedule-
3.4、案例
kubectl taint node k8s-node1 web=true:NoSchedule
key=web+value=true:污点的 “标识”,用于区分不同类型的污点;
effect=NoSchedule:污点的 “作用效果”,表示 “没有容忍该污点的 Pod,绝对不能调度到这个节点”(仅影响调度阶段,不驱逐已运行的 Pod)。如果现在创建pod,再没有加容忍,那么pod是不会被调度到node1上
若创建以下pod
apiVersion: v1
kind: Pod
metadata:
name: web-taint1
spec:
# 给Web Pod添加“容忍k8s-node1污点”的配置
tolerations:
- key: "web" # 匹配污点的key
operator: "Equal" # 匹配方式(Equal=精确匹配value,Exists=只匹配key忽略value)
value: "true" # 匹配污点的value
effect: "NoSchedule" # 匹配污点的effect(必须完全一致)
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
则 pod(web-taint1)就可以被调度到 k8s-node1 上
空 key + Exists 运算符 表示匹配任何污点
十三、HPA水平扩容
自动根据业务忙闲来调整业务工作负载的副本数,其实HPA的实现思路很容易想到:通过监控业务繁忙情况,在业务忙时,就要对workload扩容副本数;等到业务闲下来时,自然又要把副本数再缩下去

1、HPA的metrics的分类
要支持最新的custom(包括external)的metrics,也需要使用新版本的HPA:autoscaling/v2beta1,里面增加四种类型的Metrics:Resource、Pods、Object、External,每种资源对应不同的场景,下面分别说明:
-
Resource支持k8s里Pod的所有系统资源(包括cpu、memory等),但是一般只会用cpu,memory因为不太敏感而且跟语言相关:大多数语言都有内存池及内置GC机制导致进程内存监控不准确。
-
Pods类型的metrics表示cpu,memory等系统资源之外且是由Pod自身提供的自定义metrics数据,比如用户可以在web服务的pod里提供一个promesheus metrics的自定义接口,里面暴露了本pod的实时QPS监控指标,这种情况下就应该在HPA里直接使用Pods类型的metrics。
-
Object类型的metrics表示监控指标不是由Pod本身的服务提供,但是可以通过k8s的其他资源Object提供metrics查询,比如ingress等,一般Object是需要汇聚关联的Deployment下的所有的pods总的指标。
-
External类型的metrics也属于自定义指标,与Pods和Object不同的是,其监控指标的来源跟k8s本身无关,metrics的数据完全取自外部的系统。
在HPA最新的版本 autoscaling/v2beta2 中又对metrics的配置和HPA扩缩容的策略做了完善,特别是对 metrics 数据的目标指标值的类型定义更通用灵活:包括AverageUtilization(平均利用率)、AverageValue(平均值)和Value,但是不是所有的类型的Metrics都支持三种目标值的,具体对应关系如下表。
HPA里的各种类型的Metrics和Metrics Target Type的对应支持关系表
| Metrics Type I Target Type | AverageUtilization | AverageValue | Value | 备注(query metrics) |
|---|---|---|---|---|
| Resource(pod's cpu/memory etc. | Yes | Yes | No | pods metrics list |
| Pods(pod's other metrics) | No | Yes | No | pods metrics list |
| Object(k8s object) | No | Yes | Yes | object metrics |
| External(not k8s object) | No | Yes | Yes | external metrics list |
2、HPA的使用说明
# API版本,表示这是autoscaling API的v2beta2版本
apiVersion: autoscaling/v2beta2
# 资源类型,表示这是一个HorizontalPodAutoscaler资源
kind: HorizontalPodAutoscaler
# Metadata信息,定义了HPA的
metadata:
# HPA的名称
name: php-apache
# Spec配置,定义了HPA的具体配置参数
spec:
# 缩放目标引用,指定了要自动扩展的Deployment资源
scaleTargetRef:
# API版本,这是apps API的v1版本
apiVersion: apps/v1
# 资源类型,表示这是一个Deployment资源
kind: Deployment
# 要扩展的Deployment资源的名称
name: php-apache
# 最小副本数,HPA将确保Pod的副本数不会低于这个值
minReplicas: 1
# 最大副本数,HPA将确保Pod的副本数不会超过这个值
maxReplicas: 10
# 监控指标,用于触发Pod副本数的扩展
metrics:
# 类型,表示这是资源类型的监控指标
type: Resource
# 资源名称,这里是指CPU资源
resource:
# 资源名称,这里是CPU
name: cpu
#目标类型,表示监控的是资源的使用率
target:
# 目标类型,表示监控的是平均使用率
type: Utilization
# 期望的平均CPU使用率,当实际使用率高于这个值时,HPA会扩展Pod的副本数
averageUtilization: 50
从上面的例子可以看出,HPA的spec定义由三个必填部分组成:
-
HPA控制的目标workload,即scaleTargetRef,理论上HPA可以对任意支持scale子接口( sub-resource )的workload做弹性伸缩,不过statefulset一般代表有状态服务,副本不可随便修改,而Job一般代表短生命周期的,所以基本可以认为HPA目前是专门控制deployment的扩缩容的(不建议直接控制RS,否则将无法滚动升级)。
-
弹性扩缩容的上下边界,minReplicas和maxReplicas,也就是说HPA的扩缩容也不能是漫无边际,如果计算出的副本数超过max则统一取maxReplicas,maxReplicas是为了保护k8s集群的资源被耗尽,minReplicas则相反,而且minReplicas必须不大于maxReplicas,但是也要大于0(k8s v1.16之后才放开允许Objetct和External类型的metrics的minReplicas为0,需要apiserver开启–feature-gates mapStringBool HPAScaleToZero=true),两者相等就相当于关闭了自动伸缩功能了,总的来说minReplicas和maxReplicas边界机制避免metrics数据异常导致的副本数不受控,特别是HPA在k8s最新的v1.18版本也依然是alpha特性,强烈建议大家谨慎设置这两个边界。
-
metrics指标类型和目标值,在autoscaling/v1里只有targetCPUUtilizationPercentage,autoscaling/v2beta1开始就扩展为metrics数组了,也就是说一个HPA可以同时设置多个类型维度的metrics目标指标,如果有多个HPA 将会依次考量各个指标,然后最终HPA Controller选择一个会选择扩缩幅度最大的那个为最终扩容副本数。在最新的autoscaling/v2beta2版本的HPA中,metrics type共有4种类型:Resource、Pods、Object、External,target里则定义了metrics的目标期望值,这里target的type也有三种类型Utilization,AverageValue和 Value,不同的metrics type都只能支持部分target type(详见上面表格)
此外,在autoscaling/v2beta2的HPA的spec里还新增了一个Behavior可选结构,它是用来精确控制HPA的扩容和缩容的速度。
完整的HPA的定义可参考k8s的官方API文档
3、缩容冷却机制(cooldown delay)
虽然HPA同时支持扩容和缩容,但是在生产环境上扩容一般来说重要性更高,特别是流量突增的时候,能否快速扩容决定了系统的稳定性,所以HPA的算法里对扩容的时机是没有额外限制的,只要达到扩容条件就会在reconcile里执行扩容(当前一次至少扩容到原来的1.1倍)。但是为了避免过早缩导致来回波动(thrashing ),而容影响服务稳定性甚,HPA的算法对缩容的要求比较严格,通过设置一个默认5min(可配置horizontal-pod-autoscaler-downscale-stabilization)的滑动窗口,来记录过去5分钟的期望副本数,只有连续5分钟计算出的期望副本数都比当前副本数小,才执行scale缩容操作,缩容的目标副本数取5分钟窗口的最大值。
总的来说k8s HPA算法的默认扩缩容原则是:快速扩容,谨慎缩容。
4、不同扩缩容速率需求场景下的behavior用法举例
场景1:扩容越快越好
如果业务希望能尽快的扩容,可以配置大的 percent值,可以按照如下配置:
behavior: scaleUp: policies: - type: Percent value: 900 periodSeconds: 60
假如 deployment的副本数最开始是1,那么每隔60s的的极限扩容副本数的变化如下:
1 -> 10 -> 100 -> 1000
也就是每个扩容period都是(1+900%)=10倍的速度,不过最大副本数依然不可用超过HPA 的 maxReplicas上界,缩容则使用默认行为。当然Percent类型可能对资源消耗波动特别大,如果希望资源消耗可控,可以按绝对副本数来Pods类型来配置。
场景 2: 扩容越快越好但要逐步缩容
当业务希望能尽快的扩容,但是缩容需要缓慢一些时,可以使用如下配置:
behavior: scaleUp: policies: - type: Percent value: 900 periodSeconds: 60 scaleDown: policies: - type: Pods value: 1 periodSeconds: 600
假如 pod 最开始数量为 1,那么扩容路径如下:
1 -> 10 -> 100 -> 1000
同时,缩容路径如下 (每 10 分钟缩容一次,每次减少一个 pod):
1000 -> 1000 -> 1000 -> … (another 7 min) -> 999 (最小不低于minReplicas)
场景 3: 逐步扩容、正常的缩容
当希望缓慢的扩容、正常的缩容,可以使用如下配置
behavior: scaleUp: policies: - type: Pods value: 1 periodSeconds: 600
把缩容的百分比或者pod 都置为 0,那么就永远不会缩容。或者直接设置 selectPolicy: Disabled。
behavior: scaleDown: policies: - type: Pods value: 1 periodSeconds: 600
场景 4: 正常扩容、不要缩容
如果希望能正常的扩容,但是不要自动缩容,可以使用如下配置:
behavior: scaleDown: policies: - type: Percent #或 Pods value: 0 periodSeconds: 600
都置为 0,那么就永远不会缩容。或者直接设置 selectPolicy: Disabled。
behavior: scaleDown: selectPolicy: Disabled
场景 5: 延后缩容
一般在流量激增时,都希望快速扩容应对,那么发现流量降低是否应该立马缩容呢,加入只是临时的流量降低呢,这样就可能导致短时间反复的扩缩容,为了避免这种情况,缩容时应该更谨慎些,可以使用延迟缩容机制:delaySeconds(这个跟 kube-controller-manager 的 horizontal-pod-autoscaler-downscale-stabilization 非常类似,但是这个参数是全局的,如果HPA有配置优先使用delaySeconds),配置如下:
behavior: scaleDown: policies: - type: Pods value: 5 periodSeconds: 600
那么,每次缩容最多减少 5 个 pod,同时每次缩容,至少要往前看 600s 窗口期的所有推荐值,每次都从窗口期中选择最大的值。这样,除非连续600s的推荐值都比之前的最大副本数小,才开始缩容、
5、案例
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeName: k8s-node2
containers:
- name: nginx
image: nginx:latest # 使用默认配置的 nginx 镜像
ports:
- containerPort: 80
resources:
requests:
cpu: "100m" # 100毫核,用于HPA计算
limits:
cpu: "500m" # 最大CPU限制

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx # 与 Deployment 名称匹配
minReplicas: 2 # 最小副本数(保持初始值)
maxReplicas: 10 # 最大可扩容到10个副本
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 15 # CPU 使用率超过15%时触发扩容

压力测试

监控变化触发库容


![]()

默认时间内未达到阈值则进行缩容

十四、EFK日志监控
在nfs-server 生成存储目录

master
pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: es-pv-0 # PV 的名字,自定义
spec:
capacity:
storage: 10Gi # 存储大小,必须 >= PVC 要求的大小
accessModes: ["ReadWriteOnce"] #ES StatefulSet 要求 ReadWriteOnce
nfs:
path: /data/efk
server: 192.168.11.20
storageClassName: "do-block-storage" #关联 StorageClass(确保与 class.yaml 名称一致,实现动态绑定)


svc
[root@k8s-master efk]# cat serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
[root@k8s-master efk]# cat rbac.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-provisioner
apiGroup: rbac.authorization.k8s.io

[root@k8s-master efk]# cat deployment.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-provisioner
spec:
selector:
matchLabels:
app: nfs-provisioner
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
- name: nfs-provisioner
image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: example.com/nfs
- name: NFS_SERVER
value: 192.168.11.20
- name: NFS_PATH
value: /data/efk
volumes:
- name: nfs-client-root
nfs:
server: 192.168.11.20
path: /data/efk
[root@k8s-master efk]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: do-block-storage
provisioner: example.com/nfs

构建es
[root@k8s-master efk]# cat elasticsearch_svc.yaml
kind: Service
apiVersion: v1
metadata:
name: elasticsearch
namespace: kube-logging
labels:
app: elasticsearch
spec:
selector:
app: elasticsearch
clusterIP: None
ports:
- port: 9200
name: rest
- port: 9300
name: inter-node
[root@k8s-master efk]# cat kube-logging.yaml
kind: Namespace
apiVersion: v1
metadata:
name: kube-logging
[root@k8s-master efk]# cat elasticsearch-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: es-cluster
namespace: kube-logging
spec:
serviceName: elasticsearch
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
ports:
- containerPort: 9200
name: rest
protocol: TCP
- containerPort: 9300
name: inter-node
protocol: TCP
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
env:
- name: cluster.name
value: k8s-logs
- name: node.name
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: discovery.seed_hosts
value: "es-cluster-0.elasticsearch.kube-logging.svc.cluster.local" ##多节点es-cluster-1.elasticsearch.kube-logging.svc.cluster.local,es-cluster-2.elasticsearch.kube-logging.svc.cluster.local
- name: cluster.initial_master_nodes
value: "es-cluster-0" ##多节点es-cluster-1,es-cluster-2
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
initContainers:
- name: fix-permissions
image: busybox
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
securityContext:
privileged: true
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
- name: increase-vm-max-map
image: busybox
imagePullPolicy: IfNotPresent
command: ["sysctl", "-w", "vm.max_map_count=262144"]
securityContext:
privileged: true
- name: increase-fd-ulimit
image: busybox
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "ulimit -n 65536"]
securityContext:
privileged: true
volumeClaimTemplates:
- metadata:
name: data
labels:
app: elasticsearch
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: do-block-storage
resources:
requests:
storage: 10Gi

验证es是否搭建好
每个节点都安装
yum install -y socat
master执行
kubectl port-forward --address 192.168.11.10 es-cluster-0 9200:9200 --namespace=kube-logging
访问

kibana汉化
[root@k8s-master efk]# cat kibana.yml
server.name: kibana
server.host: "0"
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
xpack.monitoring.ui.container.elasticsearch.enabled: true
i18n.locale: "zh-CN"
[root@k8s-master efk]# kubectl -n kube-logging create configmap kibana-configmap --from-file=kibana.yml=./kibana.yml
configmap/kibana-configmap created

apiVersion: v1
kind: Service
metadata:
name: kibana
namespace: kube-logging
labels:
app: kibana
spec:
type: NodePort
ports:
- port: 5601
selector:
app: kibana
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
namespace: kube-logging
labels:
app: kibana
spec:
replicas: 1
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- name: kibana
image: docker.elastic.co/kibana/kibana:7.2.0
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
env:
- name: ELASTICSEARCH_URL
value: http://elasticsearch.kube-logging.svc.cluster.local:9200
ports:
- containerPort: 5601
volumeMounts:
- name: kibana-config
mountPath: /usr/share/kibana/config/
volumes:
- name: kibana-config
configMap:
name: kibana-configmap

fluentd

访问


十五、promethus
1、概述
1、什么是Prometheus
Prometheus(普罗米修斯) 是一个开源的监控系统,以多维数据模型(指标名称和键值对的标识)和基于 HTTP 的 Pull 模型,支持多种维度的数据采集和动态查询。
它的核心组件Prometheus server会定期从静态配置的监控目标或者基于服务发现自动配置的自标中进行拉取数据,当新拉取到的数据大于配置的内存缓存区时,数据就会持久化到存储设备当中。
-
每个被监控的主机都可以通过专用的exporter 程序提供输出监控数据的接口,它会在目标处收集监控数据,并暴露出一个HTTP接口供Prometheus server查询,Prometheus通过基于HTTP的pull的方式来周期性的采集数据。
-
任何被监控的目标都需要事先纳入到监控系统中才能进行时序数据采集、存储、告警和展示,监控目标可以通过配置信息以静态形式指定,也可以让Prometheus通过服务发现的机制进行动态管理。
-
Prometheus 能够直接把API Server作为服务发现系统使用,进而动态发现和监控集群中的所有可被监控的对象。
2、Zabbix和Prometheus区别
-
和Zabbix类似,Prometheus也是一个近年比较火的开源监控框架,和Zabbix不同之处在于Prometheus相对更灵活点,模块间比较解耦,比如告警模块、代理模块等等都可以选择性配置。服务端和客户端都是开箱即用,不需要进行安装。zabbix则是一套安装把所有东西都弄好,很庞大也很繁杂。
-
zabbix的客户端 agent 可以比较方便的通过脚本来读取机器内数据库、日志等文件来做上报。而 Prometheus 的上报客户端则分为不同语言的SDK和不同用途的 exporter 两种,比如如果你要监控机器状态、mysql性能等,有大量已经成熟的 exporter 来直接开箱使用,通过http 通信来对服务端提供信息上报(server去pull信息);而如果你想要监控自己的业务状态,那么针对各种语言都有官方或其他人写好的 sdk供你使用,都比较方便,不需要先把数据存入数据库或日志再供zabbix-agent采集。
-
zabbix的客户端更多是只做上报的事情,push模式。而Prometheus则是客户端本地也会存储监控数据,服务端定时来拉取想要的数据。
-
界面来说zabbix比较陈旧,而prometheus比较新且非常简洁,简洁到只能算一个测试和配置平台。要想获得良好的监控体验,搭配Grafana还是二者的必走之路。
3、Prometheus的特点
多维数据模型:由度量名称和键值对标识的时间序列数据 时序数据,是在一段时间内通过重复测量(measurement)而获得的观测值的集合;将这些观测值绘制于图形之上,它会有一个数据轴和一个时间轴;服务器指标数据、应用程序性能监控数据、网络数据等也都是时序数据;
-
内置时间序列(pime series)数据库:Prometheus;外置的远端存储通常会用:InfluxDB、openTsDB等
-
PromQL一种灵活的查询语言,可以利用多维数据完成复杂查询
-
基于HTTP的pull(拉取)方式采集时间序列数据
-
同时支持Push Gateway组件收集数据
-
通过服务发现或者静态配置,来发现目标服务对象
-
支持作为数据源接入Grafana
2、运维监控平台设计思路
-
数据收集模块
-
数据提取模块(prometheus-TSDB,查询语言是promQL)
-
监控告警模块(布尔值表达式判断是否需要告警,不成立是健康状态)
可以细化为6层
-
第六层:用户展示管理层 统一用户管理、集中监控、集中维护
-
第五层:告警事件生成层 实时记录告警事件、形成分析图表(趋势分析、可视化)
-
第四层:告警规则配置层 告警规则设置、告警阈值设置(定义布尔值表达式,筛选异常状态)
-
第三层:数据提取层 定时采集数据到监控模块
-
第二层:数据展示层 数据生成曲线图展示(对时序数据的动态展示)
-
第一层:数据收集层 多渠道监控数据(网络,硬件,应用,数据,物理环境)
3、Prometheus监控体系
1、系统层监控(需要监控的数据)
-
CPU、Load、Memory、swap、disk、I/O、process等
-
网络监控:网络设备、工作负载、网络延迟、丢包率等
2、中间件及基础设施类监控
-
消息中间件:kafka、RocketMQ、等消息代理(redis 中间件)
-
WEB服务容器:tomcat、weblogic、jboss、apache、php、spring系列
-
数据库/缓存数据库:Mysql、Postgresql、MongoDB、es、redis
redis监控内容
-
redis的服务状态
-
redis所在服务器的系统层监控
-
RDB和AOF日志监控
-
日志--->如果是哨兵模式--->哨兵共享集群信息,产生的日志--->直接包含的其他节点哨兵信息及mysql信息
3、应用层监控
用于衡量应用程序代码状态和性能
监控的分类:
-
白盒监控:自省指标,等待被下载(cadvisor)
-
黑盒监控:基于探针(snmp)的监控方式,不会主动干预、影响数据
4、业务层监控
用于衡量应用程序的价值,如电商业务的销售量,ops、dau日活、转化率等,
业务接口:登入数量,注册数、订单量、搜索量和支付量
4、prometheus时间序列数据
时序数据,是在一段时间内通过重复测量(measurement)而获得的观测值的集合将这些观测值绘制于图形之上,它会有一个数据轴和一个时间轴,服务器指标数据、应用程序性能监控数据、网络数据等也都是时序数据
1、数据来源
prometheus基于HTTP call (http/https请求),从配置文件中指定的网络端点(endpoint/IP:端口)上周期性获取指标数据。 很多环境、被监控对象,本身是没有直接响应/处理http请求的功能,prometheus-exporter则可以在被监控端收集所需的数据,收集过来之后,还会做标准化,把这些数据转化为prometheus可识别,可使用的数据(兼容格式)
2、收集数据
监控概念:白盒监控、黑盒监控 白盒监控:自省方式,被监控端内部,可以自己生成指标,只要等待监控系统来采集时提供出去即可 黑盒监控:对于被监控系统没有侵入性,对其没有直接"影响",这种类似于基于探针机制进行监控(snmp协议)
Prometheus支持通过三种类型的途径从目标上"抓取(Scrape)"指标数据(基于白盒监控);
-
Exporters ——>工作在被监控端,周期性的抓取数据并转换为pro兼容格式等待prometheus来收集,自己并不推送
-
Instrumentation ——>指被监控对象内部自身有数据收集、监控的功能,只需要prometheus直接去获取
-
Push gateway ——>短周期5s—10s的数据收集
3、prometheus(获取方式)
Prometheus同其它TSDB相比有一个非常典型的特性:它主动从各Target上拉取(pull)数据,而非等待被监控端的推送(push)
两个获取方式各有优劣,其中,Pull模型的优势在于:
-
集中控制:有利于将配置集在Prometheus server上完成,包括指标及采取速率等;
-
Prometheus的根本目标在于收集在target上预先完成聚合的聚合型数据,而非一款由事件驱动的存储系统
-
通过targets(标识的是具体的被监控端)
-
比如配置文件中的 targets:['localhost:9090']
5、prometheus生态组件
1、Prometheus Server
收集和储存时间序列数据
Prometheus server:服务核心组件,采用pull方式收集监控数据,通过http协议传输。并存储时间序列数据。Prometheus server 由三个部分组成:Retrival,Storage,PromQL
Retrieval:负责在活跃的target 主机上抓取监控指标数据。
Storage:存储,主要是把采集到的数据存储到磁盘中。默认为15天(可修改)。
PromQL:是Prometheus提供的查询语言模块。
2、Client Library
client Library:客户端库,目的在于为那些期望原生提供 Instrumentation 功能的应用程序提供便捷的开发途径,用于基于应用程序内建的测量系统。
3、Push Gateway
Pushgateway:类似一个中转站,Prometheus的server端只会使用pull方式拉取数据,但是某些节点因为某些原因只能使用push方式推送数据,那么它就是用来接收push而来的数据并暴露给Prometheus的server拉取的中转站。可以理解成目标主机可以上报短期任务的数据到Pushgateway,然后Prometheus server 统一从Pushgateway拉取数据。
4、Exporters
用于暴露现有应用程序或服务(不支持Instrumentation)的指标给Prometheus Server,而pro内建了数据样本采集器,可以通过配置文件定义,告诉prometheus到那个监控对象中采集指标数据,prometheus 采集过后,会存储在自己内建的TSDB数据库中,提供了promQL 支持查询和过滤操作,同时支持自定义规则来作为告警规则,持续分析一场指标,一旦发生,通知给alerter来发送告警信息,还支持对接外置的UI工具(grafana)来展示数据;采集、抓取数据是其自身的功能,但一般被抓去的数据一般来自于: export/instrumentation (指标数据暴露器) 来完成的,或者是应用程序自身内建的测量系统(汽车仪表盘之类的,测量、展示)来完成
5、Alertmanager
Alertmanager:是一个独立的告警模块,从Prometheus server端接收到“告警通知”后,会进行去重、分组,并路由到相应的接收方,发出报警,常见的接收方式有:电子邮件、钉钉、企业微信等。
1.Prometheus Server 仅负责生成告警指示,具体的告警行为由另一个独立的应用程序AlertManager负责; 2.告警指示由 Prometheus Server基于用户提供的告警规则周期性计算生成,Alertmanager 接收到Prometheus Server发来的告警指示后,基于用户定义的告警路由向告警接收人发送告警信息。
6、Service Discovery
Service Discovery:服务发现,用于动态发现待监控的Target,Prometheus支持多种服务发现机制:文件、DNS、Consul、Kubernetes等等。
服务发现可通过第三方提供的接口,Prometheus查询到需要监控的Target列表,然后轮询这些Target 获取监控数据。该组件目前由Prometheus Server内建支持。
7、grafana
Grafana:是一个跨平台的开源的度量分析和可视化工具,可以将采集的数据可视化的展示,并及时通知给告警接收方。其官方库中具有丰富的仪表盘插件。
Prometheus 数据流向
-
Prometheus server 定期从配置好的 jobs 或者 exporters 中拉取 metrics(指标),或者接收来自Pushgateway 发送过来的metrics,或者从其它的Prometheus server中拉取 metrics。
-
Prometheus server在本地存储收集到的 metrics,并运行定义好的 alerts.rules,记录新的时间序列或者向Alert manager推送警报。
-
Alertmanager 根据配置文件,对接收到的警报进行处理,发出告警。
-
在图形界面中,可视化采集数据。
6、prometheus工作原理
1、prometheus工作模式
-
Prometheus Server 基于服务发现(Service Discovery)机制或静态配置获取要监视的目标(Target),并通过每个目标上的指标 exporter来采集(Scrape)指标数据;
-
Prometheus Server 内置了一个基于文件的时间序列存储来持久存储指标数据,用户可使用PromQL接口来检索数据,也能够按需将告警需求发往Altermanager完成告警内容发送;
-
一些短期运行的作业的生命周期过短,难以有效地将必要的指标数据供给到Server端,它们一般会采用推送(Push)方式输出指标数据,Prometheus借助于Pushgateway 接收这些推送的数据,进而由server端进行抓取。
2、prometheus工作流程
1、图流程图
- Prometheus以prometheus Server 为核心,用于收集和存储时间序列数据。Prometheus Server从监控目标中通过pull方式拉取指标数据,或通过pushgateway 把采集的数据拉取到Prometheus server中。
- Prometheus server 把采集到的监控指标数据通过 TSDB存储到本地HDD/ssD中。
- Prometheus 采集的监控指标数据按时间序列存储,通过配置报警规则,把触发的报警发送到Alertmanager。
- Alertmanager 通过配置报警接收方,发送报警到邮件、钉钉或者企业微信等。
- Prometheus 自带的Web UI 界面提供 PromQL 查询语言,可查询监控数据。
- Grafana 可接入Prometheus 数据源,把监控数据以图形化形式展示出。
2、告警数据采集、告警信息提取、告警通知
-
首先,需要采集监控数据,pro会周期性的pull或被push指标数据,数据采集的方式主要包括exporters、instrumentation、pushgateway 3种方式,前两者为pull方式获取,pushgateway借助于push方式推送给prometheus。
-
根据prometheus配置文件中(K8S-configmap的配置中),获取被监控端的数据之后,保存在TSDB中,我们可以借助Grafana或者告警平台来展示数据,grafana的展示是通过PromQL来获取数据。
-
prometheus通过rule配置来借助于PromQL来定义布尔值表达式,产生告警信息
-
一旦出现告警,prometheus产生告警信息,发送给altermanager,altermanager根据自定义的告警路由,来进行告警通知,对接第三方平台,例如告警平台、邮件、钉钉。
3、prometheus的局限性
-
Prometheus是一款指标监控系统,不适合存储事件及日志等;它更多地展示的是趋势性的监控,而非精准数据;
-
Prometheus认为只有最近的监控数据才有查询的需要,其本地存储的设计初衷只是保存短期(例如一个月)数据,因而不支持针对大量的历史数据进行存储;若需要存储长期的历史数据,建议基于远端存储机制将数据保存于InfluxDB或openTsDB等系统中;
-
Prometheus的集群机制成熟度不高,可基于Thanos(和灭霸是一个单词)实现Prometheus集群的高可用及联邦集群
7、总结
1、prometheus如何收集k8s/服务的–三种方式收集
-
Exporters(指标暴露器):收集节点的信息、将数据格式化或转化为 promtheus 可识别的http这种转化方式/镜像拉取方式
-
Instrumentation (应用内置的指标暴露器): 收集有内置指标暴露器的信息
-
Pushgateway : 收集短周期的数据
2 、如何防止告警信息轰炸
alertmanager: prometheus可以生成告警信息,但是不能直接提供告警,需要使用一个外置的组件alertmanager来进行告警,emailetctif优势在于,收敛、支持静默、去重、可以防止告警信息的轰炸。 把这条告警规则中的支持静默开启,让它必须,配置文件里直接改alertmanager改一个单词
3、prometheus监控什么
| 级别 | 监控什么 | exporter |
|---|---|---|
| 网络 | 网络协议:http、dns、tcp、icmp; 网路硬件:路由器、交换机等 | BlockBox Exporter;SNMP Exporter |
| 主机 | 资源用量 | node exporter |
| 容器 | 资源用量 | cadvisor |
| 应用(包括Library) | 延迟、错误,QPS,内部状态 | 代码集中集成Prometheus Client |
| 中间件状态 | 资源用量,以及服务状态 | 代码集中集成Prometheus Client |
| 编排工具 | 集群资源用量,调度等 | Kubernetes Components |
8、0.14版安装

vim prometheus-service.yaml
vim grafana-service.yaml
vim alertmanager-service.yaml
#以上配置文件分别增加如下配置:
spec:
type: NodePort#因为外部访问

kubectl create -f ./setup
kubectl create -f ./
删除网络策略
kubectl delete -f prometheus-networkPolicy.yaml
kubectl delete -f grafana-networkPolicy.yaml
kubectl delete -f alertmanager-networkPolicy.yaml



十六、发布
1、蓝绿发布
在Kubernetes中,蓝绿发布(Blue-Green Deployment) 是一种部署策略,通过同时维护两个完全独立的生产环境(“蓝”和“绿”),在验证新版本(绿)后,一次性将流量从旧版本(蓝)切换到新版本,若发现问题则立即回退。其核心特点是零停机时间和快速回滚。
1.1、蓝绿发布的核心原理
-
双环境共存:
-
蓝环境(Blue):当前生产环境,处理所有用户流量。
-
绿环境(Green):新版本环境,部署完成后处于待命状态。
-
-
流量切换:
-
通过更新负载均衡规则或Service选择器,将所有流量从蓝环境切换到绿环境。
-
-
快速回滚:
-
若绿环境异常,只需将流量重新指向蓝环境即可恢复。
-
1.2、蓝绿发布的实现方法及步骤
1. 通过Service切换标签(Label Selector)
原理:利用Kubernetes Service的标签选择器,将流量从旧版本Pod(蓝)切换到新版本Pod(绿)。
步骤:
-
部署蓝环境(旧版本):
# deployment-blue.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-blue spec: replicas: 3 selector: matchLabels: app: myapp version: blue # 标签标识蓝环境 template: metadata: labels: app: myapp version: blue spec: containers: - name: myapp image: myapp:v1 # service.yaml apiVersion: v1 kind: Service metadata: name: myapp-service spec: selector: app: myapp version: blue # 初始指向蓝环境 ports: - protocol: TCP port: 80 targetPort: 8080
-
部署绿环境(新版本):
# deployment-green.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-green spec: replicas: 3 selector: matchLabels: app: myapp version: green # 标签标识绿环境 template: metadata: labels: app: myapp version: green spec: containers: - name: myapp image: myapp:v2
-
切换Service流量到绿环境:
kubectl patch service myapp-service -p '{"spec":{"selector":{"version":"green"}}}' -
验证与回滚:
-
若绿环境运行正常,删除蓝环境的Deployment。
-
若异常,重新切换Service选择器回
version: blue。
-
优缺点:
-
优点:简单直接,依赖Kubernetes原生功能。
-
缺点:需手动切换,无流量逐步验证过程。
2. 通过Ingress控制器(如Nginx)切换后端服务
原理:通过更新Ingress规则,将流量从蓝环境Service切换到绿环境Service。
步骤:
-
部署蓝环境和绿环境:
-
分别为蓝、绿环境创建Deployment和Service(如
myapp-blue-svc和myapp-green-svc)。
-
-
配置初始Ingress指向蓝环境:
# ingress-blue.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: myapp-blue-svc # 初始指向蓝环境 port: number: 80
-
更新Ingress指向绿环境:
# ingress-green.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: myapp-green-svc # 切换至绿环境 port: number: 80
-
应用新Ingress配置:
kubectl apply -f ingress-green.yaml
优缺点:
-
优点:适用于HTTP流量,支持复杂路由规则。
-
缺点:需手动操作,依赖Ingress控制器的更新速度。
1.3、总结
| 方法 | 适用场景 | 核心优势 | 局限性 |
|---|---|---|---|
| Service标签切换 | 简单场景,快速切换 | 无需额外工具 | 手动操作,无流量验证 |
| Ingress控制器 | HTTP服务,需精细路由控制 | 灵活配置路由规则 | 依赖Ingress更新速度 |
| Istio服务网格 | 复杂环境,需流量镜像或高级路由 | 支持流量镜像和动态路由 | 需引入Istio,复杂度高 |
| Argo Rollouts | 自动化全流程,需预发布验证 | 自动化创建、验证和清理环境 | 需额外组件支持 |
最佳实践
-
数据库兼容性:确保新版本与旧版本数据库模式兼容,或使用双写策略。
-
会话保持:若应用有状态(如用户登录),需确保流量切换后会话不丢失。
-
监控与告警:在切换前后监控关键指标(错误率、延迟、资源使用率)。
-
自动化测试:在切换前对绿环境进行自动化API测试和冒烟测试。
根据团队的技术栈和运维能力,选择最合适的蓝绿发布方案。对于需要全自动化和预发布验证的场景,推荐使用Argo Rollouts;对于已使用服务网格的团队,Istio是更优选择。
2、金丝雀发布
在Kubernetes中,金丝雀发布(Canary Release) 是一种渐进式部署策略,目的是将新版本应用逐步暴露给一小部分用户或流量,通过持续监控确保其稳定性后,再逐步扩大范围直至完全替换旧版本。这种策略的名称来源于“矿井中的金丝雀”——早期矿工用金丝雀来检测有毒气体,如果金丝雀存活,说明环境安全
2.1、金丝雀发布的核心原理
-
小范围验证:
-
先部署新版本(金丝雀版本)到生产环境,但仅允许少量用户或流量访问它(例如5%的请求)。
-
大部分流量仍由旧版本处理,确保用户整体体验不受影响。
-
-
监控与观察:
-
监控新版本的性能指标(如错误率、延迟、CPU/内存使用率等)。
-
如果新版本表现稳定,逐步增加其流量比例;如果发现问题,立即回滚。
-
-
逐步替换:
-
最终将100%流量切换到新版本,完成平滑升级。
-
2.2、为什么在Kubernetes中使用金丝雀发布?
-
降低风险:
-
避免一次性全量发布导致全局故障,尤其适用于关键业务场景。
-
-
快速反馈:
-
通过真实流量验证新版本,比测试环境更可靠。
-
-
无缝回滚:
-
发现问题时,只需将流量切回旧版本,无需重新部署。
-
2.3、金丝雀发布的典型实现方式
1. 基于Deployment副本数的金丝雀发布
原理
通过调整新旧版本Pod的副本数比例,利用Kubernetes Service的负载均衡能力,按比例分配流量到新旧版本。
步骤
-
部署旧版本:
# deployment-v1.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v1 spec: replicas: 9 # 初始副本数为9 selector: matchLabels: app: myapp version: v1 template: metadata: labels: app: myapp version: v1 spec: containers: - name: myapp image: myapp:v1 --- apiVersion: v1 kind: Service metadata: name: myapp-service spec: selector: app: myapp # 同时选择v1和v2的Pod ports: - protocol: TCP port: 80 targetPort: 8080
-
部署金丝雀版本:
# deployment-v2.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v2 spec: replicas: 1 # 初始副本数为1(占10%流量) selector: matchLabels: app: myapp version: v2 template: metadata: labels: app: myapp version: v2 spec: containers: - name: myapp image: myapp:v2
-
逐步调整副本比例:
-
若v2运行正常,逐步增加其副本数,同时减少v1的副本数:
kubectl scale deployment myapp-v2 --replicas=3 # 占25%流量(3/(9+3)=25%) kubectl scale deployment myapp-v1 --replicas=9 # 保持旧版本可用
-
最终将v1副本数降为0,完成全量切换。
-
优缺点
-
优点:无需额外工具,完全依赖Kubernetes原生资源。
-
缺点:流量分配不够精确(依赖负载均衡策略),需手动调整副本数。
2. 基于Nginx Ingress控制器的金丝雀发布
原理
通过Ingress的注解(Annotation)按权重分流流量,将特定比例的请求定向到新版本。
步骤
-
部署主版本和金丝雀版本:
# deployment-v1.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v1 spec: replicas: 3 template: metadata: labels: app: myapp version: v1 # ...其他配置 # service-v1.yaml apiVersion: v1 kind: Service metadata: name: myapp-v1 spec: selector: app: myapp version: v1 ports: - port: 80 targetPort: 8080 # deployment-v2.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v2 spec: replicas: 1 template: metadata: labels: app: myapp version: v2 # ...其他配置 # service-v2.yaml apiVersion: v1 kind: Service metadata: name: myapp-v2 spec: selector: app: myapp version: v2 ports: - port: 80 targetPort: 8080
-
配置Canary Ingress:
# ingress-canary.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-canary annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "10" # 10%流量到v2 spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: myapp-v2 port: number: 80
-
调整流量权重:
-
修改
canary-weight注解值,逐步增加新版本流量:kubectl annotate ingress/myapp-canary \ nginx.ingress.kubernetes.io/canary-weight="50" # 50%流量到v2
-
最终删除旧版本Ingress,完成发布。
-
优缺点
-
优点:流量控制精确,无需Service Mesh。
-
缺点:依赖Nginx Ingress控制器功能。
2.4、总结
| 方法 | 适用场景 | 核心优势 | 局限性 |
|---|---|---|---|
| Deployment副本数 | 简单场景,无需精确流量控制 | 无需额外工具 | 流量分配不精确,需手动调整 |
| Nginx Ingress | 需要按权重分流的HTTP服务 | 精确流量控制,配置简单 | 依赖Ingress控制器功能 |
| Istio服务网格 | 复杂路由需求(如基于请求头) | 高级流量控制,精准灵活 | 需引入Istio,复杂度高 |
| Flagger自动化工具 | 需要全自动化监控和回滚的关键业务 | 自动化渐进发布,安全可靠 | 依赖Prometheus和Flagger组件 |
金丝雀发布 vs 蓝绿部署
-
金丝雀发布:逐步替换,新旧版本共存,适合需要持续验证的场景。
-
蓝绿部署:同时运行两个完整环境(蓝/绿),一次性切换流量,适合快速回滚,但资源消耗更大。
最佳实践
-
关键指标监控:
-
错误率、请求延迟、资源利用率(CPU/内存)。
-
业务自定义指标(如订单成功率)。
-
-
设置回滚阈值:
-
例如:若错误率超过1%,自动回滚到旧版本。
-
-
结合A/B测试:
-
根据用户特征(如地理位置、设备类型)定向分发流量。
-
总结
金丝雀发布是Kubernetes中降低发布风险的核心策略,通过逐步验证新版本的稳定性,确保业务连续性。选择实现方式时需权衡团队技术栈、流量控制精度和运维复杂度。对于关键业务,建议结合自动化工具(如Flagger)和监控告警,实现安全可控的渐进式发布。
| 特性 | 蓝绿发布 | 金丝雀发布 |
|---|---|---|
| 环境数量 | 同时维护两个完整环境 | 新旧版本共存于同一环境 |
| 流量切换 | 一次性全量切换 | 逐步迁移流量 |
| 资源消耗 | 较高(需双倍资源) | 较低(仅需部分副本) |
| 回滚速度 | 极快(秒级切换) | 较快(需调整流量比例) |
| 适用场景 | 关键业务的全量验证 | 渐进式验证和风险控制 |
更多推荐


所有评论(0)