技术

云计算-03(kubernetes)

2025/11/27
0
0

日期2025.08.29学习日志

  1. StatefulSet:管理有状态应用
  2. 什么是有状态应用:介绍

:有一些应用,运行状态信息就很重要了,如果因为重启而丢失了状态是绝对无法接受的,这样的应用就是“有状态应用”。“有状态应用”的例子也有很多,比如 Redis、MySQL 这样的数据库,它们的“状态”就是在内存或者磁盘上产生的数据,是应用的核心价值所在,如果不能够把这些数据及时保存再恢复,那绝对会是灾难性的后果

MQ: RabbitMQ RocketMQ 消息队列 异步处理

流处理:Kafka

#使用较多的有状态应用

  • 有状态应用特点:
  1. 以集群方式运行
  2. 启动顺序 :mysql-0 mysql-1 mysql-2
  3. 依赖关系:名字不会改变,在启动时也可以使用pod 名,解决依赖关系
  4. 唯一标识 :Pod 创建一个唯一域名

#客户端如何去访问,mysql主从。就使用pod创建一个唯一域名

:用 Deployment 来保证高可用,用 PersistentVolume 来存储数据,确实可以部分达到管理“有状态应用”的目的

:但是 Kubernetes 的眼光则更加全面和长远,它认为“状态”不仅仅是数据持久化,在集群化、分布式的场景里,还有多实例的依赖关系、启动顺序和网络标识等问题需要解决,而这些问题恰恰是 Deployment 力所不及的

:但对于“有状态应用”,多个实例之间可能存在依赖关系,比如 master/slave、active/passive,需要依次启动才能保证应用正常运行,外界的客户端也可能要使用固定的网络标识来访问实例,而且这些信息还必须要保证在 Pod 重启后不变

:所以,Kubernetes 就在 Deployment 的基础之上定义了一个新的 API 对象,名字也很好理解,就叫 StatefulSet,专门用来管理有状态的应用

  1. 使用 YAML 描述 StatefulSet

:StatefulSet 也可以看做是 Deployment 的一个特例,不能直接使用kubectl create 创建样板文件

  • yaml文件头部信息:

Redis的statefulSet:yaml文件:

#在statefulSet直接把svc名字加入了进来,serviceName选项,解决给pod起一个域名

# YAML 文件里除了 kind 必须是“StatefulSet”,在spec 里还多出了一个“serviceName”字段,其余的部分和 Deployment 是一模一样的,比如 replicas、selector、template 等等

  1. 如何在 Kubernetes 里使用 StatefulSet
  2. 执行:kubectl apply -f redis-svc.yaml:创建一个svc

#可根据现有的模板进行创建

  1. 执行:kubectl apply -f redis-sts.yml:创建StatefulSet 对象
  2. 执行:kubectl get sts:进行查看
  3. 执行:kubectl get pod:进行查看

#有状态应用启动之后删除,会和之前的名字一样

#可以看出StatefulSet 所管理的 Pod 不再是随机的名字了,而是有了顺序编号,从 0 开始分别被命名为 redis-sts-0、redis-sts-1,Kubernetes 也会按照这个顺序依次创建(0 号比 1 号的 AGE 要长一点),这就解决了“有状态应用”的第一个问题:启动顺序

  • 有了启动的先后顺序,应用该怎么知道自己的身份,进而确定互相之间的依赖关系呢?
  1. 执行:kubectl exec -it redis-sts-0 -- sh

#有了这个唯一的名字,应用就可以自行决定依赖关系了,比如在这个 Redis 例子里,就可以让先启动的 0 号 Pod 是主实例,后启动的 1 号 Pod 是从实例

  • 解决了启动顺序和依赖关系,还剩下第三个问题:网络标识,这就需要用到 Service 对象

#无法进行向后轮询,就给每个pod添加一个域名

图片包含 雷达图

AI 生成的内容可能不正确。

#写 Service 对象的时候要小心一些,metadata.name 必须和 StatefulSet 里的 serviceName 相同,selector 里的标签也必须和 StatefulSet 里的一致:

文本

AI 生成的内容可能不正确。

:StatefulSet 的场景下,因为每个 Pod 也都拥有了固定的名称,所以每个 Pod 也可以分配一个固定的域名,格式是Pod 名. 服务名. 命名空间.svc.cluster.local”。解决每个pod的唯一标识

#域名在之前svc的基础上增加了一个pod名

验证测试:

  1. 执行:kubectl exec -it redis-sts-0 – sh:进入容器内部

屏幕上有字

AI 生成的内容可能不正确。

#在 StatefulSet 里的这两个 Pod 都有了各自的域名,也就是稳定的网络标识。那么接下来,外部的客户端只要知道了 StatefulSet 对象,就可以用固定的编号去访问某个具体的实例了,虽然 Pod 的 IP 地址可能会变,但这个有编号的域名由 Service 对象维护,是稳定不变的

:通过 StatefulSet 和 Service 的联合使用,Kubernetes 就解决了“有状态应用”的依赖关系、启动顺序和网络标识这三个问题

  1. headless service:无头服务

:Service 原本的目的是负载均衡,应该由它在 Pod 前面来转发流量,但是对 StatefulSet 来说,这项功能反而是不必要的,因为 Pod 已经有了稳定的域名,外界访问服务就不应该再通过 Service 这一层了

#给pod起了一个域名之后,clusterIP就没有了用处

#在创建SVC时不分配clusterIP,属于无头服务

  • 在 Service 里添加一个字段 clusterIP: None ,告诉 Kubernetes 不必再为这个对象分配 IP 地址。这种类型的 Service 对象也被称为 Headless Services (无头服务 )

#创建statefulSet对象 ,习惯上创建一个有头SVC ,再创建一个无头SVC ,根据 应用的特点 用户选择使用哪个 SVC

  • 有头SVC : redis-svc.default.svc.cluster.local :会被解析成 ClusterIP

# ClusterIP进行轮询算法 返回 一个POd IP

Name: redis-svc.default.svc.cluster.local

Address: 10.98.85.8

图形用户界面

AI 生成的内容可能不正确。

  • 无头SVC: redis-svc-headless.default.svc.cluster.local :会被解析成Pod的IP地址

Name: redis-svc-headless.default.svc.cluster.local

Address: 10.244.37.219

Name: redis-svc-headless.default.svc.cluster.local

Address: 10.244.171.3

  1. 实现 StatefulSet 数据持久化

#有了固定的名字、启动顺序和网络标识,只要再给它加上数据持久化功能,我们就可以实现对“有状态应用”的管理了

:需要用到存储时学的 PersistentVolume 和 NFS 的知识,我们可以很容易地定义 StorageClass,然后编写 PVC,再给 Pod 挂载 Volume

:强调持久化存储与 StatefulSet 的一对一绑定关系,Kubernetes 为 StatefulSet 专门定义了一个字段volumeClaimTemplates”直接把 PVC 定义嵌入 StatefulSet 的 YAML 文件里。这样能保证创建 StatefulSet 的同时,就会为每个 Pod 自动创建 PVC,让 StatefulSet 的可用性更高

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

雷达图

AI 生成的内容可能不正确。

#每创建一个pod就会创建一个pvc

#首先 StatefulSet 对象的名字是 redis-pv-sts,表示它使用了 PV 存储。然后“volumeClaimTemplates”里定义了一个 PVC,名字是 redis-100m-pvc,申请了 100MB 的 NFS 存储。在 Pod 模板里用 volumeMounts 引用了这个 PVC,把网盘挂载到了 /data 目录,也就是 Redis 的数据目录

  1. kubectl apply -f redis-pv-sts.yml:运行带有持久化的应用

#创建要保证NFS服务器是正常的

  1. 执行:kubectl get pvc -w:通过实时创建查看

电脑萤幕画面

AI 生成的内容可能不正确。

#可以看到pvc创建成功

#这两个 PVC 的命名,用的是 PVC 名字加上 StatefulSet 的名字组合而成,所以即使 Pod 被销毁,因为它的名字不变,还能够找到这个 PVC,再次绑定使用之前存储的数据

  1. 进入NFS服务器的共享目录查看

屏幕上有字

AI 生成的内容可能不正确。

#可以看到创建了两个共享目录

  1. 执行:kubectl exec -it redis-pv-sts-0 -- sh:进入容器添加一些数据查看

文本

AI 生成的内容可能不正确。

模拟意外事故,删除pod:

  1. 执行:kubectl delete pods redis-pv-sts-0
  2. 执行:Kubectl get pods:进行查看

#可以看到删除之后会重新给我们创建一个新的pod

#由于 StatefulSet 和 Deployment 一样会监控 Pod 的实例,发现 Pod 数量少了就会很快创建出新的 Pod,并且名字、网络标识也都会和之前的 Pod 一模一样:

  1. 执行:kubectl exec -it redis-pv-sts-0 -- sh:进入容器查看

文本

AI 生成的内容可能不正确。

#通过查看原有数据依旧存在,pv和pvc自动挂载了进去

#Redis 就会定期把数据落盘保存,所以新创建的 Pod 再次挂载目录的时候会从备份文件里恢复数据,内存里的数据就恢复原状了

  • 有状态应用放置k8s的方式:

Operator:更适合在 k8s 中管理有状态的应用

mysql-operator

redis-operator

#不同的应用配置不同的operator

  1. 底层原理:
  2. 控制面和数据面底层原理
  • 控制面组件:

kube-apiserver:安全

kube-scheduler:调度

kube-controller-manager:控制器暴露参数

etcd

  • 数据面组件:

kubelet

kube-proxy :SVC时以讲解

CR:CRI CNI CSI

  1. etcd

介绍:Etcd 是_CoreOS 基于 Raft 协议开发的分布式 key-value 存储可用于服务发现、共享配置以及一致性保障。在分布式系统中,如何管理节点间的状态一直是一个难题,etcd 是专门为集群环境的服务发现和注册而设计,它提供了数据TTL失效、数据改变监视、多值、目录监听、分布式锁原子操作等功能,可以方便的跟踪并管理集群节点的状态。

  • 特点:
  • 键值对存储:将数据存储在分层组织的目录中;
  • 监测变更:监测特定的值或目录以进行更改,并对值的更改做出反应;
  • 简单:curl可访问用户的API;
  • 安全:可选的SSL客户端证书认证;
  • 快速:单实例每秒1000次写操作,2000次读操作;
  • 可靠:使用 Raft 算法保证一致性。
  • etcd安装:

#实验室可在work节点进行安装,避免节点冲突

#安装时去官网下载即可,或在github上下载

  1. 执行:tar -xf etcd-v3.5.21-1inux-amd64.tar.gz:解压在官网下载的安装包
  2. 执行:cd etcd-v3.5.21-1inux-amd64:进入目录

# etcd 是server端,etcdctl 是client端

  1. 执行:./etcd:启动server端
  2. 执行以下命令查看监听端口

#2370端口是客户端去连接服务端使用,2380端口是server之间进行访问使用的

  • 列出集群成员
  1. 执行:./etcdctl --endpoints=127.0.0.1:2379 member list --write-out=table

#链接时告诉server端在哪,添加member list去列出成员,列出集群中有多少个成员

#添加--write-out=table让显示更具清晰化,可以看到节点的一个具体变化

  • etcd数据库执行写入操作:增、删、改、查

写入数据:

./etcdctl --endpoints=127.0.0.1:2379 put /key1 val1

#etcd的键必须是斜杠开头

读取数据:

./etcdctl --endpoints=localhost:2379 get /key1

模糊查询:按 Key 的前缀查询数据

./etcdctl --endpoints=localhost:2379 get --prefix /a

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

#前缀查询,以什么为开头,模糊查询

只显示键值:

./etcdctl --endpoints=localhost:2379 get --prefix / --keys-only

#添加一个--keys-only

修改值:

./etcdctl --endpoints=127.0.0.1:2379 put /a/b/c/d 123456

#使用put和要键,加上要修改的值

删除:

./etcdctl --endpoints=127.0.0.1:2379 del /a

#删除时通过返回值判断是否删除正确,1代表删除,0代表没有找到

./etcdctl --endpoints=localhost:2379 watch --prefix /name --rev 1

形状

AI 生成的内容可能不正确。

#watch功能个kubectl get pods -w的作用一致,在数据库做的任何操作,客户端都能收到通知

  • k8s组件之间如何互相通信:使用list-watch

#list-watch只要数据发生改变就会手到消息,etcd提供的功能

#加一个pod,etcd里面就会加一个key,所有watch的客户端都可以收到这个消息,调度器也会去watch一下etcd就会发现多了一个pod,对pod进行调度。kubelet如何知道调度到那个节点也是通过watch

  • 灾备

备份:etcdctl --endpoints=${ENDPOINTS} snapshot save /data/etcd_backup_dir/etcd-snapshot.db

#备份对数据库做一个快照,保存为一个文件。对etcd做的备份

还原:etcdctl --endpoints=${ENDPOINTS} snapshot restore snapshot.db

#执行restore会出现报错,查看报错

  • Etcd备份脚本

图形用户界面, 文本

AI 生成的内容可能不正确。

文本

AI 生成的内容可能不正确。

  • mysql数据库的灾备

备份:mysqldump 表 > .sql #生产环境不建议使用,数据量小可使用

xtrabackup:备份物理文件,支持全备和增量,生产环境使用

  • Kuberentes是如何使用etcd保存数据的

图形用户界面

AI 生成的内容可能不正确。

#查看etcd的数据库

  1. 执行:kubectl -n kube-system exec -it etcd-master-01 -- sh:直接进入pod

#有etcd客户端可直接链接

etcdctl --endpoints https://localhost:2379 --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key --cacert /etc/kubernetes/pki/etcd/ca.crt get --keys-only --prefix /

:客户端访问etcd服务端,需要提供证书,这种属于双向认证

#一般时单项认证,一般银行场景和安全要求严格的使用双向

证书保存位置:/etc/kubernetes/pki

#没有证书etcd是无法进行访问

#创建的命名空间和pod都在etcd有相应位置保存

  • etcd备份存储:

Etcd的默认工作目录下会生成两个子目录:wal和snap。k8s默认放置路径:/var/lib/etcd/member

Wal:是用于存放预写式日志,其最大的作用是记录整个数据变化的全部历程。所有数据的修改在提前前,都要先写入wal中。

Snap:是用于存放快照数据。为防止wal文件过多,etcd会定期(当wal中数据超过100000条记录时,由参数snapshot-count”设置)创建快照。当快照生成后,wal中数据就可以被删除了。

:如果数据遭到破坏或错误修改需要回滚到之前某个状态时,方法有两个:一是从快照中恢复数据主体,但是未被拍入快照的数据会丢失;二是执行所有wal中记录的修改操作,从最原始的数据恢复到数据损坏之前的状态,但恢复的时间较长。

图片包含 游戏机, 电脑

AI 生成的内容可能不正确。

  1. kube-controller-manager:控制器
  • 通用控制器

Job Controller:处理 job。

Pod AutoScaler:处理Pod的自动缩容/扩容

ReplicaSet:依据Replicaset Spec 创建Pod

Service Controller:为 LoadBalancer type 的 service 创建 LB VIP。

ServiceAccount Controller:确保serviceaccount 在当前namespace 存在。

StatefulSet Controller:处理 statefulset 中的Pod

Volume Controller:依据PV spec 创建 volume。

Resource qutoa Controller:在用户使用资源之后,更新状态。

Namespace Controller:保证namespace删除时,该namespace下的所有资源都先被删除。

Replication Controller:创建RC后,负责创建 Pod。

Node Controller:维护node状态,处理evict请求等。

Daemon Controller:依据 daemonset 创建 Pod。

Deployment Controller:依据 deployment spec 创建 replicaset。

Endpoint Controller:依据service spec创建 endpoint,依据 podid 更新 endpoint。

Garbage Controller:处理级联删除,比如删除deployment的同时删除replicaset以及 Pod。

CronJob Controller:处理cronjob.

#每个对象都对应一个控制器进行工作

  1. 数据面:kubelet
  • kubelet架构

每个节点上都运行一个kubelet服务进程,默认监听10250 端口。

  1. 接收并执行 master 发来的指令;
  2. 管理 Pod 及 Pod 中的容器;
  3. 每个 kubelet 进程会在 API Server上注册节点自身信息,定期向 maste 节点汇报节点的资源使用情况,并通过cAdvisor 监控节点和容器的资源。

图示

AI 生成的内容可能不正确。

#以上大部分节点都归属kubelet管理

:默认监听10250和10248,master和wrker和都有kubelet。访问10250需要双向认证,监听https。

ProbeManager:探针管理,由kubelet进行检测。OOMWatcher:内存溢出,也是kublet控制,GPU由kubelet管理。

cAdvisor:分析资源的利用率和性能

#谷歌下的一个组件,后集成到kubelet里面,用来监控容器的资源利用率

DiskSpaceManager:磁盘空间管理

#GC垃圾回收

EvictionManager:驱逐

#资源不够用kubelet进行驱逐

kubelet其他职责:创建pod,创建容器

#创建时需要使用cr,cr由多个类型

  • CRI:容器运行时接口:为了解决容器运行时和kubernetes的集成的问题

:kubelet创建容器要调用CRI,CRI再去调用cr去创建容器

#CRI层就是为了屏蔽底层的cr,去使用其他的cr类型。cri是一个抽象接口

#开发实现就是通过不同的接口,使用应用就调用接口

Ocl:(Open ContainerInitiative,开放容器计划)的主要目标是定义容器的标准规范,以确保容器在不同的容器运行时(如Docker、rkt、CRI-O等)之间具有互操作性。通过制定标准规范,OCI 旨在消除容器技术生态系统中的封闭性和供应商锁定问题,促进不同容器技术之间的兼容性和可移植性。

cridocker:使用这个插件可以使用docker

  1. Pod启动流程:

箱线图

AI 生成的内容可能不正确。

