日期2025.08.29学习日志
:有一些应用,运行状态信息就很重要了,如果因为重启而丢失了状态是绝对无法接受的,这样的应用就是“有状态应用”。“有状态应用”的例子也有很多,比如 Redis、MySQL 这样的数据库,它们的“状态”就是在内存或者磁盘上产生的数据,是应用的核心价值所在,如果不能够把这些数据及时保存再恢复,那绝对会是灾难性的后果
MQ: RabbitMQ RocketMQ 消息队列 异步处理
流处理:Kafka
#使用较多的有状态应用
#客户端如何去访问,mysql主从。就使用pod创建一个唯一域名
:用 Deployment 来保证高可用,用 PersistentVolume 来存储数据,确实可以部分达到管理“有状态应用”的目的
:但是 Kubernetes 的眼光则更加全面和长远,它认为“状态”不仅仅是数据持久化,在集群化、分布式的场景里,还有多实例的依赖关系、启动顺序和网络标识等问题需要解决,而这些问题恰恰是 Deployment 力所不及的
:但对于“有状态应用”,多个实例之间可能存在依赖关系,比如 master/slave、active/passive,需要依次启动才能保证应用正常运行,外界的客户端也可能要使用固定的网络标识来访问实例,而且这些信息还必须要保证在 Pod 重启后不变
:所以,Kubernetes 就在 Deployment 的基础之上定义了一个新的 API 对象,名字也很好理解,就叫 StatefulSet,专门用来管理有状态的应用。
:StatefulSet 也可以看做是 Deployment 的一个特例,不能直接使用kubectl create 创建样板文件
_bb0b56ce-0e44-4bde-9631-1770f2073478.png)
Redis的statefulSet:yaml文件:
_8b708e2e-58a5-4dce-8660-2f2db1b7cb41.png)
#在statefulSet直接把svc名字加入了进来,serviceName选项,解决给pod起一个域名
# YAML 文件里除了 kind 必须是“StatefulSet”,在spec 里还多出了一个“serviceName”字段,其余的部分和 Deployment 是一模一样的,比如 replicas、selector、template 等等
#可根据现有的模板进行创建
_8f69add4-e139-4a7c-b7f0-2f7419d39897.png)
_84fa8d40-6ecd-4dbc-a90a-11d2c2e67270.png)
#有状态应用启动之后删除,会和之前的名字一样
#可以看出StatefulSet 所管理的 Pod 不再是随机的名字了,而是有了顺序编号,从 0 开始分别被命名为 redis-sts-0、redis-sts-1,Kubernetes 也会按照这个顺序依次创建(0 号比 1 号的 AGE 要长一点),这就解决了“有状态应用”的第一个问题:启动顺序
_8527f589-2d40-40a3-a72e-ae5a48efd46b.png)
#有了这个唯一的名字,应用就可以自行决定依赖关系了,比如在这个 Redis 例子里,就可以让先启动的 0 号 Pod 是主实例,后启动的 1 号 Pod 是从实例
#无法进行向后轮询,就给每个pod添加一个域名
_1fcd403f-7bc5-455b-b0a5-432d9d50dea5.png)
#写 Service 对象的时候要小心一些,metadata.name 必须和 StatefulSet 里的 serviceName 相同,selector 里的标签也必须和 StatefulSet 里的一致:
_0b7e7988-096b-4f6f-9690-ec4d871823ac.png)
:StatefulSet 的场景下,因为每个 Pod 也都拥有了固定的名称,所以每个 Pod 也可以分配一个固定的域名,格式是“Pod 名. 服务名. 命名空间.svc.cluster.local”。解决每个pod的唯一标识
#域名在之前svc的基础上增加了一个pod名
验证测试:
_40bb19cd-8ba2-421c-a65e-6f2a5f34fa02.png)
#在 StatefulSet 里的这两个 Pod 都有了各自的域名,也就是稳定的网络标识。那么接下来,外部的客户端只要知道了 StatefulSet 对象,就可以用固定的编号去访问某个具体的实例了,虽然 Pod 的 IP 地址可能会变,但这个有编号的域名由 Service 对象维护,是稳定不变的
:通过 StatefulSet 和 Service 的联合使用,Kubernetes 就解决了“有状态应用”的依赖关系、启动顺序和网络标识这三个问题
:Service 原本的目的是负载均衡,应该由它在 Pod 前面来转发流量,但是对 StatefulSet 来说,这项功能反而是不必要的,因为 Pod 已经有了稳定的域名,外界访问服务就不应该再通过 Service 这一层了
#给pod起了一个域名之后,clusterIP就没有了用处
#在创建SVC时不分配clusterIP,属于无头服务
_8a36f773-1d06-4253-82c9-aad0e3a38331.png)
#创建statefulSet对象 ,习惯上创建一个有头SVC ,再创建一个无头SVC ,根据 应用的特点 用户选择使用哪个 SVC
# ClusterIP进行轮询算法 返回 一个POd IP
Name: redis-svc.default.svc.cluster.local
Address: 10.98.85.8
_0582d4bf-5b77-42cf-b750-6fa4ec566586.png)
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
_abdab2c6-3b23-4506-8047-393c02c8feba.png)
#有了固定的名字、启动顺序和网络标识,只要再给它加上数据持久化功能,我们就可以实现对“有状态应用”的管理了
:需要用到存储时学的 PersistentVolume 和 NFS 的知识,我们可以很容易地定义 StorageClass,然后编写 PVC,再给 Pod 挂载 Volume
:强调持久化存储与 StatefulSet 的一对一绑定关系,Kubernetes 为 StatefulSet 专门定义了一个字段“volumeClaimTemplates”,直接把 PVC 定义嵌入 StatefulSet 的 YAML 文件里。这样能保证创建 StatefulSet 的同时,就会为每个 Pod 自动创建 PVC,让 StatefulSet 的可用性更高
_b057479c-6196-47ee-bc15-a71472ebfe12.png)
_1dc8ab12-6ba8-4e7e-8b68-4ede1387f322.png)
#每创建一个pod就会创建一个pvc
#首先 StatefulSet 对象的名字是 redis-pv-sts,表示它使用了 PV 存储。然后“volumeClaimTemplates”里定义了一个 PVC,名字是 redis-100m-pvc,申请了 100MB 的 NFS 存储。在 Pod 模板里用 volumeMounts 引用了这个 PVC,把网盘挂载到了 /data 目录,也就是 Redis 的数据目录
#创建要保证NFS服务器是正常的
_d82d9cd1-7e76-475b-8619-00e4e91ae376.png)
#可以看到pvc创建成功
#这两个 PVC 的命名,用的是 PVC 名字加上 StatefulSet 的名字组合而成,所以即使 Pod 被销毁,因为它的名字不变,还能够找到这个 PVC,再次绑定使用之前存储的数据
_c03dcded-be2b-4a72-bb9d-6e25c152101c.png)
#可以看到创建了两个共享目录
_78611ffb-90b9-4cad-acdd-d1ea28d84d5a.png)
模拟意外事故,删除pod:
_afb7856e-04fc-47e3-8a0a-8ba24f2983cf.png)
#可以看到删除之后会重新给我们创建一个新的pod
#由于 StatefulSet 和 Deployment 一样会监控 Pod 的实例,发现 Pod 数量少了就会很快创建出新的 Pod,并且名字、网络标识也都会和之前的 Pod 一模一样:
_dd6a6917-c357-41d5-8faa-cf85d439812e.png)
#通过查看原有数据依旧存在,pv和pvc自动挂载了进去
#Redis 就会定期把数据落盘保存,所以新创建的 Pod 再次挂载目录的时候会从备份文件里恢复数据,内存里的数据就恢复原状了
Operator:更适合在 k8s 中管理有状态的应用
mysql-operator
redis-operator
#不同的应用配置不同的operator
kube-apiserver:安全
kube-scheduler:调度
kube-controller-manager:控制器暴露参数
etcd
kubelet
kube-proxy :SVC时以讲解
CR:CRI CNI CSI
介绍:Etcd 是_CoreOS 基于 Raft 协议开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障。在分布式系统中,如何管理节点间的状态一直是一个难题,etcd 是专门为集群环境的服务发现和注册而设计,它提供了数据TTL失效、数据改变监视、多值、目录监听、分布式锁原子操作等功能,可以方便的跟踪并管理集群节点的状态。
#实验室可在work节点进行安装,避免节点冲突
#安装时去官网下载即可,或在github上下载
# etcd 是server端,etcdctl 是client端
_b3c21509-5e7a-4567-83d6-3a772ba88cd4.png)
#2370端口是客户端去连接服务端使用,2380端口是server之间进行访问使用的
_63a52123-21d5-46f9-bd13-03f3eff87157.png)
#链接时告诉server端在哪,添加member list去列出成员,列出集群中有多少个成员
_6d202e26-ce1f-4609-9338-0ed428934b85.png)
#添加--write-out=table让显示更具清晰化,可以看到节点的一个具体变化
写入数据:
./etcdctl --endpoints=127.0.0.1:2379 put /key1 val1
_243b07a5-bd11-43cf-add1-b3906312bf67.png)
#etcd的键必须是斜杠开头
读取数据:
./etcdctl --endpoints=localhost:2379 get /key1
_50a36674-d416-492a-85c7-8871669ac835.png)
模糊查询:按 Key 的前缀查询数据
./etcdctl --endpoints=localhost:2379 get --prefix /a
_577eca15-140b-4e78-9992-fe3a4a097a3c.png)
#前缀查询,以什么为开头,模糊查询
只显示键值:
./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
_f84a1d46-7850-40ec-8c19-9a9f840b204c.png)
#删除时通过返回值判断是否删除正确,1代表删除,0代表没有找到
./etcdctl --endpoints=localhost:2379 watch --prefix /name --rev 1
_ac9b850a-9abd-4313-a619-d808adfbe860.png)
#watch功能个kubectl get pods -w的作用一致,在数据库做的任何操作,客户端都能收到通知
#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会出现报错,查看报错
_de4f75d5-2b7f-46cc-961e-577c7f33606b.png)
_c71c484d-5ce3-4182-b087-bf182e08d162.png)
备份:mysqldump 表 > .sql #生产环境不建议使用,数据量小可使用
xtrabackup:备份物理文件,支持全备和增量,生产环境使用
_86cc08bc-d10d-4f78-9e8e-9b824af0569a.png)
#查看etcd的数据库
#有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的默认工作目录下会生成两个子目录:wal和snap。k8s默认放置路径:/var/lib/etcd/member
Wal:是用于存放预写式日志,其最大的作用是记录整个数据变化的全部历程。所有数据的修改在提前前,都要先写入wal中。
Snap:是用于存放快照数据。为防止wal文件过多,etcd会定期(当wal中数据超过100000条记录时,由参数snapshot-count”设置)创建快照。当快照生成后,wal中数据就可以被删除了。
:如果数据遭到破坏或错误修改需要回滚到之前某个状态时,方法有两个:一是从快照中恢复数据主体,但是未被拍入快照的数据会丢失;二是执行所有wal中记录的修改操作,从最原始的数据恢复到数据损坏之前的状态,但恢复的时间较长。
_bef35138-aada-4291-a5fc-da30c30068dc.png)
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.
#每个对象都对应一个控制器进行工作
每个节点上都运行一个kubelet服务进程,默认监听10250 端口。
_f1d553b1-9090-4e83-b175-1780cd1c3519.png)
#以上大部分节点都归属kubelet管理
:默认监听10250和10248,master和wrker和都有kubelet。访问10250需要双向认证,监听https。
ProbeManager:探针管理,由kubelet进行检测。OOMWatcher:内存溢出,也是kublet控制,GPU由kubelet管理。
cAdvisor:分析资源的利用率和性能
#谷歌下的一个组件,后集成到kubelet里面,用来监控容器的资源利用率
DiskSpaceManager:磁盘空间管理
#GC垃圾回收
EvictionManager:驱逐
#资源不够用kubelet进行驱逐
_3efef720-315f-4a67-a5cc-8ad0bffaa48d.png)
kubelet其他职责:创建pod,创建容器
#创建时需要使用cr,cr由多个类型
:kubelet创建容器要调用CRI,CRI再去调用cr去创建容器
#CRI层就是为了屏蔽底层的cr,去使用其他的cr类型。cri是一个抽象接口
#开发实现就是通过不同的接口,使用应用就调用接口
Ocl:(Open ContainerInitiative,开放容器计划)的主要目标是定义容器的标准规范,以确保容器在不同的容器运行时(如Docker、rkt、CRI-O等)之间具有互操作性。通过制定标准规范,OCI 旨在消除容器技术生态系统中的封闭性和供应商锁定问题,促进不同容器技术之间的兼容性和可移植性。
cridocker:使用这个插件可以使用docker
_fd870534-c505-40c6-8964-909c638a5068.png)
:将创建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,容器网络
:网络解决方案交给社区实现
_c2d2b86a-977c-4c44-90eb-1e047db9b07b.png)
:跨节点之间通信,pod的ip在集群范围地址要唯一,网桥地址不能一样,划分网段去实现。poda如何到podc,a到网桥再到网卡,再通过路由器进行转发到work节点,
CNI网络插件职责:
# 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
_45065d94-ab91-4fc7-8c25-7526998d2eb6.png)
Kubernetes 网络基础原则:
CNI:
:CNI 标准中,网络插件是独立的可执行文件,被上层的容器管理平台调用
网络插件只有两件事情要做:把容器加入网络或把容器从网络中删除。
Kubernetes 使用 CNI 网络插件的工作流程 :
_3677ef18-29af-4f98-8826-d6911da9e5f6.png)
: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之前删除所安装的calico
删除calico方式:
部署:
注:执行前需手动修改一个内核参数:详见下述报错解决
_f996a61a-9336-427c-b506-7e745bafec1b.png)
部署flannel 网络插件:
_10cd794f-d23e-4c11-8269-5e4936718a00.png)
#可以看到给我们安装了一个namespace
_02496249-3f1a-427b-bc22-e2ea4c8cb035.png)
#每一个节点都起了一个pod,查看命名空间里面的pod
验证当前允许模式:
_70e47723-8dcc-491c-8205-3ecf4a6b8e4a.png)
#通过日志方式进行查看,会划分一个子网
# 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地址范围:
_691fcf8c-0d97-4f77-85d4-06cb5c12262c.png)
#子网分配的信息保存到了etcd中
flannel0接口:
:flanneld 进程启动后,通过 ip addr 命令可以发现节点中多了一个 叫 flannel0 的网络接口
_12a79733-47f5-492b-8f27-7ea3d29e162f.png)
# cni0:bridge相当docker0 ,flannel0归Flanneld进程管理
#进程会监听UDP 8285
kubectl apply -f nginx-master.yaml
#master和worker都运行pod,在master的nodeName手动添加一个值,绕过调度
_a94ee29b-0284-4341-afa1-2f592ff2b20a.png)
_b58fd417-c5b9-4d32-9770-f211f794f51d.png)
#ping下worker的ip可以通
源ip和目标ip是如何获取:flannel UDP 模式跨主机通信实践
_ba32a31e-6458-4d90-9ef5-8a29e5c5dd14.png)
#走10.244.0.1的网关
执行:ip addr查看
_b44850fc-b9e6-4734-8839-9941a331c269.png)
#网桥上一个接口cri0作为网关到宿主
_8e2f3117-f5e4-4186-9af1-1100110b9db5.png)
#每个节点都有一个flannel0
_49359582-87e9-4b44-b3a5-c46a60a62b92.png)
#通过对目标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的数据包中
_379b95e8-7bb9-4f82-b3f5-ef88ca6f84fa.png)
_01e32c94-6376-4e34-878f-cf44a94a4390.png)
#在启动是此处可能会出现报错,内核的一个参数
解决方法一:
#手工加载内核模块
modprobe br_netfilter
解决方法二:开机自动加载
echo "br_netfilter" > /etc/modules-load.d/br_netfilter.conf
ping 10.244.1.73
#进入容器ping目标IP,持续有数据包流量
#执行此命令先去抓取网桥cni0未进行封装前的数据包,保存为一个文件
_873f6299-1d0b-43c3-9820-3a46752ed139.png)
#此刻是不知道数据包是进行过封装的
#抓取宿主机网卡数据包保存为文件,进行分析,此处找UDP的包,宿主机出去后封装的是UDP的包
_8472fc7a-63fb-4dd6-b6b4-0c9f4c4cefe7.png)
_b39e1e49-ad86-40f8-b265-88ee8acd0b51.png)
如何看到data的数据:
_801081b4-e079-47a8-bafd-d72e740d82e1.png)
#此处改为ipv4即可,
_2c70796d-6d13-4e51-ac18-851ce0ca5f24.png)
#可以看到data除就显示一个源ip和目标ip
#ping命令没有到达对端,reply没有回来
#优化UDP模式,所有的封包和解包都在内核态完成,效率会更高
#在linux内核中支持VXLAN协议
VLAN:隔离广播域 XVLAN对vlan进行扩展
#都属于二层协议
_7785f14f-d4f4-4559-b195-361b3959348b.png)
部署flannel网络插件:
_bb02bb25-4c68-48fd-9d93-39220b47dde2.png)
_757434b5-16d8-4cb2-a48a-dc7f0b8fbad3.png)
#同udp一致也会生成子网信息,封装时会占用50个字节
_72a23ee0-3313-4588-935d-bd3328bdad80.png)
_14f172df-55c5-41ee-9547-bc7f69a055ef.png)
#可以看到会监听udp的端口,并且端口变为了8472
_2372a30a-9ad4-42b7-b4fe-d0cd788cda5d.png)
ping 10.244.1.13
验证源ip和目标ip为什么会互通:
_4553be94-6b29-4628-a80b-bf428220cc0f.png)
查看pod路由表:
_a4ba82c7-6002-4759-8129-b7361304a032.png)
#走的是10.244.0.1网关,就会到达宿主机
_85f367e3-923c-4c45-9883-15454abc9102.png)
#可以看到数据包的数据就到了flannel.1
封装方式:
_e86a6cbc-174f-4e8f-af41-82ae3ca27824.png)
eth0接口抓包分析:
#可以抓取到封装完成的结果
_ef71284e-a167-46e7-88f1-3c96f4bc6fa5.png)
#默认是4789端口,会不知到还有一层数据包,显示的是封装之后的过程
:原始数据包依旧在data里面,需要执行:编辑—首选项—VXLAN—端口改为8472
_d8fd9758-0609-4755-899c-752be9357ffb.png)
_725f191d-5f41-4190-ab8e-3afe30f9a90f.png)
_9ba3deea-b4c1-4a75-80ff-2d05e55a156c.png)
:Host Gateway 简称 host-gw ,从名字中就可以想到这种方式是通过把主机当作网关实现跨节点网络通信的 。 那么 ,具体如何实现跨节点通信呢?与 UDP 和 VXLAN 模式类似, 要使用 host-gw 模式,需要将 flannel 的Backend 中的 Type 参数设置成 “host-gw
_4b158b67-441b-4d5d-b282-0dc0ba21c3d6.png)
通信流程:
:host-gw 模式下,各个节点之间的跨节点网络通信要通过节点上的路由表实现,因此必须要通信双方所在的宿主机能够直接路由 。 这就要求 flannel host-gw 模式下集群中所有的节点必须处于同一个二层网络内, 这个限制使得 host-gw 模式无法适用于集群规模较大且需要对节点进行网段划分的场景 。 host-gw 的另外一个限制则是随着集群中节点规模的增大,flanneld 维护主机上成千上万条路由表的动态更新也是一个不小的压力 ,因此在路由方式下 ,路由表规则的数量是限制网络规模的一个重要因素
_c00930b7-13f3-4997-8146-e1d4b2d9e0e0.png)
:calico把节点面为路由器进行解决
:通过路由表实现
路由条目实现:
RIP
EIGRP、OSPF、ISIS
BGP
#calico使用BGP协议进行通信
介绍:Calico 在每一个计算节点利用 Linux 内核的一些能力实现了一个高效的 vRouter 负责数据转发,而每个 vRouter 通过 BGP 把 自己运行的工作负载的路由信息 向整个 Calico 网络传播。小规模部署可以直接互联,大规模下可以通过指定的 BGP Route Reflector 完成。最终保证所有的工作负载之间的数据流量都是通过 IP 路由的方式完成互联的 。 Calico 节点组网可以直接利用数据中心的网络结构(无论是 L2 还是 L3 ),不需要额外的 NAT 或隧道
_4f3c9489-9e23-45d2-9aca-60f7ddd765e9.png)
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:路由反射器
_cf8b60d7-f904-4687-84d9-4714cbdee934.png)
:在较大规模的部署中, Calico 建议使用 BGP Route Reflector (路由器反射器)。互联网中通常使用 BGP Route Reflector 充当 BGP 客户端连接的中心点,从而避免与互联网中的每个 BGP 客户端进行通信
#减少路由条目
#也需要etcd对子网的分配信息进行保存
calico的工作模式:IPIP(默认工作模式)、BGP、VXLAN
#ip in ip把原始的数据包再封装一层ip
Calico 可以创建并管理一个 3 层平面网络,为每个工作负载分配一个完全可路由的 IP 地址 。 工作负载可以在没有 IP 封装或 NAT 的情况下进行通信,以实现裸机性能,简化故障排除和提供更好的互操作性 。 我们称这种网络管理模式为 vRouter 模式 。 vRouter 模式直接使用物理机作为虚拟路由器,不再创建额外的隧道 。 然而在需要使用 overlay 网络的环境中, Calico 也提供了 IP-in-IP (简称 ipip )的隧道技术
_895fdf38-3404-4ee6-8070-df95336a7761.png)
:和其他 overlay 模式一样 , ipip 是在各节点之间 “架起” 一个隧道,通过隧道两端节点上的容器网络连接,实现机制简单说就是用 IP 包头封装原始 IP 报文 。 启用 ipip 模式时 ,Calico 将在各个节点上创建一个名为 tunl0 的虚拟网络接口,如上图所示
#只要两端的ip可以ping通,数据就在所搭建的隧道中进行通信
如何确定有没有使用IPIP模式,观看calico的yaml文件:
_5677ab92-3192-4254-88ee-9dec5cbe98f7.png)
查看网卡:tunl0@NONE:IPIP模式
#没有tunl0@NONE就是运行在BGP的模式下
插件以部署,执行以下内容:
_c21fd247-67a8-404a-9b4d-829770c7b4cd.png)
_39eadce3-0f9d-4f66-8f0a-6f81b70972fd.png)
验证源ip和目标ip如何进行通信:
_07d67a91-f06d-4d5c-b1aa-3ec96cda7ef7.png)
_69a20b5f-8212-43b3-af57-25924f5f755a.png)
#10.244网关走到了169,calico没有网桥,直接连接到宿主机
#pod内ping网关是不通的,把veth pair伪装成了网关
_11ab486a-98e6-45a8-9d4a-e6bf59569b72.png)
#数据通过了tunl0进行通信,tunl0就会对我们的数据包进行封装,把数据发到192.168.11.58
#使用ipip还是可以用BGP的协议把路由条目进行学习,找到转发出口
_0c4f6ae2-efed-4a0d-97a7-e5e74b125cbc.png)
#可以看到数据封装过程
_33f689ee-ba94-4b2c-bd83-b0eb0abfb4b3.png)
_9b9199c4-54ab-4642-817f-4aa8998769db.png)
#通过验证可以看到到对端节点的数据是畅通的
验证:src-ip:10.244.184.84 dest-ip:10.244.171.18
_55b0db2e-b1a2-42d2-8360-314fdf9103eb.png)
_2b37ff2a-df44-4620-9010-11c8cf7ac7a5.png)
#目标ip171.18直接通过宿主机的接口出去到达对端,没有封装过程
/opt/cni/bin/:网络插件ipamn给Pod分配IP
/etc/cni/net.d/:网络插件配置文件
#vxlan和udp模式的通信方式都是覆盖网络
:运行在一个网上的网(应用层网络),并不依靠ip地址来传递消息,而是采用一种映射机制,把ip地址和identifiers做映射来资源定位
:底层的物理网络设备组成的网络我们称为 Underlay 网络,而用于虚拟机和云中的这些技术组成的网络称为 Overlay 网络,这是一种基于物理网络的虚拟化网络实现
_7515d44f-1964-4807-8f49-950f90836c47.png)
Kubernetes 使用各种 IP 范围为节点、Pod 和服务分配 IP 地址
Kubemetes 处理 Pod 的出站流量的方式主要分为以下三种:
在 Kubemetes 集群中,每个 Pod 都有自己的 IP 地址,运行在 Pod 内的应用都可以使用标准的端口号,不用重新映射到不同的随机端口号 。 所有的 Pod 之间都可以保持三层网络的连通性,比如可以相互 ping 对方,相互发送 TCP/UDP/SCTP 数据包 。 CNI 就是用来实现这些网络功能的标准接口
Pod 的生命周期很短暂,但客户需要的是可靠的服务,因此 Kubemetes 引 人了新的资源对象 Service ,其实它就是 Pod 前面的 4 层负载均衡器。 Service 总共有 4 种类型,其中最常用的类型是 ClusterIP ,这种类型的 Service 会自动分配一个仅集群内部可以访问的 虚拟IP
Kubemetes 通过 Kube-proxy 组件实现这些功能,每台计算节点上都运行一个 Kube-proxy 进程,通过复杂的 iptables/IPVS 规则在 Pod 和 Service 之间进行各种过滤和 NAT
从 Pod 内部到集群外部的流量 , Kubemetes 会通过 SNAT 来处理。 SNAT 做的工作就是将数据包的源从 Pod 内部的 IP:Port 替换为宿主机的 IP:Port 。 当数据包返回时,再将目的地址从宿主机的 IP:Port 替换为 Pod 内部的 IP:Port ,然后发送给 Pod ,当然,中间的整个过程对 Pod 来说是完全透明的,它们对地址转换不会有任何感知
:谈到 Kubemetes 的网络模型,就不能不提它著名的 “单 Pod 单 IP”模型 , 即每个 Pod 都有一个独立的IP, Pod 内所有容器共享 network namespace (同一个网络协议栈和 IP )
:单 Pod 单 IP” 网络模型为我们勾勒了一个 Kubemetes 扁平网络的蓝图,在这个网络世界里:容器是一等公民 , 容器之间直接通信,不需要额外的 NAT,因此不存在源地址被伪装的情况; Node 与容器网络直连, 同样不需要额外的 NAT 。 扁平化网络的优点在于:没有 NAT 带来的性能损耗,而且可追溯源地址,降低网络排错的难度 。
总体而言,集群内访问 Pod , 会经过 Service ; 集群外访问 Pod , 经过的是 Ingress
Kubernetes 对网络的要求:
阿里云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学习日志
#kubernetes在代码中支持比较流行的存储协议,之前
Kubernetes 支持以插件的形式来实现不同存储的支持和扩展,这些扩展基于如下两种方式:
emptyDIr:临时存储
#空目录挂载到pod中
# emptyDir 设计的初衷主要是给应用充当缓存空间或者存储中间数据。
然而这并不是说满足以上需求的用户都被推荐使用emptyDir,我们要根据用户业务的实际特点来判断是否使用emptyDir。因为emptyDir的空间位于系统根目录下(默认位置:/var/lib/kubelet/pods/),被所有容器共享,所以在磁盘的使用率较高时会触发Pod的eviction操作,从而影响业务的稳定
hostpath:半持久化存储
:常见的半持久化存储主要是 hostPath卷。hostPath 卷能将主机节点文件系统上的文件或目录挂载到指定的Pod中。
使用 hostPath 卷时要注意以下问题:
#使用时建议不让pod移动节点,放到固定节点
:针对持久化存储,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
scheduler:为pod找到一个合适的node
_fac02f82-5bbd-4c56-80a1-dfcb29a221c3.png)
#通过调度器把nodename加一个值,把pod调到此处
_f0897cea-aa9c-4e39-af5e-e057574bff23.png)
#通过kubelet上报此处的定义的属性,去判断有多少可分配的资源
_4016dfc1-1281-4c1e-ba84-21028c4232a7.png)
执行 kubectl get pod<pod-name〉-o yaml:查看 pod 完整的定义
执行 kubectl explain pod.spec:查看 pod 完整配置字段信息
#default默认调度器
CPU:
Kubernetes调度Pod时,会判断当前节点正在运行的Pod的CPU Request的总和,再加上当前调度Pod的
CPU Request,计算其是否超过节点的CPU可分配资源。
配置cgroup 以限制资源上限。
内存:
判断节点剩余内存是否满足Pod的内存请求量,以确定是否可以将Pod调度到该节点。
配置置cgroup 以限制资源上限。
_383a89fc-d92d-4dce-9e4d-67209fb81964.png)
#containers运行的容器资源需求要累加起来,init的运行后的3G内存用完后也会释放出来,取最大值,最终使用2核心3G
Predicate:预选,过滤不符合条件的节点
Priority:优先级排序,选择优先级最高的节点
#如何找到合适节点,通过上述两种节点算法
#先进行预选,在进行优选选择节点
_36eeffe3-89a9-4948-aa6f-a3d00f9fb1e9.png)
全局最优解:
局部最优解:
#当普通调度无法满足我们的需求的时候就使用高级调度策略
#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=
_5b6208af-e3a0-4adb-bc44-ee6e2e3e1373.png)
kubectl label nodes worker-01 node-role.kubernetes.io/data-plane=
_3020058a-dad5-4308-83ac-594a46ed725a.png)
#查看可以看到worker的节点的标签已经改变,后面可以跟值
kubectl label nodes worker-01 node-type=gpu
_512c852d-6ed8-4f92-9540-ea431696a026.png)
#可以自定义增加节点的一个标签,pod对节点有要求可以使用标签方式,让pod调度到指定节点
kubectl label nodes worker-01 node-role.kubernetes.io/data-plane-
_070301da-843f-49a5-8648-1dbb189ddd38.png)
#删除时在标签后面加一个减号即可
yaml文件配置:示例
_84366e3d-4fcb-4bea-9177-0766d7a3c9b9.png)
#在yaml配置文件里面去定义调度算法
语法格式:map[string]string
作用:匹配 node.labels
排除不包含nodeSelector 中指定label的所有node
匹配机制:完全匹配
_82637f2d-6a56-4bcb-a23d-2043bdc1e265.png)
#当启动一个配置好的yaml的时候,节点没有配置相对应的标签,就会出现上述报错,没有调度器,不能容忍污点。当标签修改后就会调度成功
与nodeSelector 关键差异:
#硬亲和nodeSelector必须匹配、软亲和匹配,打高分,不匹配:打低分
_c1143ce4-1e6b-407c-9bb7-76167d632859.png)
#硬亲和标签等于ssh和等于nas有一个匹配就可以匹配
#软亲和匹配就会调度到比较喜欢的,不匹配也可以调度成功。启动yaml测试后会优先调度到store,当启动多个副本时,也会调度到其他节点
#设置的权重数值越大,影响越大
_ce0ffc0f-8e0c-4788-b7f3-a2673d2794ea.png)
与 nodeAffinity的关键差异:
podAffinity:Pod 亲和性
_e22e9ef5-a351-42f5-abd9-3560d9cdd7b0.png)
#此处使用的是硬亲和
硬亲和
软亲和
#两个pod同时跑在同一个节点用亲和性,分为硬亲和和软亲和
podAntiAffinity:Pod 反亲和性
_41ceb22f-5b19-4089-9715-374f486a14dc.png)
#都是硬亲和,可以写多个属性,使用亲和性和反亲和性自己时会一个节点启动一个pod
硬亲和
软亲和
#两个pod不跑在同一节点用软亲和,分为硬亲和和软亲和
与 podAffinity的关键差异:
:podAffinity 中可调度节点,在 podAntiAffinity 中为不可调度
:podAffinity 中高分节点,在 podAntiAffinity 中为低分
topology:拓扑 #调度时可以在按照定义的节点去分配
topologyKey: "kubernetes.io/hostname" #节点名
topologyKey: "kubernetes.io/zone" #节点上的标签
#node选择哪些pod选择在这个节点运行,污点
kubectl describe nodes master-01:里面内容可以查看到污点
_36a7e2f6-30df-46b2-a23d-cd09ac6b0d36.png)
污点:key=value:effect # value 可以省略
effect 污点影响 范围:
打污点:
kubectl taint node worker-02 node-type=gpu:NoSchedule
#打上污点后,不会影响正在运行的pod,再次启动其他pod后状态会处于pending状态,不能容忍这个污点
删除污点:
kubectl taint node worker-01 node-type-
#在key的后面加一个减号即可
:容忍 toleration Pod 可以容忍 污点,Pod 就可以调度到 有污点的 节点 上
#打分时还是优先调度到没有污点的节点
_9819f11d-3882-4078-a033-f2dfb0334a08.png)
完全匹配:
node-type=gpu:NoSchedule #使用最多,完全匹配
匹配任意:taint value #可以匹配任意的值
匹配任意:taint effect
Kubectl cordon worker-01:把节点标记为不可调度
#类似于自动打一个污点
_34856a1c-0eed-4f5b-ac3f-0866dc297915.png)
#通过查看可以看到节点状态,调度被禁用,使用这个命令会更清晰
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学习日志
_62570420-cde1-4ac5-80de-c854e23d3061.png)
Kubernetes API 的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证、授权以及准入控制(AdmissionControl)等。
_a849d21c-ffd6-4726-a97a-0e955074dc91.png)
:请求发送到api的http的handler监听6443端口,在经过Authentication(认证)和Authorization(授权,鉴权),在经过admission(准入)
#准入验证会yaml文件种内容,只要apply发送请求就会经过这三种认证
#支持web类的hook(钩子)去做验证
- 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证书:
静态Token文件:
#使用静态token可以在apiserver的启动文件/etc/kubernetes/manifests/ kube-apiserver.yaml中写入-token-auth-file=文件名
引导Token:
#例kubeadm join –token加入集群的方式就是引导token
静态密码文件:
Servive Account:(重点使用):服务用户 #k8s的内置的一个对象
:是一种用于为Pod中的应用程序提供身份的重要权限管理对象
_658b34e9-15e4-4cd0-a630-88d450277135.png)
_d64fe345-57de-43bb-915f-65456fb4cdb3.png)
#缩写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 分钟
#在大规模公司时可使用这种认证方式。所有的登录都可以用这种认证,例如邮件、用户名认证等等
:授权主要用于对集群资源的访问控制,通过检查请求包含的相关属性值,与相对应的访问策略相比较,API请求必须满足某些策略才能被处理。
:跟认证类似,Kubernetes也支持多种授权机制,并支持同时开启多个授权插件(主要有一个验证通过即可)。
:如果授权成功,则用户的请求会发送到准入控制模块做进一步的请求验证;对于授权失败的请求则返回HTTP 403。
Kubernetes 授权仅处理以下请求属性:
目前,Kubernetes 支持以下授权插件:
#云厂商使用一般
_21f7c6d0-dd60-4eff-9a8e-c3d2a38fe54e.png)
#通过/etc/kubernetes/manifests/ kube-apiserver.yaml查看使用的哪种授权方式
#允许用户使用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就拥有开发,运维等相关的权限
_fddf64e0-3a8b-4246-b910-e1a72682e60f.png)
注:授权的资源属于命名空间级别的就使用roles,通过rolebindings将用户和角色绑定到一起。属于集群级别的就使用clusterroles,通过clusterrolebindings将用户和角色绑定到一起
_73e8fb19-ef73-4324-973a-d67f2ccb5068.png)
注:RBAC的资源名都是小写的复数写法
create、get、delete、list、update、edit、watch、exec、patch
:我们想要创建一个 User Account,只能访问 dev-project 这个命名空间,对应的用户信息如下所示
_c9a04090-3869-42ad-ac07-b227236467f8.png)
_e6476939-bb9f-4838-a35f-6d56a97f022b.png)
#把证书等相关内容放入此目录里
#用户名是放置证书里面的,通过创建证书,创建用户,用户向CA申请证书。通过私钥和csr证书签发请求,CA就会签发一个证书
#注意需要确保在-subj参数中指定用户名和组(CN表示用户名 common name ,O表示组 orgnazation )
_d697f3f1-d6af-4386-b7fe-164fb1d4d2d0.png)
# Kubernetes 集群的 CA 证书,如果使用的是 kubeadm 安装的集群,CA 相关证书位于 /etc/kubernetes/pki/ 目录下面,我们会利用该目录下面的 ca.crt 和 ca.key两个文件来批准上面的证书请求。生成最终的证书文件,我们这里设置证书的有效期为 3650 天
_a0cc0cd5-2ddf-4be5-9477-6fb3ea22955c.png)
_876732cb-0468-496e-be5a-86657c3d4240.png)
_d5dfe5a5-987f-4635-89f2-6e8e05131568.png)
#使用刚刚创建的证书文件和私钥文件在集群中创建新的凭证和上下文(Context):
_27b88a13-d40c-42ab-8d7f-44fe5ab752e6.png)
#进入.kube/config文件中可以看到信息已经添加进去了
_6f880d1f-7297-40e5-b36f-005ebd81a2ef.png)
#星代表正在使用的上下文
# use-context使用哪一个上下文
注:此处可以不执行切换,等创建role并绑定角色后后在切换
_38bcf550-a184-4de5-90a2-460072bf206a.png)
_65664984-42b2-4d90-b57e-c31b994717e2.png)
#以上分别是客户端证书和私钥,data用的base64位编码,可用证书路径
#kubeconfig存放kubectl连接k8s集群的验证信息
#使用证书、私钥找 apiserver认证dev-user
#上下文用来关联用户和集群,用户的名字和上下文中user的名字一致。kubectl会找当前正在使用的上下文,告诉用哪个用户名,连接哪个集群。可以写多个集群
_a31239b3-d81c-41de-bc64-beb950b3ce13.png)
#出现报错,知道是谁进行执行的命令,后面加--v=9,显示详细日志,可以看到403
#以上操作是认证过程
#写role角色,把rolebinging用户绑定到role上
#之前如有切换上下文就执行此条命令
_d23703f5-43b0-4d5a-ad9d-a6f939e44ac5.png)
#apigroups写组,核心组写空,resources写对象,verbs写动作
#其中 Pod 属于 core 这个 API Group,在 YAML 中用空字符就可以,而 Deployment 和 ReplicaSet 现在都属于 apps 这个 API Group(如果不知道则可以用 kubectl explain 命令查看),所以 rules 下面的 apiGroups 就综合了这几个资源的 API Group:["", "apps"],其中verbs 就是我们上面提到的可以对这些资源对象执行的操作,我们这里需要所有的操作方法,所以我们也可以使用['*']来代替
_22322cd4-0666-40d2-a67f-00bdd8ccc6e8.png)
_58151e35-e516-4fac-8eaa-48005d0408ff.png)
# Role 创建完成了,但是很明显现在我们这个 Role 和我们的用户 dev-user 还没有任何关系,所以我们就需要创建一个 RoleBinding 对象,在 dev-project 这个命名空间下面将上面的 dev-user-role 角色和用户 dev-user 进行绑定:(dev-user-rolebinding.yaml)
#上面的 YAML 文件中我们看到了 subjects 字段,就是我们上面提到的用来操作集群的对象,对应上面的 User 帐号 dev-user,使用 kubectl 创建上面的资源对象
验证:
_b68ac222-b0f3-4876-84b2-cd736bde4b23.png)
#由此可以看出成功授权认证,无法跳出当前命令空间
#ns-user是default命名空间的一个普通用户
#ns-admin default 命名空间 管理员
# cluster-admin 集群
_12100301-efc9-41ea-b4c2-0d3e7b81dd5d.png)
#定义资源的增删改查
#以上用户和role和rolebingding都已创建
:每证书和私钥,使用token令牌,保持在secret
_d39430b3-5f97-4610-803e-b9259adf4bcd.png)
#type,secret的类型
_1927346f-f1f1-449f-b06e-5ba41b424591.png)
#进行查看,里面有三个data,里面有证书和token,k8s就知道身份
#此处提取的是base64解码完成后的信息,kubeconfig文件中再次添加用户就是使用token
_ae0eb6d1-c085-42ef-a35b-0747ca3cc38c.png)
#此处内容需要根据实际情况进行修改
#当需要给其他人创建授权,并在其他电脑上使用,在自己的家目录下创建一个.kube目录并创建一个config文件把内容放置进去即可
_01430e95-a165-4cf0-b466-ed09b81480fb.png)
_c6519bbf-a1ce-4c16-b475-43638de461b2.png)
_ae5baae9-530f-4e8e-9d8c-f5864e3df773.png)
#命名空间下的管理员,所有组,所有都不用限制,都是星
_203b9f88-bff3-4ca3-b0e3-4d71960caa45.png)
#subjects把用户和角色绑定在一起
_b89610b9-116c-4756-8640-2608d4a04cfc.png)
#所生成的文件就可以发送给他人进行使用
整体流程:
#每个用户创建管理员角色,集群层面命名空间
:资源对象里面有集群层面就需要使用clusterrole
_e9b92861-9199-4ac6-970e-cdfa3f175f20.png)
_39a35ad0-4ae0-475b-bf64-959124e94f4f.png)
_cf151d29-a2f6-4269-91c0-063053f8ad9e.png)
#k8s集群安装时默认创建了clusterrole,可直接使用
_a94aaca5-c39a-4a9e-a73b-0d97de7e793d.png)
#绑定角色
#创建的集群管理员就在不同的命名空间不受限制
作业:
用户: 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
示例:
_07420b3f-f921-4e0f-aaaf-81459fff430a.png)
#限制2个configmaps,2个services。限制每个命名空间可以使用多少资源
_1a80fa96-9982-4e6f-8edd-585cc1a69c29.png)
: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 不再兼容
_ecec9cf0-5022-477d-b13d-b032ade0d32d.png)
:上面的架构图中,核心是 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文件
#下载可以直接去官网下载
#一个chart可以创建多个release
:Helm 安装 chart 到 Kubernetes 集群中,每次安装都会创建一个新的 release
#把公司应用部署到 Kubernetes 集群中,需要给应用写YAML, deployment.yaml service.yaml
#当维护多个yaml文件时进行修改,就会造成工作量加大
:如果使用heml,只需要维护一个chart包
:在 Helm 中,可以理解为主要包含两类文件:模板文件和配置文件。模板文件通常有多个,配置文件通常有一个。Helm 的模板文件基于text/template模板文件,提供了更加强大的模板渲染能力。Helm 可以将配置文件中的值渲染进模板文件中,最终生成一个可以部署的 Kubernetes YAML 格式的资源定义文件,如下图所示:
_7ea846e1-f2c3-41ee-83de-937eb639b617.png)
#对yaml文件的部分值写为一个模板,在写一个配置文件,通过模板和配置文件组成一个yaml
#对所有应用YAML提取一个模板 + 每个应用的配置文件
#此处使用下载好的安装包
_95ca56f1-c158-466d-bd9e-bb6f3e34202f.png)
#可以看到有一个解压的后heml工具
_0e154080-c997-49c2-a70b-d488ad2afb35.png)
:安装完 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 列表
_c562ec79-a7e4-43c7-8c6b-b415fe8257bc.png)
#我们可以通过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
#没有添加仓库名在本地所有的仓库在中搜索
_b5a643a0-72db-4a29-8f8a-7163e0537bb9.png)
#name:chart的名字,chart version:chart的版本,app version:应用的版本,description:描述信息
#在后面加-l就列出来历史版本,例:helm search repo bitnami(仓库名)/nginx -l
#可以指定安装具体哪个版本
:查询到自己需要的 Helm Chart 后,就可以通过 helm install 命令来安装一个 Chart。helm install 支持从多种源进行安装:
#使用解压后的cahrt包目录
安装格式:helm install [NAME](release的名字) [CHART](chart的名字)[flags] #在线安装方式
#不指定版本默认安装最新版本
#使用此种方式安装nginx现版本会出现报错,可使用其他安装方式
:使用--version:可指定chart的版本
#需要下载一个chart包
_cc6ace97-fc3d-473d-a36a-2cb39bb9d71c.png)
#根据信息可以看到创建成功
#每更新一次,release就会加一
_c55bbaff-a004-4f96-a567-6ac432dcff76.png)
#可以看到安装了一个nginx-02的pod和一个svc
#基于一个chart可以安装多个release
_a10d1c4a-67e4-400e-8e90-ada56aaaa203.png)
注:镜像无法进行拉取,可以在yaml文件中的配置文件中,把镜像改为本地的镜像仓库
_188d24a6-e17a-42e6-b0ed-09bfc5d260e0.png)
_5056559c-bf5b-4776-975d-07f29387e1cf.png)
#可以看到基于一个chart安装多个release。cahrt安装完成后是一个deployed
查看nginx的chart的解压目录:
_be155e02-9acd-4b8d-80ea-1597f69748f9.png)
#模板 templates + 默认配置 values.yaml(放置所有的值),创建一个yaml
:上面的安装方式只会使用 Chart 的默认配置选项,很多时候我们需要自定义 Chart 来指定我们想要的配置。使用 helm show values 可以查看 Chart 中的可配置选项
安装过程中:传递配置数据方式:
-f,--values:使用 YAML 文件覆盖配置。可以指定多次,优先使用最右边的文件
--set:通过命令行的方式对指定配置项进行覆盖
#--set可以写多个
注:当配置文件中有参数修改时使用此命令
#安装时使用-f加自定义配置文件可以,覆盖原有的values的yaml文件
#名称自定义,把想要修改的值部署到创建的yaml的配置文件中
_3ababa61-3151-44b6-bf19-e9156a93ab6d.png)
_c29139df-19c5-44ec-be5c-0a8a9091e92f.png)
注:镜像无法进行拉取,可以在yaml文件中的配置文件中,把镜像改为本地的镜像仓库。也可以更改镜像拉取策略等多个参数
再次查看:
_3806775e-aa64-4c53-af5b-64e748b4c68c.png)
#使用本地镜像配置的文件成功创建并启动
#在大项目经常需要修改的拿出来进行修改
#通过--set对相关参数进行了修改,此种方式也可以覆盖参数
_75b9ee78-70a7-4aeb-b2cd-6c19b9e3195f.png)
#可以在自动化部署时使用
:部署完应用之后,后续还可能升级应用,可以通过helm upgrade命令来升级应用。升级操作会基于已有的 Release,根据提供的信息进行升级。Helm 在更新时,只会变更有更改的内容
更新方式:两种
helm upgrade nginx-20 -f nginx-20-value.yaml nginx
helm upgrade nginx-20 --set key=value nginx
#语法和安装类似
例:nginx-20进行更新
_54395c13-0c51-4413-b3c1-cb1cfa94e171.png)
#可以看到yaml进行了更新
_62f85142-7334-44b3-9e70-19dfbe567e49.png)
#nginx-20的revision值为2进行了次安装,一次更新
_9bb37cd1-451d-4c9a-90bc-caa419be0eb9.png)
_c781e8d7-8ac2-485b-85ac-87421961f655.png)
#查看回到了版本1
#上述命令会从 Kubernetes 卸载 nginx-01, 它将删除和该版本关联的所有资源(Service、Deployment、Pod、ConfigMap 等),包括该 Release 的所有版本历史
Helm 常用命令如下:
例:创建一个chart
helm create my-chart(chart的名字)
查看创建chart的内容:
_b5dab322-5b33-41e0-bc05-90a660f1a4b0.png)
# 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
#在本地渲染 chart 包,生成最终部署的YAML
# 下载 插件
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学习日志
部署版本:Dashboard: v2.7.0、Chart version: 6.0.8
_46f9f600-0337-4408-8a48-9cb1261bd675.png)
helm upgrade --install kubernetes-dashboard kubernetes-dashboard-6.0.8.tgz --create-namespace --namespace kubernetes-dashboard
#写脚本时可以使用此命令,自动创建命名空间
_b9b762fc-2917-4109-8129-806ba729caf3.png)
_20dc7504-e371-4bce-ad03-76d54d4e756f.png)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard NodePort 10.110.44.158 <none> 443:31268/TCP 165m
_c509138a-bf2b-439c-99ab-cda14437b115.png)
#访问使用https访问
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
_362c1757-cbe5-4ebc-b27d-9806f0a7cd0c.png)
#使用token进行验证登录,使用不同的用户进行验证
ingress:
enabled: true
className: "nginx"
hosts:
- ui.xxhf.cc
tls:
- secretName: dashboard-secret
hosts:
- ui.xxhf.cc
_3c936bf8-a2b5-4216-b4fc-e084e9afbf17.png)
#yaml文件中写使用的域名和证书
# 获取 token
kubectl config set-credentials ns-user --token='eyJhbGciOiJSUzI1NiIsI......'
registry.cn-beijing.aliyuncs.com/xxhf/dashboard:v2.7.0
:应该知道有一个命令 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服务才能进行使用
_db9710b9-8e58-4dcd-8545-0c6d68cf8469.png)
:执行kubectl top,请求发送到API server,API server在把请求转到metrics server 。它调用 kubelet 的 API 拿到节点和 Pod 的指标,再把这些信息交给 apiserver,这样 kubectl、HPA 就可以利用 apiserver 来读取指标了
kubectl scale deploy
HPA Horizontal Pod Autoscaler:水平 Pod 自动伸缩 #添加pod副本数
_9022c827-1999-4f05-a71a-b6dffcd08547.png)
#一个资源对象
VPA Vertical Pod Autoscaler:垂直 Pod 自动伸缩 #增加资源,使用不高
#有了 Metrics Server,我们就可以轻松地查看集群的资源使用状况了,不过它另外一个更重要的功能是辅助实现应用的“水平自动伸缩
:“HorizontalPodAutoscaler”,简称是 “hpa”。顾名思义,它是专门用来自动伸缩 Pod 数量的对象,适用于 Deployment 和 StatefulSet,但不能用于 DaemonSet 对象
:HorizontalPodAutoscaler 的能力完全基于 Metrics Server,它从 Metrics Server 获取当前应用的运行指标,主要是 CPU 使用率,再依据预定的策略增加或者减少 Pod 的数量
Deployment
statefulSet
CPU 60% #cpu值可以自己调整定义
Memory
#有多种部署安装方式,可在官网具体查询
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/high-availability-1.21+.yaml:下载yaml
_cd779c8f-161a-41dc-9bfb-c74242a63e33.png)
注:此处使用下载好的yaml,metrics进行部署。以上内容以修改好
_7dc0a39f-63d2-4a0c-8869-a7b0ea28a89c.png)
#默认放在了kube-system命名空间下,服务正在启动中
#服务器启动后会定时去kubelet拿监控数据
验证:
_72b8648c-8bb8-421e-afce-0b1502926e8d.png)
_bc65a73c-3336-404a-8ca7-45691b24ea3d.png)
扩缩容测试:
:使用 HorizontalPodAutoscaler,首先要定义 Deployment 和 Service,创建一个 Nginx 应用,作为自动伸缩的目标对象:
_e345d7f0-db2f-4a2a-a36a-01830c3fa14a.png)
#metrics:伸缩的依据,cpu和cpu的利用率
# HorizontalPodAutoscaler 会根据 YAML 里的描述,找到要管理的 Deployment,把 Pod 数量调整成 2 个,再通过 Metrics Server 不断地监测 Pod 的 CPU 使用率
#启动一个nginx的deployment作为伸缩目标
_656a2a4f-f9e9-47bc-b0f5-216a69afc81e.png)
_39541265-77dc-4403-9e46-4f7ef2ec8a30.png)
压力测试进行验证: # 公司一般使用Jmeter压测工具
#ab压力测试工具,-c:并发(一定时间内请求数量)-t,时间,-n多少请求
_d3b3b2b8-94e1-4c93-86af-a42839c0643e.png)
_e68d4895-c5fa-4231-9552-18ffb5198f30.png)
# Metrics Server 大约每 15 秒采集一次数据,所以 HorizontalPodAutoscaler 的自动化扩容和缩容也是按照这个时间点来逐步处理的
#cpu利用率上来后可以看到自动增加的副本数
#当它发现目标的 CPU 使用率超过了预定的 5% 后,就会以 2 的倍数开始扩容,一直到数量上限,然后持续监控一段时间,如果 CPU 使用率回落,就会再缩容到最小值
#以上监控不能看到历史数据,需要使用prometheus
#简化prometheus的部署难度
_44d3ae9c-ca60-4ca7-8da2-b089c98eb485.png)
:prometheus如何知道通过哪个点去找数据,通过job的名称进行寻找目标,并通过服务发现service discovery进行自动添加目标。通过pull去拉取目标数据,目标必须要有metrics的接口。
:pusygatway用法:将数据推送到pusygatway,在使用prometheus去pusygatway的上面拉取数据
:alertmanager主要是用来发送告警消息,通过设置的规则去告警。
# node-exporter是收集主机 的metrics , 暴露 一个接口 9100:/metrics
例:现在监控一个1000 个节点,如何告诉 prometheus 监控的目标
:通过job的名称进行寻找目标,并通过服务发现service discovery进行自动添加目标
#prometheus支持多种服务发现
#通过kube-prometheus会在集群内布置以下组件内容
_f389cb8c-7f3a-47a1-9c26-4a343793861d.png)
介绍:Operator 是由 CoreOS 开发的,用来扩展 Kubernetes API,特定的应用程序控制器,它用来创建、配置和管理复杂的有状态应用,如数据库、缓存和监控系统。Operator 基于 Kubernetes 的资源和控制器概念之上构建,但同时又包含了应用程序特定的领域知识。创建 Operator 的关键是 CRD(自定义资源)的设计
:Operator 直接使用 Kubernetes API 进行开发,也就是说他们可以根据这些控制器内部编写的自定义规则来监控集群、更改 Pods/Services、对正在运行的应用进行扩缩容
#adapter可以代替metrics server
:通过使用CR和CRD,用户可以扩展Kubernetes的功能,以适应特定的应用需求。它们提供了一种自定义资源的机制,使用户能够以声明的方式定义和操作自己的资源类型,而无需修改Kubernetes核心代码
_a8a80c80-50cb-4bcd-b093-ea236da38d74.png)
#crd也是一个资源对象
crd写法:
_7cabb5c3-7c63-436f-b2a0-af84dad8f204.png)
_5ef25e8c-b3fd-4b82-a436-1ac4b210efa5.png)
#可以看出扩展自定义出了一个资源对象
创建一个crontab的yaml:
_40c124d0-9ad1-46ef-b63a-48f7325e878a.png)
_c18a3972-5487-4d31-b0fc-73ab4d82fa60.png)
#通过查看可以看到ct创建了出来
#创建出一个deployment的yaml,还需要创建一个operator控制器进行执行工作
介绍:Prometheus Operator是一种为 Kubernetes 提供本地部署和管理 Prometheus 及相关监控组件的工具。该项目的目的是简化和自动化为 Kubernetes 集群配置基于 Prometheus 的监控堆栈
#部署了operator就相当于有了prometheus和alertmanager
wget https://github.com/prometheus-operator/prometheus-operator/releases/download/v0.69.1/bundle.yaml:github下载的快速安装yaml
#可提前下载好,以下安装使用下载好的yaml进行安装部署
#此处必须要用create
#因为需要监控数据需要使用一个ServiceAccount,要去拿应用的数据要有权限,要写一个yaml
Prometheus:Prometheus自定义资源用于定义Prometheus实例的配置和规范。可以指定版本、持久化配置、存储策略、副本数等参数,以及与其他资源的关联关系。
ServiceMonitor:ServiceMonitor 是一个自定义资源,用于定义要由Prometheus监控的服务和指标。可以指定服务的标签选择器,以便Prometheus可以动态地发现和监控符合条件的服务。 #主要用来作服务发现
Alertmanager:Alertmanager 自定义资源用于定义Alertmanager实例的配置和规范。可以指定接收告警的通知渠道、告警路由的规则等参数
_3c8431f4-b628-4593-ba0c-f96d915c048f.png)
#可以看到给我们创建了一个monitoring的这个组
创建prometheus的yaml:
_a4a28ae5-6956-49d6-957d-077376a27216.png)
#operator的文件已经定义了很多参数,在上述文件中只需写关键参数即可
_e14eb504-7588-4359-9f19-310b1301f62f.png)
_f1d07fbd-fef1-430b-9af7-4abe5acebc9f.png)
#部署的promethrus operator就是一个控制器,控制CR
_83e951e8-ae8c-4c9f-8dad-86f0de7c1663.png)
注:部署时如没有镜像,需提前导入镜像,或下载,导入的镜像也是在master
#k8s的所有镜像都在k8s.io这个命名空间
_271f83de-8d58-4f37-9922-04074e8edb9d.png)
_008aee09-6b05-4647-8c0d-e9ebc20a111c.png)
_324e0509-9eb9-48ae-ac6c-15f7f375ea57.png)
servicemonitors:找到要监控的 Pod的IP 信息,通过标签
_d918452c-41f5-4a38-a814-bf3c65039824.png)
:安装operator后就可以部署和管理prometheus server。部署prometheus server就可以通过servicemonitor或podmonitor两种方式去找service和pod进行监控,找到svc也可以找到pod
podmonitor:
#通过以上两种CR进行监控pod,主要使用servicemonitors
部署测试应用:进行监控
_b729c8ac-780d-4a98-8701-61343e4c2397.png)
#里面就是我们所监控的目标,和一些端口信息等
创建ServiceMonitor 对象:
_c928fb13-8207-4930-a072-da65d9afefd1.png)
_559f05d5-dd86-484e-a304-126890e9980f.png)
#servicemonitors:创建之后,自动 在 prometheus 配置文件中添加Job
:部署监控就一个prometheus.yaml,监控应用就创建一个ServiceMonitor
修改配置文件:servicemonitors 自动 在 prometheus 配置文件中 添加 Job
_d52e25e6-7f84-4436-826f-b6f2ed307533.png)
- --listen-metrics-urls=http://127.0.0.1:2381
# 修改为
- --listen-metrics-urls=http://0.0.0.0:2381
- --bind-address=127.0.0.1
# 修改为
- --bind-address=0.0.0.0
- --bind-address=127.0.0.1
# 修改为
- --bind-address=0.0.0.0
kubectl -n kube-system edit cm kube-proxy
metricsBindAddress: ""
# 修改为
metricsBindAddress: "0.0.0.0"
重启 kube-proxy
:全栈监控(Full Stack Monitoring)是一种综合性的监控方案,用于收集、分析和可视化应用程序的各个层面和组件的性能和健康状态。它提供了对整个应用程序栈的端到端可见性,包括前端、后端、基础设施和用户体验等方面。
:全栈监控旨在帮助开发团队、运维团队和业务团队全面了解应用程序的运行状况,以便及时发现和解决问题,并持续改进应用程序的性能和可用性。通过收集和分析各个组件的监控数据,全栈监控可以提供以下方面的信息:
日期2025.09.08学习日志
:Prometheus是一个开源的系统监控和报警框架,其本身也是一个时间序列数据库(Time Series Database,TSDB),它的设计灵感来源于Google的Borgmon,就像Kubernetes是基于Borg系统开源的
:Prometheus 被称为下一代的监控平台,具有很多和“老牌”监控不一样的特性,比如
_aa7e1db0-f03a-42c8-b3a7-caf0bd341249.png)
:Prometheus 有多种安装方式,比如二进制安装、容器安装和 Kubernetes 集群中安装,将 Prometheus 安装到Kubernetes 集群中也是官方推荐的部署方式
:将Prometheus安装到Kubernetes集群也有很多方式,比如 Helm、Operator 等,Prometheus 也是支持上述安装方式的。但是Prometheus是一个生态系统,有很多组件都需要安装,并且也有很多监控需要单独配置,于是Prometheus 官方开源了一个 kube-prometheus 项目,该项目不仅仅是用来安装 Prometheus 的,也包含很多其他的组件,如下所示
:具体可以通过 https://github.com/prometheus-operator/kube-prometheus/ 找到该项目进行查看。有了kube-prometheus项目,安装也变得非常简单,只需要两条命令即可
注:首先需要通过该项目地址找到和自己Kubernetes版本对应的Kube Prometheus Stack的版本
注:建议使用manifests的方式进行安装
_d0894249-485d-4d9c-a776-70d6c88506f3.png)
#此处使用1.32版本
git clone -b release-0.15 https://github.com/prometheus-operator/kube-prometheus.git
#下载源码
注:此处使用的是已下载配置好的安装方式,如使用operator的方式进行了安装需删除原有安装,并在新的安装方式里面执行delete -f setup
注:使用网络下载的yaml,需注意networkpolicy.yaml里面有个策略四层无法访问。
#在部署文件中setup就是存储的crd
_2c654dce-f519-4649-8f51-3996c62f7d74.png)
#安装CRD
_f45914ed-a78c-490f-b802-1317fa2d4450.png)
#可以看到会给我们创建一个monitoring的命名空间
注:此处使用离线镜像安装方式,需提前导入镜像
_f7465e50-9014-4e34-9807-e76dc347f442.png)
_5533c84e-ce5d-4069-9184-32b3ef6a1c69.png)
_9743b311-2ba2-417c-9ca3-e7ab27d1f475.png)
_d2b1dbb2-6fb3-471d-9408-cc809359299a.png)
#为了后期更新方便,这里按照类型把相关对象的资源清单文件 放在不同的目录下
#将端口进行固定,写入yaml
_3f98f250-ed07-43b0-af9a-9e3c90fd5d86.png)
#使用固定端口30030进行访问
_14fddcc3-136f-482c-a263-e636a0d4e81c.png)
_2607ea17-2a5c-4c57-b6e8-cc065ad307d7.png)
#将yaml文件中端口改为四层固定
浏览器进行访问:访问:30090
_cf36c95c-0f5a-4154-9860-0eedda039bf6.png)
#通过查看可以看到schedule没有活动的目标,就是在grafana中看到没有数据的原因
_b30c7c3e-3108-4163-90b2-a9f5e0775b94.png)
#里面有很多job,都是服务发现进行自动添加
_3dda1496-68bf-4814-8e0c-627904a1d6cb.png)
#自动在prometheus中添加job,如果想自定定义去监控,就需要进行写一个smon
#有了smon就会添加job,就会找到目标进行监控,smon通过标签去找svc
#监控各种场景方法
云原生应用:开发时考虑的监控的需求 实现了 /metrics 接口
非云原生应用:早期开发的应用,不带 /metrics 接口,这些应用需要安装 exporter
:从Prometheus的架构中了解到,Prometheus通常采用Pull的形式来拉取数据,也就意味着被监控应用只要有一个能获取到监控数据的接口,就可以采集到监控数据
:基于云原生理念开发的程序自己会暴露Metrics接口,就像Kubernetes本身的组件、Etcd等,都有一个/metrics接口,Prometheus 只需要请求这个接口即可获取到相关数据
_c97c6553-c64d-4185-8051-5f4e5ffad634.png)
: 如果使用二进制的方式安装 Prometheus,用户需要通过 Prometheus 的一个配置文件来配置需要监控哪些数据,或者配置一些告警策略。这个配置文件的维护非常麻烦,特别是监控项非常多的情况下,很容易出现配置错误,而在Kubernetes上部署Prometheus,可以不用去维护这个配置文件,而是通过一个叫ServiceMonitor 的资源来自动发现监控目标并动态生成配置
#业务监控
_6836145f-c69b-4f68-90fd-8a06b3321a62.png)
#看到启动了三个pod,并创建了svc
_1e760a59-ed63-453a-89db-78b78d019570.png)
#此应用中自带有metrics接口
#写好文件后,就可以通过标签发现svc,就能找到pod中的应用
_ee4bcbf7-2e57-4067-ab66-d52ef59dca11.png)
_84f5ed0e-2ee3-4ace-afd2-3b4f923672f7.png)
_06e28adc-8155-4535-9ab7-a24d0c2ead0d.png)
#创建出smon,就会在prometheus中的配置文件中添加一个job
_93427029-a88b-4e71-8f02-eac6816a2452.png)
#可以看到有了应用的监控点
注:当在公司进行应用监控时就可以使用此种方法,写一个smon进行服务发现
#ectd没有smon和svc,需要进行创建
注:修改配置文件之前对配件文件进行备份
_19422e7e-fc53-4e68-a4ab-7be4c02bfed8.png)
注:此处的spec的name后面是https-metrics,需进行修改
_6b1a5616-49e8-4e98-8578-bff1e7e03913.png)
#如创建其他的监控,可使用此种方式进行创建svc
#其他controller和scheduler也可使用此种方式进行创建
_64128e6b-f3c7-4f48-9635-1d08071a2799.png)
#此处改为0.0.0.0,让外面可以进来访问
_931d6c04-aeb0-4d03-b42e-ea92b008082a.png)
#修改以上基础信息,端口和标签
注:controller也可以使用上述方式进行修改
_b699a8ec-7d4e-478a-b677-45678f11d3c9.png)
#修改了etcd的监听,需要等一会,或重启kubelet
浏览器prometheus查看:
_6f348297-51cd-45c7-8840-cd42eab7dbd5.png)
#可以看到etcd被加入了进来,经过自动发现实现了监控
流程:创建svc,创建smon
非云原生应用:早期开发的应用,不带 /metrics 接口,这些应用需要安装 exporter
例:mysql-exporter 、redis-exporter
#以mysql为例进行配置验证
注:mysql-server要提前进行安装好,布置在集群外面
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:进行以下配置
_2782f116-5893-49e5-a5dd-699fd6121b2c.png)
#在mysqld_exporter 的安装目录下,创建一个 .my.cnf 的文件,里面写数据库的ip和密码,export就会自动去找这个文件
#启动后默认监听9104端口
_6afcee05-a1b2-43d9-9ced-f03f5af80c5d.png)
#请求 mysql_exporter 对外暴露的 metrics 接口
_7f3b0fad-9fce-41b8-870b-5e8644659f79.png)
#可以正常监控
:需要在 Prometheus 配置文件中添加一个 Job,用来配置抓取 mysql-exporter metric endpoint, 有两种配置方式,一种是使用 prometheus-operator 提供 CRD ScrapeConfig(抓取配置) ,另一种方法是让prometheus 加载外部配置文件
#让prometheus知道应该在192.168.81.132的固定IP上抓取指标
方法一:ScrapeConfig
_b55b28e1-ba1c-407a-aa38-f6204dc8c849.png)
#部署后就会在prometheus中添加一个job
#使用ScrapeConfig会有一定限制,需要安装operator
prometheus验证:
_29ce132f-d3c5-40d7-80f0-f5f2b49ac96c.png)
#可以看到在配置文件中添加了一个job
第二种方法:写一个附加文件,通知prometheus来读取
:首先创建一个空文件,然后通过该文件创建一个 Secret,这个 Secret 可作为 Prometheus 的静态配置:
_3bd132dd-46ad-41d2-8ff1-c60f7ba21d35.png)
#通知 prometheus 过来读取 这个 secret additional-scrape-configs,告诉使用哪个文件
_fce1ca08-b377-4129-a66a-1f0433831b23.png)
#add…附加的配置文件,name,secret的名字,key的值就是配置文件的内容
#文件改变后需执行此条命令
在 Grafana 中创建 Dashboard,导入 MySQL Dashboard 14057:
_b4c19dd8-e298-4a26-ab15-74ad11d08eeb.png)
#触发告警后会发到alertmanager,需进行配置把告警发出来
_b5c30203-3656-4a02-99d1-50198ff1e018.png)
#部分模块配置
_2f9df308-82f1-4934-ad16-7ed479d0a54e.png)
#配置文件中配置webhook,mobiles
:Alertmanager 路由规则详解:
_04630be1-71d9-48ed-b11f-48b35facf761.png)
:路由配置块的顶级配置由route开始,它是整个路由的入口,称作根路由。每一条告警进来后,都先进入route,之后根据告警自身的标签和route.group_by配置的字段进行分组。比如可以根据job、alertname或者其他自定义的标签名称进行分组,分组后进入子路由(通过route.routes配置子路由),进一步进行更加细粒度的划分,比如job名称包含mysql的发送给DBA组
#以上即为Alertmanager常用的路由配置,可以看到 Alertmanager 的路由和匹配规则非常灵活,通过不同的路由嵌套和匹配规则可以达到不同的通知效果
_60e073f1-aa22-46b0-84bb-20b429fdf46b.png)
注:使用时一定要配置安全设置
_ced42d25-7624-4870-84c7-d2b7f635845f.png)
#配置文件中配置webhook,mobiles具体@某个人
_d23cd52f-1a0c-42e9-8601-8325f143c0b5.png)
#配置部署执行后告警消息就会发出来了
_a8a70f18-27e2-4557-9f3d-7bc07c6ea6b5.png)
浏览器进行查看:
_89c95145-ad28-45af-b172-2392b113fa9b.png)
_15879e39-b47f-481c-b9b2-229ff98af2b0.png)
#可以看到钉钉消息成功进行了发送
prometheus rules 触发 > 发给 alertmanager > 看配置文件 route(根据路由发去哪) 、receiver > prometheus-webhook-dingtalk > robot
对 Etcd 或MySQL 的监控是监控应用本身,也就是程序内部的一些指标,这类监控关注的是原因,一般为出现问题的根本原因,此类监控称为白盒监控。还有一类监控关注的是现象,比如某个网站突然慢了,或者打不开了。此类告警是站在用户的角度看到的东西,比较关注现象,表示正在发生的问题,这类监控称为黑盒监控。
白盒监控可以通过Exporter采集数据,黑盒监控也可以通过Exporter采集数据,新版本的PrometheusStack已经默认安装了Blackbox Exporter,可以用其采集某个域名、接口或者TCP连接的状态、是否可用等
:前面几个小节配置监控目标时,用的都是ServiceMonitor,但是ServiceMonitor可能会有一些限制。比如,如果没有安装Prometheus Operator,可能就无法使用ServiceMonitor,另外并不是所有的监控都能使用ServiceMonitor进行配置,或者使用ServiceMonitor配置显得过于繁琐
_8977a6b6-4108-4538-b344-9dce87944a43.png)
注: 附加文件只能写一个,可以放到同一个yaml文件中
#可以看到此处的内容和传统配置的内容一致,只需要添加对应的job即可。之后通过该文件更新该Secret:
执行以下命令:进行更新yaml
在prometheus验证配置文件是否生效:
_1357afd4-7dbf-4c4a-830e-ae2ebcecef12.png)
检查targets:
_1fad965b-f46e-408b-89b3-aba6d15090ec.png)
登录 Grafana,导入Dashboard 13659,导入完成后,稍等一分钟即可在 Prometheus Web UI 看到该配置
_c19ac8ae-30b2-4d91-8ec9-b8ef619bc7dd.png)
#使用此种方式要配置pv,现在使用的是临时存储,删除pod存储消失
_035b53ff-fb76-4822-a4aa-f2ed738d5ae3.png)
#如何进行实现
_3505cab6-79e2-4d9a-85a7-76ea676e97fe.png)
商业可观测软件:ARMS(阿里云)、Datdog(做SASS)
日期2025.09.09学习日志
日志的采集:
#日志统一采集,进行查询
采集端 | 存储端 | 展示端 | |
ELK(早期使用) | Logstash | Elasticsearch | Kibana |
EFK | Filebeat Fluend | Elasticsearch | Kibana |
#EFK对采集端进行了更换,ELK是早期的采集使用方式
# Elasticsearch:可理解为文档类数据库
介绍:应用程序和系统日志可以帮助我们了解集群内部的运行情况,日志对于我们调试问题和监视集群情况也是非常有用的。而且大部分的应用都会有日志记录,对于传统的应用大部分都会写入到本地的日志文件之中。对于容器化应用程序来说则更简单,只需要将日志信息写入到 stdout 和 stderr 即可,容器默认情况下就会把这些日志输出到宿主机上的一个 JSON 文件之中,同样我们也可以通过 docker logs 或者 kubectl logs 来查看到对应的日志信息
但是,通常来说容器引擎或运行时提供的功能不足以记录完整的日志信息,比如,如果容器崩溃了、Pod 被驱逐了或者节点挂掉了,我们仍然也希望访问应用程序的日志。所以,日志应该独立于节点、Pod 或容器的生命周期,这种设计方式被称为 cluster-level-logging,即完全独立于 Kubernetes 系统,需要自己提供单独的日志后端存储、分析和查询工具
Kubernetes 中大多数的 Pod 日志被输出到控制台,在宿主机的文件系统每个Pod会创建一个存放日志的文件夹/var/log/pods/这里会存放所有这个节点运行的Pod的日志,但是这个文件夹下一般都是软连接,由于Kubernetes 底层的 CRI 容器运行时可以使用很多所以日志本身并不存放在这个文件夹,以下为容器运行时真正存放日志目录:
#找日志就可以到此处,kubelet会自动调用logrotate日志轮询自动清理日志,日志也能集中存储:建议使用的存储方式
_19c25d70-8702-4fe2-9941-1a811964f547.png)
:可以通过在每个节点上使用节点级的日志记录代理来实现集群级日志记录。 日志记录代理是一种用于暴露日志或将日志推送到后端的专用工具。 通常,日志记录代理程序是一个容器,它可以访问包含该节点上所有应用程序容器的日志文件的目录
:由于日志记录代理必须在每个节点上运行,推荐以 DaemonSet 的形式运行该代理。
节点级日志在每个节点上仅创建一个代理,不需要对节点上的应用做修改。
容器向标准输出和标准错误输出写出数据,但在格式上并不统一。 节点级代理收集这些日志并将其进行转发以完成汇总。
#每个节点只需要跑一个filebeat
_cfb1c780-f495-4441-bfac-3040425d8f62.png)
:pod里面跑一个日志代理容器和一个应用容器
_efbd1e33-75c3-4ed3-9a8a-1298f55cc913.png)
#不建议使用
#传统架构下的日志都是文件
注:单独使用一台虚拟机配置进行验证
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
检查集群监控状态:
_84f24a40-d227-404d-99f3-f7736a301563.png)
:Kibana是一个开源的数据可视化和分析平台,与Elasticsearch紧密集成。它提供了一个直观的Web界面,让用户能够轻松地探索、分析和可视化存储在Elasticsearch中的数据
wget https://artifacts.elastic.co/downloads/kibana/kibana-7.17.16-x86_64.rpm
:Filebeat是一个轻量级的开源日志数据收集器,由Elasticsearch提供支持。它专门用于收集、解析和发送日志文件和其他结构化数据到Elasticsearch或Logstash等目标系统进行处理和分析
注:此处使用在官网下载好的rpm包安装方式
_31f4bc1c-ae25-49c2-807f-043eb97c11df.png)
#配置文件放置在/etc/ elasticsearch/下
elasticsearch.yml:配置文件详解
_7d0a9e53-60bd-4407-a03a-0ef3a1c378ee.png)
#一般最少使用三个node节点
_32eaf5ee-bba4-492d-9f4f-82ddd2a58984.png)
_76791b12-9638-4a65-ae20-885c10f3a5bc.png)
#一个初始化的master节点,一个是种子节点
# elasticsearch启动后会自动创建一个用户,之后数据会自动写入到里面
_8eb35f4e-b38f-4ee8-90bc-a9b370f47a83.png)
#此处为java占用内存
注:此服务需要价高配置,最低2核4G,以上最大内存需改为1
#可以在/var/log/观看日志
_cbd147a8-55e1-4865-a57b-416cc850fd65.png)
#9200是客户端访问服务端,9300是服务端之间进行访问
_a0c4b08a-c6f3-4ffb-b8a6-6b69a0c8ef41.png)
# - green 健康 - yellow 有点问题 red 不能使用 1
# kibana和elasticsearch安装版本最好一致
#配置文件位于/etc/kibana/
_f09e4f58-2eb6-478d-ab01-110566478fee.png)
_ccdbd37a-1b27-44ef-9fc3-fb7ed559600b.png)
#需要找elasticsearch所以此处要写elasticsearch的地址,多个elasticsearch使用逗号隔开
#启动后会监听5601,并提供一个web界面,可在浏览器访问
Filebeat:采集日志数据
INPUT :输入日志来自文件
filestream:采集日志文件
container:采集容器中日志
_ae5df5f0-ab3f-4dc5-9452-6205b7eb733c.png)
_b1e9688f-d482-4640-a788-1c5af51773f3.png)
#会自动检查目录下的日志文件,进行采集
_856093e6-fe55-4510-a8d4-2d4bf63ce67d.png)
_30918b6e-707b-4b4d-b0a3-06386179f67d.png)
#生产环境中需要开启验证,并设定用户名和密码
_45d34a2d-8f9e-49fb-87f2-23f188fe02fe.png)
_ca834cf4-ea8c-474d-ab54-5ff1dfd1575c.png)
: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
_de48848a-96de-4524-9c35-3281fdeb7c1f.png)
#写以一个index pattern,把星当作一个时间戳
_46679ac1-deb6-4ae7-bc7a-a03d02e30749.png)
#创建后去discover(发现)就可以看到按照时间创建索引,下面就是日志
#左侧就是日志索引,可通过右上角选择时间
_5ef9853c-80e1-44c7-a622-3fc856769463.png)
#可以通过关键词进行搜索,会显示高亮,多个词用&&或and
_a1a6b155-4684-403e-be00-6ee71cf9ad6c.png)
#k8s架构下采集的应用都在pod中
#不建议日志输出为文件,建议日志直接输出为stdout(标准输出)
注:工作场景中elasticsearch建议放到集群外面,kibana也可以放k8s外面
#依据以下载好的的文件进行部署
注:最少需要三个节点,如使用master节点,需要把污点进行消除,否则无法启动
_8c7681a9-3565-43c6-a161-dea77936f6ae.png)
#此处使用7.17.3版本,并使用已下载好的包进行安装
#在线安装需使用此方式进行拉取helm pull elastic/elasticsearch --version=7.17.3
_3c19b62f-8a0f-435e-93fc-1f2d83f13fc9.png)
_6077d692-fbac-4790-b370-57bb36721cca.png)
#kibana是一个有状态应用,在创建svc时会创建一个有头的svc和一个无头的svc
_53db82f7-ab7c-436f-9bb9-753c7efe0945.png)
验证:
_87fc625b-b2b0-4145-b9f6-ed26b7429652.png)
_3af759e5-9ad6-45d3-b28a-63d5fdbf3a5e.png)
_01f9969e-542c-431f-8d79-01ed8edefbcb.png)
#启动后可以去web端访问
_b8445354-6f76-4bf0-8d41-e13dbb566ce2.png)
_eb4848c2-503c-47b2-a2d3-780d49dcb295.png)
#根据时间戳进行查看
#k8s里面的索引都可以进行查看
_9a9a0ee2-764c-4a65-90e8-a81d5a332f37.png)
#添加上述两段内容即可以按照应用创建索引
web端进行查看验证:
_665c4714-6ab4-4fd6-8cbe-39544ff79f1c.png)
#每个应用就会按天创建一个索引
_698dbcce-97f6-405a-8e5c-b8bf3151e3cd.png)
:选中后直接delete删除,手动删除方式
自动删除方式:(生命周期策略)
_915dffd1-bb1b-42be-a71a-adae253138e7.png)
第二种方式:curator:使用一个脚本方式删除
_d42b6acf-bc9d-4a43-b37e-564950e69362.png)
#给app加一个前缀。放到crontab里面,每天运行进行清理
:当有大量节点时,可以扩展elasticsearch或加一层kafaka(流处理工具,进行缓存),通过logstash进入到elasticsearch
_30a296fa-a051-43e1-927b-9e10549911c0.png)
#生产环境日志较大时,可以使用,kafaka至少三台,也需要搭建集群
:Elasticsearch 集群是一组 Elasticsearch 节点的集合。节点根据用途不同会划分出不同的角色,且节点之间相互通信。Elasticsearch集群常用于处理大规模数据集,目的是实现容错和高可用。Elasticsearch 集群需要一个唯一标识的集群名称来防止不必要的节点加入
:节点是指一个Elasticsearch实例,更确切地说,它是一个Elasticsearch进程。节点可以部署到物理机或者虚拟机上。每当Elasticsearch启动时,节点就会开始运行。每个节点都有唯一标识的名称,在部署多节点集群环境的时候我们要注意不要写错节点名称
:索引是 Elasticsearch 中用于存储和管理相关数据的逻辑容器。索引可以看作数据库中的一个表,它包含了一组具有相似结构的文档。在Elasticsearch中,数据以JSON格式的文档存储在索引内。每个索引具有唯一的名称,以便在执行搜索、更新和删除操作时进行引用。索引的名称可以由用户自定义,但必须全部小写
分片包含索引数据的一个子集,并且其本身具有完整的功能和独立性,可以将分片近似看作“独立索引“,分片是Elasticsearch 分布式存储的基石,是底层的基本读写单元。分片的目的是分割巨大的索引,将数据分散到集群内各处。
分片分为主分片和副本分片,一般情况,一个主分片有多个副本分片。主分片负责处理写入请求和存储数据,副本分片只负责存储数据,是主分片的拷贝,文档会存储在具体的某个主分片和副本分片上
#索引较大时,使用分片。每个分片都是一个索引
_3b5cf6c3-5722-470c-8896-6c0a93f823c6.png)
#分片有主分片和副本分片,用于高可用。主分片可以写数据,分片自动分散到节点上
日期2025.09.10学习日志
:Grafana Loki 是一套功能齐全的日志堆栈组件,与其他日志记录系统不同,Loki 是基于仅索引有关日志元数据的想法而构建的:标签(就像 Prometheus 标签一样)。日志数据本身被压缩然后并存储在对象存储(例如 S3 或 GCS)的块中,甚至存储在本地文件系统上,轻量级的索引和高度压缩的块简化了操作,并显著降低了 Loki 的成本,Loki 更适合中小团队。由于 Loki 使用和 Prometheus 类似的标签概念,所以如果你熟悉 Prometheus 那么将很容易上手,也可以直接和 Grafana 集成,只需要添加 Loki 数据源就可以开始查询日志数据了
:Loki 还提供了一个专门用于日志查询的 LogQL 查询语句,类似于 PromQL,通过 LogQL 我们可以很容易查询到需要的日志,也可以很轻松获取监控指标。Loki 还能够将 LogQL 查询直接转换为 Prometheus 指标。此外 Loki 允许我们定义有关 LogQL 指标的报警,并可以将它们和 Alertmanager 进行对接
_eddf9e66-22d9-4ad5-af58-6523bad8cca5.png)
_b2608737-b51e-42cb-ba5b-9ace7815e7c2.png)
:在grafana里面通过logQL的语法去查询日志,先发到query frontend中,在发到querier中。querier在ingester中拿到日志,ingester在底层中拿到日志,再最后把日志返回到grafana
#可以部署多个loki,每个loki负责一个功能
#backend负责管理规则
: Log-agent 是 Loki 日志代理(agent)的重要组件。它的功能是从系统中收集每个日志,标记它,然后将其发送给 Loki
:Distributor 是一个无状态组件,负责处理和验证从日志代理(如 Promtail)接收的日志,并将日志分发到 ingester
:当 Distributor 收到日志时,它首先验证日志是否符合配置,例如有效标签、不是较旧的时间戳以及日志是否太长。验证完成后,Distributor 会根据一致性哈希将日志分发到每个 ingester,以确保平均分配给每个可用的 ingester
#把日志分开传到后方
:Ingester 负责在其文件系统上存储和索引从 Distributor 收到的日志,并定期将日志传输到持久性存储(长期存储),如 S3
:Ingester 根据配置设置保留策略(自动日志删除时间)。
它使用时间序列数据库以一定的结构格式存储日志,这简化了高效查询和日志过期的过程
:Ruler 是 Loki 的监控和告警组件,其作用是记录指标并根据收到的日志数据触发告警。它不是直接衡量指标,而是将日志数据转换为指标
Ruler 监控日志并在检测到任何问题时发出通知,并通过电子邮件或 Slack 发送通知
#通过logQL的写法
:Querier 负责使用 LogQL 查询语言从存储和 ingester 中查询日志。它根据用户查询(如时间戳、标签等)过滤和聚合日志
查询器缓存之前的查询,以防止一次又一次地查询相同的日志,它只查询一次具有相同时间戳、标签和日志消息的日志
:Query Frontend 是一个与用户交互的无状态组件,它负责处理查询请求、执行查询以及通过 Grafana 仪表板可视化日志
Query Frontend 将大型查询拆分为多个较小的查询,并同时运行所有查询,这可以防止大型查询在单个查询中导致内存问题,并有助于加快执行速度
:Grafana 是一个开源工具,可帮助查询、可视化和监控日志。我们可以将 Loki 与 Grafana 集成,并在仪表板、图表等方式可视化日志数据
Grafana 使用查询语言 LogQL 与 Grafana 集成,我们也可以在 Grafana 中编写 LogQL 查询来过滤和查询日志
:Loki 存储日志数据,提高查询和接收日志的效率。将日志数据压缩成块,根据时间进行组织,并为其提供标签和时间戳。然后,它以键值对格式为每个块创建一个索引,包含块时间戳和标签等
例如:将块的索引视为一本书的索引。
Chunks 和 Index 可以存储在各种后端对象存储或文件系统中。
一旦存储了块,它就会为数据创建一个保留期,并根据保留期自动删除
如果使用文件系统作为存储,则块和索引的默认存储路径是 /var/lib/loki/chunks 和 /var/lib/loki/index
_0f2bbdfd-4669-4d26-b032-caea3e943047.png)
:采集端使用alloy,采集日志后经过loki,存储到minio(开源的对象存储),设置不同功能的loki
:gateway(网关),负责分发流量
_c39477e7-43f1-42d4-84e6-bde9dbb10147.png)
---
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
查询容器 loki-flog-1 产生的所有日志 {container="loki-flog-1"}
_c799eaf6-51a6-4259-a6a1-f235225c20b5.png)
#可查看具体的某个时间端
查询包含 status 的日志行 {container="loki-flog-1"} |= `status`
_ced69695-3b1f-4e5f-956a-94d9a6b901c7.png)
查询 status=404 的日志行 {container="loki-flog-1"} | json | status=`404`
_c4b148e3-1ff9-4040-ab75-449efa697c7f.png)
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