:将创建pod的请求发送到apiserver,并把yaml文件写入到etcd的数据库中。现在有一个pod需要创建,scheduler通过watch发现一个新的pod,并根据yaml文件中的nodeName属性去判断是否是新的pod,使用调度算法找到合适的节点对pod进行调度,将nodeName的值写入到apiserver中,apiserver在把nodeName的值写入到etcd数据库中。调用后节点的kubelet通过watch查看到由新的事件被调度到节点上,在通过yaml文件的描述去创建一个pod,第一个启动的是pause容器,去创建第一个容器sandbox。启动后给pod里面的容器占用一个网络命名空间,获取一个ip地址,pod里面所有容器共用这个ip地址。Network plugin没有问题后,在去启动其他容器,拉取镜像,创建容器,启动容器。无论容器是否起来,kubelet去上报pod的状态给apiserver,并把信息写入到etcd中去。

报错:启动时遇到sandbox报错,是sandbox创建时要调用network plugin,容器网络

  1. CNI:容器网络接口
  2. Kubernetes 网络基础

:网络解决方案交给社区实现

图表

AI 生成的内容可能不正确。

:跨节点之间通信,pod的ip在集群范围地址要唯一,网桥地址不能一样,划分网段去实现。poda如何到podc,a到网桥再到网卡,再通过路由器进行转发到work节点,

CNI网络插件职责:

  1. Pod的IP地址在集群范围内是唯一
  2. 路由

# podSubnet: 10.244.0.0/16给集群中所有 Pod 使用的,集群基于此网段去划分,可以进行拆分网段256 个网段,256个节点,每个节点使用一个网段

10.244.0.0/24 256个IP

10.244.1.0/24

10.244.2.0/24

#一个节点最多允许110个pod

  • 跨节点组网

图示

AI 生成的内容可能不正确。

  • Kubernetes 网络做如下总结:

Kubernetes 网络基础原则:

  1. 每个 Pod 都拥有一个独立的 IP 地址,而且假定所有 Pod 都在一个可以直接连通的、扁平的网络空间中,不管是否运行在同一 Node 上都可以通过 Pod 的 IP 来访问。
  2. Kubernetes 中 Pod 的 IP 是最小粒度 IP。同一个 Pod 内所有的容器共享一个网络协议栈,该模型称为 IP-per-Pod 模型。
  3. Pod 内部看到的 IP 地址和端口与外部保持一致。同一个 Pod 内的不同容器共享网络,可以通过 localhost 来访问对方的端口,类似同一个 VM 内的不同进程。
  4. IP-per-Pod 模型从端口分配、域名解析、服务发现、负载均衡、应用配置等角度看,Pod 可以看作是一台独立的 VM 或物理机

CNI:

:CNI 标准中,网络插件是独立的可执行文件,被上层的容器管理平台调用

网络插件只有两件事情要做:把容器加入网络或把容器从网络中删除

Kubernetes 使用 CNI 网络插件的工作流程 :

  • Kubelet 调用 CRI 创建 pause 容器,生成对应的 network namespace;
  • 调用网络 driver ;
  • CNI driver 根据配置调用具体的 CNI 插件;
  • CNI 插件给 pause 容器配置正确的网络, Pod 中的其他容器都是用 pause 容器的网络栈

图示

AI 生成的内容可能不正确。

  • Flannel

:Flannel 可以为容器提供跨节点网络服务,其模型为集群内所有容器使用一个网络,然后在每个主机上从该网络中划分一个子网 。 flannel 为主机上的容器创建网络时,从子网中划分一个 IP 给容器 。 根据 Kubernetes 的模型,为每个 Pod 提供一个 IP, flannel 的模型正好与之契合 。 而且 flannel 安装方便且简单易用

#使用每个节点启动一个agent(flanneld),使用daemonset

:flanneld 可以在启动时通过配置文件指定不同的 backend 进行网络通信,目前比较成熟的 backend 有 UDP 、VXLAN(默认) 和 Host Gateway 三种

UDP:早期版本的Flannel使用 UDP 封装完成报文的跨越主机转发,其安全性及性能略有不足。

VXLAN:Linux 内核在在 2012 年底的 v3.7.0之后加入了 VXLAN 协议支持,因此新版本的 Flannel也从 UDP 转换为 VXLAN,VXLAN 本质上是一种 tunnel(隧道)协议,用来基于三层网络实现虚拟的二层网络,目前flannel 的网络模型已经是基于 VXLAN 的叠加(覆盖)网络。

Host-GW:也就是 Host GateWay,通过在 node 节点上创建到达各目标容器地址的路由表而完成报文的转发,因此这种方式要求各 node 节点本身必须处于同一个局域网(二层网络)中,因此不适用于网络变动频繁或比较大型的网络环境,但是其性能较好

  • 部署 Flannel

#部署Flannel之前删除所安装的calico

删除calico方式:

  1. kubectl delete -f calico.yaml
  2. 每个节点执行 mv /etc/cni/net.d/10-calico.conflist /tmp/
  3. reboot #最好重启服务器

部署:

注:执行前需手动修改一个内核参数:详见下述报错解决

  1. kubectl apply -f flannel.yaml:根据以准备好的yaml去执行启动flannel
  • Backend: UDP
  1. 执行:vim kube-flannel-udp.yml:修改flannel配置文件

部署flannel 网络插件:

  1. 执行:kubectl apply -f kube-flannel-udp.yml
  2. 执行:kubectl get ns:查看命名空间

背景图案

AI 生成的内容可能不正确。

#可以看到给我们安装了一个namespace

  1. 执行以下命令pod状态

Word

AI 生成的内容可能不正确。

#每一个节点都起了一个pod,查看命名空间里面的pod

验证当前允许模式:

文本

AI 生成的内容可能不正确。

#通过日志方式进行查看,会划分一个子网

# FLANNEL_NETWORK=10.244.0.0/16 #集群内Pod大网段

FLANNEL_SUBNET=10.244.0.1/24 #当前节点分配的子网

FLANNEL_MTU=1472 # MTU 最大传输单元默认1500 少28

FLANNEL_IPMASQ=true

查看当前node主机ip地址范围:

  1. 执行:cat /run/flannel/subnet.env

#子网分配的信息保存到了etcd中

flannel0接口:

:flanneld 进程启动后,通过 ip addr 命令可以发现节点中多了一个 叫 flannel0 的网络接口

文本

AI 生成的内容可能不正确。

# cni0:bridge相当docker0 ,flannel0归Flanneld进程管理

#进程会监听UDP 8285

  • 验证fannel如何实现跨节点路由:创建容器测试
  1. 执行:vim nginx-worker.yaml

kubectl apply -f nginx-master.yaml

#master和worker都运行pod,在master的nodeName手动添加一个值,绕过调度

  1. 执行:kubectl exec -it nginx-master-5559c5fcd-nq6xq -- sh:进入容器

#ping下worker的ip可以通

源ip和目标ip是如何获取:flannel UDP 模式跨主机通信实践

  1. 执行命令查看以下路由表

#走10.244.0.1的网关

执行:ip addr查看

#网桥上一个接口cri0作为网关到宿主

  1. 执行命令查看宿主机的路由表

电视画面的截图

AI 生成的内容可能不正确。

#每个节点都有一个flannel0

电脑萤幕的截图

AI 生成的内容可能不正确。

#通过对目标IP进行封装伪装发到网卡,在发送到fiannel0进行解封装

src-ip: 192.168.11.18 src-port: 8285 dest-ip:192.168.11.19 dest-port: 8285

#封装头部

data: src-ip: 10.244.0.25 dest-ip:10.244.1.73 #原始数据包

#到达目标节点worker-01,10.244.1.0/24

#udp头部包含Header、Data占用8字节

#把原始的pod间通信的数据包封装到udp的数据包中

  • flannel UDP 模式跨主机通信实践流程:

图示

AI 生成的内容可能不正确。

  1. 容器 A 发出 ICMP 请求报文,通过 IP 封装后的形式为 10.244.0.6 (源)→ 10.244.1.4 ( 目的 )。 此时通过容器 A 内的路由表匹配到应该将 IP 包发送到网关 10.244.0.1 ( cni0 网桥)。
  2. 到达 cni0 的 IP 包目的地 IP 10.244.1.4 ,匹配到节点 A 上第一条路由规则( 10.244.0. 0 ) , 内核通过查本机路由表知道应该将 IP 包发送给 flannel0 接口 。
  3. 发送给 flannel0 接口的 IP 包将被 flanneld 进程接收, flanneld 进程接收 IP 包后在原有的基础上进行 UDP 封包, UDP 封包的形式为 172.16.66.30:8285 → 172.16.66.31:8285 。
  4. flanneld 将封装好的 UDP 报文经 eth0 发出,从这里可以看出网络包在通过 eth0 发出前先是加上了 UDP 头( 8 个字节),再加上 IP 头( 20 个字节)进行封装,这也是 flannel0 的 MTU 要比 eth0 的 MTU 小 28 个字节的原因,即防止封包后的以太网帧超过 eth0 的 MTU, 而在经过 eth0 时被丢弃。
  5. 网络包经过主机网络从节点 master-01 到达节点 worker-01。
  6. 主机 worker-01 收到 UDP 报文后, Linux 内核通过 UDP 端口号 8285 将包交给正在监听的 flanneld
  7. 运行在 worker-01 中的 flanneld 将 UDP 包解封包后得到 IP 包:10.244.0.6 → 10.244.1.4。
  8. 解封包后的 IP 包匹配到主机 worker-01 上的路由规则 ( 10.244.1.0 ),内核通过查本机路由表知道应该将 IP 包发送到 cni0 网桥 。
  9. cni0 网桥将 IP 包转发给连接在该网桥上的容器 B ,至此整个流程结束 。 回程报文将按上面的数据流原路返回
  • 整个通信过程中, flanneld 在其中主要起到的作用是:
  1. UDP 封包解包 #封包和解包的一个过程会进行用户态和内核态的一个切换
  2. 节点上的路由表的动态更新
  • Flannel 启动时报错:rocky9的问题

图形用户界面, 文本

AI 生成的内容可能不正确。

#在启动是此处可能会出现报错,内核的一个参数

解决方法一:

#手工加载内核模块

modprobe br_netfilter

解决方法二:开机自动加载

echo "br_netfilter" > /etc/modules-load.d/br_netfilter.conf

  • 接口抓包分析
  1. 执行:kubectl exec-itnginx-master-5559c5fcd-nq6xg--sh

ping 10.244.1.73

#进入容器ping目标IP,持续有数据包流量

  1. 执行:tcpdump -nni cni0 -s0 -vv -w flannel-udp-master-cni.pcap

#执行此命令先去抓取网桥cni0未进行封装前的数据包,保存为一个文件

表格

AI 生成的内容可能不正确。

#此刻是不知道数据包是进行过封装的

  1. 执行:执行:tcpdump -nni ens192 -s0 -vv -w flannel-udp-master-cni.pcap

#抓取宿主机网卡数据包保存为文件,进行分析,此处找UDP的包,宿主机出去后封装的是UDP的包

如何看到data的数据:

图片包含 图形用户界面

AI 生成的内容可能不正确。

#此处改为ipv4即可,

#可以看到data除就显示一个源ip和目标ip

  • 如果pind对端不通,如何进行排查

#ping命令没有到达对端,reply没有回来

  1. 去ping目标,查看又没有request到对端,有没有reply返回。没有就是中间有设备进行了拦截
  2. VXLAN模式:

#优化UDP模式,所有的封包和解包都在内核态完成,效率会更高

#在linux内核中支持VXLAN协议

VLAN:隔离广播域 XVLAN对vlan进行扩展

#都属于二层协议

  • vxlan操作实践:
  1. 执行:vim kube-flannel-vxlan.yml:修改yaml文件修改一些内容

形状

AI 生成的内容可能不正确。

部署flannel网络插件:

  1. 执行:kubectl apply -f kube-flannel-vxlan.yml
  2. 执行:kubectl -n kube-flannel get pods:进行查看

#同udp一致也会生成子网信息,封装时会占用50个字节

  1. 执行:IP addr:查看flannel0消失,增加了flannel.1

  1. 执行:ss -antp:进行查看

文本

AI 生成的内容可能不正确。

#可以看到会监听udp的端口,并且端口变为了8472

  1. 执行:kubectl get pods-o wide:查看节点ip

  1. 执行:kubectl exec -it nginx-master-5559c5fcd-18q8p -- sh:进入pod

ping 10.244.1.13

验证源ip和目标ip为什么会互通:

查看pod路由表:

  1. 执行:route -n

#走的是10.244.0.1网关,就会到达宿主机

  1. 查看宿主机路由:route -n

#可以看到数据包的数据就到了flannel.1

封装方式:

  • 抓包分析

eth0接口抓包分析:

  1. 执行:tcpdump -nni ens192 -s0 -vv -w flannel-vxlan-master-eth0.pcap

#可以抓取到封装完成的结果

图形用户界面, 应用程序, 表格

AI 生成的内容可能不正确。

#默认是4789端口,会不知到还有一层数据包,显示的是封装之后的过程

:原始数据包依旧在data里面,需要执行:编辑—首选项—VXLAN—端口改为8472

图形用户界面, 文本, 应用程序, 电子邮件

AI 生成的内容可能不正确。

  • VXLAN模拟数据路径:

表格

AI 生成的内容可能不正确。

图示

AI 生成的内容可能不正确。

  1. 同 UDP Backend 模式,容器 A 中的 IP 包通过容器 A 内的路由表被发送到 cni0 。
  2. 到达 cni0 中的 IP 包通过匹配 worker-01 中的路由表发现通往 10.244.1.4 的 IP 包应该交给 flannel.1 接口 。
  3. flannel.1 收到报文后将按照配置进行封包 。 首先,通过 etcd 得知 10.244.1.4 属于节点 worker-01 ,并得到节点 worker-01 的 IP 。 然后,通过节点 master-01 中的转发表得到节点 worker-01 对应的 MAC 地址,根据 flannel.1 设备创建时的设置参数进行 VXLAN 封包 。
  4. 通过 master-01 跟 worker-01 之间的网络连接, VXLAN 包到达 worker-01 的 eth0 接口 。
  5. 通过端口 8472, VXLAN 包被转发给 flannel.1 进行解包。
  6. 解封装后的 IP 包匹配 worker-01 中的路由 表( 10.244.1.0 ),内核将 IP 包转发给 cni0 。
  7. cni0 将 IP 包转发给连接在 cni0 上的容器 B
  8. Backend: HOST-GW

:Host Gateway 简称 host-gw ,从名字中就可以想到这种方式是通过把主机当作网关实现跨节点网络通信的 。 那么 ,具体如何实现跨节点通信呢?与 UDP 和 VXLAN 模式类似, 要使用 host-gw 模式,需要将 flannel 的Backend 中的 Type 参数设置成 “host-gw

图示

AI 生成的内容可能不正确。

通信流程:

  1. 同 UDP 、 VXLAN 模式一致,通过容器 A 的路由 表 IP 包到达 cni0 。
  2. 到达 cni0 的 IP 包匹配到 master-01 中的路由规则( 10.244.1.0 ),并且网关为 172.16.66.33 ,即 worker-01 ,所以内核将 IP 包发送给 worker-01 (172.16.66.33)。
  3. IP 包通过物理网络到达主机 worker-01 的 eth0 。
  4. 到达主机 worker-01 eth0 的 IP 包匹配到 worker-01 中的路由 表( 10.244.1.0 ) , IP 包被转发给cni0 。
  5. cni0 将 IP 包转发给连接在 cni0 上的容器 B

:host-gw 模式下,各个节点之间的跨节点网络通信要通过节点上的路由表实现,因此必须要通信双方所在的宿主机能够直接路由 。 这就要求 flannel host-gw 模式下集群中所有的节点必须处于同一个二层网络内, 这个限制使得 host-gw 模式无法适用于集群规模较大且需要对节点进行网段划分的场景 。 host-gw 的另外一个限制则是随着集群中节点规模的增大,flanneld 维护主机上成千上万条路由表的动态更新也是一个不小的压力 ,因此在路由方式下 ,路由表规则的数量是限制网络规模的一个重要因素

  • network policy:可以实现跨命名空间的网络隔离,使用calico

电脑屏幕截图

AI 生成的内容可能不正确。

  1. Calico
  • calico如何结局跨节点路由通信:

:calico把节点面为路由器进行解决

  • 路由器如何解决路由问题的:

:通过路由表实现

路由条目实现:

  1. 静态路由
  2. 动态路由 #动态路由协议
  • 动态路由协议分类:

RIP

EIGRP、OSPF、ISIS

BGP

#calico使用BGP协议进行通信

介绍:Calico 在每一个计算节点利用 Linux 内核的一些能力实现了一个高效的 vRouter 负责数据转发,而每个 vRouter 通过 BGP 把 自己运行的工作负载的路由信息 向整个 Calico 网络传播。小规模部署可以直接互联,大规模下可以通过指定的 BGP Route Reflector 完成。最终保证所有的工作负载之间的数据流量都是通过 IP 路由的方式完成互联的 。 Calico 节点组网可以直接利用数据中心的网络结构(无论是 L2 还是 L3 ),不需要额外的 NAT 或隧道

  • calico组件: #把服务器变为路由器

Felix:

:Felix 是一个守护程序,作为 agent 运行在托管容器或虚拟机的 Calico 节点上 。 Felix 负责刷新主机路由和 ACL 规则等,以便为该主机上的 Endpoint 正常运行提供所需的网络连接和管理。 进出容器 、 虚拟机和物理主机的所有流量都会遍历 Calico ,利用 Linux 内核原生的路由和 iptables 生成的规则

BGP Client:

:Calico 在每个运行 Felix 服务的节点上都部署一个 BGP Client ( BGP 客户端)。 BGP 客户端的作用是读取 Felix 编写到内核中的路由信息,由 BGP 客户端对这些路由信息进行分发 。 具体来说,当 Felix 将路由插入 Linux 内核 FIB 时, BGP 客户端将接收它们,并将它们分发到集群中的其他工作节点

Route Reflector:路由反射器

在较大规模的部署中, Calico 建议使用 BGP Route Reflector (路由器反射器)。互联网中通常使用 BGP Route Reflector 充当 BGP 客户端连接的中心点,从而避免与互联网中的每个 BGP 客户端进行通信

#减少路由条目

#也需要etcd对子网的分配信息进行保存

calico的工作模式:IPIP(默认工作模式)、BGP、VXLAN

  • Calico 的 IPIP 隧道模式 :兼容性更好

#ip in ip把原始的数据包再封装一层ip

Calico 可以创建并管理一个 3 层平面网络,为每个工作负载分配一个完全可路由的 IP 地址 。 工作负载可以在没有 IP 封装或 NAT 的情况下进行通信,以实现裸机性能,简化故障排除和提供更好的互操作性 。 我们称这种网络管理模式为 vRouter 模式 。 vRouter 模式直接使用物理机作为虚拟路由器,不再创建额外的隧道 。 然而在需要使用 overlay 网络的环境中, Calico 也提供了 IP-in-IP (简称 ipip )的隧道技术

图示

AI 生成的内容可能不正确。

:和其他 overlay 模式一样 , ipip 是在各节点之间 “架起” 一个隧道,通过隧道两端节点上的容器网络连接,实现机制简单说就是用 IP 包头封装原始 IP 报文 。 启用 ipip 模式时 ,Calico 将在各个节点上创建一个名为 tunl0 的虚拟网络接口,如上图所示

#只要两端的ip可以ping通,数据就在所搭建的隧道中进行通信

如何确定有没有使用IPIP模式,观看calico的yaml文件:

查看网卡:tunl0@NONE:IPIP模式

#没有tunl0@NONE就是运行在BGP的模式下

  • 部署calico网络插件验证跨界点通信:IPIP模式

插件以部署,执行以下内容:

  1. 执行:kubectl apply -f nginx-master.yaml -f nginx-worker.yaml

图形用户界面

AI 生成的内容可能不正确。

  1. 执行:kubectl exec -it nginx-master-5559c5fcd-bf2pz -- sh:进入pod执行

验证源ip和目标ip如何进行通信:

  1. 查看路由:route -n

#10.244网关走到了169,calico没有网桥,直接连接到宿主机

#pod内ping网关是不通的,把veth pair伪装成了网关

  1. 查看宿主机路由:route -n

日历

AI 生成的内容可能不正确。

#数据通过了tunl0进行通信,tunl0就会对我们的数据包进行封装,把数据发到192.168.11.58

#使用ipip还是可以用BGP的协议把路由条目进行学习,找到转发出口

  • 抓包分析
  1. tcpdump -nni tunl0 -s0 -vv -w calico-ipip-master-tunl0.pcap

#可以看到数据封装过程

  • calico BGP模式:验证数据包通信
  1. 修改calico的yaml文件改以下内容即可

  1. 执行以下命令

#通过验证可以看到到对端节点的数据是畅通的

验证:src-ip:10.244.184.84 dest-ip:10.244.171.18

  1. 执行:route -n:查看节点路由

  1. 执行:route -n:查看宿主机节点路由

图片包含 文本

AI 生成的内容可能不正确。

#目标ip171.18直接通过宿主机的接口出去到达对端,没有封装过程

/opt/cni/bin/:网络插件ipamn给Pod分配IP

/etc/cni/net.d/:网络插件配置文件

  1. 附录:
  2. 覆盖网络[overlay network]

#vxlan和udp模式的通信方式都是覆盖网络

:运行在一个网上的网(应用层网络),并不依靠ip地址来传递消息,而是采用一种映射机制,把ip地址和identifiers做映射来资源定位

:底层的物理网络设备组成的网络我们称为 Underlay 网络,而用于虚拟机和云中的这些技术组成的网络称为 Overlay 网络这是一种基于物理网络的虚拟化网络实现

  1. kubernetes集群ip地址分配

Kubernetes 使用各种 IP 范围为节点、Pod 和服务分配 IP 地址

  • 系统管理员为每个节点分配一个 IP 地址 。 该节点 IP 用于提供从数据面组件(如 Kube-proxy 和 Kubelet )到 控制面 Kubernetes Master 的连接;
  • 系统会为每个 Pod 分配一个地址块内的 IP 地址 。 用户可以在创建集群时通过参数 podSubnet 指定此范围; (podSubnet: 10.244.0.0/16)
  • 系统会为每个服务(Service)分配一个 IP 地址(称为 ClusterIP )。 用户可以在创建集群时通过参数 serviceSubnet 指定此范围; (serviceSubnet: 10.96.0.0/12)
  1. pod出站流量:

Kubemetes 处理 Pod 的出站流量的方式主要分为以下三种:

  • Pod 到 Pod

在 Kubemetes 集群中,每个 Pod 都有自己的 IP 地址,运行在 Pod 内的应用都可以使用标准的端口号,不用重新映射到不同的随机端口号 。 所有的 Pod 之间都可以保持三层网络的连通性,比如可以相互 ping 对方,相互发送 TCP/UDP/SCTP 数据包 。 CNI 就是用来实现这些网络功能的标准接口

  • Pod 到 Service

Pod 的生命周期很短暂,但客户需要的是可靠的服务,因此 Kubemetes 引 人了新的资源对象 Service ,其实它就是 Pod 前面的 4 层负载均衡器。 Service 总共有 4 种类型,其中最常用的类型是 ClusterIP ,这种类型的 Service 会自动分配一个仅集群内部可以访问的 虚拟IP

Kubemetes 通过 Kube-proxy 组件实现这些功能,每台计算节点上都运行一个 Kube-proxy 进程,通过复杂的 iptables/IPVS 规则在 Pod 和 Service 之间进行各种过滤和 NAT

  • Pod 到 集群外

从 Pod 内部到集群外部的流量 , Kubemetes 会通过 SNAT 来处理。 SNAT 做的工作就是将数据包的源从 Pod 内部的 IP:Port 替换为宿主机的 IP:Port 。 当数据包返回时,再将目的地址从宿主机的 IP:Port 替换为 Pod 内部的 IP:Port ,然后发送给 Pod ,当然,中间的整个过程对 Pod 来说是完全透明的,它们对地址转换不会有任何感知

  1. Kubernetes 网络架构

:谈到 Kubemetes 的网络模型,就不能不提它著名的 “单 Pod 单 IP”模型 , 即每个 Pod 都有一个独立的IP, Pod 内所有容器共享 network namespace (同一个网络协议栈和 IP )

:单 Pod 单 IP” 网络模型为我们勾勒了一个 Kubemetes 扁平网络的蓝图,在这个网络世界里:容器是一等公民 , 容器之间直接通信,不需要额外的 NAT,因此不存在源地址被伪装的情况; Node 与容器网络直连, 同样不需要额外的 NAT 。 扁平化网络的优点在于:没有 NAT 带来的性能损耗,而且可追溯源地址,降低网络排错的难度 。

总体而言,集群内访问 Pod , 会经过 Service ; 集群外访问 Pod , 经过的是 Ingress

Kubernetes 对网络的要求:

  1. 所有容器都可以不用 NAT 的方式同别的容器通信。
  2. 所有节点都可以在不用 NAT 的方式下同所有容器通信,反之亦然。
  3. 容器的地址和别人看到的地址是同一个地址。
  4. CSI:容器存储接口

阿里云CSI: https://www.alibabacloud.com/help/zh/ack/ack-managed-and-ack-dedicated/user-guide/csi-overview-1/

#使用云端存储时可以进入官网查看

Ref:容器运行时 Containerd 安装与使用:

https://mp.weixin.qq.com/s/d44ngzDbW_ublUsw-KrCJQ

CRI 客户端 crictl 命令介绍:

https://mp.weixin.qq.com/s/DYHSP8s-3PCUkVF-ierZtg

容器命令行工具 nerdctl:

https://mp.weixin.qq.com/s/OIC1M0FYd9IJJEKt2Yi6sQ

Kubernetes 集群备份 - Velero:

https://mp.weixin.qq.com/s/7k2Eit-zIb3ZZfWMweSQaQ

MinIO on Kuberntes:

https://mp.weixin.qq.com/s/3UzDr3VmNxexED7hoST2sA

日期2025.09.02学习日志

  1. CSI:容器存储接口

#kubernetes在代码中支持比较流行的存储协议,之前

Kubernetes 支持以插件的形式来实现不同存储的支持和扩展,这些扩展基于如下两种方式:

  • in-tree:在kubernetes内部代码上支持

emptyDIr:临时存储

#空目录挂载到pod中

# emptyDir 设计的初衷主要是给应用充当缓存空间或者存储中间数据。

然而这并不是说满足以上需求的用户都被推荐使用emptyDir,我们要根据用户业务的实际特点来判断是否使用emptyDir。因为emptyDir的空间位于系统根目录下(默认位置:/var/lib/kubelet/pods/),被所有容器共享,所以在磁盘的使用率较高时会触发Pod的eviction操作,从而影响业务的稳定

hostpath:半持久化存储

:常见的半持久化存储主要是 hostPath卷。hostPath 卷能将主机节点文件系统上的文件或目录挂载到指定的Pod中。

使用 hostPath 卷时要注意以下问题:

  1. 使用同一个目录的Pod可能会由于调度到不同的节点,导致目录中的内容有所不同;
  2. Kubernetes在调度时无法顾及由 hostPath 使用的资源;
  3. Pod被删除后,如果没有特别处理,hostPath上写的数据会遗留到节点上,占用磁盘空间。

#使用时建议不让pod移动节点,放到固定节点

  • out-of-tree:通过接口支持,持久化存储

:针对持久化存储,Kubernetes引入了StorageClass、Volume、PVC(Persistent Volume Claim)、PV(PersistentVolume)的概念,将存储独立于Pod的生命周期来管理。

:Kubernetes 目前支持的持久化存储包含各种主流的块存储和文件存储,比如cephfs、iscsi、nfs、hostPath等,在大类上可以将其分为网络存储和本地存储两种类型。

#外部接入的插件

#实现csi接口就可以进行使用,把存储挂载到pod

阿里云CSI: https://www.alibabacloud.com/help/zh/ack/ack-managed-and-ack-dedicated/user-guide/csi-overview-1/

#使用云端存储时可以进入官网查看

内网k8s使用存储:rook \ longhorn \ openebs junicefs Glusterfs MFS

#所有的商业存储支持CSI

  1. kube-scheduler:调度器
  2. 调度的基础概念

scheduler:为pod找到一个合适的node

图形用户界面, 图示

AI 生成的内容可能不正确。

#通过调度器把nodename加一个值,把pod调到此处

  • Node定义:

图示

AI 生成的内容可能不正确。

#通过kubelet上报此处的定义的属性,去判断有多少可分配的资源

  • Pod中影响调度的主要属性字段:

图片包含 文本

AI 生成的内容可能不正确。

执行 kubectl get pod<pod-name〉-o yaml:查看 pod 完整的定义

执行 kubectl explain pod.spec:查看 pod 完整配置字段信息

#default默认调度器

  1. 资源需求:

CPU:

  • Requests

Kubernetes调度Pod时,会判断当前节点正在运行的Pod的CPU Request的总和,再加上当前调度Pod的

CPU Request,计算其是否超过节点的CPU可分配资源。

  • Limits

配置cgroup 以限制资源上限。

内存:

  • requests

判断节点剩余内存是否满足Pod的内存请求量,以确定是否可以将Pod调度到该节点。

  • limits

配置置cgroup 以限制资源上限。

  • init Container的资源需求:
  1. 当 kube-scheduler 调度带有多个 init 容器的 Pod 时,只计算 cpu.request 最多的 init 容器,而不是计算所有的 init 容器总和。
  2. 由于多个 init 容器按顺序执行,并且执行完成立即退出,所以申请最多的资源 init 容器中的所需资源,即可满足所有 init 容器需求。
  3. Kube-scheduler 在计算该节点被占用的资源时,init 容器的资源依然会被纳入计算。因为 init 容器在特定情况下可能会被再次执行,比如由于更新镜像而引起的 Sandbox 重建时。
  • pod所需资源计算:

图示

AI 生成的内容可能不正确。

#containers运行的容器资源需求要累加起来,init的运行后的3G内存用完后也会释放出来,取最大值,最终使用2核心3G

  1. 调度器:
  • kube-scheduler 调度分为两个阶段,predicate 和 priority:

Predicate:预选,过滤不符合条件的节点

Priority:优先级排序,选择优先级最高的节点

#如何找到合适节点,通过上述两种节点算法

#先进行预选,在进行优选选择节点

  • 调度原理:

图示

AI 生成的内容可能不正确。

  • 当节点较多时解决:

全局最优解:

局部最优解:

  1. 高级调度:高级调度策略

#当普通调度无法满足我们的需求的时候就使用高级调度策略

  • nodeselector:将pod调度到特定的node上

#pod在调度时看node上的标签,如果标签匹配,调度成功,不匹配,调度失败

kubectl get nodes --show-labels:查看node的标签

:master-01 Ready control-plane 12d v1.32.1

beta.kubernetes.io/arch=amd64, #架构

beta.kubernetes.io/os=linux, #操作系统

kubernetes.io/arch=amd64,

kubernetes.io/hostname=master-01,

kubernetes.io/os=linux,

node-role.kubernetes.io/control-plane=, #node角色,可以没有值

node.kubernetes.io/exclude-from-external-load-balancers=

  • node打标签:

kubectl label nodes worker-01 node-role.kubernetes.io/data-plane=

#查看可以看到worker的节点的标签已经改变,后面可以跟值

kubectl label nodes worker-01 node-type=gpu

#可以自定义增加节点的一个标签,pod对节点有要求可以使用标签方式,让pod调度到指定节点

  • node删除标签:

kubectl label nodes worker-01 node-role.kubernetes.io/data-plane-

#删除时在标签后面加一个减号即可

yaml文件配置:示例

文本

AI 生成的内容可能不正确。

#在yaml配置文件里面去定义调度算法

语法格式:map[string]string

作用:匹配 node.labels

排除不包含nodeSelector 中指定label的所有node

匹配机制:完全匹配

#当启动一个配置好的yaml的时候,节点没有配置相对应的标签,就会出现上述报错,没有调度器,不能容忍污点。当标签修改后就会调度成功

  • nodeAffinity:nodeSelector 升级版

与nodeSelector 关键差异:

  1. 引入运算符:In,NotIn,Exists,DoesNotExists
  2. 支持枚举label可能的取值,如zone in [azl,az2,za3]
  3. 支持硬亲和和软亲和

#硬亲和nodeSelector必须匹配、软亲和匹配,打高分,不匹配:打低分

图形用户界面

AI 生成的内容可能不正确。

#硬亲和标签等于ssh和等于nas有一个匹配就可以匹配

#软亲和匹配就会调度到比较喜欢的,不匹配也可以调度成功。启动yaml测试后会优先调度到store,当启动多个副本时,也会调度到其他节点

#设置的权重数值越大,影响越大

  • podAffinity:让某些 Pod 分布在同一组 Node 上

图形用户界面

AI 生成的内容可能不正确。

与 nodeAffinity的关键差异:

  1. 亲和与反亲和规则具有对称性
  2. labelSelector的匹配对象为 Pod
  3. 对 node 分组,依据 label-key = topologyKey,每个label-value 取值为一组

podAffinity:Pod 亲和性

文本

AI 生成的内容可能不正确。

#此处使用的是硬亲和

硬亲和

软亲和

#两个pod同时跑在同一个节点用亲和性,分为硬亲和和软亲和

podAntiAffinity:Pod 反亲和性

文本

AI 生成的内容可能不正确。

#都是硬亲和,可以写多个属性,使用亲和性和反亲和性自己时会一个节点启动一个pod

硬亲和

软亲和

#两个pod不跑在同一节点用软亲和,分为硬亲和和软亲和

  • PodAntiAffinity:避免某些 Pod 分布在同一组 Node 上

与 podAffinity的关键差异:

  1. 匹配过程相同
  2. 最终处理调度结果时取反

:podAffinity 中可调度节点,在 podAntiAffinity 中为不可调度

:podAffinity 中高分节点,在 podAntiAffinity 中为低分

topology:拓扑 #调度时可以在按照定义的节点去分配

topologyKey: "kubernetes.io/hostname" #节点名

topologyKey: "kubernetes.io/zone" #节点上的标签

  • Taints:避免Pod调度到特定的Node上

#node选择哪些pod选择在这个节点运行,污点

kubectl describe nodes master-01:里面内容可以查看到污点

污点:key=value:effect # value 可以省略

effect 污点影响 范围:

  1. NoSchedule:新的 Pod 不会调度到这个节点上, 正在运行的 Pod 不受影响
  2. PreferNoSchedule:软版NoSchedule,新的 Pod 尽量不调度到这个节点上,正在运行的 Pod 不受影响 #使用最多
  3. NoExecute:新的 Pod 不会调度到这个节点上,驱逐 正在运行的 Pod 不受影响

打污点:

kubectl taint node worker-02 node-type=gpu:NoSchedule

#打上污点后,不会影响正在运行的pod,再次启动其他pod后状态会处于pending状态,不能容忍这个污点

删除污点:

kubectl taint node worker-01 node-type-

#在key的后面加一个减号即可

  • Tolerations:允许 Pod 调度到有特定 taints 的 Node上

:容忍 toleration Pod 可以容忍 污点,Pod 就可以调度到 有污点的 节点 上

#打分时还是优先调度到没有污点的节点

图片包含 图形用户界面

AI 生成的内容可能不正确。

完全匹配:

node-type=gpu:NoSchedule #使用最多,完全匹配

匹配任意:taint value #可以匹配任意的值

  1. Operator 为 Exists,value 为空 #值为空就可以容忍任意的值
  2. node-type:NoSchedule

匹配任意:taint effect

  1. Effect 为空
  2. node-type=gpu
  3. 命令

Kubectl cordon worker-01:把节点标记为不可调度

#类似于自动打一个污点

文本

AI 生成的内容可能不正确。

#通过查看可以看到节点状态,调度被禁用,使用这个命令会更清晰

kubectl uncordon worker-01:恢复节点,变为可继续调度

节点需要维护,提前把节点上所有的 pod 驱逐

kubectl drain worker-01

#当节点快要下线时可以执行此命令

maxSkew:描述这些 Pod 可能被不均匀分布的程度。你必须指定此字段且该数值必须大于零。 其语义将随着 whenUnsatisfiable 的值发生变化:

apiVersion: v1

kind: Pod

metadata:

name: example-pod

spec:

# 配置一个拓扑分布约束

topologySpreadConstraints:

- maxSkew: 1

#不均匀分散的程度不能大于一

#高级调度策略要谨慎使用,会影响速度

日期2025.09.03学习日志

  1. kubenetes集群安全
  2. kube-apiserver: 入口 #安全职责
  • kubectl作为一个客户端如何访问集群的,通过验证权限的
  1. 通过.kube/config文件进行验证

  1. 访问控制概览

Kubernetes API 的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证、授权以及准入控制(AdmissionControl)等。

图示

AI 生成的内容可能不正确。

:请求发送到api的http的handler监听6443端口,在经过Authentication(认证)和Authorization(授权,鉴权),在经过admission(准入)

#准入验证会yaml文件种内容,只要apply发送请求就会经过这三种认证

#支持web类的hook(钩子)去做验证

  • k8s集群认证:

- Authentication:认证

- Authorization:授权 鉴权

- Admission:准入 (YAML 中 内容)

yaml内容分为以下两类

- Mutating admission:变形 #例replicas: 1000副本过大,通过策略修改为100

- validating admission:验证

#例image: reg.xxhf.cc/library/,可以规定使用的镜像必须是公司镜像,去做安全防范

#关注yaml文件种内容,不符合要求会做一些调整

3A 传统安全认证:

- Authentication 认证

- Authorization 授权 鉴权

- Audit 审计 (日志)

  • 认证:

:开启TLS时,所有的请求都需要首先认证。Kubernetes支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。如果认证成功,则用户的username 会传入授权模块做进一步授权验证,而对于认证失败的请求则返回HTTP 401。

  • 认证插件

:k8s是一个CA会自己签发证书

:证书中如何去分辨用户名?:通过CN=Common Name:用户名和O=Orgnization:组名 #k8s的这种认证方式就是X509

X509证书:

  1. 使用X509 客户端证书只需要 API Server 启动时配置-client-ca-file=SOMEFILE。在证书认证时,其CN域名作用户名,而组织机构域则用作group2

静态Token文件:

  1. 使用静态 Token 文件认证只需要 API Server 启动时配置-token-auth-file=SOMEFILE.
  2. token文件是至少包含3列的csv格式文件:token,user name,user uid,第四列为可选 group 名。注意如果有多个group名,列必须用””双引号包含其中,例如 token,user,uid,"groupl,group2,group3“

#使用静态token可以在apiserver的启动文件/etc/kubernetes/manifests/ kube-apiserver.yaml中写入-token-auth-file=文件名

引导Token:

  1. 引导 Token 是动态生成的,存储在 kube-system namespace 的 Secret 中,用来部署新的 Kubernetes 集群。
  2. 在使用kubeadm 部署 Kubernetes 时,kubeadm 会自动创建默认 token,可通过 kubeadm token list 命令查询

#例kubeadm join –token加入集群的方式就是引导token

静态密码文件:

  1. 需要 API Server 启动时配置--basic-auth-file=SOMEFILE,文件格式为csv,每行至少三列 password,user,uid,后面是可选的group 名,如password,user,uid,"group1,group2,group3 “

Servive Account:(重点使用):服务用户 #k8s的内置的一个对象

:是一种用于为Pod中的应用程序提供身份的重要权限管理对象

  1. serviceaccount是kubernetes自动生成的,并会自动挂载到容器的/var/run/secrets/kubernetes.io/serviceaccount目录中

#缩写sa,核心组v1,命名空间级别。可以根据需要自己去创建一个sa

#使用创建的sa去登录集群,集群就会知道是哪一个登录

sa创建:kubectl create sa zhangsan

webhook令牌身份认证:

API Server 需要配置

-authentication-token-webhook-config-file #配置如何访问webhook server

-authentication-token-webhook-cache-ttl #默认2 分钟

#在大规模公司时可使用这种认证方式。所有的登录都可以用这种认证,例如邮件、用户名认证等等

  1. 授权、鉴权

:授权主要用于对集群资源的访问控制,通过检查请求包含的相关属性值,与相对应的访问策略相比较,API请求必须满足某些策略才能被处理。

:跟认证类似,Kubernetes也支持多种授权机制,并支持同时开启多个授权插件(主要有一个验证通过即可)。

:如果授权成功,则用户的请求会发送到准入控制模块做进一步的请求验证;对于授权失败的请求则返回HTTP 403。

  • 授权:

Kubernetes 授权仅处理以下请求属性:

  1. User,group,extra
  2. API、请求方法和请求路径
  3. 请求资源和子资源
  4. Namespace
  5. API Group

目前,Kubernetes 支持以下授权插件:

  1. ABAC:attribute-Based Access Control:基于属性的访问控制

#云厂商使用一般

  1. RBAC:Role-Based Access Control:基于角色的访问控制
  2. Webhook
  3. Node:只能管理自己节点上的pod,不能跨界点管理

#通过/etc/kubernetes/manifests/ kube-apiserver.yaml查看使用的哪种授权方式

  1. RBAC:Role-Based Access Control:基于角色的访问控制

#允许用户使用kubectl get pods,不允许用户kubectl get secret,控制用户可以访问什么资源

#Role写一个角色,对不同环境设置不同的权限,对哪些资源执行什么动作(增删改查)get,edit,delete都是动作pod就属于资源对象

#开发允许 查询 get pod

测试允许 查询 get pod , get cm

运维允许 查询 get pod , get cm , edit cm , delete

例:授权创建用户tom绑定到角色上开发运维

#tom就拥有开发,运维等相关的权限

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

注:授权的资源属于命名空间级别的就使用roles,通过rolebindings将用户和角色绑定到一起。属于集群级别的就使用clusterroles,通过clusterrolebindings将用户和角色绑定到一起

图示

AI 生成的内容可能不正确。

注:RBAC的资源名都是小写的复数写法

  • 对于上面这些资源对象的可能存在的操作动作有:

create、get、delete、list、update、edit、watch、exec、patch

  1. 实验验证:认证授权:X509

:我们想要创建一个 User Account,只能访问 dev-project 这个命名空间,对应的用户信息如下所示

图形用户界面

AI 生成的内容可能不正确。

  • 创建命名空间:认证
  1. 执行:kubectl create ns dev-project

  1. 执行:mkdir dev-project:创建一个目录,并cd进入目录

#把证书等相关内容放入此目录里

  • 创建用户凭证:
  1. 执行:openssl genrsa -out dev-user.key 2048:创建私钥

#用户名是放置证书里面的,通过创建证书,创建用户,用户向CA申请证书。通过私钥和csr证书签发请求,CA就会签发一个证书

  1. 执行:openssl req -new -key dev-user.key -out dev-user.csr -subj "/CN=dev-user/O=developer":创建一个csr

#注意需要确保在-subj参数中指定用户名和组(CN表示用户名 common name ,O表示组 orgnazation )

  • 创建证书
  1. 执行:openssl x509 -req -in dev-user.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out dev-user.crt -days 3650

# Kubernetes 集群的 CA 证书,如果使用的是 kubeadm 安装的集群,CA 相关证书位于 /etc/kubernetes/pki/ 目录下面,我们会利用该目录下面的 ca.crt 和 ca.key两个文件来批准上面的证书请求。生成最终的证书文件,我们这里设置证书的有效期为 3650 天

  1. 执行:openssl verify -CAfile /etc/kubernetes/pki/ca.crt dev-user.crt:验证是否是CA签发

  • kubeconfig文件中添加用户和上下文 : #可以新建一个config文件
  1. 执行:kubectl config set-credentials dev-user --client-certificate=dev-user.crt --client-key=dev-user.key:添加用户,私钥目录下执行

  1. 执行:kubectl config set-context dev-user-context --cluster=kubernetes --namespace=dev-project --user=dev-user:添加上下文

#使用刚刚创建的证书文件和私钥文件在集群中创建新的凭证和上下文(Context):

背景图案

AI 生成的内容可能不正确。

#进入.kube/config文件中可以看到信息已经添加进去了

  • 切换上下文:
  1. 执行:kubectl config get-contexts:获取上下文

#星代表正在使用的上下文

  1. 执行:kubectl config use-context dev-user-context

# use-context使用哪一个上下文

注:此处可以不执行切换,等创建role并绑定角色后后在切换

图形用户界面, 文本, 应用程序, 电子邮件

AI 生成的内容可能不正确。

背景图案

AI 生成的内容可能不正确。

#以上分别是客户端证书和私钥,data用的base64位编码,可用证书路径

#kubeconfig存放kubectl连接k8s集群的验证信息

#使用证书、私钥找 apiserver认证dev-user

#上下文用来关联用户和集群,用户的名字和上下文中user的名字一致。kubectl会找当前正在使用的上下文,告诉用哪个用户名,连接哪个集群。可以写多个集群

  1. 执行:kubectl get pods

#出现报错,知道是谁进行执行的命令,后面加--v=9,显示详细日志,可以看到403

#以上操作是认证过程

  • 授权:RBAC方式

#写role角色,把rolebinging用户绑定到role上

  1. 执行:kubectl config use-context kubernetes-admin@kubernetes

#之前如有切换上下文就执行此条命令

  • 创建角色
  1. 执行:vim dev-user-role.yaml:写一个role角色

#apigroups写组,核心组写空,resources写对象,verbs写动作

#其中 Pod 属于 core 这个 API Group,在 YAML 中用空字符就可以,而 Deployment 和 ReplicaSet 现在都属于 apps 这个 API Group(如果不知道则可以用 kubectl explain 命令查看),所以 rules 下面的 apiGroups 就综合了这几个资源的 API Group:["", "apps"],其中verbs 就是我们上面提到的可以对这些资源对象执行的操作,我们这里需要所有的操作方法,所以我们也可以使用['*']来代替

  1. 执行: kubectl apply -f dev-user-role.yaml:创建role
  • 绑定角色:
  1. 执行:vim dev-user-rolebinding.yaml:写一个绑定

图片包含 图形用户界面

AI 生成的内容可能不正确。

图片包含 背景图案

AI 生成的内容可能不正确。

# Role 创建完成了,但是很明显现在我们这个 Role 和我们的用户 dev-user 还没有任何关系,所以我们就需要创建一个 RoleBinding 对象,在 dev-project 这个命名空间下面将上面的 dev-user-role 角色和用户 dev-user 进行绑定:(dev-user-rolebinding.yaml)

#上面的 YAML 文件中我们看到了 subjects 字段,就是我们上面提到的用来操作集群的对象,对应上面的 User 帐号 dev-user,使用 kubectl 创建上面的资源对象

  1. 执行:kubectl apply -f dev-user-rolebinding.yaml:创建上面的资源对象
  2. 执行:kubectl config use-context dev-user-context:切换上下文

验证:

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#由此可以看出成功授权认证,无法跳出当前命令空间

  1. Servive Account授权方式:
  2. 执行:kubectl config use-context kubernetes-admin@kubernetes:切换成原有的上下文
  3. 执行:kubectl -n default create sa ns-user:创建一个用户ns-user

#ns-user是default命名空间的一个普通用户

#ns-admin default 命名空间 管理员

# cluster-admin 集群

  • 创建role
  1. 执行:vim ns-user-role.yaml

图片包含 图形用户界面

AI 生成的内容可能不正确。

#定义资源的增删改查

  1. 执行:kubectl apply -f ns-user-role.yaml
  2. 执行:kubectl apply -f ns-user-rolebinding.yaml

#以上用户和role和rolebingding都已创建

  • 如何使用ns-user SA kubeconfig

:每证书和私钥,使用token令牌,保持在secret

  • 创建service account的token
  1. 执行:vim ns-user-secret.yaml

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#type,secret的类型

  1. 执行:kubectl apply -f ns-user-secret.yaml

#进行查看,里面有三个data,里面有证书和token,k8s就知道身份

  1. kubectl get secrets ns-user -o jsonpath={.data.token} | base64 -d:精确提取token的信息

#此处提取的是base64解码完成后的信息,kubeconfig文件中再次添加用户就是使用token

  1. 执行:./ sa-to-kubeconfig-user.sh:使用脚本的方式生成一个kubecongfig文件

图形用户界面, 应用程序, Word

AI 生成的内容可能不正确。

#此处内容需要根据实际情况进行修改

#当需要给其他人创建授权,并在其他电脑上使用,在自己的家目录下创建一个.kube目录并创建一个config文件把内容放置进去即可

  1. 创建命名空间的管理员ns-admin default
  2. 执行:vim ns-admin.yaml:创建一个ns-admin

  1. 执行:kubectl apply -f ns-admin.yaml
  2. 执行:kubectl get sa:进行查看

图片包含 应用程序

AI 生成的内容可能不正确。

  • 写一个role文件:
  1. 执行:vim ns-admin-role.yaml:创建一个管理员的role

背景图案

AI 生成的内容可能不正确。

#命名空间下的管理员,所有组,所有都不用限制,都是星

  1. 执行:kubectl apply -f ns-admin-role.yaml
  • 写一个RoleBinding
  1. 执行:vim ns-admin-rolebinding.yaml

图片包含 图形用户界面

AI 生成的内容可能不正确。

#subjects把用户和角色绑定在一起

  1. 执行:kubectl apply -f ns-admin-rolebinding.yaml
  • 创建secret进行token认证
  1. vim ns-admin-secret.yaml

图形用户界面, 应用程序

AI 生成的内容可能不正确。

  1. 执行:kubectl apply -f ns-admin-secret.yaml
  • 生成kubeconfig文件 #使用脚本进行生成
  1. 执行:./ sa-to-kubeconfig-admin.sh

#所生成的文件就可以发送给他人进行使用

整体流程:

  1. create sa
  2. create role
  3. create rolebinding
  4. create secret (token )
  5. generate kubeconfig file:通过脚本
  6. 创建cluster-admin集群

#每个用户创建管理员角色,集群层面命名空间

:资源对象里面有集群层面就需要使用clusterrole

  • 创建一个集群用户:
  1. 执行:vim cs-admin.yaml

  1. 执行:kubectl apply -f cs-admin.yaml
  • 创建secret
  1. vim cs-admin-secret.yaml

图形用户界面, 应用程序

AI 生成的内容可能不正确。

  1. 执行:kubectl apply -f cs-admin-secret.yaml

表格

AI 生成的内容可能不正确。

#k8s集群安装时默认创建了clusterrole,可直接使用

  1. 执行:kubectl apply -f cs-admin-clusterolebinding.yaml

图片包含 图形用户界面

AI 生成的内容可能不正确。

#绑定角色

  • 生成kubeconfig文件 #使用脚本进行生成
  1. 执行:./ sa-to-kubeconfig.sh

#创建的集群管理员就在不同的命名空间不受限制

作业:

用户: zhangsan 项目经理 管理 多个项目 , 拥有多个命名空间的管理员 , 分配权限 1个 kubeconfig

日期2025.09.04学习日志

用户: zhangsan 项目经理 管理 多个项目 , 拥有多个命名空间的管理员 , 分配权限 1个 kubeconfig

#多个命名空间使用多个绑定

#在每个命名空间创建role和rolebinding

:可以使用clusterrole减少对role的创建使用 ClusterRole+ rolebinging

#不使用时之间删除绑定即可

:创建多个congfig文件时可以在执行kubectl get pods --kubeconfig=congfig-test

#可以使用--kubeconfig=congfig-test指定具体使用哪个congfig文件

#使用其他的就创建其他的role和rolebinding

  • 准入控制:

:准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数。不同于授权和认证只关心请求的用户和操作,准入控制还处理请求的内容,并且仅对创建、更新、删除或连接(如代理)等有效,而对读操作无效。

:准入控制支持同时开启多个插件,它们依次调用,只有全部插件都通过的请求才可以放过进入系统。

ResourceQuota:限制每个命名空间中可以创建的资源数量:一个资源对象,缩写quota

#对命名空间中的pod进行限额

  • 配额管理

资源有限,如何限定某个用户可以使用多少资源?

方案:

预定义每个namespace的ResourceQuota,并把spec保存为configmap;

用户可以创建多少个Pod;

BestEffortPod

QoSPod

用户可以创建多少个service;

用户可以创建多少个ingress;

用户可以创建多少个serviceVIP;

Apiserver开启ResourceQuota的 admission plugin

示例:

形状

AI 生成的内容可能不正确。

#限制2个configmaps,2个services。限制每个命名空间可以使用多少资源

图示

AI 生成的内容可能不正确。

  1. heml
  2. 介绍:

Helm 是 Kubernetes 的包管理器,类似于 Python 的 pip ,centos 的 yum 。Helm 主要用来管理 Chart 包。Helm Chart 包中包含一系列 YAML 格式的 Kubernetes 资源定义文件,以及这些资源的配置,可以通过 Helm Chart 包来整体维护这些资源

:Helm 也提供了一个 helm 命令行工具,该工具可以基于 Chart 包一键创建应用,在创建应用时,可以自定义 Chart 配置。应用发布者可以通过 Helm 打包应用、管理应用依赖关系、管理应用版本,并发布应用到软件仓库;对于使用者来说,使用 Helm 后不需要编写复杂的应用部署文件,可以非常方便地在 Kubernetes 上查找、安装、升级、回滚、卸载应用程序

:Helm 最新的版本是 v3,Helm3 以 Helm2 的核心功能为基础,对 Chart repo、发行版管理、安全性和 library Charts 进行了改进。和 Helm2 比起来,Helm3 最明显的变化是删除了 Tiller(Helm2 是一种 Client-Server 结构,客户端称为 Helm,服务器称为 Tiller)。Helm3 还新增了一些功能,并废弃或重构了 Helm2 的部分功能,与 Helm2 不再兼容

图示

AI 生成的内容可能不正确。

:上面的架构图中,核心是 Helm Client(helm命令)和 Helm Chart 包。helm 命令可以从 Chart Repository 中下载 Helm Chart 包,读取kubeconfig文件,并构建 kube-apiserver REST API 接口的 HTTP 请求。通过调用 Kubernetes 提供的 REST API 接口,将 Chart 包中包含的所有以 YAML 格式定义的 Kubernetes 资源,在 Kubernetes 集群中创建。

:这些资源以 Release 的形式存在于 Kubernetes 集群中,每个 Release 又包含多个 Kubernetes 资源,例如 Deployment、Pod、Service 等

#helm也是用config文件

#下载可以直接去官网下载

  1. Helm 三大基本概念
  • Chart:代表一个 Helm 包。它包含了在 Kubernetes 集群中运行应用程序、工具或服务所需的所有 YAML 格式的资源定义文件。

#一个chart可以创建多个release

  • Repository(仓库): 它是用来存放和共享 Helm Chart 的地方,类似于存放源码的 GitHub 的 Repository,以及存放镜像的 Docker 的 Repository。
  • Release:它是运行在 Kubernetes 集群中的 Chart 的实例。一个 Chart 通常可以在同一个集群中安装多次。每一次安装都会创建一个新的 Release #类似容器

:Helm 安装 chart 到 Kubernetes 集群中,每次安装都会创建一个新的 release

  1. 为什么使用helm

#把公司应用部署到 Kubernetes 集群中,需要给应用写YAML, deployment.yaml service.yaml

#当维护多个yaml文件时进行修改,就会造成工作量加大

:如果使用heml,只需要维护一个chart包

:在 Helm 中,可以理解为主要包含两类文件:模板文件和配置文件。模板文件通常有多个,配置文件通常有一个。Helm 的模板文件基于text/template模板文件,提供了更加强大的模板渲染能力。Helm 可以将配置文件中的值渲染进模板文件中,最终生成一个可以部署的 Kubernetes YAML 格式的资源定义文件,如下图所示:

日程表

AI 生成的内容可能不正确。

#对yaml文件的部分值写为一个模板,在写一个配置文件,通过模板和配置文件组成一个yaml

#对所有应用YAML提取一个模板 + 每个应用的配置文件

  1. Helm安装

#此处使用下载好的安装包

  1. 执行:tar -xf helm-v3.17.0-linux-amd64.tar.gz:解压安装包
  2. 执行:cd linux-amd64:进入解压目录并查看

文本

AI 生成的内容可能不正确。

#可以看到有一个解压的后heml工具

  1. 执行:mv helm /usr/local/bin/:将工具包移动到PATH路径下
  2. 执行:helm version:查看

  1. helm部署应用:
  • 初始化仓库

:安装完 Helm 之后,就可以使用 helm 命令添加一个 Chart 仓库。类似于用来托管 Docker 镜像的 DockerHub、用来托管代码的 GitHub,Chart 包也有一个托管平台,当前比较流行的 Chart 包托管平台是 Artifact Hub #chart仓库

:Artifact Hub 上有很多 Chart 仓库,我们可以添加需要的 Chart 仓库,这里我们添加 BitNami 提供的 Chart 仓库

#使用helm去安装就要去添加一个仓库

  • 添加仓库

helm repo add bitnami https://charts.bitnami.com/bitnami

#添加 Chart Repository,bitnami(仓库名),后面仓库url

helm repo list:查看添加的 Repository 列表

#我们可以通过helm search命令,来查询需要的 Chart 包。helm search支持两种不同的查询方式

  • 常用仓库列表:

kubernetes-dashboard https://kubernetes.github.io/dashboard/

prometheus-community https://prometheus-community.github.io/helm-charts

grafana https://grafana.github.io/helm-charts

elastic https://helm.elastic.co

bitnami https://charts.bitnami.com/bitnami

myrepo http://127.0.0.1:8080

  • helm search repo nginx:在添加的仓库中,查看chark包:本地搜索

#没有添加仓库名在本地所有的仓库在中搜索

表格

AI 生成的内容可能不正确。

#name:chart的名字,chart version:chart的版本,app version:应用的版本,description:描述信息

  • helm search repo bitnami(仓库名)/nginx:在指定的仓库中搜索

#在后面加-l就列出来历史版本,例:helm search repo bitnami(仓库名)/nginx -l

#可以指定安装具体哪个版本

  1. 安装一个chart包:

:查询到自己需要的 Helm Chart 后,就可以通过 helm install 命令来安装一个 Chart。helm install 支持从多种源进行安装:

  • Chart 的 Repository: helm install bitnami/nginx --generate-name
  • 本地的 Chart Archive:例如 helm install foo foo-1.0.0.tgz。
  • 一个未打包的 Chart 路径:例如 helm install foo path/to/foo

#使用解压后的cahrt包目录

安装格式:helm install [NAME](release的名字) [CHART](chart的名字)[flags] #在线安装方式

  1. 执行:helm install nginx-01 bitnami/nginx:安装一个nginx

#不指定版本默认安装最新版本

#使用此种方式安装nginx现版本会出现报错,可使用其他安装方式

:使用--version:可指定chart的版本

  • 离线安装:

#需要下载一个chart包

  1. 执行:helm pull bitnami/nginx --version=18.1.15:下载一个chart包,并指定版本 #如没有提前下载好chart包,可使用此命令进行下载chart包
  2. 执行:helm install nginx-02 nginx-18.1.15.tgz :进行安装

图片包含 背景图案

AI 生成的内容可能不正确。

#根据信息可以看到创建成功

#每更新一次,release就会加一

  1. 执行:kubectl get pods kubectl get svc:进行查看

图形用户界面, 表格

AI 生成的内容可能不正确。

#可以看到安装了一个nginx-02的pod和一个svc

#基于一个chart可以安装多个release

注:镜像无法进行拉取,可以在yaml文件中的配置文件中,把镜像改为本地的镜像仓库

  1. helm install nginx-03 nginx-18.1.15.tgz

  1. 执行:helm ls:进行查看

图片包含 表格

AI 生成的内容可能不正确。

#可以看到基于一个chart安装多个release。cahrt安装完成后是一个deployed

  1. 自定义chart

查看nginx的chart的解压目录:

文本, 表格

AI 生成的内容可能不正确。

#模板 templates + 默认配置 values.yaml(放置所有的值),创建一个yaml

:上面的安装方式只会使用 Chart 的默认配置选项,很多时候我们需要自定义 Chart 来指定我们想要的配置。使用 helm show values 可以查看 Chart 中的可配置选项

  • 修改默认配置:

安装过程中:传递配置数据方式:

-f,--values:使用 YAML 文件覆盖配置。可以指定多次,优先使用最右边的文件

--set:通过命令行的方式对指定配置项进行覆盖

#--set可以写多个

  1. 执行:helm install nginx-10 -f nginx-10-values.yaml(文件路径) nginx

注:当配置文件中有参数修改时使用此命令

#安装时使用-f加自定义配置文件可以,覆盖原有的values的yaml文件

  1. 执行:touch nginx-values.yaml:创建一个yaml文件

#名称自定义,把想要修改的值部署到创建的yaml的配置文件中

  1. 执行:kubectl get pods

图形用户界面, 应用程序, Word

AI 生成的内容可能不正确。

注:镜像无法进行拉取,可以在yaml文件中的配置文件中,把镜像改为本地的镜像仓库。也可以更改镜像拉取策略等多个参数

再次查看:

#使用本地镜像配置的文件成功创建并启动

#在大项目经常需要修改的拿出来进行修改

  • 验证--set使用方式
  1. 执行:helm install nginx-20 --set replicaCount=3 --set updateStrategy.rollingUpdate.maxSurge=1 --set updateStrategy.rollingUpdate.maxUnavailable=1 nginx

#通过--set对相关参数进行了修改,此种方式也可以覆盖参数

  1. 执行:kubectl get pods

#可以在自动化部署时使用

  1. 升级release

:部署完应用之后,后续还可能升级应用,可以通过helm upgrade命令来升级应用。升级操作会基于已有的 Release,根据提供的信息进行升级。Helm 在更新时,只会变更有更改的内容

更新方式:两种

helm upgrade nginx-20 -f nginx-20-value.yaml nginx

helm upgrade nginx-20 --set key=value nginx

#语法和安装类似

例:nginx-20进行更新

  1. helm upgrade nginx-20 --set replicaCount=2 --set updateStrategy.rollingUpdate.maxSurge=2 --set updateStrategy.rollingUpdate.maxUnavailable=0 nginx

图片包含 应用程序

AI 生成的内容可能不正确。

#可以看到yaml进行了更新

  1. 执行:helm ls:进行查看

图形用户界面, 表格

AI 生成的内容可能不正确。

#nginx-20的revision值为2进行了次安装,一次更新

  • 回滚:
  1. 执行:helm history nginx-20:查看更新历史版本

表格

AI 生成的内容可能不正确。

  1. 执行:helm rollback nginx-20:回滚到上一个版本

图形用户界面

AI 生成的内容可能不正确。

#查看回到了版本1

  • 回滚到指定版本:helm rollback nginx-20 2(revision号)
  • helm uninstall nginx-10(release名字):删除release

#上述命令会从 Kubernetes 卸载 nginx-01, 它将删除和该版本关联的所有资源(Service、Deployment、Pod、ConfigMap 等),包括该 Release 的所有版本历史

  1. helm命令

Helm 常用命令如下:

  • helm create:在本地创建新的 chart;模板
  • helm intall:安装 chart;
  • helm list:列出所有 release;
  • helm repo:列出、增加、更新、删除 chart 仓库;
  • helm rollback:回滚 release 到历史版本;
  • helm pull:拉取远程 chart 到本地;
  • helm search:使用关键词搜索 chart;
  • helm uninstall:卸载 release;
  • helm upgrade:升级 release;

例:创建一个chart

helm create my-chart(chart的名字)

查看创建chart的内容:

# charts # 子chart,当前 chart 的依赖

Chart.yaml # 元信息 基础信息

templates # 模板放置目录

values.yaml # 默认配置文件

  • 模板信息

模板语法: {{ }} go template

1. include #包含来自另一个文件,helpers.tpl define 定义 的

metadata:

name: {{ include "my-chart.fullname" . }}

labels:

{{- include "my-chart.labels" . | nindent 4 }}

2. if 逻辑判断 #第二种方式

spec:

{{- if true not false=.Values.autoscaling.enabled }} # .Values = values.yaml

replicas: {{ .Values.replicaCount }}

{{- end }}

autoscaling:

enabled: true

spec:

replicas:1

  • yaml完成后验证:helm template my-nginx my-chart/

#在本地渲染 chart 包,生成最终部署的YAML

  1. ChartMuseum (Chart 仓库)
  2. 使用本地存储
  3. ./chartmuseum --debug --port=8080 --storage="local" --storage-local-rootdir="./chartstorage"
  4. helm repo add my-repo http://127.0.0.1:8080
  5. helm plugin install https://github.com/chartmuseum/helm-push
  6. helm cm-push nginx-15.4.3.tgz my-repo
  7. 上传chart包到仓库

# 下载 插件

wget https://github.com/chartmuseum/helm-push/releases/download/v0.10.4/helm-push_0.10.4_linux_amd64.tar.gz

mkdir /root/.local/share/helm/plugins/helm-push -p

tar xvf helm-push_0.10.4_linux_amd64.tar.gz -C /root/.local/share/helm/plugins/helm-push

# 上传 chart 包

helm cm-push nginx-15.4.3.tgz my-repo

# 更新仓库

helm repo update my-repo

[root@node-01 18-helm]# helm search repo my-repo

NAME CHART VERSION APP VERSION DESCRIPTION

my-repo/nginx 15.4.3 1.25.3 NGINX Open Source is a web server that can be a...

  • 附录

registry.cn-beijing.aliyuncs.com/xxhf/nginx:1.27.0-debian-12-r5

#nginx镜像

日期2025.09.05学习日志

  1. 部署Dashboard

部署版本:Dashboard: v2.7.0、Chart version: 6.0.8

  • 添加chart仓库
  1. 执行:helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/:添加一个仓库
  2. 执行:helm repo ls:进行查看仓库中的chart包
  3. helm search repo kubernetes-dashboard -l:查看adshboard
  • 下载chart包
  1. helm pull kubernetes-dashboard/kubernetes-dashboard --version=6.0.8
  2. 执行:tar -xf kubernetes-dashboard-6.0.8.tgz
  3. 执行:helm install kubernetes-dashboard kubernetes-dashboard-6.0.8.tg:安装

  • 部署方式二:

helm upgrade --install kubernetes-dashboard kubernetes-dashboard-6.0.8.tgz --create-namespace --namespace kubernetes-dashboard

#写脚本时可以使用此命令,自动创建命名空间

  1. kubectl -n kubernetes-dashboard edit svc kubernetes-dashboard:修改svc为NodePort

  • 获取访问地址:
  1. kubectl -n kubernetes-dashboard edit svc kubernetes-dashboard
  2. kubectl -n kubernetes-dashboard get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

kubernetes-dashboard NodePort 10.110.44.158 <none> 443:31268/TCP 165m

  • 浏览器进行访问:

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#访问使用https访问

  • 创建用户:
  1. 执行以下命令

kubectl apply -f 01-admin-user-sa.yaml

kubectl apply -f 02-admin-user-bind.yaml

kubectl apply -f 03-sa-secret.yaml

kubectl get secret admin-user -n kubernetes-dashboard -o jsonpath={".data.token"} | base64 -d

图形用户界面

AI 生成的内容可能不正确。

#使用token进行验证登录,使用不同的用户进行验证

  • 启用ingress
  1. 修改 values.yaml

ingress:

enabled: true

className: "nginx"

hosts:

- ui.xxhf.cc

tls:

- secretName: dashboard-secret

hosts:

- ui.xxhf.cc

  • 创建tls证书
  1. kubectl -n kubernetes-dashboard create secret tls kubernetes-dashboard-tls --cert=ui.xxhf.cc_bundle.crt --key=ui.xxhf.cc.key

#yaml文件中写使用的域名和证书

  • 更新部署:
  1. helm upgrade --install kubernetes-dashboard -f kubernetes-dashboard/dashboard-values.yaml ./kubernetes-dashboard --create-namespace --namespace kubernetes-dashboard
  • 使用token进行验证:

# 获取 token

  1. kubectl -n demo-ns get secrets namespace-user-token-h5fgd -o jsonpath={.data.token} | base64 -d
  2. curl -k -H 'Accept: application/json' -H "Authorization: Bearer token......" https://172.16.66.52:6443/api/v1/namespaces/demo-ns/pods?limit=500
  • 创建context
  1. kubectl config --kubeconfig=config set-context ns-user --cluster=kubernetes --namespace=demo-ns --user=ns-user

kubectl config set-credentials ns-user --token='eyJhbGciOiJSUzI1NiIsI......'

  • 镜像:

registry.cn-beijing.aliyuncs.com/xxhf/dashboard:v2.7.0

  1. 监控
  2. Metrics Server

:应该知道有一个命令 top 能够实时显示当前系统的 CPU 和内存利用率,它是性能分析和调优的基本工具,非常有用。Kubernetes 也提供了类似的命令,就是 kubectl top,不过默认情况下这个命令不会生效,必须要安装一个插件 Metrics Server 才可以

:Metrics Server 是一个专门用来收集 Kubernetes 核心资源指标(metrics)的工具,它定时从所有节点的 kubelet 里采集信息,但是对集群的整体性能影响极小,每个节点只大约会占用 1m 的 CPU 和 2MB 的内存,所以性价比非常高

kubectl top pod:查看pod的资源

kubectl top node:查看node的资源使用

注:需要安装Metrics Server服务才能进行使用

:执行kubectl top,请求发送到API server,API server在把请求转到metrics server 。它调用 kubelet 的 API 拿到节点和 Pod 的指标,再把这些信息交给 apiserver,这样 kubectl、HPA 就可以利用 apiserver 来读取指标了

  • 手工伸缩:

kubectl scale deploy

  • 自动伸缩

HPA Horizontal Pod Autoscaler:水平 Pod 自动伸缩 #添加pod副本数

#一个资源对象

VPA Vertical Pod Autoscaler:垂直 Pod 自动伸缩 #增加资源,使用不高

  1. HorizontalPodAutoscaler(HPA)

#有了 Metrics Server,我们就可以轻松地查看集群的资源使用状况了,不过它另外一个更重要的功能是辅助实现应用的“水平自动伸缩

:“HorizontalPodAutoscaler”,简称是 “hpa”。顾名思义,它是专门用来自动伸缩 Pod 数量的对象适用于 Deployment 和 StatefulSet,但不能用于 DaemonSet 对象

:HorizontalPodAutoscaler 的能力完全基于 Metrics Server,它从 Metrics Server 获取当前应用的运行指标,主要是 CPU 使用率,再依据预定的策略增加或者减少 Pod 的数量

  • 伸缩目标: #可以进行伸缩的对象

Deployment

statefulSet

  • 依据: 扩容 缩容

CPU 60% #cpu值可以自己调整定义

Memory

  1. metrics server部署

#有多种部署安装方式,可在官网具体查询

  • Github安装方式:

wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/high-availability-1.21+.yaml:下载yaml

  1. 修改YAML 添加 --kubelet-insecure-tls

文本

AI 生成的内容可能不正确。

注:此处使用下载好的yaml,metrics进行部署。以上内容以修改好

  • metrics server部署:
  1. 执行:kubectl apply -f metrics-server-1.21+.yaml:进行安装
  2. 执行:kubectl -n kube-system get pods

#默认放在了kube-system命名空间下,服务正在启动中

#服务器启动后会定时去kubelet拿监控数据

验证:

  1. 执行:kubectl top node

  1. 执行:kubectl top pod

扩缩容测试:

:使用 HorizontalPodAutoscaler,首先要定义 Deployment 和 Service,创建一个 Nginx 应用,作为自动伸缩的目标对象:

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#metrics:伸缩的依据,cpu和cpu的利用率

# HorizontalPodAutoscaler 会根据 YAML 里的描述,找到要管理的 Deployment,把 Pod 数量调整成 2 个,再通过 Metrics Server 不断地监测 Pod 的 CPU 使用率

  1. 执行:kubectl apply -f nginx-deployment.yaml

#启动一个nginx的deployment作为伸缩目标

  1. 执行:kubectl apply -f nginx-hpa-v2.yaml:进行扩缩容部署
  2. 执行:kubectl get hpa:进行查看

压力测试进行验证: # 公司一般使用Jmeter压测工具

  1. 执行:kubectl run test -it --image=httpd:alpine -- sh:启动一个pod进行测试 #需要准备httpd:alpine的镜像
  2. 容器内执行:ab -c 10 -t 60 -n 100000 'http://nginx-hpa-svc/':进行压力测试

#ab压力测试工具,-c:并发(一定时间内请求数量)-t,时间,-n多少请求

  1. 执行:kubectl top pod:进行查看

图形用户界面, 文本

AI 生成的内容可能不正确。

# Metrics Server 大约每 15 秒采集一次数据,所以 HorizontalPodAutoscaler 的自动化扩容和缩容也是按照这个时间点来逐步处理的

#cpu利用率上来后可以看到自动增加的副本数

#当它发现目标的 CPU 使用率超过了预定的 5% 后,就会以 2 的倍数开始扩容,一直到数量上限,然后持续监控一段时间,如果 CPU 使用率回落,就会再缩容到最小值

#以上监控不能看到历史数据,需要使用prometheus

  1. kube-prometheus #开箱即用的监控方案

#简化prometheus的部署难度

:prometheus如何知道通过哪个点去找数据,通过job的名称进行寻找目标,并通过服务发现service discovery进行自动添加目标。通过pull去拉取目标数据,目标必须要有metrics的接口。

:pusygatway用法:将数据推送到pusygatway,在使用prometheus去pusygatway的上面拉取数据

:alertmanager主要是用来发送告警消息,通过设置的规则去告警。

# node-exporter是收集主机 的metrics , 暴露 一个接口 9100:/metrics

例:现在监控一个1000 个节点,如何告诉 prometheus 监控的目标

:通过job的名称进行寻找目标,并通过服务发现service discovery进行自动添加目标

#prometheus支持多种服务发现

  • 组件:

#通过kube-prometheus会在集群内布置以下组件内容

  • KSM:拿到对象的状态,会生成一个关于objects的mertics,可以拿到所有对象的状态,暴露出来让prometheus可以拉取到数据
  1. Operator

介绍:Operator 是由 CoreOS 开发的,用来扩展 Kubernetes API特定的应用程序控制器,它用来创建、配置和管理复杂的有状态应用,如数据库、缓存和监控系统。Operator 基于 Kubernetes 的资源和控制器概念之上构建,但同时又包含了应用程序特定的领域知识。创建 Operator 的关键是 CRD(自定义资源)的设计

:Operator 直接使用 Kubernetes API 进行开发,也就是说他们可以根据这些控制器内部编写的自定义规则来监控集群、更改 Pods/Services、对正在运行的应用进行扩缩容

#adapter可以代替metrics server

  • CR:CR 代表自定义资源(Custom Resource)是一种扩展 Kubernetes API 的方式,允许用户定义自己的资源类型和规范。它们允许用户在Kubernetes中创建和管理自定义资源对象,这些对象可以与Kubernetes核心资源(如Pod、Service、Deployment等)一样进行操作
  • CRD:CRD(Custom Resource Definition)是一种 Kubernetes 资源,用于定义 CR 的结构和行为。通过创建CRD对象,用户可以定义新的 CR 类型,包括它们的API结构、字段、验证规则和操作行为 #自定义资源

:通过使用CR和CRD,用户可以扩展Kubernetes的功能,以适应特定的应用需求。它们提供了一种自定义资源的机制,使用户能够以声明的方式定义和操作自己的资源类型,而无需修改Kubernetes核心代码

#crd也是一个资源对象

crd写法:

  1. 执行:kubectl apply -f resourcedefinition.yaml

#可以看出扩展自定义出了一个资源对象

创建一个crontab的yaml:

  1. 执行:kubectl apply -f my-crontab.yaml

#通过查看可以看到ct创建了出来

#创建出一个deployment的yaml,还需要创建一个operator控制器进行执行工作

  1. Prometheus Operator

介绍:Prometheus Operator是一种为 Kubernetes 提供本地部署和管理 Prometheus 及相关监控组件的工具。该项目的目的是简化和自动化为 Kubernetes 集群配置基于 Prometheus 的监控堆栈

  • Prometheus Operator 包括但不限于以下功能:
  1. Kubernetes自定义资源:使用Kubernetes自定义资源来部署和管理Prometheus、Alertmanager和相关组件。通过定义自定义资源对象(CRD),可以在Kubernetes中声明和配置 Prometheus 实例、Alertmanager 实例等

#部署了operator就相当于有了prometheus和alertmanager

  1. 简化的部署配置:通过本地的Kubernetes资源,可以配置Prometheus的基本设置,如版本、持久化、数据保留策略和副本数。这样可以更方便地进行部署配置,无需涉及复杂的配置文件。
  2. Prometheus 目标配置:基于熟悉的Kubernetes标签查询,自动生成监控目标的配置。无需学习Prometheus特定的配置语言,即可快速定义要监控的目标。这样可以简化监控目标的配置过程。
  • 安装operator

wget https://github.com/prometheus-operator/prometheus-operator/releases/download/v0.69.1/bundle.yaml:github下载的快速安装yaml

#可提前下载好,以下安装使用下载好的yaml进行安装部署

  1. 执行:kubectl create -f bundle.yaml:进行部署安装

#此处必须要用create

  1. 执行:kubectl apply -f rbac.yaml

#因为需要监控数据需要使用一个ServiceAccount,要去拿应用的数据要有权限,要写一个yaml

  • Prometheus Operator 在Kubernetes中引入了自定义资源,用于声明 Prometheus 和 Alertmanager 集群的期望状态以及Prometheus的配置

Prometheus:Prometheus自定义资源用于定义Prometheus实例的配置和规范。可以指定版本、持久化配置、存储策略、副本数等参数,以及与其他资源的关联关系。

ServiceMonitor:ServiceMonitor 是一个自定义资源,用于定义要由Prometheus监控的服务和指标。可以指定服务的标签选择器,以便Prometheus可以动态地发现和监控符合条件的服务。 #主要用来作服务发现

Alertmanager:Alertmanager 自定义资源用于定义Alertmanager实例的配置和规范。可以指定接收告警的通知渠道、告警路由的规则等参数

  1. 执行:kubectl api-resources | grep monitoring

#可以看到给我们创建了一个monitoring的这个组

创建prometheus的yaml:

  1. 执行:kubectl apply -f prometheus.yaml

#operator的文件已经定义了很多参数,在上述文件中只需写关键参数即可

  1. 执行:kubectl get prometheus

  1. 执行:kubectl get pods:进行查看

表格

AI 生成的内容可能不正确。

#部署的promethrus operator就是一个控制器,控制CR

  1. 执行:kubectl apply -f alertmanager.yaml:启动一个alertmanager

注:部署时如没有镜像,需提前导入镜像,或下载,导入的镜像也是在master

#k8s的所有镜像都在k8s.io这个命名空间

  1. 执行:Kubectl get svc:进行网页的端访问

  • 监控pod,如何去找到pod:使用service discovery:服务发现

servicemonitors:找到要监控的 Pod的IP 信息,通过标签

:安装operator后就可以部署和管理prometheus server。部署prometheus server就可以通过servicemonitor或podmonitor两种方式去找service和pod进行监控,找到svc也可以找到pod

podmonitor:

#通过以上两种CR进行监控pod,主要使用servicemonitors

部署测试应用:进行监控

  1. 执行:kubectl apply -f example-app-dep.yaml -f example-app-svc.yaml

#里面就是我们所监控的目标,和一些端口信息等

创建ServiceMonitor 对象:

  1. 执行:kubectl apply -f serviceMonitor.yaml

  1. 执行:kubectl get smon:进行查看

#servicemonitors:创建之后,自动 在 prometheus 配置文件中添加Job

:部署监控就一个prometheus.yaml,监控应用就创建一个ServiceMonitor

修改配置文件:servicemonitors 自动 在 prometheus 配置文件中 添加 Job

  1. 附录:
  2. metric server vs kube-state-metric vs cAdvisor
  • Metric Server(指标服务器):
  1. Metric Server是Kubernetes的核心组件之一,用于收集和聚合集群级别的资源利用率指标,如CPU使用率、内存使用量等。
  2. Metric Server使用Kubernetes API提供的Metrics API来获取和暴露指标数据,可以通过kubectl命令或API查询这些指标。
  3. Metric Server通常用于水平扩展Pod的自动伸缩、资源配额管理和监控集群整体的资源利用率。
  • kube-state-metrics(Kubernetes 状态指标)KSM:
  1. kube-state-metrics 是一个独立的监控工具,用于收集和暴露Kubernetes集群中的各种资源对象的状态指标。
  2. kube-state-metrics 通过解析 Kubernetes 的 API 服务器中的资源对象状态,生成与资源对象相关的指标数据,如节点数量、Pod 数量、ReplicaSet 数量等。
  3. kube-state-metrics 提供了丰富的资源指标,可以用于监控和告警,以及与 Prometheus 等监控系统集成。
  • cAdvisor(容器监控代理):
  1. cAdvisor 是一个容器监控代理,用于收集和暴露单个节点上容器级别的资源指标。它是Kubernetes默认集成的监控工具之一。
  2. cAdvisor 运行在每个节点上,通过直接与Docker或其他容器运行时交互,收集容器的CPU、内存、磁盘和网络等资源使用情况。
  3. cAdvisor 提供了实时的容器级别指标,可以用于监控容器的性能和资源利用情况
  4. 修复unhealthy target

图片包含 文本

AI 生成的内容可能不正确。

  • etcd.yaml

- --listen-metrics-urls=http://127.0.0.1:2381

# 修改为

- --listen-metrics-urls=http://0.0.0.0:2381

  • kube-controller-manager.yaml

- --bind-address=127.0.0.1

# 修改为

- --bind-address=0.0.0.0

  • kube-scheduler.yaml

- --bind-address=127.0.0.1

# 修改为

- --bind-address=0.0.0.0

  • Kube-proxy

kubectl -n kube-system edit cm kube-proxy

metricsBindAddress: ""

# 修改为

metricsBindAddress: "0.0.0.0"

重启 kube-proxy

  1. 全栈监控 可观测

:全栈监控(Full Stack Monitoring)是一种综合性的监控方案,用于收集、分析和可视化应用程序的各个层面和组件的性能和健康状态。它提供了对整个应用程序栈的端到端可见性,包括前端、后端、基础设施和用户体验等方面。

:全栈监控旨在帮助开发团队、运维团队和业务团队全面了解应用程序的运行状况,以便及时发现和解决问题,并持续改进应用程序的性能和可用性。通过收集和分析各个组件的监控数据,全栈监控可以提供以下方面的信息:

  1. 应用程序性能:全栈监控可以实时监测应用程序的性能指标,例如响应时间、吞吐量、错误率等。这些指标可以帮助识别性能瓶颈和优化机会,从而提升应用程序的效率和用户体验。
  2. 用户体验:全栈监控可以跟踪用户在应用程序中的行为和交互,并提供关于用户体验的指标,如页面加载时间、交互延迟等。这些指标可以帮助了解用户对应用程序的满意度,并识别可能影响用户体验的问题。
  3. 服务依赖关系:应用程序通常依赖于多个服务和组件。全栈监控可以跟踪这些依赖关系,并提供服务之间的关联性和性能指标。这有助于识别服务之间的依赖问题、故障传播和性能影响。
  4. 基础设施监控:全栈监控可以监控应用程序运行所需的基础设施层,包括服务器、数据库、网络等。它可以提供有关基础设施的指标和警报,以确保其正常运行和可用性。
  5. 日志和错误跟踪:全栈监控可以收集应用程序的日志和错误信息,并提供对这些信息的分析和可视化。这有助于快速定位和解决应用程序中的错误和异常

日期2025.09.08学习日志

  1. 监控 - kube-prometheus 部署
  2. Prometheus 架构介绍

:Prometheus是一个开源的系统监控和报警框架,其本身也是一个时间序列数据库(Time Series Database,TSDB),它的设计灵感来源于Google的Borgmon,就像Kubernetes是基于Borg系统开源的

:Prometheus 被称为下一代的监控平台,具有很多和“老牌”监控不一样的特性,比如

  • 一个多维的数据模型,具有由指标名称和键-值对标识的时间序列数据。
  • 使用PromQL查询和聚合数据,可以非常灵活地对数据进行检索。
  • 不依赖额外的数据存储,Prometheus本身就是一个时序数据库,提供本地存储和分布式存储,并且每个Prometheus都是自治的。
  • 应用程序暴露Metrics接口,Prometheus通过基于HTTP的Pull模型采集数据。
  • 同时可以使用PushGateway进行Push数据。
  • Prometheus同时支持动态服务和静态配置发现目标机器。
  • 支持多种图形和仪表盘,和Grafana堪称“绝配”
  • Prometheus生态系统由多个组件组成,其架构如下:

图示

AI 生成的内容可能不正确。

  1. Prometheus Server:Prometheus生态最重要的组件,主要用于抓取和存储时间序列数据,同时提供数据的查询和告警策略的配置管理。
  2. Alertmanager:Prometheus生态用于告警的组件,Prometheus Server会将告警发送给Alertmanager,Alertmanager根据路由配置将告警信息发送给指定的人或组。Alertmanager支持邮件、Webhook、微信、钉钉、短信等媒介进行告警通知。
  3. Push Gateway:Prometheus本身是通过Pull的方式拉取数据的,但是有些监控数据可能是短期的,如果没有采集数据可能会出现丢失。Push Gateway可以用来解决此类问题,它可以用来接收数据,也就是客户端可以通过Push的方式将数据推送到PushGateway,之后Prometheus可以通过Pull拉取该数据。
  4. Exporter:主要用来采集监控数据,比如主机的监控数据可以通过node_exporter采集,MySQL的监控数据可以通过mysql_exporter采集,之后Exporter暴露一个接口,比如/metrics,Prometheus可以通过该接口采集到数据。
  5. PromQL:PromQL其实不算Prometheus的组件,它是用来查询数据的一种语法,比如可以通过SQL语句查询数据库的数据,通过LogQL语句查询Loki的数据,通过PromQL语句查询Prometheus的数据。
  6. Service Discovery:用来发现监控目标的自动发现,常用的有基于Kubernetes、Consul、Eureka、文件的自动发现等。
  7. Grafana:用于展示数据,便于数据的查询和观测
  8. Prometheus 安装

:Prometheus 有多种安装方式,比如二进制安装、容器安装和 Kubernetes 集群中安装,将 Prometheus 安装到Kubernetes 集群中也是官方推荐的部署方式

:将Prometheus安装到Kubernetes集群也有很多方式,比如 Helm、Operator 等,Prometheus 也是支持上述安装方式的。但是Prometheus是一个生态系统,有很多组件都需要安装,并且也有很多监控需要单独配置,于是Prometheus 官方开源了一个 kube-prometheus 项目,该项目不仅仅是用来安装 Prometheus 的,也包含很多其他的组件,如下所示

  • Prometheus Operator
  • 高可用的 Prometheus
  • 高可用的 Alertmanager
  • 主机监控 Node Exporter
  • Prometheus Adapter
  • 容器监控 kube-state-metrics
  • 图形化展示 Grafana

:具体可以通过 https://github.com/prometheus-operator/kube-prometheus/ 找到该项目进行查看。有了kube-prometheus项目,安装也变得非常简单,只需要两条命令即可

注:首先需要通过该项目地址找到和自己Kubernetes版本对应的Kube Prometheus Stack的版本

注:建议使用manifests的方式进行安装

#此处使用1.32版本

  1. Prometheus 安装部署流程:
  • 在github下载对应的分支代码

git clone -b release-0.15 https://github.com/prometheus-operator/kube-prometheus.git

#下载源码

注:此处使用的是已下载配置好的安装方式,如使用operator的方式进行了安装需删除原有安装,并在新的安装方式里面执行delete -f setup

注:使用网络下载的yaml,需注意networkpolicy.yaml里面有个策略四层无法访问。

#在部署文件中setup就是存储的crd

  1. 执行:cd kube-prometheus:进入已配置好的文件目录

  1. 执行:kubectl create -f manifests-orig/setup/:安装crd

#安装CRD

  1. 执行:kubectl get ns:进行查看

#可以看到会给我们创建一个monitoring的命名空间

注:此处使用离线镜像安装方式,需提前导入镜像

  1. 执行:ctr -n k8s.io image import kube-prometheus-image-0.15.tar
  2. 执行:kubectl apply -f manifests-orig/:进行部署
  3. kubectl -n monitoring get pods:查看看启动的pod

表格

AI 生成的内容可能不正确。

  1. 执行:Kubectl -n monitoring get svc:进行查看相关信息

  • 验证对grafana进行访问:使用四层进行访问
  1. 执行:cd manifests:进入目录(自定义的目录)

#为了后期更新方便,这里按照类型把相关对象的资源清单文件 放在不同的目录下

  1. 执行:cd grafana
  2. 执行:kubectl apply -f grafana-service.yaml:部署应用

#将端口进行固定,写入yaml

  1. 执行:Kubectl -n monitoring get svc:再次查看

#使用固定端口30030进行访问

图形用户界面

AI 生成的内容可能不正确。

  • 查看grafana的数据来源
  1. 执行:kubectl apply -f prometheus-service.yaml:启动部署

形状

AI 生成的内容可能不正确。

#将yaml文件中端口改为四层固定

浏览器进行访问:访问:30090

#通过查看可以看到schedule没有活动的目标,就是在grafana中看到没有数据的原因

#里面有很多job,都是服务发现进行自动添加

  1. 执行:kubectl -n monitoring get smon:可以看到监控的对象

表格

AI 生成的内容可能不正确。

#自动在prometheus中添加job,如果想自定定义去监控,就需要进行写一个smon

#有了smon就会添加job,就会找到目标进行监控,smon通过标签去找svc

  1. 云原生应用监控

#监控各种场景方法

云原生应用:开发时考虑的监控的需求 实现了 /metrics 接口

非云原生应用:早期开发的应用,不带 /metrics 接口,这些应用需要安装 exporter

  1. 监控数据来源:

:从Prometheus的架构中了解到,Prometheus通常采用Pull的形式来拉取数据,也就意味着被监控应用只要有一个能获取到监控数据的接口,就可以采集到监控数据

:基于云原生理念开发的程序自己会暴露Metrics接口,就像Kubernetes本身的组件、Etcd等,都有一个/metrics接口,Prometheus 只需要请求这个接口即可获取到相关数据

图示

AI 生成的内容可能不正确。

  • 什么是 ServiceMonitor

: 如果使用二进制的方式安装 Prometheus,用户需要通过 Prometheus 的一个配置文件来配置需要监控哪些数据,或者配置一些告警策略。这个配置文件的维护非常麻烦,特别是监控项非常多的情况下,很容易出现配置错误,而在Kubernetes上部署Prometheus,可以不用去维护这个配置文件,而是通过一个叫ServiceMonitor 的资源来自动发现监控目标并动态生成配置

  1. 监控example-app 应用

#业务监控

  1. 执行:kubectl apply -f example-app-dep.yaml -f example-app-svc.yaml:进行部署
  2. 执行:kubectl get pods

文本

AI 生成的内容可能不正确。

#看到启动了三个pod,并创建了svc

  1. 执行:kubectl get pods -o wide:查看详细信息

屏幕的截图

AI 生成的内容可能不正确。

#此应用中自带有metrics接口

  • 写一个ServiceMonitor:把pod的数据加入到prometheus中

#写好文件后,就可以通过标签发现svc,就能找到pod中的应用

  1. 执行: kubectl apply -f example-app-serviceMonitor.yaml:进行部署

  1. 执行:kubectl get smon:进行查看

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#创建出smon,就会在prometheus中的配置文件中添加一个job

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#可以看到有了应用的监控点

注:当在公司进行应用监控时就可以使用此种方法,写一个smon进行服务发现

  1. 监控etcd

#ectd没有smon和svc,需要进行创建

注:修改配置文件之前对配件文件进行备份

  1. 执行:kubectl apply -f etcd-svc.yaml:创建部署

背景图案

AI 生成的内容可能不正确。

注:此处的spec的name后面是https-metrics,需进行修改

  1. 执行:kubectl -n kube-system get svc

#如创建其他的监控,可使用此种方式进行创建svc

#其他controller和scheduler也可使用此种方式进行创建

  1. 执行:cp etcd-svc.yaml kube-scheduler-svc.yaml:创建一个scheduler模板
  2. 执行:cp etcd-svc.yaml kube-controller-svc.yaml:创建一个controller模板
  3. 创建的scheduler的/etc/kubernetes/manifests/kube-scheduler.yaml需要修改以下内容并查看端口:执行:vim /etc/kubernetes/manifests/kube-scheduler.yaml

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

#此处改为0.0.0.0,让外面可以进来访问

  1. 执行:Kubectl -n kube-system get pods --show-labels | grep scheduler:对标签进行查看
  2. 执行:kubectl apply -f kube-scheduler-svc.yaml

图片包含 图形用户界面

AI 生成的内容可能不正确。

#修改以上基础信息,端口和标签

注:controller也可以使用上述方式进行修改

  1. 执行:kubectl apply -f etcd-servicemonitor.yaml:启动servicemonitor
  2. 执行:vim /etc/kubernetes/manifests/etcd.yaml:修改以下内容

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

  1. 执行:system restart kubelet

#修改了etcd的监听,需要等一会,或重启kubelet

浏览器prometheus查看:

图形用户界面, 文本, 应用程序, 电子邮件

AI 生成的内容可能不正确。

#可以看到etcd被加入了进来,经过自动发现实现了监控

流程:创建svc,创建smon

  1. 非云原生应用监控

非云原生应用:早期开发的应用,不带 /metrics 接口,这些应用需要安装 exporter

例:mysql-exporter 、redis-exporter

  1. 配置配置 mysql-exporter

#以mysql为例进行配置验证

注:mysql-server要提前进行安装好,布置在集群外面

  1. 执行:wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.16.0/mysqld_exporter-0.16.0.linux-amd64.tar.gz
  2. tar xvf mysqld_exporter-0.16.0.linux-amd64.tar.gz -C /usr/local/
  3. ln -s /usr/local/mysqld_exporter-0.16.0.linux-amd64 /usr/local/mysqld_exporter
  4. cd /usr/local/mysqld_exporter:安装mysql
  • 创建用户和授权:mysql
  1. 进入数据库:执行以下操作

CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'xxhf' WITH MAX_USER_CONNECTIONS 3;

GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';

注:mariadb和mysql写法不一,需要进行查询

:连接 mysql 需要用户名、密码,所以下载之后,首先要创建配置文件,把用户名、密码以及mysql服务器地址,这些基本信息填进去:如何告诉export:进行以下配置

  1. 执行:vim .my.cnf:写入以下内容

沙滩上站着

AI 生成的内容可能不正确。

#在mysqld_exporter 的安装目录下,创建一个 .my.cnf 的文件,里面写数据库的ip和密码,export就会自动去找这个文件

  1. 执行:nohup ./mysqld_exporter &:后台启动mysql_export

#启动后默认监听9104端口

  1. 执行:curl 127.0.0.1:9104/metrics:进行验证

#请求 mysql_exporter 对外暴露的 metrics 接口

#可以正常监控

  • 配置抓取目标:

:需要在 Prometheus 配置文件中添加一个 Job,用来配置抓取 mysql-exporter metric endpoint, 有两种配置方式,一种是使用 prometheus-operator 提供 CRD ScrapeConfig(抓取配置) ,另一种方法是让prometheus 加载外部配置文件

#让prometheus知道应该在192.168.81.132的固定IP上抓取指标

方法一:ScrapeConfig

  1. 执行:kubectl apply -f mysql-scrape-config.yaml:进行部署

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#部署后就会在prometheus中添加一个job

#使用ScrapeConfig会有一定限制,需要安装operator

prometheus验证:

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

#可以看到在配置文件中添加了一个job

第二种方法:写一个附加文件,通知prometheus来读取

:首先创建一个空文件,然后通过该文件创建一个 Secret,这个 Secret 可作为 Prometheus 的静态配置:

  1. vim additional-scrape-configs.yaml:写一个yaml文件

  1. kubectl -n monitoring create secret generic additional-scrape-configs --from-file=additional-scrape-configs.yaml:将yaml文件创建为一个secret
  2. 执行:kubectl edit prometheus -n monitoring k8s:修改对象,修改以下内容

#通知 prometheus 过来读取 这个 secret additional-scrape-configs,告诉使用哪个文件

图形用户界面

AI 生成的内容可能不正确。

#add…附加的配置文件,name,secret的名字,key的值就是配置文件的内容

  1. 执行:kubectl -n monitoring create secret generic additional-scrape-configs --from-file=additional-scrape-configs.yaml --dry-run=client -o yaml | kubectl -n monitoring apply -f - (此步骤可以忽略不执行)

#文件改变后需执行此条命令

在 Grafana 中创建 Dashboard,导入 MySQL Dashboard 14057:

电脑游戏的屏幕

AI 生成的内容可能不正确。

  1. 配置告警

#触发告警后会发到alertmanager,需进行配置把告警发出来

  • 从配置文件可以看出,Alertmanager的配置主要分为5大块:

文本

AI 生成的内容可能不正确。

#部分模块配置

  1. Global:全局配置,主要进行一些通用的配置,比如邮件通知的账号、密码、SMTP服务器、微信告警等。Global块配置下的配置选项在本配置文件内的所有配置项下可见,但是文件内其他位置的子配置可以覆盖Global配置。
  2. Templates:用于放置自定义模板的位置。
  3. Route:告警路由配置,用于告警信息的分组路由,可以将不同分组的告警发送给不同的收件人。比如将数据库告警发送给DBA,服务器告警发送给OPS。
  4. Inhibit_rules:告警抑制,主要用于减少告警的次数,防止“告警轰炸”。比如某个宿主机宕机,可能会引起容器重建、漂移、服务不可用等一系列问题,如果每个异常均有告警,会一次性发送很多告警,造成告警轰炸,并且也会干扰定位问题的思路,所以可以使用告警抑制,屏蔽由宿主机宕机引来的其他问题,只发送宿主机宕机的消息即可。
  5. Receivers:告警收件人配置,每个receiver都有一个名字,经过route分组并且路由后需要指定一个receiver,就在此处配置

文本

AI 生成的内容可能不正确。

#配置文件中配置webhook,mobiles

  • 路由规则

:Alertmanager 路由规则详解:

图形用户界面

AI 生成的内容可能不正确。

:路由配置块的顶级配置由route开始,它是整个路由的入口,称作根路由。每一条告警进来后,都先进入route,之后根据告警自身的标签和route.group_by配置的字段进行分组。比如可以根据job、alertname或者其他自定义的标签名称进行分组,分组后进入子路由(通过route.routes配置子路由),进一步进行更加细粒度的划分,比如job名称包含mysql的发送给DBA组

  • Route 常用的配置:
  • receiver:告警的通知目标,需要和receivers配置中的name进行匹配。需要注意的是,route.routes下也可以有receiver配置,优先级高于route.receiver配置的默认接收人,当告警没有匹配到子路由时,会使用route.receiver进行通知,比如上述配置中的 default-team-mails。
  • group_by:分组配置,值类型为列表。比如配置成['job', 'severity'],代表告警信息包含job和severity标签的会进行分组,且标签的key和value都相同才会被分到一组。
  • continue:决定匹配到第一个路由后,是否继续后续匹配。默认为false,即匹配到第一个子节点后停止继续匹配。
  • match:一对一匹配规则,比如match配置的为job: mysql,那么具有job=mysql的告警会进入该路由。
  • match_re:和match类似,只不过match_re是正则匹配。
  • matchers:这是Alertmanager 0.22版本新添加的一个配置项,用于替换match和match_re。
  • group_wait:告警通知等待,值类型为字符串。若一组新的告警产生,则会等group_wait后再发送通知,该功能主要用于当告警在很短时间内接连产生时,在group_wait内合并为单一的告警后再发送,防止告警过多,默认值为30s。
  • group_interval:同一组告警通知后,如果有新的告警添加到该组中,再次发送告警通知的时间,默认值为5m。
  • repeat_interval:如果一条告警通知已成功发送,且在间隔repeat_interval后,该告警仍然未被设置为resolved,则会再次发送该告警通知,默认值为4h

#以上即为Alertmanager常用的路由配置,可以看到 Alertmanager 的路由和匹配规则非常灵活,通过不同的路由嵌套和匹配规则可以达到不同的通知效果

  1. 配置钉钉告警
  2. 钉钉上配置机器人

图形用户界面, 文本

AI 生成的内容可能不正确。

注:使用时一定要配置安全设置

  • 配置钉钉配置文件:
  1. 进入webhook安装目录执行:./ prometheus-webhook-dingtalk

文本

AI 生成的内容可能不正确。

#配置文件中配置webhook,mobiles具体@某个人

  1. 执行:kubectl apply -f alertmanager-secret.yaml:更新部署配置文件

表格

AI 生成的内容可能不正确。

#配置部署执行后告警消息就会发出来了

  1. 执行:kubectl apply -f alertmanager-service.yaml:部署web界面进行查看

电脑屏幕截图

AI 生成的内容可能不正确。

浏览器进行查看:

图形用户界面, 文本, 应用程序, 电子邮件

AI 生成的内容可能不正确。

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#可以看到钉钉消息成功进行了发送

  • 告警流程:

prometheus rules 触发 > 发给 alertmanager > 看配置文件 route(根据路由发去哪) 、receiver > prometheus-webhook-dingtalk > robot

  1. Blackbox 黑盒监控
  2. 介绍:

对 Etcd 或MySQL 的监控是监控应用本身,也就是程序内部的一些指标,这类监控关注的是原因,一般为出现问题的根本原因,此类监控称为白盒监控。还有一类监控关注的是现象,比如某个网站突然慢了,或者打不开了。此类告警是站在用户的角度看到的东西,比较关注现象,表示正在发生的问题,这类监控称为黑盒监控。

白盒监控可以通过Exporter采集数据,黑盒监控也可以通过Exporter采集数据,新版本的PrometheusStack已经默认安装了Blackbox Exporter,可以用其采集某个域名、接口或者TCP连接的状态、是否可用等

  1. Prometheus 静态配置

:前面几个小节配置监控目标时,用的都是ServiceMonitor,但是ServiceMonitor可能会有一些限制。比如,如果没有安装Prometheus Operator,可能就无法使用ServiceMonitor,另外并不是所有的监控都能使用ServiceMonitor进行配置,或者使用ServiceMonitor配置显得过于繁琐

  1. 在 additional-scrape-configs.yaml 文件内继续添加以下静态配置,用于黑盒监控的配置

文本

AI 生成的内容可能不正确。

注: 附加文件只能写一个,可以放到同一个yaml文件中

#可以看到此处的内容和传统配置的内容一致,只需要添加对应的job即可。之后通过该文件更新该Secret:

执行以下命令:进行更新yaml

  1. kubectl -n monitoring create secret generic additional-scrape-configs --from-file=additional-scrape-configs.yaml --dry-run=client -o yaml | kubectl -n monitoring replace -f -

在prometheus验证配置文件是否生效:

图片包含 文本

AI 生成的内容可能不正确。

检查targets:

图形用户界面, 应用程序

AI 生成的内容可能不正确。

登录 Grafana,导入Dashboard 13659,导入完成后,稍等一分钟即可在 Prometheus Web UI 看到该配置

  1. Prometheus 高可用
  • 多 prometheus 实例

#使用此种方式要配置pv,现在使用的是临时存储,删除pod存储消失

  • Thanos
  • VictoriaMetrics

  1. 全栈可观测

#如何进行实现

商业可观测软件:ARMS(阿里云)、Datdog(做SASS)

日期2025.09.09学习日志

日志的采集:

  1. 日志方案_EFK

#日志统一采集,进行查询

  • 日志采集点:

采集端

存储端

展示端

ELK(早期使用)

Logstash

Elasticsearch

Kibana

EFK

Filebeat

Fluend

Elasticsearch

Kibana

#EFK对采集端进行了更换,ELK是早期的采集使用方式

# Elasticsearch:可理解为文档类数据库

  1. Pod 日志收集

介绍:应用程序和系统日志可以帮助我们了解集群内部的运行情况,日志对于我们调试问题和监视集群情况也是非常有用的。而且大部分的应用都会有日志记录,对于传统的应用大部分都会写入到本地的日志文件之中。对于容器化应用程序来说则更简单,只需要将日志信息写入到 stdout 和 stderr 即可,容器默认情况下就会把这些日志输出到宿主机上的一个 JSON 文件之中,同样我们也可以通过 docker logs 或者 kubectl logs 来查看到对应的日志信息

但是,通常来说容器引擎或运行时提供的功能不足以记录完整的日志信息,比如,如果容器崩溃了、Pod 被驱逐了或者节点挂掉了,我们仍然也希望访问应用程序的日志。所以,日志应该独立于节点、Pod 或容器的生命周期,这种设计方式被称为 cluster-level-logging,即完全独立于 Kubernetes 系统,需要自己提供单独的日志后端存储、分析和查询工具

Kubernetes 中大多数的 Pod 日志被输出到控制台,在宿主机的文件系统每个Pod会创建一个存放日志的文件夹/var/log/pods/这里会存放所有这个节点运行的Pod的日志,但是这个文件夹下一般都是软连接,由于Kubernetes 底层的 CRI 容器运行时可以使用很多所以日志本身并不存放在这个文件夹,以下为容器运行时真正存放日志目录:

  • container log: /var/log/containers/*.log

#找日志就可以到此处,kubelet会自动调用logrotate日志轮询自动清理日志,日志也能集中存储:建议使用的存储方式

  • Pod log:/var/log/pods
  1. 集群级别日志架构 :采集方式
  • 使用在每个节点上运行的节点级日志记录代理。
  • 在应用程序的 Pod 中,包含专门记录日志的边车(Sidecar)容器。
  • 将日志直接从应用程序中推送到日志记录后端
  • 使用节点级日志代理:建议使用

:可以通过在每个节点上使用节点级的日志记录代理来实现集群级日志记录。 日志记录代理是一种用于暴露日志或将日志推送到后端的专用工具。 通常,日志记录代理程序是一个容器,它可以访问包含该节点上所有应用程序容器的日志文件的目录

:由于日志记录代理必须在每个节点上运行,推荐以 DaemonSet 的形式运行该代理。

节点级日志在每个节点上仅创建一个代理,不需要对节点上的应用做修改。

容器向标准输出和标准错误输出写出数据,但在格式上并不统一。 节点级代理收集这些日志并将其进行转发以完成汇总。

#每个节点只需要跑一个filebeat

  • 使用边车容器运行日志代理 sidecar

图示

AI 生成的内容可能不正确。

:pod里面跑一个日志代理容器和一个应用容器

  • Istio:服务网格:管理微服务应用。就是用了很多:sidecar
  • 从应用中直接暴露日志目录

图示

AI 生成的内容可能不正确。

#不建议使用

  1. EFK部署:传统架构方式

#传统架构下的日志都是文件

注:单独使用一台虚拟机配置进行验证

  • yum仓库下载:

rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

vim /etc/yum.repos.d/elasic.repo

[elasticsearch]

name=Elasticsearch repository for 7.x packages

baseurl=https://artifacts.elastic.co/packages/7.x/yum

gpgcheck=1

gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch

enabled=1

autorefresh=1

type=rpm-md

:Elasticsearch 是一个开源的分布式搜索和分析引擎,建立在 Apache Lucene 库之上。它提供了一个高性能、可伸缩和全文搜索能力强大的分布式系统,适用于处理大规模数据集的搜索、分析和近实时数据处理

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.16-x86_64.rpm

rpm --install elasticsearch-7.17.16-x86_64.rpm

检查集群监控状态:

图片包含 文本

AI 生成的内容可能不正确。

:Kibana是一个开源的数据可视化和分析平台,与Elasticsearch紧密集成。它提供了一个直观的Web界面,让用户能够轻松地探索、分析和可视化存储在Elasticsearch中的数据

wget https://artifacts.elastic.co/downloads/kibana/kibana-7.17.16-x86_64.rpm

:Filebeat是一个轻量级的开源日志数据收集器,由Elasticsearch提供支持。它专门用于收集、解析和发送日志文件和其他结构化数据到Elasticsearch或Logstash等目标系统进行处理和分析

  1. 安装部署:

注:此处使用在官网下载好的rpm包安装方式

  1. 执行:rpm -ivh elasticsearch-7.17.16-x86_64.rpm

#配置文件放置在/etc/ elasticsearch/下

  1. 执行:cd /etc/elasticsearch/:进入目录
  2. 执行:vim elasticsearch.yml:修改以下内容

elasticsearch.yml:配置文件详解

图片包含 日程表

AI 生成的内容可能不正确。

#一般最少使用三个node节点

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

文本

AI 生成的内容可能不正确。

#一个初始化的master节点,一个是种子节点

  1. 执行:mkdir /data/ cd /data/
  2. 执行:mkdir /elasticsearch
  3. 执行:chown -R elasticsearch: elasticsearch elasticsearch:修改数据目录的所有者和所属组

# elasticsearch启动后会自动创建一个用户,之后数据会自动写入到里面

  1. 执行:vim /etc/elasticsearch/ jvm.options:修改以下内容

#此处为java占用内存

注:此服务需要价高配置,最低2核4G,以上最大内存需改为1

  1. 执行:systemctl start elasticsearch:启动服务

#可以在/var/log/观看日志

  1. 执行:ss -antp:查看端口

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#9200是客户端访问服务端,9300是服务端之间进行访问

  1. 执行:curl -XGET 127.0.0.1:9200/_cluster/health\?pretty:显示cluster状态

# - green 健康 - yellow 有点问题 red 不能使用 1

  1. 执行:rpm -ivh kibana-7.17.16-x86_64.rpm:安装前端,展示数据界面

# kibana和elasticsearch安装版本最好一致

#配置文件位于/etc/kibana/

  1. 执行:cd /etc/kibana/
  2. 执行:vim kibana.yml:修改以下内容

#需要找elasticsearch所以此处要写elasticsearch的地址,多个elasticsearch使用逗号隔开

  1. 执行:systemctl start kibana:启动服务:监听:5601

#启动后会监听5601,并提供一个web界面,可在浏览器访问

Filebeat:采集日志数据

INPUT :输入日志来自文件

filestream:采集日志文件

container:采集容器中日志

  1. 执行:rpm -ivh filebeat-7.17.15-x86_64.rpm
  2. 执行:cd /etc/filebeat/
  3. 执行:vim filebeat.yml:修改以下内容

背景图案

AI 生成的内容可能不正确。

#会自动检查目录下的日志文件,进行采集

图形用户界面, 应用程序

AI 生成的内容可能不正确。

图片包含 图形用户界面

AI 生成的内容可能不正确。

#生产环境中需要开启验证,并设定用户名和密码

  1. 执行:systemctl restart filebeat:启动服务
  • web端查看验证:

图形用户界面, 应用程序

AI 生成的内容可能不正确。

indes:索引。elasticsearch的数据都是存储在索引里面

#索引的分片默认分为两个,一个主,一个副本。此处副本分片没有其他节点放,所以状态显示yellow。30秒检测一次

  • 如何查询索引:

#工作中一般按天创建索引

例:filebeat-7.17.15-2025.09.09

filebeat-7.17.15-2025.09.10

filebeat-7.17.15-2025.09.11

filebeat-7.17.15-2025.09.12

filebeat-7.17.15-2025.09.13

#写以一个index pattern,把星当作一个时间戳

图形用户界面, 日程表

AI 生成的内容可能不正确。

#创建后去discover(发现)就可以看到按照时间创建索引,下面就是日志

#左侧就是日志索引,可通过右上角选择时间

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

#可以通过关键词进行搜索,会显示高亮,多个词用&&或and

  • 搜索方式:第二种方式

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

  1. EFK部署:kubernetes架构方式

#k8s架构下采集的应用都在pod中

  • 应用被放到pod中,如何输出日志:

#不建议日志输出为文件,建议日志直接输出为stdout(标准输出)

注:工作场景中elasticsearch建议放到集群外面,kibana也可以放k8s外面

  1. EFK部署流程:
  • 此处使用helm进行部署:

#依据以下载好的的文件进行部署

注:最少需要三个节点,如使用master节点,需要把污点进行消除,否则无法启动

  1. 执行:helm repo add elastic https://helm.elastic.co:添加仓库
  2. helm search repo elastic/elasticsearch -l:查询版本

#此处使用7.17.3版本,并使用已下载好的包进行安装

  1. 执行:helm upgrade --install els -n logging -f elasticsearch/els-values.yaml ./elasticsearch --create-namespace --namespace logging:进行安装部署 #节点不足时需要到yaml文件中调整副本数 minimumMasterNodes: 1,replicas: 2

#在线安装需使用此方式进行拉取helm pull elastic/elasticsearch --version=7.17.3

  1. 执行:kubectl -n logging get pods:在命名空间下查看:集群验证

#kibana是一个有状态应用,在创建svc时会创建一个有头的svc和一个无头的svc

  • 安装kibana
  1. 执行:helm -n logging upgrade --install kibana -f kibana/kibana-values.yaml ./kibana:部署启动kubana

验证:

  1. 执行:curl -XGET 10.107.84.183:9200/_cluster/health\?pretty:查看集群状态

文本

AI 生成的内容可能不正确。

  • 安装filebeat
  1. 执行:helm -n logging install filebeat -f filebeat/filebeat-values-1.yaml ./filebeat

图片包含 文本

AI 生成的内容可能不正确。

#启动后可以去web端访问

  • web端查看:

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#根据时间戳进行查看

#k8s里面的索引都可以进行查看

  • 按应用创建索引,修改filebeat配置文件

图片包含 应用程序

AI 生成的内容可能不正确。

#添加上述两段内容即可以按照应用创建索引

  1. 执行:helm -n logging upgrade filebeat -f filebeat/filebeat-values-2.yaml ./filebeat:进行部署或更新

web端进行查看验证:

#每个应用就会按天创建一个索引

  • 删除索引:

:选中后直接delete删除,手动删除方式

自动删除方式:(生命周期策略)

第二种方式:curator:使用一个脚本方式删除

#给app加一个前缀。放到crontab里面,每天运行进行清理

:当有大量节点时,可以扩展elasticsearch或加一层kafaka(流处理工具,进行缓存),通过logstash进入到elasticsearch

图片包含 图示

AI 生成的内容可能不正确。

#生产环境日志较大时,可以使用,kafaka至少三台,也需要搭建集群

  • Loki:轻量级日志解决方案 #Grafana公司产品 思路 prometheus
  1. 附录:
  • Elasticsearch 基础概念
  • 集群

:Elasticsearch 集群是一组 Elasticsearch 节点的集合。节点根据用途不同会划分出不同的角色,且节点之间相互通信。Elasticsearch集群常用于处理大规模数据集,目的是实现容错和高可用。Elasticsearch 集群需要一个唯一标识的集群名称来防止不必要的节点加入

  • 节点 node

:节点是指一个Elasticsearch实例,更确切地说,它是一个Elasticsearch进程。节点可以部署到物理机或者虚拟机上。每当Elasticsearch启动时,节点就会开始运行。每个节点都有唯一标识的名称,在部署多节点集群环境的时候我们要注意不要写错节点名称

  • 索引 index

:索引是 Elasticsearch 中用于存储和管理相关数据的逻辑容器。索引可以看作数据库中的一个表,它包含了一组具有相似结构的文档。在Elasticsearch中,数据以JSON格式的文档存储在索引内。每个索引具有唯一的名称,以便在执行搜索、更新和删除操作时进行引用。索引的名称可以由用户自定义,但必须全部小写

  • 分片 shard

分片包含索引数据的一个子集,并且其本身具有完整的功能和独立性,可以将分片近似看作“独立索引“,分片是Elasticsearch 分布式存储的基石,是底层的基本读写单元。分片的目的是分割巨大的索引,将数据分散到集群内各处。

分片分为主分片和副本分片,一般情况,一个主分片有多个副本分片。主分片负责处理写入请求和存储数据,副本分片只负责存储数据,是主分片的拷贝,文档会存储在具体的某个主分片和副本分片上

#索引较大时,使用分片。每个分片都是一个索引

#分片有主分片和副本分片,用于高可用。主分片可以写数据,分片自动分散到节点上

日期2025.09.10学习日志

  1. 日志方案-Loki
  2. Loki 介绍

Grafana Loki 是一套功能齐全的日志堆栈组件,与其他日志记录系统不同,Loki 是基于仅索引有关日志元数据的想法而构建的:标签(就像 Prometheus 标签一样)。日志数据本身被压缩然后并存储在对象存储(例如 S3 或 GCS)的块中,甚至存储在本地文件系统上,轻量级的索引和高度压缩的块简化了操作,并显著降低了 Loki 的成本,Loki 更适合中小团队。由于 Loki 使用和 Prometheus 类似的标签概念,所以如果你熟悉 Prometheus 那么将很容易上手,也可以直接和 Grafana 集成,只需要添加 Loki 数据源就可以开始查询日志数据了

:Loki 还提供了一个专门用于日志查询的 LogQL 查询语句,类似于 PromQL,通过 LogQL 我们可以很容易查询到需要的日志,也可以很轻松获取监控指标。Loki 还能够将 LogQL 查询直接转换为 Prometheus 指标。此外 Loki 允许我们定义有关 LogQL 指标的报警,并可以将它们和 Alertmanager 进行对接

  • Grafana Loki 主要由 3 部分组成:
  • loki: 日志记录引擎,负责存储日志和处理查询
  • Agent : 日志代理,负责收集日志并将其发送给 loki,可以使用 Alloy 或 Promtail
  • grafana

图片包含 文本

AI 生成的内容可能不正确。

  1. Loki 组件

图示

AI 生成的内容可能不正确。

:在grafana里面通过logQL的语法去查询日志,先发到query frontend中,在发到querier中。querier在ingester中拿到日志,ingester在底层中拿到日志,再最后把日志返回到grafana

#可以部署多个loki,每个loki负责一个功能

#backend负责管理规则

  • Log-agent (采集器) Alloy 或 Promtail

: Log-agent 是 Loki 日志代理(agent)的重要组件。它的功能是从系统中收集每个日志,标记它,然后将其发送给 Loki

  • Distributor (分发器)

:Distributor 是一个无状态组件,负责处理和验证从日志代理(如 Promtail)接收的日志,并将日志分发到 ingester

:当 Distributor 收到日志时,它首先验证日志是否符合配置,例如有效标签、不是较旧的时间戳以及日志是否太长。验证完成后,Distributor 会根据一致性哈希将日志分发到每个 ingester,以确保平均分配给每个可用的 ingester

#把日志分开传到后方

  • Ingester (接收器)

:Ingester 负责在其文件系统上存储和索引从 Distributor 收到的日志,并定期将日志传输到持久性存储(长期存储),如 S3

:Ingester 根据配置设置保留策略(自动日志删除时间)。

它使用时间序列数据库以一定的结构格式存储日志,这简化了高效查询和日志过期的过程

  • Ruler (规则器)

:Ruler 是 Loki 的监控和告警组件,其作用是记录指标并根据收到的日志数据触发告警。它不是直接衡量指标,而是将日志数据转换为指标

Ruler 监控日志并在检测到任何问题时发出通知,并通过电子邮件或 Slack 发送通知

#通过logQL的写法

  • Querier (查询器)

:Querier 负责使用 LogQL 查询语言从存储和 ingester 中查询日志。它根据用户查询(如时间戳、标签等)过滤和聚合日志

查询器缓存之前的查询,以防止一次又一次地查询相同的日志,它只查询一次具有相同时间戳、标签和日志消息的日志

  • Query Frontend (查询前端)

:Query Frontend 是一个与用户交互的无状态组件,它负责处理查询请求、执行查询以及通过 Grafana 仪表板可视化日志

Query Frontend 将大型查询拆分为多个较小的查询,并同时运行所有查询,这可以防止大型查询在单个查询中导致内存问题,并有助于加快执行速度

  • Grafana (前端展示)

:Grafana 是一个开源工具,可帮助查询、可视化和监控日志。我们可以将 Loki 与 Grafana 集成,并在仪表板、图表等方式可视化日志数据

Grafana 使用查询语言 LogQL 与 Grafana 集成,我们也可以在 Grafana 中编写 LogQL 查询来过滤和查询日志

  • Log Storage (后端存储)

:Loki 存储日志数据,提高查询和接收日志的效率。将日志数据压缩成块,根据时间进行组织,并为其提供标签和时间戳。然后,它以键值对格式为每个块创建一个索引,包含块时间戳和标签等

例如:将块的索引视为一本书的索引。

Chunks 和 Index 可以存储在各种后端对象存储或文件系统中。

一旦存储了块,它就会为数据创建一个保留期,并根据保留期自动删除

如果使用文件系统作为存储,则块和索引的默认存储路径是 /var/lib/loki/chunks/var/lib/loki/index

  1. 部署 Loki
  • Flog: 日志生成器,模拟应用程序产生日志。
  • Alloy:日志代理,用来抓取日志并把日志发给Loki,类似 filebeat 的角色。
  • Gateway: 接收请求并根据请求的URL 转发给后端应用。
  • Loki read component: 运行 Query Frontend 和 Querier。
  • Loki write component: 运行 Distributor 和 Ingester。
  • Loki backend component: Index Gateway、Compactor 和 Ruler。
  • Minio:存储日志 index and chunks
  • Grafana:展示和搜索日志

图示

AI 生成的内容可能不正确。

:采集端使用alloy,采集日志后经过loki,存储到minio(开源的对象存储),设置不同功能的loki

:gateway(网关),负责分发流量

  1. Docker compose

---

networks:

loki:

services:

read: #负责读的loki

image: grafana/loki:3.5

command: "-config.file=/etc/loki/config.yaml -target=read"

ports:

- 3101:3100

- 7946

- 9095

volumes:

- ./loki-config.yaml:/etc/loki/config.yaml

depends_on:

- minio

healthcheck:

test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1" ]

interval: 10s

timeout: 5s

retries: 5

networks: &loki-dns

loki:

aliases:

- loki

write: #负责写的loki

image: grafana/loki:3.5

command: "-config.file=/etc/loki/config.yaml -target=write"

ports:

- 3102:3100

- 7946

- 9095

volumes:

- ./loki-config.yaml:/etc/loki/config.yaml

healthcheck:

test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1" ]

interval: 10s

timeout: 5s

retries: 5

depends_on:

- minio

networks:

<<: *loki-dns

alloy:

image: grafana/alloy:v1.8.2

volumes:

- ./alloy-local-config.yaml:/etc/alloy/config.alloy:ro

- /var/run/docker.sock:/var/run/docker.sock

command: run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy

ports:

- 12345:12345

depends_on:

- gateway

networks:

- loki

minio:

image: minio/minio:RELEASE.2025-04-08T15-41-24Z

entrypoint:

- sh

- -euc

- |

mkdir -p /data/loki-data && \

mkdir -p /data/loki-ruler && \

minio server /data

environment:

- MINIO_ROOT_USER=loki

- MINIO_ROOT_PASSWORD=supersecret

- MINIO_PROMETHEUS_AUTH_TYPE=public

- MINIO_UPDATE=off

ports:

- 9000

volumes:

- ./.data/minio:/data

healthcheck:

test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ]

interval: 15s

timeout: 20s

retries: 5

networks:

- loki

grafana:

image: grafana/grafana:11.4.4

environment:

- GF_PATHS_PROVISIONING=/etc/grafana/provisioning

- GF_AUTH_ANONYMOUS_ENABLED=true

- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin

depends_on:

- gateway

entrypoint:

- sh

- -euc

- |

mkdir -p /etc/grafana/provisioning/datasources

cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml

apiVersion: 1

datasources:

- name: Loki

type: loki

access: proxy

url: http://gateway:3100

jsonData:

httpHeaderName1: "X-Scope-OrgID"

secureJsonData:

httpHeaderValue1: "tenant1"

EOF

/run.sh

ports:

- "3000:3000"

healthcheck:

test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1" ]

interval: 10s

timeout: 5s

retries: 5

networks:

- loki

backend:

image: grafana/loki:3.5

volumes:

- ./loki-config.yaml:/etc/loki/config.yaml

ports:

- "3100"

- "7946"

command: "-config.file=/etc/loki/config.yaml -target=backend -legacy-read-mode=false"

depends_on:

- gateway

networks:

- loki

gateway:

image: nginx:1.27.5

depends_on:

- read

- write

entrypoint:

- sh

- -euc

- |

cat <<EOF > /etc/nginx/nginx.conf

user nginx;

worker_processes 5; ## Default: 1

events {

worker_connections 1000;

}

http {

resolver 127.0.0.11;

server {

listen 3100;

location = / {

return 200 'OK';

auth_basic off;

}

location = /api/prom/push {

proxy_pass http://write:3100\$$request_uri;

}

location = /api/prom/tail {

proxy_pass http://read:3100\$$request_uri;

proxy_set_header Upgrade \$$http_upgrade;

proxy_set_header Connection "upgrade";

}

location ~ /api/prom/.* {

proxy_pass http://read:3100\$$request_uri;

}

location = /loki/api/v1/push {

proxy_pass http://write:3100\$$request_uri;

}

location = /loki/api/v1/tail {

proxy_pass http://read:3100\$$request_uri;

proxy_set_header Upgrade \$$http_upgrade;

proxy_set_header Connection "upgrade";

}

location ~ /loki/api/.* {

proxy_pass http://read:3100\$$request_uri;

}

}

}

EOF

/docker-entrypoint.sh nginx -g "daemon off;"

ports:

- "3100:3100"

healthcheck:

test: ["CMD", "service", "nginx", "status"]

interval: 10s

timeout: 5s

retries: 5

networks:

- loki

flog:

image: mingrammer/flog:0.4.3

command: -f json -d 200ms -l

networks:

- loki

  1. 日志查询:grafana

查询容器 loki-flog-1 产生的所有日志 {container="loki-flog-1"}

电脑萤幕的截图

AI 生成的内容可能不正确。

#可查看具体的某个时间端

查询包含 status 的日志行 {container="loki-flog-1"} |= `status`

电脑萤幕的截图

AI 生成的内容可能不正确。

查询 status=404 的日志行 {container="loki-flog-1"} | json | status=`404`

电脑萤幕截图

AI 生成的内容可能不正确。

  1. Ref:

Loki 安装: https://grafana.com/docs/loki/v3.3.x/setup/install/local/

Promtail 安装: https://grafana.com/docs/loki/v3.3.x/send-data/promtail/

日志轮转: https://grafana.com/docs/loki/latest/operations/storage/retention/

Promtail 配置文件: https://grafana.com/docs/loki/latest/send-data/promtail/configuration/#global