K8S

kubernetes
1 概述
Kubernetes是一款跨节点的容器编排工具,一般情况下都是以集群的方式运行。

官网介绍
Kubernetes也称为K8s,是用于自动部署、扩缩和管理容器化应用程序的开源系统。

它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现。Kubernetes源自Google 15 年生产环境的运维经验,同时凝聚了社区的最佳创意和实践。

Google每周运行数十亿个容器,Kubernetes 基于与之相同的原则来设计,能够在不扩张运维团队的情况下进行规模扩展。

Kubernetes是一款跨节点的容器编排工具,一般情况下都是以集群的方式运行。

官网介绍
Kubernetes也称为K8s,是用于自动部署、扩缩和管理容器化应用程序的开源系统。

它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现。Kubernetes源自Google 15 年生产环境的运维经验,同时凝聚了社区的最佳创意和实践。

Google每周运行数十亿个容器,Kubernetes 基于与之相同的原则来设计,能够在不扩张运维团队的情况下进行规模扩展。

2 简史
– K8S简史
– 2013年docker开源,IT界的福音,备受关注
– 2014.06 Google有15年的容器编排Borg(博格,商业产品)使用经验,并将K8S(基于borg系统使用go语言研发)底层基于docker作为容器运行时开源
– 2014.12 docker inc公司推出了K8S竞品,docker swarm
– Google kubernets vs docker inc swarm 【3年对抗赛】 2017年年底结束,k8s完胜。(k8s 72% vs swarm %13)
– 2014 coreOS 公司推出了rkt容器管理工具并站队K8S
– 2015 Google公司将K8S开源并贡献给了CNCF组织,成为该组织的第一个毕业项目。
– 2015 docker inc公司推出了OCI提议,主要针对容器运行时和镜像规范,并开源了runc。
– 2016 Google推出了CRI规范,目前市面上没有任何产品可以满足,于是就开源了docker-shim组件(会调用docker接口并满足cri规范)支持CRI接口;
– 2016,RedHat公司基于cri-o(既符合CRI也符合OCI规范)开发框架让rkt容器管理工具支持CRI接口;
– 2017,docker inc公司将containerd从docker engine剥离,并将containerd开源给了CNCF组织,
– containerd底层调用runc,因此该产品是支持OCI提议的;
– containerd组件本身不支持CRI,因此社区大佬们(包含国内外)集体开发cri-containerd组件,最后合并到containerd项目
– 2018 年国内开始流程K8S,各大云厂商已经开始大规模使用K8S集群,
– 阿里云的ACK的SAAS产品
– 腾讯云的TKE的SAAS产品
– 华为云的CCE的SAAS产品
– ucloud的UK8S的SAAS产品
– 亚马逊的Amazon EKS的SAAS产品
– 京东云,百度云等
– 2018年,coreOS公司被Redhat以2.5亿美元收购。
– 2018年10月29日,IBM宣布以340亿美元的价格收购Red Hat。
– 曾经一度,Docker方面的炒作非常猛。
– Docker从Greylock Partners、Insight Partners和红杉资本等大牌投资者处筹资超过2.7亿美元,
– 2018年估值达到最高峰:13.2亿美元。
– 2019年2月,Docker一分为二,将企业业务出售给了云咨询公司Mirantis(对于OpenStack代码贡献量非常大,能排到前3)。
– 2020年,Google宣布K8S将在1.22+版本后弃用docker容器运行时,当时年底发布的最新版是1.20.X;
– 2020年3月11日公布的,当时Docker宣布被云计算软件巨头微软(Microsoft)以 6.7亿美元收购。
– 2021年底 K8S 1.23的RC版本发布;
– 2022年初,K8S 1.24横空出世,直接将docker-shim组件移除,而是使用containerd作为容器运行时;
– 2023年初,K8S 1.27.X发布;
– 2023年3月,K8S 1.23.17 发布了最后一个支持docker-shim的版本。
– docker和Mirantis公司作为合作伙伴,将维护该项目,运维小伙伴如果需要在K8S 1.24及以后的版本使用docker的话,需要单独cri-docker组件。
– 2024年初,K8S 1.30.x版本发布
– 2024年12月,K8S 1.32.x版本发布
– 2025年初,K8S 1.33.X版本发布

参考链接:
https://landscape.cncf.io/
3 架构
1 master(contronl plane控制面板)

1.1 etcd
数据库,基于go语言研发

1.2 api-server
k8s集群的访问唯一入口,可以用于认证鉴权,资源访问控制

1.3 scherduler
调度器,负载完成pod的调度

1.4 contronller manager
控制器管理者,维护k8s集群状态

1.5 cloud contronller manager
该组件是可选组件,可以不部署,一般云厂商使用

2 slave(worker node工作节点)
2.1 kubelet
管理pod的生命周期,并监控worker node节点资源状态(cpu,内存,磁盘)和容器状态生命周期性上报给api-server

2.2 kube-proxy
负责完成pod的负载均衡组件,底层支持iptables和ipvs两种调度方式

3 CNI
falnnel,calico…
4 网络类型
1 K8S各组件通信的网络
使用时物理网卡,默认网段: 10.0.0.0/24。

2 跨节点容器实现通信的网段:
用户可以自定义,学习环境推荐: 10.100.0.0/16。

但是在自定义网段时,要考虑将来能够分片的IP地址数量,”10.100.0.0/16″最多有65536个IP地址。

如果将来容器运行的数量超过该规模时,应该考虑将网段地址调大,比如”10.0.0.0/8″。

2 Service网段:
为容器提供负载均衡和服务发现功能。也是需要一个独立的网段,比如”10.200.0.0/16″最多有65536个IP地址。

同理,如果规模较大时,应该考虑网段分配的问题。
5 部署方式
1 官方默认都有两种部署方式: (在生产环境中都可以使用,且都支持高可用环境。咱们学习过程中,建议选择kubeadm。)
1.1 二进制部署K8S集群
手动部署K8S各个组件,配置文件,启动脚本及证书生成,kubeconfig文件。
配置繁琐,对新手不友好,尤其是证书管理。但是可以自定义配置信息,老手部署的话2小时起步,新手20小时+

1.2 kubeadm部署K8S集群
是官方提供的一种快速部署K8S各组件的搭建,如果镜像准备就绪的情况下,基于容器的方式部署。

需要提前安装kubelet,docker或者containerd,kubeadm组件。

配置简单,适合新手。新手在镜像准备好的情况下,仅需要2分钟部署完毕。

2 第三方提供的部署方式:
2.1 国内公司:
– 青云科技: kubesphere
底层基于kubeadm快速部署K8S,提供了丰富的图形化管理界面。
– kuboard
底层基于kubeadm快速部署K8S,提供了丰富的图形化管理界面。
– kubeasz
底层基于二进制方式部署,结合ansible的playbook实现的快速部署管理K8S集群。

2.2 国外的产品:
– rancher:
和国内的kubesphere很相似,也是K8S发行商,提供了丰富的图形化管理界面。
还基于K8S研发出来了K3S,号称轻量级的K8S。

2.3 云厂商:
– 阿里云的ACK的SAAS产品
– 腾讯云的TKE的SAAS产品
– 华为云的CCE的SAAS产品
– ucloud的UK8S的SAAS产品
– 亚马逊的Amazon EKS的SAAS产品
– 京东云,百度云的SAAS产品等。

2.4 其他部署方式:
– minikube:
适合在windows部署K8S,适合开发环境搭建的使用。不建议生产环境部署。

– kind:
可以部署多套K8S环境,轻量级的命令行管理工具。

– yum:
不推荐,版本支持较低,默认是1.5.2。

CNCF技术蓝图:
https://landscape.cncf.io/


3 二进制部署和kubeadm部署的区别:
相同点:
都可以部署K8S高可用集群。

不同点:
– 1.部署难度: kubeadm简单.
– 2.部署时间: kubeadm短时间。
– 3.证书管理: 二进制需要手动生成,而kubeadm自建一个10年的CA证书,各组件证书有效期为1年。
– 4.软件安装: kubeadm需要单独安装kubeadm,kubectl和kubelet组件,由kubelet组件启动K8S其他相关Pod,而二进制需要安装除了kubeadm的其他K8S组件。
6 集群环境准备
1 环境准备
官方文档
https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

环境准备:
硬件配置: 2core 4GB
磁盘: 50GB+
操作系统: Ubuntu 22.04.04 LTS
IP和主机名:
10.0.0.231 master231
10.0.0.232 worker232
10.0.0.233 worker233

k8s版本:1.23.17
原因:此版本是k8s最后一个支持docker-shim的版本,以后都不支持了

2 关闭swap分区(所有节点执行)
swapoff -a && sysctl -w vm.swappiness=0 # 临时关闭
sed -ri ‘/^[^#]*swap/s@^@#@’ /etc/fstab # 基于配置文件关闭

3 确保各个节点mac地址和product_uuid唯一(所有节点执行)
apt install net-tools
ifconfig ens37 | grep ether | awk ‘{print $2}’
cat /sys/class/dmi/id/product_uuid

4 检查网络是否通外网(所有节点执行)
ping baidu.com -c 10

5 允许iptables检查桥接流量(所有节点执行)
cat </etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update

8.3 查看当前环境支持的k8s版本
apt-cache madison kubeadm

8.4 安装kubeadm,kubectl,kubelet
apt-get -y install kubelet=1.23.17-00 kubeadm=1.23.17-00 kubectl=1.23.17-00

8.5 检查各组件版本
kubeadm version
kubelet –verion
kubectl version

参考链接:
https://kubernetes.io/zh/docs/tasks/tools/install-kubectl-linux/

9 检查时区(所有节点执行)
ln -svf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ll /etc/localtime
date -R



此时关机拍快照



7 基于kubeadm组件初始化k8s的master组件
这里所有操作均只对master节点操作

1 提前导入镜像
root@master231:~# docker load -i master-1.23.17.tar.gz
root@master231:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.aliyuncs.com/google_containers/kube-apiserver v1.23.17 62bc5d8258d6 2 years ago 130MB
registry.aliyuncs.com/google_containers/kube-controller-manager v1.23.17 1dab4fc7b6e0 2 years ago 120MB
registry.aliyuncs.com/google_containers/kube-scheduler v1.23.17 bc6794cb54ac 2 years ago 51.9MB
registry.aliyuncs.com/google_containers/kube-proxy v1.23.17 f21c8d21558c 2 years ago 111MB
registry.aliyuncs.com/google_containers/etcd 3.5.6-0 fce326961ae2 2 years ago 299MB
registry.aliyuncs.com/google_containers/coredns v1.8.6 a4ca41631cc7 3 years ago 46.8MB
registry.aliyuncs.com/google_containers/pause 3.6 6270bb605e12 3 years ago 683kB

2 使用kubeadm初始化节点
root@master231:~#kubeadm init –kubernetes-version=v1.23.17 –image-repository registry.aliyuncs.com/google_containers –pod-network-cidr=10.100.0.0/16 –service-cidr=10.200.0.0/16 –service-dns-domain=yangsenlin.top –apiserver-advertise-address=10.0.0.231

相关参数说明:
–kubernetes-version:
指定K8S master组件的版本号。

–image-repository:
指定下载k8s master组件的镜像仓库地址。

–pod-network-cidr:
指定Pod的网段地址。

–service-cidr:
指定SVC的网段

–service-dns-domain:
指定service的域名。若不指定,默认为”cluster.local”。

–apiserver-advertise-address
多网卡指定ip地址

使用kubeadm初始化集群时,可能会出现如下的输出信息:
[init]
使用初始化的K8S版本。

[preflight]
主要是做安装K8S集群的前置工作,比如下载镜像,这个时间取决于你的网速。

[certs]
生成证书文件,默认存储在”/etc/kubernetes/pki”目录哟。

[kubeconfig]
生成K8S集群的默认配置文件,默认存储在”/etc/kubernetes”目录哟。

[kubelet-start]
启动kubelet,
环境变量默认写入:”/var/lib/kubelet/kubeadm-flags.env”
配置文件默认写入:”/var/lib/kubelet/config.yaml”

[control-plane]
使用静态的目录,默认的资源清单存放在:”/etc/kubernetes/manifests”。
此过程会创建静态Pod,包括”kube-apiserver”,”kube-controller-manager”和”kube-scheduler”

[etcd]
创建etcd的静态Pod,默认的资源清单存放在:””/etc/kubernetes/manifests”

[wait-control-plane]
等待kubelet从资源清单目录”/etc/kubernetes/manifests”启动静态Pod。

[apiclient]
等待所有的master组件正常运行。

[upload-config]
创建名为”kubeadm-config”的ConfigMap在”kube-system”名称空间中。

[kubelet]
创建名为”kubelet-config-1.22″的ConfigMap在”kube-system”名称空间中,其中包含集群中kubelet的配置

[upload-certs]
跳过此节点,详情请参考”–upload-certs”

[mark-control-plane]
标记控制面板,包括打标签和污点,目的是为了标记master节点。

[bootstrap-token]
创建token口令,例如:”kbkgsa.fc97518diw8bdqid”。
如下图所示,这个口令将来在加入集群节点时很有用,而且对于RBAC控制也很有用处哟。

[kubelet-finalize]
更新kubelet的证书文件信息

[addons]
添加附加组件,例如:”CoreDNS”和”kube-proxy”

出现以下则说明成功

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run “kubectl apply -f [podnetwork].yaml” with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.0.231:6443 –token v5peds.tj27wmcwsttl2ydk \
–discovery-token-ca-cert-hash sha256:829b9f6b642b548ec4e311028eb6d56c04f3f52240804aa631337ab43165af4d

3 拷贝授权文件,用于管理k8s集群
root@master231:~# mkdir -p $HOME/.kube
root@master231:~# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
root@master231:~# sudo chown $(id -u):$(id -g) $HOME/.kube/config
root@master231:~#

4 查看master组件是否正常工作
root@master231:~# kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
etcd-0 Healthy {“health”:”true”,”reason”:””}
controller-manager Healthy ok

cs是componentstatuses的缩写,所以两个命令效果是一样的
root@master231:~# kubectl get componentstatuses
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {“health”:”true”,”reason”:””}
root@master231:~#

5 查看工作节点
root@master231:~# kubectl get no
NAME STATUS ROLES AGE VERSION
master231 NotReady control-plane,master 4m30s v1.23.17
root@master231:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 NotReady control-plane,master 4m36s v1.23.17
root@master231:~# kubectl get no -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master231 NotReady control-plane,master 4m46s v1.23.17 10.0.0.231 Ubuntu 22.04.4 LTS 5.15.0-136-generic docker://20.10.24
root@master231:~#

6.master初始化不成功解决问题的方法
可能存在的原因:
– 由于没有禁用swap分区导致无法完成初始化;
– 每个2core以上的CPU导致无法完成初始化;
– 没有手动导入镜像;

解决方案:
– 1.检查上面的是否有上面的情况
free -h
lscpu

– 2.重置当前节点环境
[root@master231 ~]# kubeadm reset -f

– 3.再次尝试初始化master节点

8 基于kubeadm部署worker组件
这里所有操作均只对两个worker节点操作,两个worker节点操作不分先后

1 提前导入镜像
root@worker232:~# docker load -i slave-1.23.17.tar.gz
root@worker232:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flannel/flannel v0.24.3 f6f0ee58f497 13 months ago 78.6MB
flannel/flannel-cni-plugin v1.4.0-flannel1 77c1250c26d9 14 months ago 9.87MB
registry.aliyuncs.com/google_containers/kube-proxy v1.23.17 f21c8d21558c 2 years ago 111MB
registry.aliyuncs.com/google_containers/coredns v1.8.6 a4ca41631cc7 3 years ago 46.8MB
registry.aliyuncs.com/google_containers/pause 3.6 6270bb605e12 3 years ago 683kB
root@worker232:~#

2 将worker节点加入到master集群
233节点
root@worker233:~# kubeadm join 10.0.0.231:6443 –token yur5x7.wl1dhvwgbif7n1ac \
–discovery-token-ca-cert-hash sha256:2ebc712f7a7355137b43d67d46c79844898acb4012c508b114f61cfbfb51875b
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster…
[preflight] FYI: You can look at this config file with ‘kubectl -n kube-system get cm kubeadm-config -o yaml’
W0402 11:50:12.272164 59289 utils.go:69] The recommended value for “resolvConf” in “KubeletConfiguration” is: /run/systemd/resolve/resolv.conf; the provided value is: /run/systemd/resolve/resolv.conf
[kubelet-start] Writing kubelet configuration to file “/var/lib/kubelet/config.yaml”
[kubelet-start] Writing kubelet environment file with flags to file “/var/lib/kubelet/kubeadm-flags.env”
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap…

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run ‘kubectl get nodes’ on the control-plane to see this node join the cluster.

root@worker233:~#


232节点
root@worker232:~# kubeadm join 10.0.0.231:6443 –token yur5x7.wl1dhvwgbif7n1ac \
–discovery-token-ca-cert-hash sha256:2ebc712f7a7355137b43d67d46c79844898acb4012c508b114f61cfbfb51875b
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster…
[preflight] FYI: You can look at this config file with ‘kubectl -n kube-system get cm kubeadm-config -o yaml’
W0402 11:49:56.952952 59532 utils.go:69] The recommended value for “resolvConf” in “KubeletConfiguration” is: /run/systemd/resolve/resolv.conf; the provided value is: /run/systemd/resolve/resolv.conf
[kubelet-start] Writing kubelet configuration to file “/var/lib/kubelet/config.yaml”
[kubelet-start] Writing kubelet environment file with flags to file “/var/lib/kubelet/kubeadm-flags.env”
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap…

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run ‘kubectl get nodes’ on the control-plane to see this node join the cluster.

root@worker232:~#



3 验证worker节点是否加入成功(master节点执行)
root@master231:~# kubectl get no
NAME STATUS ROLES AGE VERSION
master231 NotReady control-plane,master 20m v1.23.17
worker232 NotReady 103s v1.23.17
worker233 NotReady 88s v1.23.17
root@master231:~# kubectl get no -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master231 NotReady control-plane,master 20m v1.23.17 10.0.0.231 Ubuntu 22.04.4 LTS 5.15.0-136-generic docker://20.10.24
worker232 NotReady 113s v1.23.17 10.0.0.232 Ubuntu 22.04.4 LTS 5.15.0-119-generic docker://20.10.24
worker233 NotReady 98s v1.23.17 10.0.0.233 Ubuntu 22.04.4 LTS 5.15.0-119-generic docker://20.10.24
root@master231:~#


6 有些时候开机启动cni0可能会消失,需要写一个检查脚本(每个节点执行)
root@master231:~# cat check_cni0.sh
#!/bin/bash

# 检查 cni0 网卡是否存在
if ! ip link show cni0 &> /dev/null; then
echo “cni0 网卡不存在,正在创建…”

# 获取 flannel.1 的 IP 地址段
FLANNEL_IP=$(ip -4 addr show flannel.1 | grep -oP ‘(?<=inet\s)\d+(\.\d+){3}') ​ if [ -z "$FLANNEL_IP" ] ; then echo "无法获取 flannel.1 的 IP 地址或子网掩码,脚本退出。" exit 1 fi ​ # 创建 cni0 网桥 ip link add name cni0 type bridge ​ # 为 cni0 分配与 flannel.1 相同的 IP 地址段 ip addr add $FLANNEL_IP/24 dev cni0 ​ # 启用 cni0 网桥 ip link set cni0 up ​ echo "cni0 网卡已创建并配置完成。" else echo "cni0 网卡已存在,无需创建。" fi ​ root@master231:~# cp check_cni0.sh /usr/local/bin/ root@master231:~# vim /etc/rc.local root@master231:~# vi /etc/rc.local root@master231:~# chmod +x /etc/rc.local root@master231:~# cat /etc/rc.local #!/bin/bash /usr/local/bin/check_cni0.sh ​ root@master231:~# sh check_cni0.sh cni0 网卡不存在,正在创建... 6: cni0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
link/ether b6:bd:ee:6b:55:5a brd ff:ff:ff:ff:ff:ff
RTNETLINK answers: File exists
cni0 网卡已创建并配置完成。



9 部署flannel的CNI插件
CNI
container network interface

1 部署网络插件地址
https://kubernetes.io/docs/concepts/cluster-administration/addons/
点击flannel跳转到github下载地址
https://github.com/flannel-io/flannel#deployslg-flannel-manually

复制flannel资源清单下载地址
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

下载下来后需要做两个步骤
1.1 因为下载的资源清单默认pod-network地址是10.244.0.0/16,需要修改为部署master组件时候设置的10.100.0.0/16

1.2 在kube-flannel.yml中搜索image,使用docker pull拉取涉及到的image(所有节点执行)
root@master231:~# cat kube-flannel.yml | grep image
image: docker.io/flannel/flannel:v0.25.6
image: docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel2
image: docker.io/flannel/flannel:v0.25.6
root@master231:~# docker pull docker.io/flannel/flannel:v0.25.6
root@master231:~# docker pull docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel2

1.3


3 获取资源清单并部署(master节点执行)
部署前集群环境如下
root@master231:~# kubectl get no
NAME STATUS ROLES AGE VERSION
master231 NotReady control-plane,master 8m6s v1.23.17
worker232 NotReady 3m28s v1.23.17
worker233 NotReady 3m20s v1.23.17
root@master231:~# kubectl get no -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master231 NotReady control-plane,master 8m13s v1.23.17 10.0.0.231 Ubuntu 22.04.4 LTS 5.15.0-136-generic docker://20.10.24
worker232 NotReady 3m35s v1.23.17 10.0.0.232 Ubuntu 22.04.4 LTS 5.15.0-119-generic docker://20.10.24
worker233 NotReady 3m27s v1.23.17 10.0.0.233 Ubuntu 22.04.4 LTS 5.15.0-119-generic docker://20.10.24

root@master231:~# kubectl apply -f kube-flannel.yml
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

3 验证flannel是否部署成功(master节点执行)
root@master231:~# kubectl get no
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 39m v1.23.17
worker232 Ready 35m v1.23.17
worker233 Ready 35m v1.23.17
root@master231:~# kubectl get pods -o wide -n kube-flannel
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel-ds-4k9mm 1/1 Running 0 3m58s 10.0.0.233 worker233
kube-flannel-ds-bx879 1/1 Running 0 3m58s 10.0.0.232 worker232
kube-flannel-ds-sb5l9 1/1 Running 0 3m58s 10.0.0.231 master231

4 查看网卡
4.1 master231节点网卡
root@master231:~# ifconfig
docker0: flags=4099 mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:b8:bc:95:18 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens33: flags=4163 mtu 1500
inet 192.168.137.231 netmask 255.255.255.0 broadcast 192.168.137.255
inet6 fe80::250:56ff:fe37:70cb prefixlen 64 scopeid 0x20 ether 00:50:56:37:70:cb txqueuelen 1000 (Ethernet)
RX packets 614472 bytes 882596312 (882.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 110749 bytes 7048996 (7.0 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens37: flags=4163 mtu 1500
inet 10.0.0.231 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::250:56ff:fe35:de69 prefixlen 64 scopeid 0x20 ether 00:50:56:35:de:69 txqueuelen 1000 (Ethernet)
RX packets 9874 bytes 1173652 (1.1 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 117229 bytes 168823751 (168.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

flannel.1: flags=4163 mtu 1450
inet 10.100.0.0 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::c46b:8aff:fea2:d629 prefixlen 64 scopeid 0x20 ether c6:6b:8a:a2:d6:29 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 12 overruns 0 carrier 0 collisions 0

lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 1000 (Local Loopback)
RX packets 320546 bytes 63975014 (63.9 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 320546 bytes 63975014 (63.9 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

root@master231:~#

4.2 worker232节点
root@worker232:~# ifconfig
cni0: flags=4163 mtu 1450
inet 10.100.1.1 netmask 255.255.255.0 broadcast 10.100.1.255
inet6 fe80::b4bd:eeff:fe6b:555a prefixlen 64 scopeid 0x20 ether ea:76:0a:f4:0b:1c txqueuelen 1000 (Ethernet)
RX packets 732 bytes 61883 (61.8 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 752 bytes 92948 (92.9 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

docker0: flags=4099 mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:33:0f:11:e1 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens33: flags=4163 mtu 1500
inet 192.168.137.232 netmask 255.255.255.0 broadcast 192.168.137.255
inet6 fe80::250:56ff:fe26:cd31 prefixlen 64 scopeid 0x20 ether 00:50:56:26:cd:31 txqueuelen 1000 (Ethernet)
RX packets 184295 bytes 264386223 (264.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 33455 bytes 2134847 (2.1 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens37: flags=4163 mtu 1500
inet 10.0.0.232 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::250:56ff:fe24:61f5 prefixlen 64 scopeid 0x20 ether 00:50:56:24:61:f5 txqueuelen 1000 (Ethernet)
RX packets 58631 bytes 84478895 (84.4 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4912 bytes 570292 (570.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

flannel.1: flags=4163 mtu 1450
inet 10.100.1.0 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::68c8:9aff:fe00:1525 prefixlen 64 scopeid 0x20 ether 6a:c8:9a:00:15:25 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 12 overruns 0 carrier 0 collisions 0

lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 1000 (Local Loopback)
RX packets 98 bytes 8093 (8.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 98 bytes 8093 (8.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth294b5b44: flags=4163 mtu 1450
inet6 fe80::403f:99ff:fed5:45df prefixlen 64 scopeid 0x20 ether e2:a3:02:bc:65:b8 txqueuelen 0 (Ethernet)
RX packets 364 bytes 35909 (35.9 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 387 bytes 47387 (47.3 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth31aeeb30: flags=4163 mtu 1450
inet6 fe80::b448:daff:fe51:b1c8 prefixlen 64 scopeid 0x20 ether b6:48:da:51:b1:c8 txqueuelen 0 (Ethernet)
RX packets 370 bytes 36306 (36.3 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 384 bytes 47147 (47.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

root@worker232:~#

4.3 worker233节点
root@worker233:~# ifconfig
docker0: flags=4099 mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:46:66:68:37 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens33: flags=4163 mtu 1500
inet 192.168.137.233 netmask 255.255.255.0 broadcast 192.168.137.255
inet6 fe80::250:56ff:fe27:1b99 prefixlen 64 scopeid 0x20 ether 00:50:56:27:1b:99 txqueuelen 1000 (Ethernet)
RX packets 520244 bytes 767347313 (767.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 44260 bytes 2788219 (2.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens37: flags=4163 mtu 1500
inet 10.0.0.233 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::250:56ff:fe2c:85e1 prefixlen 64 scopeid 0x20 ether 00:50:56:2c:85:e1 txqueuelen 1000 (Ethernet)
RX packets 58657 bytes 84362405 (84.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5025 bytes 609905 (609.9 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

flannel.1: flags=4163 mtu 1450
inet 10.100.2.0 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::a840:1dff:fe4d:6f37 prefixlen 64 scopeid 0x20 ether aa:40:1d:4d:6f:37 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 12 overruns 0 carrier 0 collisions 0

lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 1000 (Local Loopback)
RX packets 110 bytes 9615 (9.6 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 110 bytes 9615 (9.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

root@worker233:~#



查看网络后我们发现
1 master231 多出来一个flannel.1虚拟网卡
2 worker232 节点多出来一个cni0网卡和flannel.1网卡,且是同网段
3 worker233 节点多出来一个flannel.1网卡

按道理来说master231和worker233节点也应该有一个cni0网卡,所以需要手动创建


cni0网卡作用是同节点中pod通信使用的
flannel网卡是集群之间通信

5 cni0网卡重建
注意:
手动创建重启机器后会丢失配置,最好是开机自动巡检

—> 假设 master231的flannel.1是10.100.0.0网段。
root@master231:~# ip link add cni0 type bridge
root@master231:~# ip link set dev cni0 up
root@master231:~# ip addr add 10.100.0.1/24 dev cni0


—> 假设 worker233的flannel.1是10.100.0.0网段。
ip link add cni0 type bridge
ip link set dev cni0 up
ip addr add 10.100.0.1/24 dev cni0

5.1 查看master231节点的网卡
root@master231:~# ifconfig
cni0: flags=4099 mtu 1500
inet 10.100.0.1 netmask 255.255.255.0 broadcast 0.0.0.0
ether b6:bd:ee:6b:55:5a txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
flannel.1: flags=4163 mtu 1450
inet 10.100.0.0 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::c46b:8aff:fea2:d629 prefixlen 64 scopeid 0x20 ether c6:6b:8a:a2:d6:29 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 14 overruns 0 carrier 0 collisions 0


5.2 查看worker232节点网卡
root@worker233:~# ifconfig
cni0: flags=4099 mtu 1500
inet 10.100.2.1 netmask 255.255.255.0 broadcast 0.0.0.0
ether b6:bd:ee:6b:55:5a txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
flannel.1: flags=4163 mtu 1450
inet 10.100.2.0 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::a840:1dff:fe4d:6f37 prefixlen 64 scopeid 0x20 ether aa:40:1d:4d:6f:37 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 14 overruns 0 carrier 0 collisions 0
10 验证pod的CNI网络是否正常
1 编写pod资源清单
root@master231:~# mkdir -pv /manifests/pods
cd /manifests/pods
root@master231:/manifests/pods# cat > network-cni-test.yaml <
xiuxian-v2 1/1 Running 0 7s 10.100.2.5 worker233


11 kubectl 工具实现自动补全功能
root@master231:/manifests/pods# kubectl completion bash > ~/.kube/completion.bash.inc
root@master231:/manifests/pods# echo source ‘$HOME/.kube/completion.bash.inc’ >> ~/.bashrc
root@master231:/manifests/pods# source ~/.bashrc
root@master231:/manifests/pods#

再次关机拍快照

12 主机巡检流程
1 查看master组件是否正常
root@master231:~# kubectl get cs

2 查看工作节点是否就绪
root@master231:~# kubectl get no

3 查看flannel组件是否正常运行
root@master231:~# kubectl get pods -o wide -n kube-flannel

4 检查网卡flannel.1和cni0
root@master231:~# ifconfig


13 部署k8s可能会出现的错误
1 时区配置错误;
2 初始化失败可能是cpu核心不足,内存没有禁用swap
3 镜像拉取失败,在对应节点手动导入镜像
4 节点名称不一致,需要修改过来,建议重做,加深印象;
5 flannel.1和cni0网段不一致,删除cni0网卡继续执行
ip link del cni0 type bridge

6 虚拟机无法联网,检查配置是否正确:
7 虚拟机开不起来了;
14 k8s资源
linux 一切皆文件,k8s一切皆资源

1 查看k8s集群内置资源
随着后期的附加组件部署,资源的种类会增多
root@master231:~# kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus


1.1 NAME
资源的名称
1.2 SHORTNAMES
资源的简称
1.3 APIVERSION
资源的api版本号
1.4 NAMESPACED
是否支持名称空间
1.5 KIND
资源的类型
15 资源清单的结构
1 apiVersion:
资源的API版本号,固定的,但是定义时必须声明

2 kind
资源的类型。固定的,但是定义时必须声明

3 metadata
元数据资源,用于描述资源的信息,包括但不限于:name,labels,namespace,annotations

4 spec
期望资源运行的状态

5 status
资源的实际状态,由k8s自行维护

16 资源清单的创建、查看和删除
1 编写资源清单
root@master231:/manifests/pods# cat 01-pods-xiuxian.yaml
#声明资源的版本号
apiVersion: v1
#声明资源的类型
kind: Pod
#声明资源的元数据信息
metadata:
#声明资源的名称
name: xiuxian
#定义资源的期望状态
spec:
#定义容器的相关配置
containers:
#定义容器的名称
– name: c1
#定义镜像名称
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

2 创建资源
2.1 create(非幂等性)
kubectl create -f 01-pods-xiuxian.yaml

2.2 apply(幂等性)
kubectl apply -f 01-pods-xiuxian.yaml

幂等操作:多次执行相同的操作,结果保持一致。
非幂等操作:多次执行相同的操作,可能会导致不同的结果

3 查看资源
root@master231:/manifests/pods# kubectl apply -f 01-pods-xiuxian.yaml
pod/xiuxian created

root@master231:/manifests/pods# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian 1/1 Running 0 38s 10.100.2.8 worker233

相关资源说明:
3.1 NAME
资源的名称。

3.2 READY:
以”/”为分隔符,右侧的数字表示Pod有多少个容器。左侧的数字表示Pod内有多少个容器处于运行状态。

3.3 STATUS:
资源是否处于就绪状态,目前认为”Running”就表示资源处于正常运行状态。

3.4 RESTARTS:
Pod内容器的重启次数总和。

3.5 AGE:
表示该资源创建的时间统计。

3.6 IP:
表示Pod的IP地址。

3.7 NODE:
表示Pod调度到哪个worker node节点。

4 删除资源
root@master231:/manifests/pods# kubectl delete -f 01-pods-xiuxian.yaml
pod “xiuxian” deleted
root@master231:/manifests/pods# kubectl get pods -o wide
No resources found in default namespace.

5 声明是标签管理的pod资源删除
root@master231:/manifests/pods# kubectl apply -f 02-pods-xiuxian-labels.yaml
pod/xiuxian-labels created
root@master231:/manifests/pods# cat 02-pods-xiuxian-labels.yaml
apiVersion: v1
kind: Pod
metadata:
name: xiuxian-labels
#给资源打标签,标签的key和value都可以自定义
labels:
xingming: zhangsan
city: Sichuan
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
root@master231:/manifests/pods#

6 查看资源标签
root@master231:/manifests/pods# kubectl get pods -o wide –show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
xiuxian-labels 1/1 Running 0 52s 10.100.2.9 worker233 city=Sichuan,xingming=zhangsan

7 基于标签匹配pod,从而删除pod
root@master231:/manifests/pods# kubectl delete pods -l city=Sichuan
pod “xiuxian-labels” deleted
root@master231:/manifests/pods#

8 基于资源的名称删除pod
root@master231:/manifests/pods# kubectl delete pod xiuxian-labels
pod “xiuxian-labels” deleted
17 响应式管理pod资源
1 创建pod资源
root@master231:/manifests/pods# kubectl run xiuxian –image=crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
pod/xiuxian created

2 查看pod资源
root@master231:/manifests/pods# kubectl get pods
NAME READY STATUS RESTARTS AGE
xiuxian 1/1 Running 0 29s

3 给资源打标签
root@master231:/manifests/pods# kubectl get pods –show-labels
NAME READY STATUS RESTARTS AGE LABELS
xiuxian 1/1 Running 0 73s run=xiuxian

root@master231:/manifests/pods# kubectl label pod xiuxian xingming=zhangsan city=Sichuan
pod/xiuxian labeled
root@master231:/manifests/pods# kubectl get pods –show-labels
NAME READY STATUS RESTARTS AGE LABELS
xiuxian 1/1 Running 0 4m57s city=Sichuan,run=xiuxian,xingming=zhangsan
root@master231:/manifests/pods#

4 修改资源标签
root@master231:/manifests/pods# kubectl label pods xiuxian city=cq –overwrite
pod/xiuxian unlabeled
root@master231:/manifests/pods# kubectl get pods –show-labels
NAME READY STATUS RESTARTS AGE LABELS
xiuxian 1/1 Running 0 8m15s city=cq,run=xiuxian,xingming=zhangsan
root@master231:/manifests/pods#

5 删除资源
root@master231:/manifests/pods# kubectl delete pods –all
pod “xiuxian” deleted
18 指定nodeName节点调度
1 编写资源清单
root@master231:/manifests/pods# cat 03-pods-xiuxian-nodeName.yaml
apiVersion: v1
kind: Pod
metadata:
name: xiuxian-nodename
labels:
xingming: zhangsan
city: Sichuan
spec:
nodeName: worker232
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

2 部署应用
root@master231:/manifests/pods# kubectl apply -f 03-pods-xiuxian-nodeName.yaml
pod/xiuxian-nodename created
root@master231:/manifests/pods#
19 hostNetwork使用宿主机网络
[root@master231 pods]# cat 04-pods-xiuxian-hostNetwork.yaml
apiVersion: v1
kind: Pod
metadata:
name: ysl-ysl-hostnetwork
labels:
school: ysl
class: ysl
spec:
# 使用宿主机网络,不为容器分配网络名称空间
hostNetwork: true
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
[root@master231 pods]#

2 部署服务
root@master231:/manifests/pods# kubectl apply -f 04-pods-xiuxian-hostNetwork.yaml
pod/xiuxian-hostnetwork created

3 windows访问测试
http://10.0.0.233
20 将多个资源合并为一个资源清单
1 同时执行多个资源清单文件创建多个资源
root@master231:/manifests/pods# kubectl apply -f 03-pods-xiuxian-nodeName.yaml -f 04-pods-xiuxian-hostNetwork.yaml
pod/xiuxian-nodename created
pod/xiuxian-hostnetwork created

2 将多个资源卸载同一个资源清单中
root@master231:/manifests/pods# cat 05-pods-all-in-one-file.yaml
apiVersion: v1
kind: Pod
metadata:
name: xiuxian-v1
labels:
apps: v1
spec:
hostNetwork: true
nodeName: worker232
containers:
– image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
name: xiuxian

# 此处的”—“表示一个文件的结束


apiVersion: v1
kind: Pod
metadata:
name: xiuxian-v2
labels:
apps: v2
spec:
hostNetwork: true
nodeName: worker233
containers:
– image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2

root@master231:/manifests/pods# kubectl apply -f 05-pods-all-in-one-file.yaml
pod/xiuxian-v1 created
pod/xiuxian-v2 created
21 容器的类型
1 基础架构容器
pause:3.6

优先于业务容器启动,负责名称空间的初始化工作。
其中,基础架构容器的ipc,net,time,user这四个名称空间会被业务容器共享

2 初始化容器
初始化容器在基础架构容器之后启动,在业务容器之前运行的容器
业务容器可以定义多个,当所有的初始化容器都执行完毕后才回去执行业务容器

一般初始化容器的应用场景是为业务容器做一些初始化的动作而设定的,如果没有必要,可以不定义初始化容器

3 业务容器
指的是实际用户运行的容器

4 删除业务容器时,业务容器会自动启动,启动后地址并不会变动

5 删除基础架构容器时,此基础架构容器会重新初始化,导致ip地址变动

6 验证基础架构容器和业务容器的关系

6.1 在master231节点上部署应用
root@master231:/manifests/pods# kubectl apply -f 05-pods-all-in-one-file.yaml
pod/xiuxian-v1 created
pod/xiuxian-v2 created

6.2 在worker233节点上查看容器
root@worker233:~# docker ps -a | grep xiuxian-
2b49ec88c400 d65adc8a2f32 “/docker-entrypoint.…” 19 seconds ago Up 18 seconds k8s_xiuxian_xiuxian-v2_default_0cd7f72e-cd5b-4560-a731-8d9be81c6577_0
e67f1c3cfa44 f28fd43be4ad “/docker-entrypoint.…” 19 seconds ago Up 18 seconds k8s_xiuxian_xiuxian-v1_default_8d1b9146-2542-485e-b1d5-1d3319a0a515_0
3bb838ecd88c registry.aliyuncs.com/google_containers/pause:3.6 “/pause” 19 seconds ago Up 18 seconds k8s_POD_xiuxian-v2_default_0cd7f72e-cd5b-4560-a731-8d9be81c6577_0
2d49b42ccea4 registry.aliyuncs.com/google_containers/pause:3.6 “/pause” 19 seconds ago Up 18 seconds k8s_POD_xiuxian-v1_default_8d1b9146-2542-485e-b1d5-1d3319a0a515_0

6.3 在worker233节点查看xiuxian:v1的基础架构容器进程和业务容器进程
root@worker233:~# docker inspect -f “{{.State.Pid}}” 2d49b42ccea4
257658
root@worker233:~# docker inspect -f “{{.State.Pid}}” e67f1c3cfa44
257870

root@worker233:~# ll /proc/257658/ns ####基础架构容器的名称空间
total 0
dr-x–x–x 2 65535 65535 0 Apr 6 20:25 ./
dr-xr-xr-x 9 65535 65535 0 Apr 6 20:25 ../
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 cgroup -> ‘cgroup:[4026532744]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:25 ipc -> ‘ipc:[4026532658]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 mnt -> ‘mnt:[4026532656]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:25 net -> ‘net:[4026532671]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 pid -> ‘pid:[4026532659]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 pid_for_children -> ‘pid:[4026532659]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 time -> ‘time:[4026531834]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 time_for_children -> ‘time:[4026531834]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 user -> ‘user:[4026531837]’
lrwxrwxrwx 1 65535 65535 0 Apr 6 20:29 uts -> ‘uts:[4026532657]’
root@worker233:~# ll /proc/257870/ns ####业务容器的名称空间
total 0
dr-x–x–x 2 root root 0 Apr 6 20:30 ./
dr-xr-xr-x 9 root root 0 Apr 6 20:25 ../
lrwxrwxrwx 1 root root 0 Apr 6 20:30 cgroup -> ‘cgroup:[4026532820]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 ipc -> ‘ipc:[4026532658]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 mnt -> ‘mnt:[4026532817]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 net -> ‘net:[4026532671]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 pid -> ‘pid:[4026532819]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 pid_for_children -> ‘pid:[4026532819]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 time -> ‘time:[4026531834]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 time_for_children -> ‘time:[4026531834]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 user -> ‘user:[4026531837]’
lrwxrwxrwx 1 root root 0 Apr 6 20:30 uts -> ‘uts:[4026532818]’

从对比来看,业务容器的名称空间和基础架构容器的名称空间有以下4点是相同的
ipc,net,time,user


7 验证初始化容器和业务容器的执行顺序
root@master231:/manifests/pods# cat 06-pods-xiuxian-initContainers.yaml
apiVersion: v1
kind: Pod
metadate:
name: xiuxian-initcontainers
labels:
xm: yanzhenginitcontainers
spec:
nodeName: worker233
initContainers:
– name: init01
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
# 用于替代Dockerfile的ENTRYPOINT指令
command: [“sleep”,”30″]
– name: init02
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command: [“sleep”,”10″]
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

[root@master231 pods]# kubectl apply -f 06-pods-xiuxian-initContainers.yaml

[root@worker233 ~]# docker ps -a | grep xiuxian-initcontainers



8 一个pod启动多个容器
root@master231:/manifests/pods# kubectl apply -f 07-pods-multiple.yaml
pod/multiple-containers created
root@master231:/manifests/pods# kubectl get pods
NAME READY STATUS RESTARTS AGE
multiple-containers 2/2 Running 0 4s
root@master231:/manifests/pods# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
multiple-containers 2/2 Running 1 (6s ago) 16s 10.100.2.18 worker233
root@master231:/manifests/pods# cat 07-pods-multiple.yaml
apiVersion: v1
kind: Pod
metadata:
name: multiple-containers
labels:
xm: zhangsan
city: Sichuan
spec:
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command: [“sleep”,”30″]
– name: c2
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command: [“sleep”,”10″]
root@master231:/manifests/pods#
22 pod排障命令
1 查看描述describe
root@master231:/manifests/pods# cat 08-pods-describe.yaml
apiVersion: v1
kind: Pod
metadata:
name: multiple-describe
labels:
name: describe
spec:
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v111111111

root@master231:/manifests/pods# kubectl apply -f 08-pods-describe.yaml
pod/multiple-describe created
root@master231:/manifests/pods# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
multiple-describe 0/1 ErrImagePull 0 14s 10.100.2.19 worker233

root@master231:/manifests/pods#

root@master231:/manifests/pods# kubectl describe pod multiple-describe

Normal Pulling 69s (x4 over 2m36s) kubelet Pulling image “crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v111111111”
Warning Failed 68s (x4 over 2m34s) kubelet Failed to pull image “crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v111111111”: rpc error: code = Unknown desc = Error response from daemon: manifest for crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v111111111 not found: manifest unknown: manifest unknown
Warning Failed 68s (x4 over 2m34s) kubelet Error: ErrImagePull
Warning Failed 41s (x6 over 2m34s) kubelet Error: ImagePullBackOff
Normal BackOff 27s (x7 over 2m34s) kubelet Back-off pulling image “crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v111111111”
root@master231:/manifests/pods#

此处就可以定位问题
修改资源清单中的错误即可

2 执行命令exec
root@master231:/manifests/pods# kubectl delete -f 08-pods-describe.yaml
pod “multiple-describe” deleted
root@master231:/manifests/pods# kubectl apply -f 09-pods-exec.yaml
pod/ysl-multiple-exec created
root@master231:/manifests/pods# cat 09-pods-exec.yaml
apiVersion: v1
kind: Pod
metadata:
name: multiple-exec
labels:
xm: zhangsan
city: Sichuan
spec:
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command: [“tail”,”-f”,”/etc/hosts”]
– name: c2
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command: [“sleep”,”3600″]

2.1 执行命令查看
root@master231:/manifests/pods# kubectl exec -it multiple-exec -c c1 — ifconfig
eth0 Link encap:Ethernet HWaddr 1A:7B:FD:6C:92:F9
inet addr:10.100.2.21 Bcast:10.100.2.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1
RX packets:7 errors:0 dropped:0 overruns:0 frame:0
TX packets:1 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:666 (666.0 B) TX bytes:42 (42.0 B)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

root@master231:/manifests/pods#

2.2 进入容器查看
root@master231:/manifests/pods# kubectl exec -it multiple-exec -c c1 — sh
/ # ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0@if16: mtu 1450 qdisc noqueue state UP
link/ether 1a:7b:fd:6c:92:f9 brd ff:ff:ff:ff:ff:ff
inet 10.100.2.21/24 brd 10.100.2.255 scope global eth0
valid_lft forever preferred_lft forever
/ #


3 查看日志 logs
root@master231:/manifests/pods# cat 10-pods-logs.yaml
apiVersion: v1
kind: Pod
metadata:
name: multiple-logs
labels:
xingming: zhangsan
city: Sichuan
spec:
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
root@master231:/manifests/pods# kubectl apply -f 10-pods-logs.yaml
pod/multiple-logs created
root@master231:/manifests/pods# kubectl get pods
NAME READY STATUS RESTARTS AGE
multiple-logs 1/1 Running 0 14s

3.1 查看实时日志
root@master231:/manifests/pods# kubectl logs -f multiple-logs

3.2 查看最近2分钟日志
root@master231:/manifests/pods# kubectl logs -f –since 2m multiple-logs

3.3 查看指定容器的日志
root@master231:/manifests/pods# kubectl logs -f –since 2m multiple-logs -c c1

3.4 查看容器重启前上一个容器的日志(前提是该容器还存在)
root@master231:/manifests/pods# kubectl logs -f multiple-logs -c c1 -p

4 重启策略restartPolicy
root@master231:/manifests/pods# cat 11-pods-restartPolicy.yaml
apiVersion: v1
kind: Pod
metadata:
name: restartpolicy
labels:
xingming: zhangsan
city: Sichuan
spec:
# 指定容器的重启策略,默认值为Always,有效值为: Always, OnFailure,Never。
# Always:
# 无论容器是否正常退出,始终重启容器。
# Never:
# 无论容器是否正常退出,始终不重启容器。
# OnFailure:
# 当容器异常退出时,才会重启容器,正常退出时不重启。
# restartPolicy: Always
# restartPolicy: Never
restartPolicy: OnFailure
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
# command: [“sleep”,”10″]
command:
– “sleep”
– “30”

root@master231:/manifests/pods# kubectl apply -f 11-pods-restartPolicy.yaml

5 复制 cp
root@master231:/manifests/pods# cat 12-pods-cp.yaml
apiVersion: v1
kind: Pod
metadata:
name: xiuxian-cp
labels:
xingming: zhangsan
city: Sichuan
spec:
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

5.1 将宿主机的文件拷贝到容器的指定目录
root@master231:/manifests/pods# kubectl cp 12-pods-cp.yaml xiuxian-cp:/12-pods-cp.yaml
root@master231:/manifests/pods# kubectl exec -it xiuxian-cp — ls -l /
total 76
-rw-r–r– 1 root root 253 Apr 6 13:16 12-pods-cp.yaml

5.2 将容器内的文件拷贝到宿主机
root@master231:/manifests/pods# kubectl cp xiuxian-cp:/docker-entrypoint.sh /root/docker-entrypoint.sh
tar: removing leading ‘/’ from member names
root@master231:/manifests/pods# ll /root/docker-entrypoint.sh
-rw-r–r– 1 root root 1202 Apr 6 21:17 /root/docker-entrypoint.sh

注意:
容器和宿主机之间拷贝东西都是文件对文件,目录对目录

6 文档说明 explain
root@master231:/manifests/pods# cat 13-pods-explain.yaml
apiVersion: v1
kind: Pod
metadata:
name: xiuxian-explain
labels:
xingming: zhangsan
city: Sichuan
spec:
restartpolicy: Always #此处故意写错测试
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
root@master231:/manifests/pods# kubectl apply -f 13-pods-explain.yaml
error: error validating “13-pods-explain.yaml”: error validating data: ValidationError(Pod.spec): unknown field “restartpolicy” in io.k8s.api.core.v1.PodSpec; if you choose to ignore these errors, turn validation off with –validate=false


6.1 查看explain说明文档看有哪些字段
root@master231:/manifests/pods# kubectl explain pod.spec


[root@master231 pods]# kubectl explain po.spec.containers.command
[root@master231 pods]# kubectl explain po.spec.containers.args
[root@master231 pods]# kubectl explain po.spec.containers.ports
[root@master231 pods]# kubectl explain po.metadata
[root@master231 pods]# kubectl explain po.metadata.labels


7 入口命令和参数 command args
root@master231:/manifests/pods# cat 14-pods-command-args.yaml
apiVersion: v1
kind: Pod
metadata:
name: command-args
labels:
xingming: zhangsan
city: Sichuan
spec:
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
– name: c2
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
# 相当于替换ENTRYPOINT指令
#command:
#- tail
#- -f
#- /etc/hosts
command:
– tail
# 相当于替换CMD指令,当command和args同时使用时,args将作为参数传递给command
args:
– -f
– /etc/hosts

root@master231:/manifests/pods# kubectl apply -f 14-pods-command-args.yaml
pod/command-args created

7.1 查看容器的启动命令
root@worker233:~# docker ps -a | grep command-args
a8106258232d f28fd43be4ad “tail -f /etc/hosts” About a minute ago Up About a minute k8s_c2_command-args_default_f39178d8-bfee-4d4f-8350-14622951e3ba_0
e1522eda135f f28fd43be4ad “/docker-entrypoint.…” About a minute ago Up About a minute k8s_c1_command-args_default_f39178d8-bfee-4d4f-8350-14622951e3ba_0
ec9be95027f8 registry.aliyuncs.com/google_containers/pause:3.6 “/pause” About a minute ago Up About a minute k8s_POD_command-args_default_f39178d8-bfee-4d4f-8350-14622951e3ba_0
23 端口暴露
root@master231:/manifests/pods# cat 15-pods-ports.yaml
apiVersion: v1
kind: Pod
metadata:
name: ysl-ports
labels:
xingming: zhangsan
city: Sichuan
spec:
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
# 配置容器的端口映射,如果容器监听端口,此配置应该配置上便于用户识别。
# 当然,尽管你的容器监听了80端口,不配置此字段也是可以的,但用户体验不好。
ports:
# 容器监听的端口
– containerPort: 80
# 表示容器端口使用的协议,支持的协议为: UDP, TCP, or SCTP
protocol: TCP
# 给端口起名字
name: nginx
# 绑定worker节点的IP地址
hostIP: 0.0.0.0
# 将容器绑定到worker节点的81端口,有点类似于docker的端口映射: docker run -p 81:80 …
# 一旦配置了该字段,就会修改worker节点的iptables规则,这一点和docker很相似,但是docker会监听端口
hostPort: 81
– containerPort: 9200
name: es-http
– containerPort: 9300
name: es-tcp
– containerPort: 21
– containerPort: 20
root@master231:/manifests/pods# kubectl apply -f 15-pods-ports.yaml
pod/ysl-ports created

root@master231:/manifests/pods# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ysl-ports 1/1 Running 0 111s 10.100.2.26 worker233
root@master231:/manifests/pods#

root@worker233:~# iptables-save | grep 81
-A CNI-DN-def73841a3876e584d36b -p tcp -m tcp –dport 81 -j DNAT –to-destination 10.100.2.26:80

24 安装各种应用
安装gitlab、jenkins、sonarqube、mysql、wordpress、elasticsearch、kibana
提前导入镜像,或者官网下载

1 gitlab
root@master231:/manifests/pods# cat 16-pods-casedemo-gitlab.yaml
apiVersion: v1
kind: Pod
metadata:
name: gitlab
labels:
apps: gitlab
spec:
hostNetwork: true
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
image: gitlab/gitlab-ce:17.5.2-ce.0
ports:
– containerPort: 80
root@master231:/manifests/pods# kubectl apply -f 16-pods-casedemo-gitlab.yaml
pod/gitlab created
root@master231:/manifests/pods# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINE
gitlab 1/1 Running 0 11s 10.0.0.233 worker233

1.1 查看初始密码

root@master231:/manifests/pods# kubectl exec -it gitlab — cat /etc/gitlab/initial_root_password
# WARNING: This value is valid only in the following conditions
# 1. If provided manually (either via `GITLAB_ROOT_PASSWORD` environment variable or via `gitlab_rails[‘initial_root_password’]` setting in `gitlab.rb`, it was provided before database was seeded for the first time (usually, the first reconfigure run).
# 2. Password hasn’t been changed manually, either via UI or via command line.
#
# If the password shown here doesn’t work, you must reset the admin password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.

Password: uhyTfFUBOH55+kasoiSkeD6n4g0gD4YXunE5UW14ddQ=

1.2 登录测试
http://192.168.137.233
root/密码



2 jenkins
root@master231:/manifests/pods# cat 17-pod-jenkins.yaml
apiVersion: v1
kind: Pod
metadata:
name: jenkins
labels:
apps: jenkins
spec:
hostNetwork: true
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
image: jenkins/jenkins:2.479.1-alpine-jdk21
ports:
– containerPort: 8080
root@master231:/manifests/pods# kubectl apply -f 17-pod-jenkins.yaml
pod/jenkins created
root@master231:/manifests/pods#

2.1 查看密码

root@master231:/manifests/pods# kubectl logs jenkins

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

cd814b0c82284265820e5cba45998658

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

*************************************************************
*************************************************************
*************************************************************

root@master231:/manifests/pods# kubectl exec -it jenkins — cat /var/jenkins_home/secrets/initialAdminPassword
cd814b0c82284265820e5cba45998658
root@master231:/manifests/pods#

2.2 访问测试
http://192.168.137.233:8080


3 sonarqube
root@master231:/manifests/pods# cat 18-pods-sonarqube.yaml
apiVersion: v1
kind: Pod
metadata:
name: sonarqube
labels:
apps: sonarqube
spec:
hostNetwork: true
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
image: sonarqube:9.9.7-community
ports:
– containerPort: 9000
root@master231:/manifests/pods# kubectl apply -f 18-pods-sonarqube.yaml
pod/sonarqube created

3.1访问测试
http://192.168.137.233:9000


4 mysql
root@master231:/manifests/pods# cat 19-pods-mysql.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-env
labels:
apps: mysql
spec:
hostNetwork: true
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
image: mysql:8.0.36-oracle
# 启动容器时,传递参数
args:
– –character-set-server=utf8
– –collation-server=utf8_bin
– –default-authentication-plugin=mysql_native_password
ports:
– containerPort: 3306
# 向容器传递环境变量
env:
# 指定变量的名称
– name: MYSQL_ALLOW_EMPTY_PASSWORD
# 向变量传递值
value: “yes”
– name: MYSQL_DATABASE
value: test
– name: MYSQL_USER
value: test
– name: MYSQL_PASSWORD
value: “123456”
root@master231:/manifests/pods# kubectl apply -f 19-pods-mysql.yaml
pod/mysql-env created

4.1 测试
root@master231:/manifests/pods# kubectl exec -it mysql-env — mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.36 MySQL Community Server – GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql>


5 wordpress
root@master231:/manifests/pods# cat 20-pods-wordpress.yaml
apiVersion: v1
kind: Pod
metadata:
name: wp
labels:
apps: mysql
spec:
hostNetwork: true
restartPolicy: Always
nodeName: worker233
containers:
– name: c1
# WordPress关于下面2个镜像启动的是9000端口,默认启用了php-fpm进程
# image: wordpress:php8.3-fpm-alpine
# image: wordpress:6.7.1-php8.3-fpm-alpine
# 推荐使用下面的镜像,默认启动的是80端口,进程包含apache
image: wordpress:6.7.1-php8.1-apache
ports:
– containerPort: 80
env:
– name: WORDPRESS_DB_HOST
value: 10.0.0.233
– name: WORDPRESS_DB_NAME
value: wordpress
– name: WORDPRESS_DB_USER
value: wordpress
– name: WORDPRESS_DB_PASSWORD
value: “123456”
[root@master231 pods]# kubectl apply -f 20-pods-wordpress.yaml
pod/wp created
[root@master231 pods]#
[root@master231 pods]# kubectl get pods -o wide

5.1 访问测试
http://192.168.137.233

6 elasticsearch
root@master231:/manifests/pods# cat 21-pods-es.yaml
apiVersion: v1
kind: Pod
metadata:
name: single-es
labels:
apps: es7
spec:
hostNetwork: true
nodeName: worker233
containers:
– name: c1
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.24
ports:
– containerPort: 9200
name: http
– containerPort: 9300
name: tcp
env:
– name: discovery.type
value: single-node
– name: cluster.name
value: es7
– name: ES_JAVA_OPTS
value: -Xms256m -Xmx256m

root@master231:/manifests/pods# kubectl apply -f 21-pods-es.yaml
pod/single-es created

6.1 访问测试
root@master231:/manifests/pods# curl http://10.0.0.233:9200


7 kibana
root@master231:/manifests/pods# cat 22-pods-kibana.yaml
apiVersion: v1
kind: Pod
metadata:
name: kibana
labels:
apps: kibana
spec:
hostNetwork: true
nodeName: worker233
containers:
– name: c1
image: docker.elastic.co/kibana/kibana:7.17.24
ports:
– containerPort: 5601
name: webui
env:
– name: ELASTICSEARCH_HOSTS
value: http://10.0.0.233:9200
– name: I18N_LOCALE
value: zh-CN
root@master231:/manifests/pods# kubectl apply -f 22-pods-kibana.yaml
pod/kibana created

7.1 访问测试
http://10.0.0.233:5601/
25 控制器
常见控制器:
rc,rs,deployment,ds,job,cj

使用kubectl api-resources查看以下所有控制器


1 rc

1.1 rc概述
rc的全称为“replicationcontronllers”,表示副本控制器

1.2 创建资源并部署
root@master231:/manifests/replicationcontrollers# cat 01-rc-xiuxian.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: xiuxian-rc
labels:
xingming: zhangsan
spec:
# 创建Pod的副本数量
replicas: 3
# 当前控制器关联的Pod标签,如果不写,则默认为template字段中的pod标签。
selector:
apps: xiuxian
city: Sichuan
# 定义Pod的模板
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
root@master231:/manifests/replicationcontrollers# kubectl apply -f 01-rc-xiuxian.yaml
replicationcontroller/xiuxian-rc created
root@master231:/manifests/replicationcontrollers#

root@master231:/manifests/replicationcontrollers# kubectl get rc,pods –show-labels -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR LABELS
replicationcontroller/xiuxian-rc 3 3 3 44s c1 crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1 apps=xiuxian,city=Sichuan xingming=zhangsan

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
pod/xiuxian-rc-7dv8t 1/1 Running 0 44s 10.100.1.22 worker232 apps=xiuxian,city=Sichuan,xingming=lisi
pod/xiuxian-rc-p84m5 1/1 Running 0 44s 10.100.1.21 worker232 apps=xiuxian,city=Sichuan,xingming=lisi
pod/xiuxian-rc-qhx6g 1/1 Running 0 44s 10.100.1.23 worker232 apps=xiuxian,city=Sichuan,xingming=lisi


1.3 删除pod和删除rc资源对比
1.3.1 删除pod
root@master231:/manifests/replicationcontrollers# kubectl delete pods –all
pod “xiuxian-rc-7dv8t” deleted
pod “xiuxian-rc-p84m5” deleted
pod “xiuxian-rc-qhx6g” deleted
root@master231:/manifests/replicationcontrollers# kubectl get rc,pods
NAME DESIRED CURRENT READY AGE
replicationcontroller/xiuxian-rc 3 3 3 2m56s

NAME READY STATUS RESTARTS AGE
pod/xiuxian-rc-bnsdw 1/1 Running 0 12s
pod/xiuxian-rc-mqvhw 1/1 Running 0 12s
pod/xiuxian-rc-rzvtv 1/1 Running 0 12s

1.3.2 删除rc
root@master231:/manifests/replicationcontrollers# kubectl delete xiuxian-rc
replicationcontroller “xiuxian-rc” deleted
root@master231:/manifests/replicationcontrollers# kubectl get rc,pods
No resources found in default namespace.

结论:
rc控制器部署资源后,删除pod是无效的,会被rc重新拉起来,但是删除rc后,pod会被级联删除


2 rs
2.1 rs概述
replicaset和rc功能类似,也是保证pod副本数量始终存活,但是比rc更加轻量级,功能更加完善

2.2 创建资源并部署
root@master231:~/manifests/replicasets# cat 01-rs-matchLabels-xiuxian.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-xiuxian
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
# 基于标签匹配Pod
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:~/manifests/replicasets# kubectl apply -f 01-rs-matchLabels-xiuxian.yaml
replicaset.apps/rs-xiuxian created
root@master231:~/manifests/replicasets# kubectl get pods
NAME READY STATUS RESTARTS AGE
rs-xiuxian-9mbr7 1/1 Running 0 4s
rs-xiuxian-rbfh2 1/1 Running 0 4s
rs-xiuxian-rr6pd 1/1 Running 0 4s
rs-xiuxian-t4nlz 1/1 Running 0 4s
rs-xiuxian-w82zk 1/1 Running 0 4s

2.3 rs可以实现rc没有的功能
2.3.1 环境准备
root@master231:~/manifests/replicasets# kubectl run test01 –image=crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1 -l apps=v1
pod/test01 created
root@master231:~/manifests/replicasets# kubectl run test02 –image=crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2 -l apps=v2
pod/test02 created

2.3.2 部署应用
root@master231:~/manifests/replicasets# cat 02-rs-matchExpressions-xiuxian.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-xiuxian
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
# 基于标签表达式匹配Pod标签
matchExpressions:
# 声明标签的key
– key: apps
# 声明标签的value,可以有多个值
values:
– xiuxian
– v1
– v2
# 表示key和value之间的映射关系,有效值为: In, NotIn, Exists and DoesNotExist
operator: In
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:~/manifests/replicasets# kubectl apply -f 02-rs-matchExpressions-xiuxian.yaml replicaset.apps/rs-xiuxian-matchexpressions created

2.3.3 查看结果
root@master231:~/manifests/replicasets# kubectl get rs,pods –show-labels -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR LABELS
replicaset.apps/rs-xiuxian-matchexpressions 5 5 5 16s c1 crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1 apps in (v1,v2,xiuxian) xingming=zhangsan

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
pod/rs-xiuxian-matchexpressions-586h4 1/1 Running 0 16s 10.100.1.56 worker232 apps=xiuxian,city=Sichuan,xingming=lisi
pod/rs-xiuxian-matchexpressions-7nmpp 1/1 Running 0 16s 10.100.1.58 worker232 apps=xiuxian,city=Sichuan,xingming=lisi
pod/rs-xiuxian-matchexpressions-bbw8v 1/1 Running 0 16s 10.100.1.57 worker232 apps=xiuxian,city=Sichuan,xingming=lisi
pod/test01 1/1 Running 0 40s 10.100.1.55 worker232 apps=v1
pod/test02 1/1 Running 0 47s 10.100.1.54 worker232 apps=v2


2.3.4 结论
rs可以创建5个副本,但是已经匹配到有两个标签存在,所以值创建了3个副本



3 deploy
3.1 概述
deployment底层基于rs实现pod副本控制,deploy支持“声明式”更新

3.2 应用部署
3.2.1 matchLables
root@master231:~/manifests# mkdir deployments
root@master231:~/manifests# cd deployments/
root@master231:~/manifests/deployments# kubectl apply -f 01-deploy-matchLables-xiuxian.yaml
deployment.apps/deploy-xiuxian created
root@master231:~/manifests/deployments# kubectl get deploy,rs,pods -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/deploy-xiuxian 5/5 5 5 4s c1 crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1 apps=xiuxian

NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/deploy-xiuxian-66b55568cd 5 5 5 4s c1 crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1 apps=xiuxian,pod-template-hash=66b55568cd

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-xiuxian-66b55568cd-csqzt 1/1 Running 0 4s 10.100.1.78 worker232
pod/deploy-xiuxian-66b55568cd-kkwpz 1/1 Running 0 4s 10.100.1.75 worker232
pod/deploy-xiuxian-66b55568cd-rcgrq 1/1 Running 0 4s 10.100.1.74 worker232
pod/deploy-xiuxian-66b55568cd-t9fth 1/1 Running 0 4s 10.100.1.77 worker232
pod/deploy-xiuxian-66b55568cd-znsnj 1/1 Running 0 4s 10.100.1.76 worker232

root@master231:~/manifests/deployments# kubectl delete rs deploy-xiuxian-66b55568cd
replicaset.apps “deploy-xiuxian-66b55568cd” deleted
root@master231:~/manifests/deployments# kubectl get deploy,rs,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deploy-xiuxian 5/5 5 5 3m46s

NAME DESIRED CURRENT READY AGE
replicaset.apps/deploy-xiuxian-66b55568cd 5 5 5 17s

NAME READY STATUS RESTARTS AGE
pod/deploy-xiuxian-66b55568cd-49qct 1/1 Running 0 17s
pod/deploy-xiuxian-66b55568cd-72swr 1/1 Running 0 17s
pod/deploy-xiuxian-66b55568cd-fp4ww 1/1 Running 0 17s
pod/deploy-xiuxian-66b55568cd-k2b9s 1/1 Running 0 17s
pod/deploy-xiuxian-66b55568cd-vmtsz 1/1 Running 0 17s

root@master231:~/manifests/deployments# kubectl delete deployments.apps deploy-xiuxian
deployment.apps “deploy-xiuxian” deleted
root@master231:~/manifests/deployments# kubectl get deploy,rs,pods
No resources found in default namespace.

根据以上结论可以得出deploy是基于rs来实现的

3.2.2 matchExpressions
root@master231:~/manifests/deployments# cat 02-deploy-matchExpressions-xiuxian.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-matchexpressions
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchExpressions:
– key: apps
values:
– xiuxian
– v1
– v2
operator: In
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:~/manifests/deployments# kubectl apply -f 02-deploy-matchExpressions-xiuxian.yaml
deployment.apps/deploy-xiuxian-matchexpressions created

root@master231:~/manifests/deployments# kubectl get deploy,rs,pods –show-labels
NAME READY UP-TO-DATE AVAILABLE AGE LABELS
deployment.apps/deploy-xiuxian-matchexpressions 5/5 5 5 95s xingming=zhangsan

NAME DESIRED CURRENT READY AGE LABELS
replicaset.apps/deploy-xiuxian-matchexpressions-66b55568cd 5 5 5 95s apps=xiuxian,city=Sichuan,pod-template-hash=66b55568cd,xingming=lisi

NAME READY STATUS RESTARTS AGE LABELS
pod/deploy-xiuxian-matchexpressions-66b55568cd-djfv6 1/1 Running 0 95s apps=xiuxian,city=Sichuan,pod-template-hash=66b55568cd,xingming=lisi
pod/deploy-xiuxian-matchexpressions-66b55568cd-fm4vp 1/1 Running 0 95s apps=xiuxian,city=Sichuan,pod-template-hash=66b55568cd,xingming=lisi
pod/deploy-xiuxian-matchexpressions-66b55568cd-hpf9k 1/1 Running 0 95s apps=xiuxian,city=Sichuan,pod-template-hash=66b55568cd,xingming=lisi
pod/deploy-xiuxian-matchexpressions-66b55568cd-w47xl 1/1 Running 0 95s apps=xiuxian,city=Sichuan,pod-template-hash=66b55568cd,xingming=lisi
pod/deploy-xiuxian-matchexpressions-66b55568cd-wmhzs 1/1 Running 0 95s apps=xiuxian,city=Sichuan,pod-template-hash=66b55568cd,xingming=lisi

root@master231:~/manifests/deployments# kubectl delete -f 02-deploy-matchExpressions-xiuxian.yaml
deployment.apps “deploy-xiuxian-matchexpressions” deleted
root@master231:~/manifests/deployments# kubectl get deploy,rs,pods
No resources found in default namespace.
root@master231:~/manifests/deployments#

4 对比rc,rs,deploy的关系
4.1 相同点
都能控制副本数量始终存活

4.2 不同点
1 rc标签选择器比较单一,key和value只能成对出现
2 rs相比rc而言,功能更加强大,key的values可以对应多个值,即一对多
3 deployment底层基于rs实现pod副本控制,相比于rc,rs而已,deploy还支持声明式更新

5 ds
5.1 ds概述
daemonset可以让每个worker节点有且仅有一个pod运行,也支持声明式更新

5.2 应用部署
root@master231:~/manifests# mkdir daemonsets
root@master231:~/manifests# cd daemonsets/
root@master231:~/manifests/daemonsets#
root@master231:~/manifests/daemonsets# cat 01-ds-xiuxian.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ds-xiuxain
labels:
xingming: zhangsan
spec:
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
root@master231:~/manifests/daemonsets# kubectl apply -f 01-ds-xiuxian.yaml
daemonset.apps/ds-xiuxain created
root@master231:~/manifests/daemonsets# kubectl get ds,pods -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
daemonset.apps/ds-xiuxain 1 1 1 1 1 29s c1 crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1 apps=xiuxian

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/ds-xiuxain-2dwfp 1/1 Running 0 29s 10.100.1.99 worker232

6 jobs
6.1 概述
用于实现一次性任务

6.2 应用部署
root@master231:~/manifests# mkdir jobs
root@master231:~/manifests# cd jobs/
root@master231:~/manifests/jobs# vi 01-jobs-xiuxian.yaml
root@master231:~/manifests/jobs# cat 01-jobs-xiuxian.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: jobs-xiuxian
labels:
xingming: zhangsan
spec:
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
restartPolicy: OnFailure
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command:
– sleep
– “5”
root@master231:~/manifests/jobs# kubectl apply -f 01-jobs-xiuxian.yaml
job.batch/jobs-xiuxian created
root@master231:~/manifests/jobs# kubectl get jobs,pods
NAME COMPLETIONS DURATION AGE
job.batch/jobs-xiuxian 1/1 8s 15s

NAME READY STATUS RESTARTS AGE
pod/ds-xiuxain-2dwfp 1/1 Running 0 5m41s
pod/jobs-xiuxian-znfxb 0/1 Completed 0 15s


资源清单有个command,sleep 5 ,这里5秒后容器退出,所有status状态为完成


root@master231:~/manifests/jobs# kubectl delete ds ds-xiuxain
daemonset.apps “ds-xiuxain” deleted
root@master231:~/manifests/jobs# kubectl get pods
NAME READY STATUS RESTARTS AGE
jobs-xiuxian-znfxb 0/1 Completed 0 109s
root@master231:~/manifests/jobs# kubectl delete jobs.batch jobs-xiuxian
job.batch “jobs-xiuxian” deleted
root@master231:~/manifests/jobs# kubectl get pods
No resources found in default namespace.
root@master231:~/manifests/jobs#


7 cj
7.1 概述
cronjob底层基于jobs控制实现pod创建,用于定义周期性任务

7.2 应用部署
root@master231:~/manifests# mkdir cronjob
root@master231:~/manifests# cd cronjob/
root@master231:~/manifests/cronjob# vi 01-cj-xiuxian.yaml
root@master231:~/manifests/cronjob# cat 01-cj-xiuxian.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: cj-xiuxian
labels:
xingming: zhangsan
spec:
# 周期性调度Jobs控制器,参考: https://en.wikipedia.org/wiki/Cron
schedule: “* * * * *”
# 定义Job模板,而非Pod模板
jobTemplate:
spec:
# 定义Pod模板
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
restartPolicy: Never
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command:
– /bin/sh
– -c
– date -R; echo “test_cronjob”
root@master231:~/manifests/cronjob# kubectl apply -f 01-cj-xiuxian.yaml
cronjob.batch/cj-xiuxian created
root@master231:~/manifests/cronjob# kubectl get cj,jobs,pods
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob.batch/cj-xiuxian * * * * * False 0 9s 24s

NAME COMPLETIONS DURATION AGE
job.batch/cj-xiuxian-29068361 1/1 3s 9s

NAME READY STATUS RESTARTS AGE
pod/cj-xiuxian-29068361-qbl66 0/1 Completed 0 9s
root@master231:~/manifests/cronjob# kubectl logs pod/cj-xiuxian-29068361-qbl66
Tue, 08 Apr 2025 08:41:00 +0000
test_cronjob
root@master231:~/manifests/cronjob# kubectl get cj,jobs,pods
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob.batch/cj-xiuxian * * * * * False 0 51s 66s

NAME COMPLETIONS DURATION AGE
job.batch/cj-xiuxian-29068361 1/1 3s 51s

NAME READY STATUS RESTARTS AGE
pod/cj-xiuxian-29068361-qbl66 0/1 Completed 0 51s
root@master231:~/manifests/cronjob# kubectl logs pod/cj-xiuxian-29068361-qbl66

root@master231:~/manifests/cronjob# kubectl delete cj cj-xiuxian
cronjob.batch “cj-xiuxian” deleted
root@master231:~/manifests/cronjob# kubectl get pods
No resources found in default namespace.
root@master231:~/manifests/cronjob#

8 sts有状态服务
8.1 概述
K8S 1.9+引入,主要作用就是部署有状态服务,自带特性:
– 1.每个Pod有独立的存储;
– 2.每个Pod有唯一的网络标识;
– 3.有顺序的启动和停止Pod;

所谓的有状态服务,指的是服务在启动时逻辑并不相同,比如部署MySQL主从,第一个启动更多Pod逻辑和第二个Pod启动逻辑并不相通。

root@master231:~/manifests/statefulsets# cat 01-sts-xiuxian.yaml
apiVersion: v1
kind: Service
metadata:
name: headless-apps
spec:
ports:
– port: 80
name: web
clusterIP: None
selector:
app: v1



apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sts-xiuxian
spec:
selector:
matchLabels:
app: v1
# 和headless svc的名称保持一致
serviceName: “headless-apps”
# 升级策略
updateStrategy:
# 指定更新类型
type: RollingUpdate
# 配置滚动更新的参数
rollingUpdate:
# 指定要更新的分区数,0表示小于2的分区不更新
partition: 2
replicas: 5
# 定义Pod的创建和删除的顺序,有效值为: OrderedReady(default),Parallel。
# podManagementPolicy: Parallel
podManagementPolicy: OrderedReady
template:
metadata:
labels:
app: v1
spec:
initContainers:
– name: init01
image: harbor.ysl.com/ysl-xiuxian/apps:v1
volumeMounts:
– name: www
mountPath: /ceshi
env:
– name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
– /bin/sh
– -c
– echo “www.yangsenlin.top —> ${POD_NAME}” > /ysl/index.html
containers:
– name: c1
# image: harbor.ysl.com/ysl-xiuxian/apps:v1
image: harbor.ysl.com/ysl-xiuxian/apps:v2
ports:
– containerPort: 80
name: web
volumeMounts:
– name: www
mountPath: /usr/share/nginx/html
# 卷申请模板,会为Pod自动绑定pvc
volumeClaimTemplates:
– metadata:
name: www
spec:
accessModes: [ “ReadWriteOnce” ]
storageClassName: “nfs-csi”
resources:
requests:
storage: 5Mi
limits:
storage: 20Mi
root@master231:~/manifests/statefulsets#

root@master231:~/manifests/statefulsets# kubectl apply -f 01-sts-xiuxian.yaml
service/headless-apps created
statefulset.apps/sts-xiuxian created
root@master231:~/manifests/statefulsets#

查看启动顺序即可
26 Pod调度
常见调度有
nodeName
hostPort
hostNetwork
resources
nodeslector
taints
tolerations
cordon
uncordon
drain
podaffinity
nodeaffinity
podantiaffinity

1 nodeName指定节点调度
root@master231:~/manifests# mkdir scheduler
root@master231:~/manifests# cd scheduler

root@master231:~/manifests/scheduler# vi 01-scheduler-nodeName.yaml
root@master231:~/manifests/scheduler# cat 01-scheduler-nodeName.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-nodename
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
nodeName: worker233
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:~/manifests/scheduler# kubectl apply -f 01-scheduler-nodeName.yaml
deployment.apps/deploy-xiuxian-nodename created
root@master231:~/manifests/scheduler# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-nodename-889c57b8b-b7xtp 0/1 Pending 0 24s worker233
deploy-xiuxian-nodename-889c57b8b-dkdts 0/1 Pending 0 24s worker233
deploy-xiuxian-nodename-889c57b8b-lccn6 0/1 Pending 0 24s worker233
deploy-xiuxian-nodename-889c57b8b-rw2fg 0/1 Pending 0 24s worker233
deploy-xiuxian-nodename-889c57b8b-w4cfb 0/1 Pending 0 24s worker233
root@master231:~/manifests/scheduler#

虽然nodeName称为调度,但是并没有用到调度

root@master231:~/manifests/scheduler# kubectl describe deployments.apps deploy-xiuxian-nodename
….
Normal ScalingReplicaSet 2m26s deployment-controller Scaled up replica set deploy-xiuxian-nodename-889c57b8b to 5
看到最后一行并没有使用到scheduler

root@master231:~/manifests/scheduler# kubectl delete deployments.apps deploy-xiuxian-nodename

2 hostPort端口暴露
root@master231:~/manifests/scheduler# cat 02-scheduler-ports.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-ports
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80
hostPort: 81
root@master231:~/manifests/scheduler# kubectl apply -f 02-scheduler-ports.yaml
deployment.apps/deploy-xiuxian-ports created


3 hostNerwork使用宿主机网络
root@master231:~/manifests/scheduler# cat 03-scheduler-hostNetwork.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-hostnetwork
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
hostNetwork: true
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80
root@master231:~/manifests/scheduler# kubectl apply -f 03-scheduler-hostNetwork.yaml
deployment.apps/deploy-xiuxian-hostnetwork created
root@master231:~/manifests/scheduler# kubectl get deploy,rs,pods -o wide

4 resources

1 resources概述
表示可以对pod某个容器实现资源限制,可以配置pod调度的期望资源和使用上限
如果一个pod不配置资源上限,则默认会使用worker node节点的所有资源

2 reuqests定义期望资源
root@master231:/manifests/scheduler# cat 04-scheduler-resources-requests.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-resources
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: forestysl2020/ysl-linux-tools:v0.1
# 为容器分配一个标准输入,类似于docker run -i
stdin: true
# 为容器配置资源限制
resources:
# 表示用户的期望资源,符合期望才会被调度
requests:
cpu: 0.5
# memory: 1G
memory: 10G

root@master231:/manifests/scheduler# kubectl apply -f 04-scheduler-resources-requests.yaml
deployment.apps/deploy-xiuxian-resources created
root@master231:/manifests/scheduler# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-xiuxian-resources-754bc47779-czzsk 0/1 Pending 0 4s
deploy-xiuxian-resources-754bc47779-rmwp5 0/1 Pending 0 4s
deploy-xiuxian-resources-754bc47779-v8bh8 0/1 Pending 0 4s
deploy-xiuxian-resources-754bc47779-xv5jc 0/1 Pending 0 4s
deploy-xiuxian-resources-754bc47779-zbqjz 0/1 Pending 0 4s

因为memory配置的期望是10G,虚拟机并没有符合的,所有都处于pending状态
将memory: 10G修改为1G就可以了,但是只配置requests有个问题,比如,cpu和内存其实是可以超过这个期望的,可能会占用完所有宿主机资源,此时需要配合limits来配置

压力测试
压力测试命令
stress -m 5 –vm-bytes 200000000 –vm-keep –verbose

5 nodeselector 节点标签调度
1 概述
nodeselector可以就节点标签调度pod到对应的worker节点

2 应用部署
root@master231:~# kubectl label nodes worker232 xingming=zhangsan
node/worker232 labeled
root@master231:~# kubectl label nodes worker233 xingming=lisi
node/worker233 labeled

root@master231:~# kubectl get nodes -l xingming –show-labels
NAME STATUS ROLES AGE VERSION LABELS
worker232 Ready 4d2h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux,xingming=zhangsan
worker233 Ready 4d2h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux,xingming=lisi

[root@master231 scheduler]# cat 06-scheduler-nodeSelector.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-nodeselector
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
# 基于节点标签调度Pod
nodeSelector:
school: lisi
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

[root@master231 scheduler]# kubectl apply -f 06-scheduler-nodeSelector.yaml
root@master231:~/manifests/scheduler# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-nodeselector-bf8f56fbf-8td2f 1/1 Running 0 14s 10.100.2.33 worker233
deploy-xiuxian-nodeselector-bf8f56fbf-9mdp8 1/1 Running 0 14s 10.100.2.32 worker233
deploy-xiuxian-nodeselector-bf8f56fbf-fm6zl 1/1 Running 0 14s 10.100.2.34 worker233
deploy-xiuxian-nodeselector-bf8f56fbf-z4mww 1/1 Running 0 14s 10.100.2.31 worker233
deploy-xiuxian-nodeselector-bf8f56fbf-zpqn8 1/1 Running 0 14s 10.100.2.30 worker233

6 taints 污点
1 概述
taints翻译为污点,taints作用在worker nodejiedian
taints格式为“key[=value]:effect”
其中key和value可以自定义,但字符不得超过63个,其中value可以省略不写

effect有3中类型
NoSchedule
不接受新的Pod,已经调度到该节点的Pod并不驱逐。

PreferNoSchedule:
尽可能调度到其他节点,当其他节点不满足时,再调度到当前节点。

NoExecute:
不接受新的Pod调度,与此同时,还会驱逐已经调度到给节点的所有Pod,不推荐使用。


温馨提示:
只要effect不同,尽管key和value相同,则表示2个不同的污点。


2 查看污点
root@master231:~/manifests/scheduler# kubectl describe nodes| grep -i taints
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
Taints:


3 打污点
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 xingming=zhangsan:NoSchedule
node/worker233 tainted
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taint
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
Taints: xingming=zhangsan:NoSchedule

root@master231:~/manifests/scheduler# kubectl taint nodes –all city=Sichuan:PreferNoSchedulenode/master231 tainted
node/worker232 tainted
node/worker233 tainted

root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taint -A2
Taints: node-role.kubernetes.io/master:NoSchedule
city=Sichuan:PreferNoSchedule
Unschedulable: false

Taints: city=Sichuan:PreferNoSchedule
Unschedulable: false
Lease:

Taints: xingming=zhangsan:NoSchedule
city=Sichuan:PreferNoSchedule
Unschedulable: false

4 删除污点
在key后面加个减号-
root@master231:~/manifests/scheduler# kubectl taint node –all city-
node/master231 untainted
node/worker232 untainted
node/worker233 untainted
root@master231:~/manifests/scheduler# kubectl taint nodes worker232 xingming-
error: taint “xingming” not found
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 xingming-
node/worker233 untainted
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taint
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
Taints:

5 修改污点
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 xingming=zhangsan:NoSchedule
node/worker233 tainted
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 xingming=zhangsan:NoExecute
node/worker233 tainted
root@master231:~/manifests/scheduler# kubectl describe nodes worker233| grep -i taint
Taints: xingming=zhangsan:NoExecute
root@master231:~/manifests/scheduler#
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 xingming=lisi:NoExecute –overwrite
node/worker233 modified
root@master231:~/manifests/scheduler# kubectl describe nodes worker233| grep -i taint
Taints: xingming=lisi:NoExecute

6 清理污点
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 xingming-
node/worker233 untainted
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taint
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
Taints:
root@master231:~/manifests/scheduler#

7 验证污点
root@master231:~/manifests/scheduler# cat 07-scheduler-Taints.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-taints
labels:
xingming: zhangsan
spec:
replicas: 10
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
resources:
requests:
cpu: 0.2
memory: 500Mi

8 tolerations污点容忍
1 概述
一个pod想要调度到一个有污点的worker node上,则该pod需要容忍该污点

2 打污点
root@master231:~/manifests/scheduler# kubectl taint node worker232 xingming=zhangsan:NoSchedule
node/worker232 tainted
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 xingming=lisi:NoExecute
node/worker233 tainted
root@master231:~/manifests/scheduler# kubectl taint nodes worker233 city=Sichuan:NoSchedule
node/worker233 tainted
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taints -A2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:

Taints: xingming=zhangsan:NoSchedule
Unschedulable: false
Lease:

Taints: xingming=lisi:NoExecute
city=Sichuan:NoSchedule
Unschedulable: false
root@master231:~/manifests/scheduler#

3 编写资源清单
root@master231:~/manifests/scheduler# cat 08-scheduler-tolerations.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-tolerations
labels:
xingming: zhangsan
spec:
replicas: 10
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: Sichuan
xingming: lisi
spec:
# 配置污点容忍
tolerations:
# 匹配污点的key
– key: node-role.kubernetes.io/master
# 匹配污点的effect
effect: NoSchedule
# 表示key和value之间的关系,有效值为:Exists,Equal(default)。
operator: Equal
– key: school
value: laonanhai
effect: NoExecute
operator: Equal
– key: class
value: test
effect: NoSchedule
operator: Equal
– key: school
value: yangsenlin
effect: NoSchedule
# 无视任何污点,生产环境不推荐使用,临时测试可以.
#tolerations:
#- operator: Exists
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
resources:
requests:
cpu: 0.2
memory: 500Mi

4 测试

9 cordon
1 概述
标记节点不可调度,与此同时会给节点打上污点

2 cordon测试
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taint -A2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:

Taints:
Unschedulable: false
Lease:

Taints:
Unschedulable: false
Lease:
root@master231:~/manifests/scheduler# kubectl get pods
No resources found in default namespace.
root@master231:~/manifests/scheduler# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 4d2h v1.23.17
worker232 Ready 4d2h v1.23.17
worker233 Ready 4d2h v1.23.17
root@master231:~/manifests/scheduler# kubectl cordon worker232
node/worker232 cordoned
root@master231:~/manifests/scheduler# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 4d2h v1.23.17
worker232 Ready,SchedulingDisabled 4d2h v1.23.17
worker233 Ready 4d2h v1.23.17
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taint -A2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:

Taints: node.kubernetes.io/unschedulable:NoSchedule
Unschedulable: true
Lease:

Taints:
Unschedulable: false
Lease:

10 uncordon
1 概述
和cordon相反

2 uncordon测试
root@master231:~/manifests/scheduler# kubectl uncordon worker232
node/worker232 uncordoned
root@master231:~/manifests/scheduler# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 4d2h v1.23.17
worker232 Ready 4d2h v1.23.17
worker233 Ready 4d2h v1.23.17
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taint
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
Taints:


11 drain 驱逐
1 概述
drain 可以驱逐已经调度到节点的pod,底层会调用cordon标记节点不可调度

2 drain 测试
root@master231:~/manifests/scheduler# kubectl apply -f 07-scheduler-Taints.yaml
root@master231:~/manifests/scheduler# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-xiuxian-taints-55d8ff8b5c-257sk 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-2lmn2 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-57fkn 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-87f79 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-gzj77 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-j7m7m 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-lmckj 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-r95nl 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-s7bzs 1/1 Running 0 21s
deploy-xiuxian-taints-55d8ff8b5c-x2n8w 1/1 Running 0 21s
root@master231:~/manifests/scheduler#

root@master231:~/manifests/scheduler# kubectl drain worker233
node/worker233 cordoned
error: unable to drain node “worker233” due to error:cannot delete DaemonSet-managed Pods (use –ignore-daemonsets to ignore): kube-flannel/kube-flannel-ds-k7dp4, kube-system/kube-proxy-hn6g6, continuing command…
There are pending nodes to be drained:
worker233
cannot delete DaemonSet-managed Pods (use –ignore-daemonsets to ignore): kube-flannel/kube-flannel-ds-k7dp4, kube-system/kube-proxy-hn6g6
root@master231:~/manifests/scheduler# kubectl drain worker233 –ignore-daemonsets
node/worker233 already cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-flannel/kube-flannel-ds-k7dp4, kube-system/kube-proxy-hn6g6
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-x2n8w
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-57fkn
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-gzj77
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-j7m7m
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-r95nl
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-s7bzs
pod/deploy-xiuxian-taints-55d8ff8b5c-gzj77 evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-j7m7m evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-x2n8w evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-r95nl evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-s7bzs evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-57fkn evicted
node/worker233 drained

root@master231:~/manifests/scheduler# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-taints-55d8ff8b5c-257sk 1/1 Running 0 2m23s 10.100.1.112 worker232
deploy-xiuxian-taints-55d8ff8b5c-2lmn2 1/1 Running 0 2m23s 10.100.1.115 worker232
deploy-xiuxian-taints-55d8ff8b5c-468z4 1/1 Running 0 39s 10.100.1.118 worker232
deploy-xiuxian-taints-55d8ff8b5c-4wtr5 0/1 Pending 0 39s
deploy-xiuxian-taints-55d8ff8b5c-87f79 1/1 Running 0 2m23s 10.100.1.114 worker232
deploy-xiuxian-taints-55d8ff8b5c-dspkp 1/1 Running 0 39s 10.100.1.116 worker232
deploy-xiuxian-taints-55d8ff8b5c-fsqfk 0/1 Pending 0 39s
deploy-xiuxian-taints-55d8ff8b5c-khnvf 1/1 Running 0 39s 10.100.1.117 worker232
deploy-xiuxian-taints-55d8ff8b5c-lmckj 1/1 Running 0 2m23s 10.100.1.113 worker232
deploy-xiuxian-taints-55d8ff8b5c-z5nxm 0/1 Pending 0 39s

root@master231:~/manifests/scheduler# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 4d3h v1.23.17
worker232 Ready 4d2h v1.23.17
worker233 Ready,SchedulingDisabled 4d2h v1.23.17
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taints
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
default deploy-xiuxian-taints-55d8ff8b5c-257sk 200m (10%) 0 (0%) 500Mi (13%) 0 (0%) 3m
default deploy-xiuxian-taints-55d8ff8b5c-2lmn2 200m (10%) 0 (0%) 500Mi (13%) 0 (0%) 3m
default deploy-xiuxian-taints-55d8ff8b5c-468z4 200m (10%) 0 (0%) 500Mi (13%) 0 (0%) 76s
default deploy-xiuxian-taints-55d8ff8b5c-87f79 200m (10%) 0 (0%) 500Mi (13%) 0 (0%) 3m
default deploy-xiuxian-taints-55d8ff8b5c-dspkp 200m (10%) 0 (0%) 500Mi (13%) 0 (0%) 76s
default deploy-xiuxian-taints-55d8ff8b5c-khnvf 200m (10%) 0 (0%) 500Mi (13%) 0 (0%) 76s
default deploy-xiuxian-taints-55d8ff8b5c-lmckj 200m (10%) 0 (0%) 500Mi (13%) 0 (0%) 3m
Taints: node.kubernetes.io/unschedulable:NoSchedule


12 nodeaffinity 节点亲和力
1 概述
nodeAffinity 表示pod调度到期望节点

2 应用部署

2.1 给节点打标签
root@master231:~/manifests/scheduler# kubectl label nodes master231 dc=shanghai
node/master231 labeled
root@master231:~/manifests/scheduler# kubectl label nodes worker232 dc=Sichuan
node/worker232 labeled
root@master231:~/manifests/scheduler# kubectl label nodes worker233 dc=shenzhen
node/worker233 labeled
root@master231:~/manifests/scheduler# kubectl get nodes –show-labels | grep dc
master231 Ready control-plane,master 5d15h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,dc=shanghai,kubernetes.io/arch=amd64,kubernetes.io/hostname=master231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
worker232 Ready 36h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,dc=Sichuan,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux
worker233 Ready 5d15h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,dc=shenzhen,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux,xingming=lisi
root@master231:~/manifests/scheduler#


2.2 使用nodeAffinity实现nodeSelector功能
root@master231:~/manifests/scheduler# kubectl explain deployment
root@master231:~/manifests/scheduler# cat 09-scheduler-nodeAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-nodeaffinity
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: cq
xm: lisi
spec:
tolerations:
– operator: Exists
# 定义亲和性
affinity:
# 定义节点亲和性
nodeAffinity:
# 定义硬限制
requiredDuringSchedulingIgnoredDuringExecution:
# 定义节点选择器
nodeSelectorTerms:
# 基于表达式匹配节点
– matchExpressions:
# 定义节点标签的key
– key: dc
# 定义节点标签的value
values:
– Sichuan
# 定义key和values之间的关系,有效值为: In,NotIn, Exists, DoesNotExist. Gt, and
operator: In
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

2.3 部署应用
root@master231:~/manifests/scheduler# kubectl apply -f 09-scheduler-nodeAffinity.yaml
deployment.apps/deploy-xiuxian-nodeaffinity created
root@master231:~/manifests/scheduler# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-nodeaffinity-7df457c957-hg2s2 1/1 Running 0 13s 10.100.1.18 worker232
deploy-xiuxian-nodeaffinity-7df457c957-w58rb 1/1 Running 0 13s 10.100.1.19 worker232
deploy-xiuxian-nodeaffinity-7df457c957-w8zfl 1/1 Running 0 13s 10.100.1.20 worker232
deploy-xiuxian-nodeaffinity-7df457c957-wfmfl 1/1 Running 0 13s 10.100.1.21 worker232
deploy-xiuxian-nodeaffinity-7df457c957-zxjgr 1/1 Running 0 13s 10.100.1.22 worker232

2.4 总结
此处可以看出,配置nodeaffinity后,第一个pod部署在哪一个节点上,后面的pod都会在同一个节点部署,但是第一个pod是不确认部署哪个节点的


3 使用nodeaffinity实现超越nodeselector功能,支持多值匹配
3.1编写资源清单并查看节点标签

root@master231:~/manifests/scheduler# cat 09-scheduler-nodeAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-nodeaffinity
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: cq
xm: lisi
spec:
tolerations:
– operator: Exists
# 定义亲和性
affinity:
# 定义节点亲和性
nodeAffinity:
# 定义硬限制
requiredDuringSchedulingIgnoredDuringExecution:
# 定义节点选择器
nodeSelectorTerms:
# 基于表达式匹配节点
– matchExpressions:
# 定义节点标签的key
– key: dc
# 定义节点标签的value
values:
– Sichuan
– shanghai
# 定义key和values之间的关系,有效值为: In,NotIn, Exists, DoesNotExist. Gt, and Lt
operator: In
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:~/manifests/scheduler# kubectl get nodes -l dc=Sichuan
NAME STATUS ROLES AGE VERSION
worker232 Ready 36h v1.23.17
root@master231:~/manifests/scheduler# kubectl get nodes -l dc=shanghai
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 5d15h v1.23.17

3.2 部署应用
root@master231:~/manifests/scheduler# kubectl apply -f 09-scheduler-nodeAffinity.yaml
deployment.apps/deploy-xiuxian-nodeaffinity created
root@master231:~/manifests/scheduler# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-nodeaffinity-5849dbdb8-5gfpk 1/1 Running 0 13s 10.100.0.24 master231
deploy-xiuxian-nodeaffinity-5849dbdb8-b9xps 1/1 Running 0 13s 10.100.1.24 worker232
deploy-xiuxian-nodeaffinity-5849dbdb8-hpbtx 1/1 Running 0 13s 10.100.1.25 worker232
deploy-xiuxian-nodeaffinity-5849dbdb8-kj9w6 1/1 Running 0 13s 10.100.0.25 master231
deploy-xiuxian-nodeaffinity-5849dbdb8-sj7rf 1/1 Running 0 13s 10.100.1.23 worker232

3.3 查看污点
root@master231:~/manifests/scheduler# kubectl describe nodes | grep -i taints
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
Taints:

3.4 总结
nodeAffinity可以实现多标签匹配


13 PodAffinity POD亲和力
13.1 概述
podAffinity在调度pod时可以基于拓扑域进行调度,当某个pod调度到特定的拓扑域后,后续的所有pod都往该拓扑域调度

13.2 应用部署
13.2.1 查看标签
root@master231:~/manifests/scheduler# kubectl get nodes –show-labels -l “dc in(Sichuan,shanghai)”
NAME STATUS ROLES AGE VERSION LABELS
master231 Ready control-plane,master 5d15h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,dc=shanghai,kubernetes.io/arch=amd64,kubernetes.io/hostname=master231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
worker232 Ready 36h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,dc=Sichuan,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux

13.2.2 编写资源清单
root@master231:~/manifests/scheduler# cat 10-scheduler-podAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-podaffinity
labels:
xingming: zhangsan
spec:
replicas: 10
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: cq
xm: lisi
spec:
tolerations:
– operator: Exists
# 定义亲和性
affinity:
# 定义Pod亲和性
podAffinity:
# 定义硬限制
requiredDuringSchedulingIgnoredDuringExecution:
# 定义拓扑域(“机房”)
– topologyKey: dc
# 定义Pod标签选择器
labelSelector:
# 基于表达式匹配节点
matchExpressions:
# 定义节点标签的key
– key: apps
# 定义节点标签的value
values:
– xiuxian
# 定义key和values之间的关系,有效值为: In,NotIn, Exists, DoesNotExist. Gt, and Lt
operator: In
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:~/manifests/scheduler#

root@master231:~/manifests/scheduler# kubectl apply -f 10-scheduler-podAffinity.yaml

root@master231:~/manifests/scheduler# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-podaffinity-74c6558c8f-2xz84 1/1 Running 0 31s 10.100.2.70 worker233
deploy-xiuxian-podaffinity-74c6558c8f-4ggrt 1/1 Running 0 31s 10.100.2.71 worker233
deploy-xiuxian-podaffinity-74c6558c8f-5pf4c 1/1 Running 0 31s 10.100.2.72 worker233
deploy-xiuxian-podaffinity-74c6558c8f-6b64b 1/1 Running 0 31s 10.100.2.64 worker233
deploy-xiuxian-podaffinity-74c6558c8f-d7skb 1/1 Running 0 31s 10.100.2.69 worker233
deploy-xiuxian-podaffinity-74c6558c8f-drbmg 1/1 Running 0 31s 10.100.2.66 worker233
deploy-xiuxian-podaffinity-74c6558c8f-jvxgh 1/1 Running 0 31s 10.100.2.68 worker233
deploy-xiuxian-podaffinity-74c6558c8f-kd6f2 1/1 Running 0 31s 10.100.2.63 worker233
deploy-xiuxian-podaffinity-74c6558c8f-nt6pr 1/1 Running 0 31s 10.100.2.65 worker233
deploy-xiuxian-podaffinity-74c6558c8f-s6ds8 1/1 Running 0 31s 10.100.2.67 worker233


14 podantiaffinity pod反亲和性
14.1 概述
在调度Pod时可以基于拓扑域进行调度,当某个Pod调度到特定的拓扑域后,后续的Pod都不能往该拓扑域调度。

14.2 应用部署
root@master231:~/manifests/scheduler# cat 11-scheduler-podAntiAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-podantiaffinity
labels:
xingming: zhangsan
spec:
replicas: 5
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
city: cq
xm: lisi
spec:
tolerations:
– operator: Exists
# 定义亲和性
affinity:
# 定义Pod反亲和性
podAntiAffinity:
# 定义硬限制
requiredDuringSchedulingIgnoredDuringExecution:
# 定义拓扑域(“机房”)
– topologyKey: dc
# 定义Pod标签选择器
labelSelector:
# 基于表达式匹配节点
matchExpressions:
# 定义节点标签的key
– key: apps
# 定义节点标签的value
values:
– xiuxian
# 定义key和values之间的关系,有效值为: In,NotIn, Exists, DoesNotExist. Gt, and Lt
operator: In
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:~/manifests/scheduler# kubectl apply -f 11-scheduler-podAntiAffinity.yaml
deployment.apps/deploy-xiuxian-podantiaffinity created
root@master231:~/manifests/scheduler#

14.3 测试验证
root@master231:~/manifests/scheduler# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-podantiaffinity-df6d7bfbf-c97z7 0/1 Pending 0 38s
deploy-xiuxian-podantiaffinity-df6d7bfbf-cxctb 0/1 Pending 0 38s
deploy-xiuxian-podantiaffinity-df6d7bfbf-hb95h 1/1 Running 0 38s 10.100.1.26 worker232
deploy-xiuxian-podantiaffinity-df6d7bfbf-hg5pz 1/1 Running 0 38s 10.100.0.26 master231
deploy-xiuxian-podantiaffinity-df6d7bfbf-sfkqh 1/1 Running 0 38s 10.100.2.83 worker233

15 扩展
– limits
https://www.cnblogs.com/ysl/p/17968870

– quota
https://www.cnblogs.com/ysl/p/17955506
27 集群的扩容和缩容
1 缩容

k8s集群节点下线流程
1 驱逐已经调度到节点的pod

2 worker节点停止kubelet组件并禁止开机启动

3 worker节点重置环境或备份

4 重新安装操作系统

5 master节点删除worker节点

6 缩容测试

6.1 驱逐
root@master231:~/manifests/scheduler# kubectl drain worker232 –ignore-daemonsets
node/worker232 already cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-flannel/kube-flannel-ds-bx879, kube-system/kube-proxy-tqc9v
evicting pod kube-system/coredns-6d8c4cb4d-v7bjz
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-87f79
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-257sk
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-2lmn2
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-468z4
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-khnvf
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-dspkp
evicting pod default/deploy-xiuxian-taints-55d8ff8b5c-lmckj
evicting pod kube-system/coredns-6d8c4cb4d-gf2ps
pod/deploy-xiuxian-taints-55d8ff8b5c-87f79 evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-2lmn2 evicted
I0408 22:38:06.327155 32824 request.go:685] Waited for 1.193868197s due to client-side throttling, not priority and fairness, request: GET:https://10.0.0.231:6443/api/v1/namespaces/default/pods/deploy-xiuxian-taints-55d8ff8b5c-257sk
pod/deploy-xiuxian-taints-55d8ff8b5c-257sk evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-lmckj evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-dspkp evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-khnvf evicted
pod/deploy-xiuxian-taints-55d8ff8b5c-468z4 evicted
pod/coredns-6d8c4cb4d-v7bjz evicted
pod/coredns-6d8c4cb4d-gf2ps evicted
node/worker232 drained

6.2 停止kubelet并禁止开机启动
root@worker232:~# systemctl disable –now kubelet
Removed /etc/systemd/system/multi-user.target.wants/kubelet.service.
root@worker232:~#

6.3 节点重置
root@worker232:~# kubeadm reset -f

6.4 worker节点重新安装操作系统
此处为测试环境,不重新安装操作系统,等下扩容还需要使用

6.5 master节点删除worker节点
root@master231:~/manifests/scheduler# kubectl delete nodes worker232
node “worker232” deleted

root@master231:~/manifests/scheduler# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 4d3h v1.23.17
worker233 Ready 4d3h v1.23.17

2 节点扩容

kubeadm实现token管理
1 创建并查看token
root@master231:~/manifests/scheduler# kubeadm token create
xdid4z.e23pjdhn1w90qzl7
root@master231:~/manifests/scheduler# kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
xdid4z.e23pjdhn1w90qzl7 23h 2025-04-09T14:45:42Z authentication,signing system:bootstrappers:kubeadm:default-node-token

2 删除token
root@master231:~/manifests/scheduler# kubeadm token delete xdid4z
bootstrap token “xdid4z” deleted
root@master231:~/manifests/scheduler# kubeadm token list
root@master231:~/manifests/scheduler#

3 创建自定义token
root@master231:~/manifests/scheduler# kubeadm token create –ttl 0 –print-join-command
kubeadm join 10.0.0.231:6443 –token 74lbdb.8wmb24q5xtjarbps –discovery-token-ca-cert-hash sha256:829b9f6b642b548ec4e311028eb6d56c04f3f52240804aa631337ab43165af4d

4 新建worker232
– 1.K8S环境准备,禁用swap,开启内核参数,核心数量,安装软件包(docker,kubelet,kubeadm,kubectl)等;
– 2.将kubelet设置为开机自启动;
– 3.worker节点加入集群 —》kubeadm join
– 4.master查看node是否加入集群;

在worker232节点使用
kubeadm join 10.0.0.231:6443 –token 74lbdb.8wmb24q5xtjarbps –discovery-token-ca-cert-hash sha256:829b9f6b642b548ec4e311028eb6d56c04f3f52240804aa631337ab43165af4d

5 master节点查看集群
root@master231:~/manifests/scheduler# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 4d3h v1.23.17
worker232 Ready 72s v1.23.17
worker233 Ready 4d3h v1.23.17


28 pod创建流程
1.执行kubectl命令时会加载”~/.kube/config”,从而识别到apiserver的地址,端口及认证证书;

2.apiserver进行证书认证,鉴权,语法检查,若成功则可以进行数据的读取或者写入;

3.若用户是写入操作(创建,修改,删除)则需要修改etcd数据库的信息;

4.如果创建Pod,此时scheduler负责Pod调度,将Pod调度到合适的worker节点,并将结果返回给ApiServer,由apiServer负责存储到etcd中;

5.kubelet组件会周期性上报给apiServer节点,包括Pod内的容器资源(cpu,memory,disk,gpu,…)及worker宿主机节点状态,apiServer并将结果存储到etcd中,若有该节点的任务也会直接返回给该节点进行调度;

6.kubelet开始调用CRI接口创建容器(依次创建pause,initContainers,containers);

7.在运行过程中,若Pod容器,正常或者异常退出时,kubelet会根据重启策略是否重启容器(Never,Always,OnFailure);

8.若一个节点挂掉,则需要controller manager介入维护,比如Pod副本数量缺失,则需要创建watch事件,要求控制器的副本数要达到标准,从而要创建新的Pod,此过程重复步骤4-6。



29 pod的端口转发
1 环境准备
root@master231:~/manifests/scheduler# kubectl apply -f 11-scheduler-podAntiAffinity.yaml
root@master231:~/manifests/scheduler# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-xiuxian-podantiaffinity-df6d7bfbf-c97z7 0/1 Pending 0 150m
deploy-xiuxian-podantiaffinity-df6d7bfbf-cxctb 0/1 Pending 0 150m
deploy-xiuxian-podantiaffinity-df6d7bfbf-hb95h 1/1 Running 0 150m
deploy-xiuxian-podantiaffinity-df6d7bfbf-hg5pz 1/1 Running 0 150m
deploy-xiuxian-podantiaffinity-df6d7bfbf-sfkqh 1/1 Running 0 150m

2 配置端口转发
root@master231:~/manifests/scheduler# kubectl port-forward deploy-xiuxian-podantiaffinity-df6d7bfbf-hb95h –address=0.0.0.0 81:80

3 测试
http://192.168.137.231:81

4 总结
用于临时测试使用,响应式暴露服务

5 现已接触到的端口转发
hostPorts 端口暴露
port-forward 响应式暴露端口
hostNetwork 使用宿主机网络

30 发布策略
1 灰度发布|金丝雀发布
特点:
新版本逐渐替代旧版本,在运行过程中新版本和旧版本共存
但最终会保留一个版本

2 蓝绿部署
特点
同步部署两套集群环境,但仅有一套环境对外提供服务

3 A|B测试
特点
针对一部分用户进行升级,或者说将一部分用户进行新版本体验

1 灰度发布

1.1 应用部署
root@master231:~/manifests# cd /manifests/
root@master231:/manifests# mkdir huidu
root@master231:/manifests# cd huidu/
root@master231:/manifests/huidu#

root@master231:/manifests/huidu# cat 01-deploy-xiuxian-old.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-old
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
version: v1
template:
metadata:
labels:
apps: xiuxian
version: v1
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

root@master231:/manifests/huidu# kubectl apply -f 01-deploy-xiuxian-old.yaml

root@master231:/manifests/huidu# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-old-568cf47956-j7h2k 1/1 Running 0 5m26s 10.100.2.84 worker233
deploy-xiuxian-old-568cf47956-jmhrp 1/1 Running 0 5m26s 10.100.1.27 worker232
deploy-xiuxian-old-568cf47956-wxprj 1/1 Running 0 5m26s 10.100.2.85 worker233
root@master231:/manifests/huidu#

1.2 定义svc

1.2.1 编写资源清单
root@master231:/manifests/huidu# kubectl explain service
root@master231:/manifests/huidu# kubectl apply -f 02-svc-xiuxian.yaml
service/svc-xiuxian created
root@master231:/manifests/huidu# cat 02-svc-xiuxian.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian
spec:
#定义标签选择器
selector:
apps: xiuxian
#关联svc到pods的端口映射
ports:
#svc自身监听的端口
– port: 81
#反向代理到后端的pod端口
targetPort: 80

1.2.2 查看svc资源
root@master231:/manifests/huidu# kubectl get svc svc-xiuxian
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-xiuxian ClusterIP 10.200.224.60 81/TCP 77s

root@master231:/manifests/huidu# kubectl describe svc svc-xiuxian | egrep -i ‘ip|endpoint’
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.200.224.60
IPs: 10.200.224.60
Endpoints: 10.100.1.27:80,10.100.2.84:80,10.100.2.85:80

1.2.3 测试svc有负载均衡的能力
root@master231:/manifests/huidu# kubectl exec -it deploy-xiuxian-old-568cf47956-j7h2k — sh
/ # echo 1111111111111 > /usr/share/nginx/html/index.html
/ # exit
root@master231:/manifests/huidu# kubectl exec -it deploy-xiuxian-old-568cf47956-jmhrp — sh
/ # echo 22222222222 > /usr/share/nginx/html/index.html
/ # exit
root@master231:/manifests/huidu# kubectl exec -it deploy-xiuxian-old-568cf47956-wxprj — sh
/ # echo 3333333333 > /usr/share/nginx/html/index.html
/ # exit
root@master231:/manifests/huidu# while true ; do curl 10.200.224.60:81;sleep 0.5;done
22222222222
1111111111111
22222222222
22222222222
22222222222
22222222222
1111111111111
22222222222
22222222222
3333333333

1.2.4 验证svc的服务发现功能
root@master231:/manifests/huidu# kubectl delete pods –all
pod “deploy-xiuxian-old-568cf47956-j7h2k” deleted
pod “deploy-xiuxian-old-568cf47956-jmhrp” deleted
pod “deploy-xiuxian-old-568cf47956-wxprj” deleted
root@master231:/manifests/huidu# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-xiuxian-old-568cf47956-bj7qt 1/1 Running 0 34s
deploy-xiuxian-old-568cf47956-pf4kr 1/1 Running 0 34s
deploy-xiuxian-old-568cf47956-q4m6d 1/1 Running 0 34s
root@master231:/manifests/huidu# curl 10.200.224.60:81




ysl apps v1



凡人修仙传 v1




root@master231:/manifests/huidu#

1.2.5 总结
1 svc有服务发现的作用,删除pod重新创建后能够自动关联新的pod
2 svc拥有负载均衡的能力
3 为客户端提供统一的访问入口

1.3 灰度发布流程
1 先部署旧版本(3副本)
2 部署svc关联旧版本
3 部署新版本(3副本)
4 将旧版本的副本数从3-0,将新版本的副本数从1-3
5 删除旧版本控制器

1.3.1 部署新版本
while true ; do curl 10.200.224.60:81;sleep 0.5;done

此时发现新版本和旧版本共存的现象。

1.3.2 修改01和03资源清单的副本数量
部署应用
root@master231:/manifests/huidu# cat 01-deploy-xiuxian-old.yaml 03-deploy-xiuxian-new.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-old
spec:
replicas: 2
selector:
matchLabels:
apps: xiuxian
version: v1
template:
metadata:
labels:
apps: xiuxian
version: v1
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-new
spec:
replicas: 2
selector:
matchLabels:
apps: xiuxian
version: v2
template:
metadata:
labels:
apps: xiuxian
version: v2
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2


root@master231:/manifests/huidu# kubectl get pods -o wide –show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
deploy-xiuxian-new-845ffc675b-8fxgc 1/1 Running 0 12m 10.100.2.88 worker233 apps=xiuxian,pod-template-hash=845ffc675b,version=v2
deploy-xiuxian-new-845ffc675b-f5l79 1/1 Running 0 34s 10.100.1.29 worker232 apps=xiuxian,pod-template-hash=845ffc675b,version=v2
deploy-xiuxian-old-568cf47956-pf4kr 1/1 Running 0 27m 10.100.2.86 worker233 apps=xiuxian,pod-template-hash=568cf47956,version=v1
deploy-xiuxian-old-568cf47956-q4m6d 1/1 Running 0 27m 10.100.1.28 worker232 apps=xiuxian,pod-template-hash=568cf47956,version=v1

以此一直到所有的01的副本配置为0,03的副本配置为3,最后将01资源删除即可

2 蓝绿部署

2.1 流程
1 部署旧版本
2 通过svc关联旧版本
3 部署新版本
4 将svc指向新版本

1 部署旧版本
root@master231:/manifests/blue-green# cat 01-deploy-blue.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-blue
spec:
replicas: 5
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1

2 通过svc关联旧版本
root@master231:/manifests/blue-green# cat 02-svc-xiuxian.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian
spec:
selector:
apps: v1
ports:
– port: 81
targetPort: 80

root@master231:/manifests/blue-green# kubectl get -f 02-svc-xiuxian.yaml -f 02-svc-xiuxian.yaml
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-xiuxian ClusterIP 10.200.224.60 81/TCP 64m
svc-xiuxian ClusterIP 10.200.224.60 81/TCP 64m

root@master231:/manifests/blue-green# kubectl get -f 01-deploy-blue.yaml -f 02-svc-xiuxian.yaml
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deploy-xiuxian-blue 5/5 5 5 100s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/svc-xiuxian ClusterIP 10.200.224.60 81/TCP 65m

root@master231:/manifests/blue-green# kubectl get svc,pods -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.200.0.1 443/TCP 2d
service/svc-xiuxian ClusterIP 10.200.224.60 81/TCP 65m apps=v1

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-xiuxian-blue-5d88dd4cfb-4f7b7 1/1 Running 0 2m21s 10.100.2.91 worker233
pod/deploy-xiuxian-blue-5d88dd4cfb-knfhv 1/1 Running 0 2m21s 10.100.1.31 worker232
pod/deploy-xiuxian-blue-5d88dd4cfb-n6vwd 1/1 Running 0 2m21s 10.100.2.89 worker233
pod/deploy-xiuxian-blue-5d88dd4cfb-ppd96 1/1 Running 0 2m21s 10.100.1.30 worker232
pod/deploy-xiuxian-blue-5d88dd4cfb-t6qft 1/1 Running 0 2m21s 10.100.2.90 worker233

3 访问测试
root@master231:/manifests/blue-green# while true ; do curl 10.200.224.60:81;sleep 0.5;done




ysl apps v1



凡人修仙传 v1





4 部署新版本
root@master231:/manifests/blue-green# kubectl apply -f 03-deploy-xiuxian-green.yaml
deployment.apps/deploy-xiuxian-green created
root@master231:/manifests/blue-green# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-blue-5d88dd4cfb-4f7b7 1/1 Running 0 13m 10.100.2.91 worker233
deploy-xiuxian-blue-5d88dd4cfb-knfhv 1/1 Running 0 13m 10.100.1.31 worker232
deploy-xiuxian-blue-5d88dd4cfb-n6vwd 1/1 Running 0 13m 10.100.2.89 worker233
deploy-xiuxian-blue-5d88dd4cfb-ppd96 1/1 Running 0 13m 10.100.1.30 worker232
deploy-xiuxian-blue-5d88dd4cfb-t6qft 1/1 Running 0 13m 10.100.2.90 worker233
deploy-xiuxian-green-54c7bddb9b-6bb6j 1/1 Running 0 13s 10.100.2.92 worker233
deploy-xiuxian-green-54c7bddb9b-cksbs 1/1 Running 0 13s 10.100.1.32 worker232
deploy-xiuxian-green-54c7bddb9b-jh92r 1/1 Running 0 13s 10.100.2.93 worker233
deploy-xiuxian-green-54c7bddb9b-lzlpv 1/1 Running 0 13s 10.100.1.33 worker232
deploy-xiuxian-green-54c7bddb9b-zgs2z 1/1 Running 0 13s 10.100.2.94 worker233
root@master231:/manifests/blue-green# cat 03-deploy-xiuxian-green.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-green
spec:
replicas: 5
selector:
matchLabels:
apps: v2
template:
metadata:
labels:
apps: v2
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2

root@master231:/manifests/blue-green#

5 将svc指向新版本
root@master231:/manifests/blue-green# kubectl get svc,pods -o wide –show-labels
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR LABELS
service/kubernetes ClusterIP 10.200.0.1 443/TCP 2d1h component=apiserver,provider=kubernetes
service/svc-xiuxian ClusterIP 10.200.224.60 81/TCP 78m apps=v2

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
pod/deploy-xiuxian-blue-5d88dd4cfb-4f7b7 1/1 Running 0 15m 10.100.2.91 worker233 apps=v1,pod-template-hash=5d88dd4cfb
pod/deploy-xiuxian-blue-5d88dd4cfb-knfhv 1/1 Running 0 15m 10.100.1.31 worker232 apps=v1,pod-template-hash=5d88dd4cfb
pod/deploy-xiuxian-blue-5d88dd4cfb-n6vwd 1/1 Running 0 15m 10.100.2.89 worker233 apps=v1,pod-template-hash=5d88dd4cfb
pod/deploy-xiuxian-blue-5d88dd4cfb-ppd96 1/1 Running 0 15m 10.100.1.30 worker232 apps=v1,pod-template-hash=5d88dd4cfb
pod/deploy-xiuxian-blue-5d88dd4cfb-t6qft 1/1 Running 0 15m 10.100.2.90 worker233 apps=v1,pod-template-hash=5d88dd4cfb
pod/deploy-xiuxian-green-54c7bddb9b-6bb6j 1/1 Running 0 2m1s 10.100.2.92 worker233 apps=v2,pod-template-hash=54c7bddb9b
pod/deploy-xiuxian-green-54c7bddb9b-cksbs 1/1 Running 0 2m1s 10.100.1.32 worker232 apps=v2,pod-template-hash=54c7bddb9b
pod/deploy-xiuxian-green-54c7bddb9b-jh92r 1/1 Running 0 2m1s 10.100.2.93 worker233 apps=v2,pod-template-hash=54c7bddb9b
pod/deploy-xiuxian-green-54c7bddb9b-lzlpv 1/1 Running 0 2m1s 10.100.1.33 worker232 apps=v2,pod-template-hash=54c7bddb9b
pod/deploy-xiuxian-green-54c7bddb9b-zgs2z 1/1 Running 0 2m1s 10.100.2.94 worker233 apps=v2,pod-template-hash=54c7bddb9b

此时apps=v1是没有对外提供业务的

6 再次查看访问的数据
root@master231:/manifests/blue-green# curl 10.200.224.60:81
此时都是V2版本


3 istio实现A|B测试
3.1 概述
Istio
Istio是Google、IBM和Lyft联合开源的微服务Service Mesh框架,旨在解决大量微服务的发现、连接、管理、监控以及安全等问题。

Istio的主要特性包括:
– HTTP、gRPC和TCP网络流量的自动负载均衡
– 丰富的路由规则,细粒度的网络流量行为控制
– 流量加密、服务间认证,以及强身份声明
– 全范围(Fleet-wide)策略执行
– 深度遥测和报告
Istio是2017年5月发布的第一个的0.1版本,目的是为了抢占市场。

但是在2018年7月才发布了1.0版本,而在2020年的3月发布了1.5版本。2022年的2月份发布了1.13版本。2023年2月份发布了1.17版本。2023年9月份发布了1.20版本。

3.2 istio个版本支持的k8s版本
参考地址:
https://istio.io/latest/docs/releases/supported-releases/#support-status-of-istio-releases


3.3 下载istio软件包
wget https://github.com/istio/istio/releases/download/1.17.8/istio-1.17.8-linux-amd64.tar.gz

3.4 解压软件包
[root@master231 istio]# tar xf istio-1.17.8-linux-amd64.tar.gz

3.5 配置istioctl工具环境变量
[root@master231 istio-1.17.8]# cat /etc/profile.d/istio.sh
export PATH=$PATH:/manifests/add-ones/istio/istio-1.17.8/bin
[root@master231 istio-1.17.8]# source /etc/profile.d/istio.sh
[root@master231 istio-1.17.8]# istioctl –help
Istio configuration command line utility for service operators to
debug and diagnose their Istio mesh.

Usage:
istioctl [command]
…..

3.6 安装istio
在安装 Istio 时所能够使用的内置配置文件。这些配置文件提供了对Istio控制平面和Istio数据平面Sidecar的定制内容。
您可以从Istio内置配置文件的其中一个开始入手,然后根据您的特定需求进一步自定义配置文件。当前提供以下几种内置配置文件:
– default:
根据 IstioOperator API 的默认设置启动组件。
建议用于生产部署和 Multicluster Mesh 中的 Primary Cluster。
您可以运行 istioctl profile dump 命令来查看默认设置。

– demo:
这一配置具有适度的资源需求,旨在展示 Istio 的功能。
它适合运行 Bookinfo 应用程序和相关任务。 这是通过快速开始指导安装的配置。
此配置文件启用了高级别的追踪和访问日志,因此不适合进行性能测试。

– minimal:
与默认配置文件相同,但只安装了控制平面组件。
它允许您使用 Separate Profile 配置控制平面和数据平面组件(例如 Gateway)。

– remote:
配置 Multicluster Mesh 的 Remote Cluster。

– empty:
不部署任何东西。可以作为自定义配置的基本配置文件。

– preview:
预览文件包含的功能都是实验性。这是为了探索 Istio 的新功能。不确保稳定性、安全性和性能(使用风险需自负)。
参考链接:
https://istio.io/v1.17/zh/docs/setup/additional-setup/config-profiles/
https://istio.io/v1.17/zh/docs/setup/getting-started/#download

[root@master231 istio]# istioctl install –set profile=demo -y

3.7 查看拉取的镜像是否成功
root@master231:~# kubectl -n istio-system get pods

3.8 添加istioctl客户端自动补全功能
[root@master231 istio]# ll istio-1.17.8/tools/istioctl.bash
-rw-r–r– 1 root root 11294 Oct 11 2023 istio-1.17.8/tools/istioctl.bash
[root@master231 istio]#
[root@master231 istio]# source istio-1.17.8/tools/istioctl.bash
[root@master231 istio]#
[root@master231 istio]# istioctl
admin (Manage control plane (istiod) configuration)
analyze (Analyze Istio configuration and print validation messages)
authz ((authz is experimental. Use `istioctl experimental authz`))
bug-report (Cluster information and log capture support tool.)


3.9 查看istio的版本号
[root@master231 istio]# istioctl version
client version: 1.17.8
control plane version: 1.17.8
data plane version: 1.17.8 (2 proxies)
[root@master231 istio]#

4 istio实现A|B测试
4.1 编写资源清单
[root@master231 /server/kubernetes/istio/case-demo]# cat 01-deploy-apps.yaml
apiVersion: v1
kind: Namespace
metadata:
name: yangsenlin



apiVersion: apps/v1
# 注意,创建pod建议使用deploy资源,不要使用rc资源,否则istioctl可能无法手动注入。
kind: Deployment
metadata:
name: apps-v1
namespace: yangsenlin
spec:
replicas: 1
selector:
matchLabels:
app: xiuxian01
version: v1
auther: yangsenlin
template:
metadata:
labels:
app: xiuxian01
version: v1
auther: yangsenlin
spec:
volumes:
– name: data
emptyDir: {}
initContainers:
– name: init
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2
volumeMounts:
– name: data
mountPath: /data
command:
– /bin/sh
– -c
– echo c1 > /data/index.html
containers:
– name: c1
ports:
– containerPort: 80
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html



apiVersion: apps/v1
kind: Deployment
metadata:
name: apps-v2
namespace: yangsenlin
spec:
replicas: 1
selector:
matchLabels:
app: xiuxian02
version: v2
auther: yangsenlin
template:
metadata:
labels:
app: xiuxian02
version: v2
auther: yangsenlin
spec:
volumes:
– name: data
emptyDir: {}
initContainers:
– name: init
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
volumeMounts:
– name: data
mountPath: /data
command:
– /bin/sh
– -c
– echo c2 > /data/index.html
containers:
– name: c2
ports:
– containerPort: 80
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
[root@master231 case-demo]# cat 02-svc-apps.yaml
apiVersion: v1
kind: Service
metadata:
name: apps-svc-v1
namespace: yangsenlin
spec:
selector:
version: v1
ports:
– protocol: TCP
port: 80
targetPort: 80
name: http



apiVersion: v1
kind: Service
metadata:
name: apps-svc-v2
namespace: yangsenlin
spec:
selector:
version: v2
ports:
– protocol: TCP
port: 80
targetPort: 80
name: http



apiVersion: v1
kind: Service
metadata:
name: apps-svc-all
namespace: yangsenlin
spec:
selector:
auther: yangsenlin
ports:
– protocol: TCP
port: 80
targetPort: 80
name: http
[root@master231 case-demo]# cat 03-deploy-client.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: apps-client
namespace: yangsenlin
spec:
replicas: 1
selector:
matchLabels:
app: client-test
template:
metadata:
labels:
app: client-test
spec:
containers:
– name: c1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
command:
– tail
– -f
– /etc/hosts
[root@master231 case-demo]# cat 04-vs-apps-svc-all.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: apps-svc-all-vs
namespace: yangsenlin
spec:
hosts:
– apps-svc-all
http:
# 定义匹配规则
– match:
# 基于header信息匹配将其进行路由,header信息自定义即可。
– headers:
# 匹配用户名包含”forestysl”的用户,这个KEY是咱们自定义的。
yangsenlin-username:
# “eaxct”关键词是包含,也可以使用”prefix”进行前缀匹配。
exact: forestysl
route:
– destination:
host: apps-svc-v1
– route:
– destination:
host: apps-svc-v2

4.2 手动注入
istioctl kube-inject -f 03-deploy-client.yaml | kubectl -n yangsenlin apply -f –
istioctl kube-inject -f 01-deploy-apps.yaml | kubectl -n yangsenlin apply -f –
kubectl get all -n yangsenlin

4.3 开始测试
[root@master231 /server/kubernetes/istio/case-demo]# kubectl get pods -n yangsenlin
NAME READY STATUS RESTARTS AGE
apps-client-5f579696d5-5n8zh 2/2 Running 0 3m39s
apps-v1-867845f5f9-wrkgv 2/2 Running 0 3m39s
apps-v2-7dfbc7c579-8nvsg 2/2 Running 0 3m39s
[root@master231 /server/kubernetes/istio/case-demo]#
[root@master241 yangsenlin]# kubectl -n yangsenlin exec -it apps-client-5cc67d864-g2r2v — sh
/ #
/ # while true; do curl -H “yangsenlin-username:forestysl” http://apps-svc-all;sleep 0.1;done # 添加用户认证的header信息
c1
c1
c1
c1
c1
c1
c1




/ # while true; do curl http://apps-svc-all;sleep 0.1;done # 不添加用户认证
c2
c2
c2
c2
c2
c2
c2






31 存储卷
常见的存储卷有
emptyDir
hostPath
nfs
configMap
secrets
downloadAPI
projected
pv
pvc
sc
local sc

1 emptyDir
1.1 emptyDir概述
emptyDir表示“空目录”(临时目录)存储卷,可以对容器的指定路径做数据持久化。

1.2 特点
随着pod生命周期的结束而结束

应用场景
1 实现同一个pod内不同容器的数据共享;
2 对数据做临时存储

1.3 对容器的指定目录做数据持久化
root@master231:/manifests# mkdir volumes
root@master231:/manifests# cd volumes/
root@master231:/manifests/volumes#

root@master231:/manifests/volumes# cat 01-deploy-emptyDir.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-emptydir
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
# 定义存储卷
volumes:
# 定义存储类型是一个”空目录”(emptyDir)
– emptyDir: {}
# 为存储卷起名字
name: data
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
# 定义存储卷挂载
volumeMounts:
# 需要要挂载的存储卷
– name: data
# 挂载到容器的指定路径,如果路径有文件,则会将文件的内容全部清空
mountPath: /usr/share/nginx/html

1.4 查看emptyDir数据的存储路径
/var/lib/kubelet/pods//volumes/kubernetes.io~empty-dir//

1.5 master节点写入测试数据,worker节点上查看
root@worker233:~# ll /var/lib/kubelet/pods/5a653aea-3acb-4525-8707-78dfc1024cd0/volumes/kubernetes.io~empty-dir/data/
total 8
drwxrwxrwx 2 root root 4096 Apr 10 20:59 ./
drwxr-xr-x 3 root root 4096 Apr 10 20:59 ../


root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-emptydir-745ffd54fc-d99ng — sh
/ # echo 111111111111111111 > /usr/share/nginx/html/index.html
/ # exit
root@master231:/manifests/volumes#

root@worker233:~# docker ps -a | grep deploy-xiuxian-emptydir-745ffd54fc-d99ng
fa31078b4b9f f28fd43be4ad “/docker-entrypoint.…” 46 seconds ago Up 45 seconds k8s_c1_deploy-xiuxian-emptydir-745ffd54fc-d99ng_default_5a653aea-3acb-4525-8707-78dfc1024cd0_0
bbd6aaefef3c registry.aliyuncs.com/google_containers/pause:3.6 “/pause” 47 seconds ago Up 47 seconds k8s_POD_deploy-xiuxian-emptydir-745ffd54fc-d99ng_default_5a653aea-3acb-4525-8707-78dfc1024cd0_0

root@worker233:~# ll /var/lib/kubelet/pods/5a653aea-3acb-4525-8707-78dfc1024cd0/volumes/kubernetes.io~empty-dir/data/
total 12
drwxrwxrwx 2 root root 4096 Apr 10 21:05 ./
drwxr-xr-x 3 root root 4096 Apr 10 20:59 ../
-rw-r–r– 1 root root 19 Apr 10 21:05 index.html

root@worker233:~# docker ps -a | grep deploy-xiuxian-emptydir-745ffd54fc-2644m
1d4664f3c397 f28fd43be4ad “/docker-entrypoint.…” 9 minutes ago Up 9 minutes k8s_c1_deploy-xiuxian-emptydir-745ffd54fc-2644m_default_071e2d24-955e-4218-bb03-1635eeee8388_0
cb5aa2df92e8 registry.aliyuncs.com/google_containers/pause:3.6 “/pause” 9 minutes ago Up 9 minutes k8s_POD_deploy-xiuxian-emptydir-745ffd54fc-2644m_default_071e2d24-955e-4218-bb03-1635eeee8388_0

root@worker233:~# ll /var/lib/kubelet/pods/071e2d24-955e-4218-bb03-1635eeee8388/volumes/kubernetes.io~empty-dir/data/
total 8
drwxrwxrwx 2 root root 4096 Apr 10 20:59 ./
drwxr-xr-x 3 root root 4096 Apr 10 20:59 ../

root@worker232:~# docker ps -a | grep deploy-xiuxian-emptydir-745ffd54fc-22xpb
1416ba87b6c1 f28fd43be4ad “/docker-entrypoint.…” 11 minutes ago Up 11 minutes k8s_c1_deploy-xiuxian-emptydir-745ffd54fc-22xpb_default_f0d37fdb-4364-4f43-9668-cfe1309dc359_0
b3e3d65ffeb9 registry.aliyuncs.com/google_containers/pause:3.6 “/pause” 11 minutes ago Up 11 minutes k8s_POD_deploy-xiuxian-emptydir-745ffd54fc-22xpb_default_f0d37fdb-4364-4f43-9668-cfe1309dc359_0
root@worker232:~# ll /var/lib/kubelet/pods/f0d37fdb-4364-4f43-9668-cfe1309dc359/volumes/kubernetes.io~empty-dir/data/
total 8
drwxrwxrwx 2 root root 4096 Apr 10 20:59 ./
drwxr-xr-x 3 root root 4096 Apr 10 20:59 ../
root@worker232:~#

1.6 持久化总结
只有在pod中写入数据的容器才会改变,没有写入数据的pod容器中无变化

1.7 实现同一个pod内不同容器的数据共享
root@master231:/manifests/volumes# cat 02-deploy-emptyDir.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-emptydir-multiple
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– emptyDir: {}
name: data
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
– name: c2
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command:
– /bin/sh
– -c
– echo www.yangsenlin.top >> /ysl/index.html; tail -f /etc/hosts
volumeMounts:
– name: data
mountPath: /ysl

root@master231:/manifests/volumes# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-emptydir-multiple-67cb889f5d-9q894 2/2 Running 0 19s 10.100.2.97 worker233
deploy-xiuxian-emptydir-multiple-67cb889f5d-rwc2p 2/2 Running 0 19s 10.100.2.98 worker233
deploy-xiuxian-emptydir-multiple-67cb889f5d-xvqxh 2/2 Running 0 19s 10.100.1.36 worker232
root@master231:/manifests/volumes#

1.8 测试
root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-emptydir-multiple-67cb889f5d-xvqxh -c c1 — sh
/ # ls -l /usr/share/nginx/html/
total 4
-rw-r–r– 1 root root 19 Apr 10 13:17 index.html
/ # cat /usr/share/nginx/html/index.html
www.yangsenlin.top
/ #

root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-emptydir-multiple-67cb889f5d-xvqxh -c c2 — sh
/ # ls -l /ysl/index.html
-rw-r–r– 1 root root 19 Apr 10 13:17 /ysl/index.html
/ # cat /ysl/index.html
www.yangsenlin.top
/ #

2 hostPath
2.1 概述
hostPath用于pod内容器访问worker节点宿主机任意路径

2.2 应用场景
1 将某个worker节点的宿主机数据共享给pod的容器指定路径
2 同步时区

2.3 部署应用
root@master231:/manifests/volumes# cat 03-deploy-hostPath.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-hostpath
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– emptyDir: {}
name: data01
# 声明存储卷的名称是hostPath
– hostPath:
# 将worker节点宿主机路径暴露给容器,如果目录不存在会自动创建。
path: /ysl
name: data02
– name: data03
hostPath:
path: /etc/localtime
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80
volumeMounts:
– name: data01
mountPath: /usr/share/nginx/html
– name: data02
mountPath: /ysl-container
– name: data03
mountPath: /etc/localtime
root@master231:/manifests/volumes# kubectl apply -f 03-deploy-hostPath.yaml

2.4 worker233节点准备测试数据
root@worker233:~# echo ceshi > /ysl/index.html

2.5 进入属于worker233节点的pod查看和worker232节点的pod作对比
root@master231:/manifests/volumes# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-hostpath-74db47bd86-kdqld 1/1 Running 0 11m 10.100.2.101 worker233
deploy-xiuxian-hostpath-74db47bd86-nh7hb 1/1 Running 0 11m 10.100.1.38 worker232
deploy-xiuxian-hostpath-74db47bd86-njvnm 1/1 Running 0 11m 10.100.2.102 worker233
root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-hostpath-74db47bd86-kdqld — sh
/ # ls -l /ysl-container/index.html
-rw-r–r– 1 root root 6 Apr 10 21:47 /ysl-container/index.html
/ # cat /ysl-container/index.html
ceshi
/ # exit
root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-hostpath-74db47bd86-nh7hb — sh
/ # ls -l /ysl-container/
total 0
/ #

2.6 总结
hostPath不能跨节点的pod数据共享,nfs就可以解决


3 nfs
3.1 概述
nfs表示网络文件系统,存在客户端和服务端,需要单独部署服务端
k8s在使用nfs时,集群应该安装nfs的相关模块(每个节点均需安装)

nfs的应用场景
1 实现跨节点不同pod的数据共享
2 实现跨节点存储数据

3.2 部署nfs服务器
所有节点安装nfs程序
apt -y install nfs-kernel-server

3.3 服务端配置nfs
root@master231:/manifests/volumes# mkdir -pv /software/data/nfs-server
root@master231:/manifests/volumes# tail -1 /etc/exports
/software/data/nfs-server *(rw,no_root_squash)
root@master231:/manifests/volumes#
root@master231:/manifests/volumes# systemctl restart nfs-server.service
root@master231:/manifests/volumes# exportfs
/software/data/nfs-server

3.4 应用部署
root@master231:/manifests/volumes# cat 04-deploy-nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-nfs
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– emptyDir: {}
name: data01
– name: data02
hostPath:
path: /etc/localtime
– name: data03
# 表示存储卷的类型是nfs
nfs:
# 指定nfs的服务器
server: 10.0.0.231
# 指定nfs共享的数据路径
path: /software/data/nfs-server
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80
volumeMounts:
– name: data01
mountPath: /usr/share/nginx/html
– name: data02
mountPath: /etc/localtime
– name: data03
mountPath: /nfsdata

root@master231:/manifests/volumes# kubectl apply -f 04-deploy-nfs.yaml
deployment.apps/deploy-xiuxian-nfs created

root@master231:/manifests/volumes# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-nfs-66c674bccb-7dh2w 1/1 Running 0 29s 10.100.2.104 worker233
deploy-xiuxian-nfs-66c674bccb-7sjst 1/1 Running 0 29s 10.100.1.39 worker232
deploy-xiuxian-nfs-66c674bccb-g6d72 1/1 Running 0 29s 10.100.2.103 worker233

root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-nfs-66c674bccb-7dh2w — sh/ # echo www.yangsenlin.top > /nfsdata/index.html
/ # exit
root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-nfs-66c674bccb-7sjst — sh/ # cat /nfsdata/index.html
www.yangsenlin.top
/ # exit
root@master231:/manifests/volumes# kubectl exec -it deploy-xiuxian-nfs-66c674bccb-g6d72 — sh
/ # cat /nfsdata/index.html
www.yangsenlin.top
/ # exit
root@master231:/manifests/volumes# cat /software/data/nfs-server/index.html
www.yangsenlin.top
root@master231:/manifests/volumes#


4 存储卷综合案例测试
root@master231:/manifests/volumes# cat 05-deploy-multiple.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-multiple
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
initContainers:
– name: init01
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
command:
– cp
args:
– /haha/index.html
– /xixi/
volumeMounts:
– name: data01
mountPath: /xixi
– name: data03
mountPath: /haha
volumes:
– emptyDir: {}
name: data01
– name: data02
hostPath:
path: /etc/localtime
– name: data03
nfs:
server: 10.0.0.231
path: /software/data/nfs-server
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80
volumeMounts:
– name: data01
mountPath: /usr/share/nginx/html
– name: data02
mountPath: /etc/localtime
– name: data03
mountPath: /nfsdata
root@master231:/manifests/volumes#


4 configMap

4.1 什么是configMap
configMap的本质就是将配置信息基于键值对的方式进行映射的一种手段,数据存储在etcd
configMap将你的环境配置信息和容器镜像解耦,便于应用配置的修改

4.2 声明式API创建cm资源
root@master231:/manifests/volumes# kubectl explain configMap.data
root@master231:~/manifests/configmaps# cat 01-cm.demo
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
# 定义配置信息
data:
# 类属性键;每一个键都映射到一个简单的值
player_initial_lives: “3”
ui_properties_file_name: “user-interface.properties”
# 自定义键值对
xingming: zhangsan
city: Sichuan

# 类文件键
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
# 定义MySQL的配置信息
my.cnf: |
datadir=/data/mysql80
basedir=/softwares/mysql80
port=3306
socket=/tmp/mysql80.sock
root@master231:~/manifests/configmaps#

root@master231:/manifests/volumes# kubectl apply -f 01-cm.demo
configmap/game-demo created
root@master231:/manifests/volumes# kubectl get cm
NAME DATA AGE
game-demo 7 8s
kube-root-ca.crt 1 7d14h
root@master231:/manifests/volumes# kubectl get -f 01-cm.demo
NAME DATA AGE
game-demo 7 24s
root@master231:/manifests/volumes# kubectl get cm game-demo
NAME DATA AGE
game-demo 7 38s

4.3 响应式创建cm
root@master231:~/manifests/configmaps# kubectl create configmap test-xy –from-file=myhosts=/etc/hosts –from-literal=username=admin –from-literal=password=admin123 –from-literal=myos=/etc/os-release

root@master231:~/manifests/configmaps# kubectl get cm
NAME DATA AGE
game-demo 7 24h
kube-root-ca.crt 1 8d
test-xy 4 44s
root@master231:~/manifests/configmaps# kubectl get cm test-xy
NAME DATA AGE
test-xy 4 54s
root@master231:~/manifests/configmaps# kubectl describe cm test-xy

root@master231:~/manifests/configmaps# kubectl get cm test-xy -o yaml

4.4 基于环境变量引用cm资源
root@master231:~/manifests/volumes# cat 07-deploy-cm-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-cm-env
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
env:
– name: test-xingming
# 值从哪里引用
valueFrom:
# 表示值从一个cm类型引用
configMapKeyRef:
# 指定引用cm资源的名称
name: game-demo
# 引用cm的某个key
key: xingming
– name: test-mysql
valueFrom:
configMapKeyRef:
name: game-demo
key: my.cnf

root@master231:~/manifests/volumes# kubectl apply -f 07-deploy-cm-env.yaml
root@master231:~/manifests/volumes# kubectl exec -it deploy-cm-env-6987ccb879-ddlbk — env|grep test
test-xingming=zhangsan
test-mysql=datadir=/data/mysql80

4.5 pod基于存储卷引用cm资源
root@master231:~/manifests/volumes# cat 08-deploy-cm-volume.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-cm-volume
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– name: data
# 表示存储卷的类型是cm
configMap:
# 指定cm的名称
name: game-demo
# 引用cm的具体key,若不定义,则会将cm的所有key全部引用,将每个key作为文件名称。
# 如果定义,可以引用具体的字段名称,且指定文件名称。
items:
# 引用cm资源具体的KEY
– key: game.properties
# 指定将来挂载时的文件名称
path: test-game.properties
– key: my.cnf
path: ysl-my.cnf
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
volumeMounts:
– name: data
mountPath: /ysl

root@master231:~/manifests/volumes# kubectl apply -f 08-deploy-cm-volume.yaml

root@master231:~/manifests/volumes# kubectl exec -it deploy-cm-volume-b645c76cc-h9pfm — ls -l /ysl
total 0
lrwxrwxrwx 1 root root 27 Apr 13 03:01 test-game.properties -> ..data/test-game.properties
lrwxrwxrwx 1 root root 17 Apr 13 03:01 ysl-my.cnf -> ..data/ysl-my.cnf

4.6 cm资源映射nginx配置文件subPath

root@master231:~/manifests/volumes# cat 09-deploy-cm-nginx-subPath.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-subfile
data:
nginx.conf: |
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}


default.conf: |
server {
listen 81;
listen [::]:81;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

}




apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-cm-nginx-subpath
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– name: data01
configMap:
name: nginx-subfile
items:
– key: default.conf
path: default.conf
– name: data02
configMap:
name: nginx-subfile
items:
– key: nginx.conf
path: nginx.conf
– name: data03
hostPath:
path: /etc/localtime
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
#command: [“tail”,”-f”,”/etc/hosts”]
volumeMounts:
– name: data01
mountPath: /etc/nginx/conf.d/
– name: data02
mountPath: /etc/nginx/nginx.conf
# 当subPath的值和存储卷的path相同时,mountPath挂载点将是一个文件,而非目录。
subPath: nginx.conf
– name: data03
mountPath: /etc/localtime
root@master231:~/manifests/volumes# kubectl apply -f 09-deploy-cm-nginx-subPath.yaml
configmap/nginx-subfile created
deployment.apps/deploy-cm-nginx-subpath created
root@master231:~/manifests/volumes#


root@master231:~/manifests/volumes# kubectl exec -it deploy-cm-nginx-subpath-6f7cc6446b-66jvf — ls -l /etc/nginx;date -R
total 32
drwxrwxrwx 3 root root 4096 Apr 13 11:09 conf.d
-rw-r–r– 1 root root 1077 May 25 2021 fastcgi.conf
-rw-r–r– 1 root root 1007 May 25 2021 fastcgi_params
-rw-r–r– 1 root root 5231 May 25 2021 mime.types
lrwxrwxrwx 1 root root 22 Nov 13 2021 modules -> /usr/lib/nginx/modules
-rw-r–r– 1 root root 597 Apr 13 11:09 nginx.conf
-rw-r–r– 1 root root 636 May 25 2021 scgi_params
-rw-r–r– 1 root root 664 May 25 2021 uwsgi_params
Sun, 13 Apr 2023 11:10:49 +0800

5 secrets
5.1 概述
和cm作用类似,但secrets是k8s用于存储敏感数据(密码、令牌或密钥的对象)的资源
会将数据以base64进行编码,将敏感数据单独存储这样让数据泄露的风险会减小。
官网链接:
https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/
https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/#secret-types

5.2 声明式创建创建secret的两种方式
5.2.1 基于stringData
root@master231:~/manifests/secrets# kubectl apply -f 01-secrets-demo.yaml
secret/test-mysql-conn created
root@master231:~/manifests/secrets# kubectl get -f 01-secrets-demo.yaml
NAME TYPE DATA AGE
test-mysql-conn Opaque 3 11s
root@master231:~/manifests/secrets# kubectl describe -f 01-secrets-demo.yaml
Name: test-mysql-conn
Namespace: default
Labels:
Annotations:

Type: Opaque

Data
====
my.cnf: 92 bytes
password: 3 bytes
username: 5 bytes
root@master231:~/manifests/secrets# cat 01-secrets-demo.yaml
apiVersion: v1
kind: Secret
metadata:
name: test-mysql-conn
# 创建secret时会自动将value的值自动编码
stringData:
username: admin
password: ysl
my.cnf: |
datadir=/ysl/data/mysql80
basedir=/ysl/softwares/mysql80
port=3306
socket=/tmp/mysql80.sock
root@master231:~/manifests/secrets# kubectl get secrets test-mysql-conn -o yaml
apiVersion: v1
data:
my.cnf: ZGF0YWRpcj0veXNsL2RhdGEvbXlzcWw4MApiYXNlZGlyPS95c2wvc29mdHdhcmVzL215c3FsODAKcG9ydD0zMzA2CnNvY2tldD0vdG1wL215c3FsODAuc29jawo=
password: eXNs
username: YWRtaW4=
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{“apiVersion”:”v1″,”kind”:”Secret”,”metadata”:{“annotations”:{},”name”:”test-mysql-conn”,”namespace”:”default”},”stringData”:{“my.cnf”:”datadir=/ysl/data/mysql80\nbasedir=/ysl/softwares/mysql80\nport=3306\nsocket=/tmp/mysql80.sock\n”,”password”:”ysl”,”username”:”admin”}}
creationTimestamp: “2025-04-13T03:18:26Z”
name: test-mysql-conn
namespace: default
resourceVersion: “476167”
uid: b1d5bdc1-31a9-4d41-adb5-6a660fccd588
type: Opaque

5.2.2 将编码的文件解码
base64解码
echo -n base64编码 | base64 -d

base64编码
echo 需要编码的文件 | base64

5.2.3 基于data(反推yaml)
root@master231:~/manifests/secrets# kubectl get secrets test-mysql-conn -o yaml > 02-secrets-Data-demo.yaml
root@master231:~/manifests/secrets# kubectl apply -f 02-secrets-Data-demo.yaml

5.3 响应式创建secret
root@master231:~/manifests/secrets# kubectl create secret generic test-secrets –from-file=myhost=/etc/hosts –from-file=myos=/etc/os-release –from-literal=xingming=ysl –from-literal=class=ysl
secret/test-secrets created

root@master231:~/manifests/secrets# kubectl get secrets test-secrets
NAME TYPE DATA AGE
test-secrets Opaque 4 28s
root@master231:~/manifests/secrets# kubectl describe secrets test-secrets

5.4 pod基于环境变量应用secret
root@master231:~/manifests/volumes# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-secret-env-5dfb865b94-468t7 1/1 Running 0 3s
deploy-secret-env-5dfb865b94-mmztq 1/1 Running 0 3s
deploy-secret-env-5dfb865b94-vnpr2 1/1 Running 0 3s
root@master231:~/manifests/volumes# kubectl exec -it deploy-secret-env-5dfb865b94-468t7 — env | grep test
test-username=admin
test-password=ysl
test-class=datadir=/ysl/data/mysql80
root@master231:~/manifests/volumes# cat 10-deploy-secrets-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-secret-env
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
env:
– name: test-username
valueFrom:
# 表示值从一个secret类型引用
secretKeyRef:
# 指定引用secret资源的名称
name: test-mysql-conn
# 引用secret的某个key
key: username
– name: test-password
valueFrom:
secretKeyRef:
name: test-mysql-conn
key: password
– name: test-class
valueFrom:
secretKeyRef:
name: test-mysql-conn
key: my.cnf
root@master231:~/manifests/volumes#

5.5 基于存储卷应用secret
root@master231:~/manifests/volumes# cat 11-deploy-secrets-volume.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-secret-volume
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– name: data
# 表示存储卷的类型是secret
secret:
# 指定secret的名称
secretName: test-mysql-conn
items:
– key: username
path: username.txt
– key: password
path: pwd.txt
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
volumeMounts:
– name: data
mountPath: /ysl
root@master231:~/manifests/volumes# kubectl apply -f 11-deploy-secrets-volume.yaml
deployment.apps/deploy-secret-volume created
root@master231:~/manifests/volumes# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-secret-volume-6d5f7df59-55fmg 1/1 Running 0 9s
deploy-secret-volume-6d5f7df59-7q4df 1/1 Running 0 9s
deploy-secret-volume-6d5f7df59-lkmcz 1/1 Running 0 9s
root@master231:~/manifests/volumes# kubectl exec -it deploy-secret-volume-6d5f7df59-55fmg —
cat /ysl/username.txt;cat /ysl/pwd.txt

root@master231:~/manifests/volumes# kubectl exec -it deploy-secret-volume-6d5f7df59-55fmg — sh
/ # ls /ysl
pwd.txt username.txt
/ # cat /ysl/pwd.txt
/ # cat /ysl/pwd.txt -n
1 ysl
/ # exit

6 拉取harbor私有镜像
6.1 推送镜像到harbor
root@worker233:~# docker tag crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:nginx-1.24 harbor.ysl.com/ysl-xiuxian/apps:nginx-1.24
root@worker233:~# docker push harbor.ysl.com/ysl-xiuxian/apps:nginx-1.24

6.2 将harbor仓库设置为私有
在配置管理里面将“公开”勾选叉掉并保存
6.3 创建harbor的普通用户并授权项目


6.4 响应式创建secrets
root@master231:~/manifests/volumes# kubectl create secret docker-registry ysl-xiuxian –docker-username=ceshi –docker-password=XZnh@95599 –docker-email=ceshi@qq.com –docker-server=harbor.ysl.com
secret/ysl-xiuxian created
root@master231:~/manifests/volumes#

root@master231:~/manifests/volumes# kubectl get secret/ysl-xiuxian
NAME TYPE DATA AGE
ysl-xiuxian kubernetes.io/dockerconfigjson 1 48s
root@master231:~/manifests/volumes# kubectl describe secret/ysl-xiuxian

root@master231:~/manifests/volumes# kubectl get secret/ysl-xiuxian -o yaml

6.5 拉取镜像时指定secret
root@master231:~/manifests/volumes# cat 12-deploy-secrets-harbor.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-secret-harbor
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
# 指定拉取私有仓库的镜像仓库的secret认证信息
imagePullSecrets:
– name: ysl-xiuxian
containers:
– name: c1
image: harbor.ysl.com/ysl-xiuxian/apps:v2


root@master231:~/manifests/volumes# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-secret-harbor-57b7f55bb9-gdl7g 1/1 Running 0 5s
deploy-secret-harbor-57b7f55bb9-hkrhz 1/1 Running 0 5s
deploy-secret-harbor-57b7f55bb9-k4z7w 1/1 Running 0 5s


6.6 容器拉取镜像策略
Always
1 如果本地没有镜像,则会去远程仓库拉取镜像
2 如果本地有镜像,则会对比本地的镜像摘要信息和远程仓库的摘要信息对比,相同则不拉取,不同则拉取

Never
1 不管本地有没有镜像,都不会拉取

IfNotPresent
1 本地没有镜像,则会去远程仓库拉取镜像
2 如果本地没有镜像,则尝试启动容器

温馨提示:
Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.

如果镜像标签的tag为”:latest”时,默认的镜像策略为”Always”,否则默认镜像拉取策略为”IfNotPresent”。

7 servieaccounts
7.1 概述
serviceaccounts简称sa,表示服务账号,其作用就是用于身份验证。
创建一个sa是会自动关联一个secrets资源
为pod内的服务提供服务账号,可以基于该账号进行认证操作

7.2 响应式创建sa
root@master231:~/manifests/volumes# kubectl create serviceaccount ysl
serviceaccount/ysl created

root@master231:~/manifests/volumes# kubectl get sa
NAME SECRETS AGE
default 1 8d
ysl 1 50s
root@master231:~/manifests/volumes# kubectl get sa ysl -o yaml

secrets:
– name: ysl-token-wl69r

root@master231:~/manifests/volumes# kubectl get secrets ysl-token-wl69r
NAME TYPE DATA AGE
ysl-token-wl69r kubernetes.io/service-account-token 3 2m2s
root@master231:~/manifests/volumes#

7.3 声明式创建服务账号
root@master231:~/manifests/serviceaccounts# kubectl delete -f 01-sa.yaml
serviceaccount “ysl” deleted
root@master231:~/manifests/serviceaccounts# kubectl apply -f 01-sa.yaml
serviceaccount/ysl created
root@master231:~/manifests/serviceaccounts# kubectl get -f 01-sa.yaml
NAME SECRETS AGE
ysl 2 7s
root@master231:~/manifests/serviceaccounts#

7.4 基于sa引用secret实现镜像拉取
root@master231:~/manifests/volumes# cat 13-deploy-imagePullPolicy-serviceAccountName.yaml
apiVersion: v1
kind: Secret
metadata:
name: harbor-ysl
type: kubernetes.io/dockerconfigjson
stringData:
# 解码:
# echo bGludXg5NTpMaW51eDk1QDIwMjU= | base64 -d
# 编码:
# echo -n ysl:ysl@2025 | base64
.dockerconfigjson: ‘{“auths”:{“harbor.ysl.com”:{“username”:”ceshi”,”password”:”XZnh@95599″,”email”:”ceshi@qq.com”,”auth”:”Y2VzaGkK”}}}’



apiVersion: v1
kind: ServiceAccount
metadata:
name: ysl
imagePullSecrets:
– name: harbor-ysl



apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-secret-harbor
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
#imagePullSecrets:
#- name: harbor-ysl
# 也可以不适用”imagePullSecrets”,而是基于sa进行认证
serviceAccountName: ysl
containers:
– name: c1
image: harbor.ysl.com/test-xiuxian/test:v2
# imagePullPolicy: Never
# imagePullPolicy: IfNotPresent
imagePullPolicy: Always
root@master231:~/manifests/volumes# kubectl apply -f 13-deploy-imagePullPolicy-serviceAccountName.yaml
[root@master231 volumes]# kubectl get pods -o wide


8 valueFrom之fieldRef及resourceFieldRef
fieldRef有效值:
– metadata.name
– metadata.namespace,
– `metadata.labels[‘‘]`
– `metadata.annotations[‘‘]`
– spec.nodeName
– spec.serviceAccountName
– status.hostIP
– status.podIP
– status.podIPs

resourceFieldRef有效值:
– limits.cpu
– limits.memory
– limits.ephemeral-storage
– requests.cpu
– requests.memory
– requests.ephemeral-storage
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-valuefrom
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
containers:
– name: c1
image: harbor.ysl.com/ysl-xiuxian/apps:v2
resources:
requests:
cpu: 0.2
memory: 200Mi
limits:
cpu: 0.5
memory: 500Mi
imagePullPolicy: Always
env:
– name: test-PODNAME
valueFrom:
fieldRef:
fieldPath: metadata.name
– name: test-IP
valueFrom:
fieldRef:
fieldPath: status.podIP
– name: test-REQUESTS
valueFrom:
resourceFieldRef:
resource: requests.cpu
– name: test-LIMITS
valueFrom:
resourceFieldRef:
resource: limits.memory
[root@master231 volumes]# kubectl apply -f 14-deploy-valueFrom.yaml
deployment.apps/deploy-valuefrom created
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
[root@master231 volumes]# kubectl exec deploy-valuefrom-7f48549b-5v4rn — env

test-LIMITS=524288000
test-PODNAME=deploy-valuefrom-7f48549b-5v4rn
test-IP=10.100.2.182
# 很明显,对于requests字段并没有抓到0.2,而是”向上取整”。
test-REQUESTS=1



9 downloadAPI
9.1 概述
与ConfigMap和Secret不同,DownwardAPI自身并非一种独立的API资源类型。

DownwardAPI只是一种将Pod的metadata、spec或status中的字段值注入到其内部Container里的方式。

DownwardAPI提供了两种方式用于将POD的信息注入到容器内部
– 环境变量:
用于单个变量,可以将POD信息和容器信息直接注入容器内部.
– Volume挂载:
将 POD 信息生成为文件,直接挂载到容器内部中去

9.2 应用部署测试
root@master231:~/manifests/volumes# kubectl apply -f 15-deploy-download-API.yaml
deployment.apps/downloadapi-demo created
root@master231:~/manifests/volumes# kubectl get pods
NAME READY STATUS RESTARTS AGE
downloadapi-demo-684844f646-pdx9l 2/2 Running 0 4s
root@master231:~/manifests/volumes# cat 15-deploy-download-API.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: downloadapi-demo
spec:
replicas: 1
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
volumes:
– name: data01
downwardAPI:
items:
– path: pod-name
# 仅支持: annotations, labels, name and namespace。
fieldRef:
fieldPath: “metadata.name”
– name: data02
downwardAPI:
items:
– path: pod-ns
fieldRef:
fieldPath: “metadata.namespace”
– name: data03
downwardAPI:
items:
– path: containers-limists-memory
# 仅支持: limits.cpu, limits.memory, requests.cpu and requests.memory
resourceFieldRef:
containerName: c1
resource: “limits.memory”
containers:
– name: c1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
resources:
requests:
cpu: 0.2
memory: 300Mi
limits:
cpu: 0.5
memory: 500Mi
volumeMounts:
– name: data01
mountPath: /xixi
– name: data02
mountPath: /haha
– name: data03
mountPath: /hehe
– name: c2
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2
command:
– tail
args:
– -f
– /etc/hosts
resources:
limits:
cpu: 1.5
memory: 1.5Gi
root@master231:~/manifests/volumes#

root@master231:~/manifests/volumes# kubectl exec -it downloadapi-demo-684844f646-pdx9l -c c1 — sh
/ # ls /xixi/
pod-name
/ # ls /h
haha/ hehe/ home/
/ # ls /hehe/
containers-limists-memory
/ # ls /haha
pod-ns
/ #

10 projected
10.1 概述
Projected Volume是一种特殊的卷类型,它能够将已存在的多个卷投射进同一个挂载点目录中。

Projected Volume仅支持对如下四种类型的卷(数据源)进行投射操作,这类的卷一般都是用于为容器提供预先定义好的数据:
– Secret:
投射Secret 对象。
– ConfigMap:
投射ConfigMap对象。
– DownwardAPI:
投射Pod元数据。
– ServiceAccountToken:
投射ServiceAccount Token。

10.2 部署应用测试
root@master231:~/manifests/volumes# cat 16-deploy-projested-volumes.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ysl-cm
data:
blog: “https://www.cnblogs.com/yangsenlin”
k8s: “https://space.bilibili.com/600805398/channel/series”



apiVersion: v1
kind: Secret
metadata:
name: ysl-secrets
stringData:
username: admin
password: yangsenlin


apiVersion: apps/v1
kind: Deployment
metadata:
name: projected-demo
spec:
replicas: 1
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
volumes:
– name: data01
projected:
sources:
– downwardAPI:
items:
– path: containers-limists-memory
resourceFieldRef:
containerName: c1
resource: “limits.memory”
– configMap:
name: ysl-cm
– secret:
name: ysl-secrets
– serviceAccountToken:
path: ysl-token
containers:
– name: c1
image: harbor.ysl.com/ysl-xiuxian/apps:v1
resources:
limits:
cpu: 0.5
memory: 500Mi
volumeMounts:
– name: data01
mountPath: /ysl-xixi
root@master231:~/manifests/volumes# kubectl apply -f 16-deploy-projested-volumes.yaml
configmap/ysl-cm unchanged
secret/ysl-secrets configured
deployment.apps/projected-demo created
root@master231:~/manifests/volumes# kubectl get pods
NAME READY STATUS RESTARTS AGE
projected-demo-d5544c7d7-kpbxb 1/1 Running 0 3s
root@master231:~/manifests/volumes# kubectl exec -it projected-demo-d5544c7d7-kpbxb — sh
/ # ls /ysl-xixi
blog k8s username
containers-limists-memory password ysl-token
/ #

11 pv sc pvc
11.1 概述
– pv
pv用于和后端存储对接的资源,关联后端存储。

– sc
sc可以动态创建pv的资源,关联后端存储。

– pvc
可以向pv或者sc进行资源请求,获取特定的存储。

pod只需要在存储卷声明使用哪个pvc即可。

11.2 手动创建pv和pvc及pod引用
1 手动创建pv
root@master231:~/manifests/volumes# mkdir -pv /ysl/data/nfs-server/pv/linux/pv00{1,2,3}

root@master231:~/manifests/persistentvolumes# cat manual-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: test-linux-pv01
labels:
xingming: zhangsan
spec:
# 声明PV的访问模式,常用的有”ReadWriteOnce”,”ReadOnlyMany”和”ReadWriteMany”:
# ReadWriteOnce:(简称:”RWO”)
# 只允许单个worker节点读写存储卷,但是该节点的多个Pod是可以同时访问该存储卷的。
# ReadOnlyMany:(简称:”ROX”)
# 允许多个worker节点进行只读存储卷。
# ReadWriteMany:(简称:”RWX”)
# 允许多个worker节点进行读写存储卷。
# ReadWriteOncePod:(简称:”RWOP”)
# 该卷可以通过单个Pod以读写方式装入。
# 如果您想确保整个集群中只有一个pod可以读取或写入PVC,请使用ReadWriteOncePod访问模式。
# 这仅适用于CSI卷和Kubernetes版本1.22+。
accessModes:
– ReadWriteMany
# 声明存储卷的类型为nfs
nfs:
path: /ysl/data/nfs-server/pv/linux/pv001
server: 10.0.0.231
# 指定存储卷的回收策略,常用的有”Retain”和”Delete”
# Retain:
# “保留回收”策略允许手动回收资源。
# 删除PersistentVolumeClaim时,PersistentVolume仍然存在,并且该卷被视为”已释放”。
# 在管理员手动回收资源之前,使用该策略其他Pod将无法直接使用。
# Delete:
# 对于支持删除回收策略的卷插件,k8s将删除pv及其对应的数据卷数据。
# Recycle:
# 对于”回收利用”策略官方已弃用。相反,推荐的方法是使用动态资源调配。
# 如果基础卷插件支持,回收回收策略将对卷执行基本清理(rm -rf /thevolume/*),并使其再次可用于新的声明。
persistentVolumeReclaimPolicy: Retain
# 声明存储的容量
capacity:
storage: 2Gi



apiVersion: v1
kind: PersistentVolume
metadata:
name: test-linux-pv02
labels:
xingming: zhangsan
spec:
accessModes:
– ReadWriteMany
nfs:
path: /ysl/data/nfs-server/pv/linux/pv002
server: 10.0.0.231
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 5Gi



apiVersion: v1
kind: PersistentVolume
metadata:
name: test-linux-pv03
labels:
xingming: zhangsan
spec:
accessModes:
– ReadWriteMany
nfs:
path: /ysl/data/nfs-server/pv/linux/pv003
server: 10.0.0.231
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 10Gi
root@master231:~/manifests/persistentvolumes# kubectl apply -f manual-pv.yaml
persistentvolume/test-linux-pv01 created
persistentvolume/test-linux-pv02 created
persistentvolume/test-linux-pv03 created
root@master231:~/manifests/persistentvolumes# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
test-linux-pv01 2Gi RWX Retain Available 4s
test-linux-pv02 5Gi RWX Retain Available 4s
test-linux-pv03 10Gi RWX Retain Available 4s
root@master231:~/manifests/persistentvolumes#


相关资源说明:
NAME :
pv的名称
CAPACITY :
pv的容量
ACCESS MODES:
pv的访问模式
RECLAIM POLICY:
pv的回收策略。
STATUS :
pv的状态。
CLAIM:
pv被哪个pvc使用。
STORAGECLASS
sc的名称。
REASON
pv出错时的原因。
AGE
创建的时间。

2 手动创建pvc
root@master231:~/manifests/persistentvolumes# kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/test-linux-pvc Bound test-linux-pv02 5Gi RWX 7s

NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/test-linux-pv01 2Gi RWX Retain Available 2m34s
persistentvolume/test-linux-pv02 5Gi RWX Retain Bound default/test-linux-pvc 2m34s
persistentvolume/test-linux-pv03 10Gi RWX Retain Available 2m34s
root@master231:~/manifests/persistentvolumes#
root@master231:/manifests/volumes# cat 17-deploy-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-pvc-demo
spec:
replicas: 1
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
volumes:
– name: data
# 声明存储卷的类型是pvc
persistentVolumeClaim:
# 声明pvc的名称
claimName: test-linux-pvc
– name: dt
hostPath:
path: /etc/localtime
initContainers:
– name: init01
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
volumeMounts:
– name: data
mountPath: /ysl
– name: dt
mountPath: /etc/localtime
command:
– /bin/sh
– -c
– date -R >> /ysl/index.html ; echo www.ysl.com >> /ysl/index.html
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
– name: dt
mountPath: /etc/localtime
root@master231:/manifests/volumes# kubectl apply -f 17-deploy-pvc.yaml
deployment.apps/deploy-pvc-demo created
root@master231:/manifests/volumes#






4.验证Pod后端的存储数据
4.1 找到pvc的名称
[root@master231 volumes]# kubectl describe pod deploy-pvc-demo-688b57bdd-dlkzd
Name: deploy-pvc-demo-688b57bdd-dlkzd
Namespace: default

Volumes:
data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: test-linux-pvc

4.2 基于pvc找到与之关联的pv
[root@master231 volumes]# kubectl get pvc test-linux-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-linux-pvc Bound test-linux-pv02 5Gi RWX 12m
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pv test-linux-pv02
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
test-linux-pv02 5Gi RWX Retain Bound default/test-linux-pvc 15m
[root@master231 volumes]#


4.3 查看pv的详细信息
[root@master231 volumes]# kubectl describe pv test-linux-pv02
Name: test-linux-pv02
Labels: school=ysl

Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 10.0.0.231
Path: /ysl/data/nfs-server/pv/linux/pv002
ReadOnly: false



4.4 验证数据的内容
[root@master231 volumes]# ll /ysl/data/nfs-server/pv/linux/pv002
total 12
drwxr-xr-x 2 root root 4096 Feb 14 16:46 ./
drwxr-xr-x 5 root root 4096 Feb 14 16:36 ../
-rw-r–r– 1 root root 68 Feb 14 16:49 index.html
[root@master231 volumes]#
[root@master231 volumes]# cat /ysl/data/nfs-server/pv/linux/pv002/index.html
Fri, 14 Feb 2025 16:49:42 +0800
www.ysl.com
[root@master231 volumes]#


12 基于nfs4.9.0版本实现动态存储类应用部署
推荐阅读:
https://github.com/kubernetes-csi/csi-driver-nfs/blob/master/docs/install-csi-driver-v4.9.0.md

https://kubernetes.io/docs/concepts/storage/storage-classes/#nfs
12.1 克隆代码
[root@master231 nfs]# git clone https://github.com/kubernetes-csi/csi-driver-nfs.git


12.2 安装动态存储类
root@master231:~/csi-driver-nfs-4.9.0# ./deploy/install-driver.sh v4.9.0 local
use local deploy
Installing NFS CSI driver, version: v4.9.0 …
serviceaccount/csi-nfs-controller-sa created
serviceaccount/csi-nfs-node-sa created
clusterrole.rbac.authorization.k8s.io/nfs-external-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/nfs-csi-provisioner-binding created
csidriver.storage.k8s.io/nfs.csi.k8s.io created
deployment.apps/csi-nfs-controller created
daemonset.apps/csi-nfs-node created
NFS CSI driver installed successfully.

12.3 验证安装
root@master231:~/images# kubectl -n kube-system get pods -o wide | grep csi
csi-nfs-controller-5c5c695fb-qxxp2 4/4 Running 0 4m31s 10.0.0.232 worker232
csi-nfs-node-6k297 3/3 Running 0 37m 10.0.0.231 master231
csi-nfs-node-sxjwx 3/3 Running 0 37m 10.0.0.232 worker232
csi-nfs-node-tjm4p 3/3 Running 0 4m13s 10.0.0.233 worker233
root@master231:~/images#

4.创建存储类
root@master231:~/csi-driver-nfs-4.9.0# mkdir -p /ysl/data/nfs-server/sc

root@master231:~/csi-driver-nfs-4.9.0# cat deploy/v4.9.0/storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 10.0.0.231
share: /ysl/data/nfs-server/sc
# csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume
# csi.storage.k8s.io/provisioner-secret-name: “mount-options”
# csi.storage.k8s.io/provisioner-secret-namespace: “default”
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
– nfsvers=4.1

root@master231:~/csi-driver-nfs-4.9.0# kubectl apply -f deploy/v4.9.0/storageclass.yaml
storageclass.storage.k8s.io/nfs-csi created
root@master231:~/csi-driver-nfs-4.9.0# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 7s
root@master231:~/csi-driver-nfs-4.9.0#


5.删除pv和pvc保证环境”干净”
root@master231:/manifests/persistentvolumes# kubectl delete -f .
persistentvolume “ysl-linux-pv01” deleted
persistentvolume “ysl-linux-pv02” deleted
persistentvolume “ysl-linux-pv03” deleted
persistentvolumeclaim “ysl-linux-pvc” deleted
root@master231:/manifests/persistentvolumes# kubectl get pv,pvc,pods
No resources found

6.创建pvc测试
[root@master231 persistentvolumeclaims]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 9m15s
[root@master231 persistentvolumeclaims]#
[root@master231 persistentvolumeclaims]# cat pvc-sc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-linux-pvc
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 4Gi
requests:
storage: 3Gi
[root@master231 persistentvolumeclaims]#
[root@master231 persistentvolumeclaims]# kubectl apply -f pvc-sc.yaml
persistentvolumeclaim/test-linux-pvc created
[root@master231 persistentvolumeclaims]#
[root@master231 persistentvolumeclaims]# kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/test-linux-pvc Bound pvc-f47d1e5b-a2f1-463f-b06c-7940add76104 3Gi RWX nfs-csi 14s

NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-f47d1e5b-a2f1-463f-b06c-7940add76104 3Gi RWX Delete Bound default/test-linux-pvc nfs-csi 14s
[root@master231 persistentvolumeclaims]#


7.pod引用pvc
[root@master231 volumes]# kubectl apply -f 17-deploy-pvc.yaml
deployment.apps/deploy-pvc-demo created
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-pvc-demo-688b57bdd-td2z7 1/1 Running 0 4s 10.100.1.143 worker232
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-pvc-demo-688b57bdd-td2z7 1/1 Running 0 4s 10.100.1.143 worker232
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.1.143
Fri, 14 Feb 2025 17:27:25 +0800
www.ysl.com
[root@master231 volumes]#


8.验证pod的后端存储数据
[root@master231 volumes]# kubectl describe pod deploy-pvc-demo-688b57bdd-td2z7 | grep ClaimName
ClaimName: test-linux-pvc
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pvc test-linux-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-linux-pvc Bound pvc-b425481e-3b15-4854-bf34-801a29edfcc5 3Gi RWX nfs-csi 2m29s
[root@master231 volumes]#
[root@master231 volumes]# kubectl describe pv pvc-b425481e-3b15-4854-bf34-801a29edfcc5 | grep Source -A 5
Source:
Type: CSI (a Container Storage Interface (CSI) volume source)
Driver: nfs.csi.k8s.io
FSType:
VolumeHandle: 10.0.0.231#ysl/data/nfs-server/sc#pvc-b425481e-3b15-4854-bf34-801a29edfcc5##
ReadOnly: false
[root@master231 volumes]#
[root@master231 volumes]# ll /ysl/data/nfs-server/sc/pvc-b425481e-3b15-4854-bf34-801a29edfcc5/
total 12
drwxr-xr-x 2 root root 4096 Feb 14 17:27 ./
drwxr-xr-x 3 root root 4096 Feb 14 17:26 ../
-rw-r–r– 1 root root 50 Feb 14 17:27 index.html
[root@master231 volumes]#
[root@master231 volumes]# cat /ysl/data/nfs-server/sc/pvc-b425481e-3b15-4854-bf34-801a29edfcc5/index.html
Fri, 14 Feb 2025 17:27:25 +0800
www.ysl.com
[root@master231 volumes]#


– K8S配置默认的存储类及多个存储类定义
1.响应式配置默认存储类
[root@master231 nfs]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 165m
[root@master231 nfs]#
[root@master231 nfs]# kubectl patch sc nfs-csi -p ‘{“metadata”: {“annotations”:{“storageclass.kubernetes.io/is-default-class”:”true”}}}’
storageclass.storage.k8s.io/nfs-csi patched
[root@master231 nfs]#
[root@master231 nfs]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi (default) nfs.csi.k8s.io Delete Immediate false 166m
[root@master231 nfs]#
[root@master231 nfs]#

2.响应式取消默认存储类
[root@master231 nfs]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi (default) nfs.csi.k8s.io Delete Immediate false 168m
[root@master231 nfs]#
[root@master231 nfs]# kubectl patch sc nfs-csi -p ‘{“metadata”: {“annotations”:{“storageclass.kubernetes.io/is-default-class”:”false”}}}’
storageclass.storage.k8s.io/nfs-csi patched
[root@master231 nfs]#
[root@master231 nfs]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 168m
[root@master231 nfs]#


3.声明式配置多个存储类
[root@master231 storageclasses]# cat sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: test-sc-xixi
annotations:
storageclass.kubernetes.io/is-default-class: “false”
provisioner: nfs.csi.k8s.io
parameters:
server: 10.0.0.231
share: /ysl/data/nfs-server/sc-xixi
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
– nfsvers=4.1




apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: test-sc-haha
annotations:
storageclass.kubernetes.io/is-default-class: “true”
provisioner: nfs.csi.k8s.io
parameters:
server: 10.0.0.231
share: /ysl/data/nfs-server/sc-haha
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
– nfsvers=4.1

[root@master231 storageclasses]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 174m
[root@master231 storageclasses]#
[root@master231 storageclasses]# kubectl apply -f sc.yaml
storageclass.storage.k8s.io/test-sc-xixi created
storageclass.storage.k8s.io/test-sc-haha created
[root@master231 storageclasses]#
[root@master231 storageclasses]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 174m
test-sc-haha (default) nfs.csi.k8s.io Delete Immediate false 2s
test-sc-xixi nfs.csi.k8s.io Delete Immediate false 2s
[root@master231 storageclasses]#


4.准备目录
[root@master231 storageclasses]# mkdir -pv /ysl/data/nfs-server/sc-{xixi,haha}


5.测试验证
[root@master231 persistentvolumeclaims]# cat manual-pvc-4.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-sc
spec:
accessModes:
– ReadWriteMany
resources:
limits:
storage: 4Gi
requests:
storage: 3Gi
[root@master231 persistentvolumeclaims]#
[root@master231 persistentvolumeclaims]# kubectl apply -f manual-pvc-4.yaml
persistentvolumeclaim/pvc-linux94 created
[root@master231 persistentvolumeclaims]#
[root@master231 persistentvolumeclaims]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-linux-pvc Bound pvc-f47d1e5b-a2f1-463f-b06c-7940add76104 3Gi RWX nfs-csi 173m
pvc-linux94 Bound pvc-af3b36cc-cf89-4476-895c-7eeef3946564 3Gi RWX test-sc-haha 24s
[root@master231 persistentvolumeclaims]#

6.pod引用pvc
[root@master231 deployments]# cat 17-deploy-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-pvc-default-sc
spec:
replicas: 1
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– name: data
persistentVolumeClaim:
claimName: pvc-sc
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
[root@master231 deployments]#
[root@master231 deployments]# kubectl apply -f 17-deploy-pvc.yaml
deployment.apps/deploy-xiuxian-pvc-default-sc created
[root@master231 deployments]#
[root@master231 deployments]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-xiuxian-pvc-default-sc-56c4948fb9-wjqtd 1/1 Running 0 3s 10.100.1.171 worker232
[root@master231 deployments]#
[root@master231 deployments]# kubectl exec -it deploy-xiuxian-pvc-default-sc-56c4948fb9-wjqtd — sh
/ # echo www.ysl.com > /usr/share/nginx/html/index.html
/ #
[root@master231 deployments]#
[root@master231 deployments]# curl 10.100.1.171
www.ysl.com
[root@master231 deployments]#
[root@master231 deployments]# kubectl describe pod deploy-xiuxian-pvc-default-sc-56c4948fb9-wjqtd | grep ClaimName
ClaimName: pvc-linux94
[root@master231 deployments]#
[root@master231 deployments]# kubectl get pvc pvc-linux94
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-linux94 Bound pvc-af3b36cc-cf89-4476-895c-7eeef3946564 3Gi RWX test-sc-haha 3m
[root@master231 deployments]#
[root@master231 deployments]# kubectl describe pv pvc-af3b36cc-cf89-4476-895c-7eeef3946564 | grep Source -A 5
Source:
Type: CSI (a Container Storage Interface (CSI) volume source)
Driver: nfs.csi.k8s.io
FSType:
VolumeHandle: 10.0.0.231#ysl/data/nfs-server/sc-haha#pvc-af3b36cc-cf89-4476-895c-7eeef3946564##
ReadOnly: false
[root@master231 deployments]#
[root@master231 deployments]# ll /ysl/data/nfs-server/sc-haha/pvc-af3b36cc-cf89-4476-895c-7eeef3946564/
total 12
drwxr-xr-x 2 root root 4096 Nov 27 14:53 ./
drwxr-xr-x 3 root root 4096 Nov 27 14:50 ../
-rw-r–r– 1 root root 18 Nov 27 14:53 index.html
[root@master231 deployments]#
[root@master231 deployments]# more /ysl/data/nfs-server/sc-haha/pvc-af3b36cc-cf89-4476-895c-7eeef3946564/index.html
www.ysl.com
[root@master231 deployments]#


13 local sc
– 为什么要使用local卷
1.使用PV存储数据的痛点
– 1.基于网络存储的PV通常性能损耗较大,因为要涉及到跨节点传输数据,尤其是pod和pv持久卷不在同一个节点的情况下;

– 2.直接使用节点本地的SSD磁盘可获取较好的IO性能,更适用于存储类的服务,例如MongoDB、Ceph,MySQL,ElasticSearch等。


2.hostPath解决pv的问题
这个时候你可能会想到使用hostPath来解决上面提到的问题,但是我们不得不承认以下的问题:
– 1.hostPath卷在Pod被重建后可能被调试至其它节点而无法再次使用此前的数据的情况;
– 2.hostPath卷允许Pod访问节点上的任意路径,也存在一定程度的安全风险;

3.local卷解决hostPath存储卷的不足
local卷插件主要用于将本地存储设备(如磁盘、分区或目录)配置为卷。

local卷相比hostPath而言,带来了如下优势:
– 1.基于local卷,调度器能自行完成调度绑定;
说白了就是当第一次完成调度后,后续重新创建Pod时都会被调度到该节点,因为K8S调度器之前系统有记录。

– 2.local卷只能关联静态置备的PV,目前尚不支持动态置备;

– 3.local卷支持”延迟绑定”特性,延迟绑定机制,提供了基于消费者的需求来判定将PVC绑定至哪个PV的可能性
说白了,在Pod完成调度之前,还没有消费pvc时,此时的pvc一直处于Pending状态。
举个例子:
Pod有3个节点可以满足调度,但由于Pod没有完成调度前,pvc并不知道调度到那个pv,
因为pv是关联的是local卷,其必须和pod在同一个节点才行。

4.local卷案例
1 创建local动态存储类
root@master231:/manifests/volumes# cat 18-local-sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ysl-local-sc
# “kubernetes.io/no-provisioner”表示不使用动态置备PV,因为local插件不支持
provisioner: kubernetes.io/no-provisioner
# “WaitForFirstConsumer”表示等待消费者(Pod)申请使用PVC时(即第一次被调度时)再进行PV绑定,即“延迟绑定”
# 延迟绑定机制,提供了基于消费者的需求来判定将PVC绑定至哪个PV的可能性
# 说白了,在Pod完成调度之前,还没有消费pvc时,此时的pvc一直处于Pending状态。
# 举个例子:
# Pod有3个节点可以满足调度,但由于Pod没有完成调度前,pvc并不知道调度到那个pv,
# 因为pv是本地卷。其必须和pod在同一个节点才行。
volumeBindingMode: WaitForFirstConsumer

2 查看动态存储类(这个存储类无法自动创建pv,因为此配置为”kubernetes.io/no-provisioner”)
root@master231:/manifests/volumes# kubectl apply -f 18-local-sc.yaml
storageclass.storage.k8s.io/ysl-local-sc created
root@master231:/manifests/volumes# kubectl get sc ysl-local-sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
ysl-local-sc kubernetes.io/no-provisioner Delete WaitForFirstConsumer false 8s

3 手动创建pv关联sc
root@master231:/manifests/volumes# kubectl apply -f 19-custom-pv.yaml
persistentvolume/yangsenlin-pv-worker232 created
persistentvolume/yangsenlin-pv-worker233 created
root@master231:/manifests/volumes# cat 19-custom-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: yangsenlin-pv-worker232
labels:
type: ssd
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
– ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
# 指定pv关联的存储类
storageClassName: ysl-local-sc
# 表示卷插件类型是local
local:
# 指定本地的路径,这个路径最好是对应的是一块本地磁盘,此路径最好提前创建好,若路径不存在,将来调度成功后会报错:
# MountVolume.NewMounter initialization failed for volume “…” : path “…” does not exist
path: /yangsenlin/data/sc/local01
# 声明pv与节点的关联关系,与此同时,调度器将基于nodeAffinity将影响Pod调度。
nodeAffinity:
required:
nodeSelectorTerms:
– matchExpressions:
– key: kubernetes.io/hostname
operator: In
values:
– worker232


apiVersion: v1
kind: PersistentVolume
metadata:
name: yangsenlin-pv-worker233
labels:
type: hdd
spec:
capacity:
storage: 20Gi
volumeMode: Filesystem
accessModes:
– ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: ysl-local-sc
local:
path: /yangsenlin/data/sc/local02
nodeAffinity:
required:
nodeSelectorTerms:
– matchExpressions:
– key: kubernetes.io/hostname
operator: In
values:
– worker233
root@master231:/manifests/volumes#

root@master231:/manifests/volumes# kubectl get pv -l type
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
yangsenlin-pv-worker232 10Gi RWO Delete Available ysl-local-sc 29s
yangsenlin-pv-worker233 20Gi RWO Delete Available ysl-local-sc 29s


4 worker节点创建对应目录
root@worker232:~/images# mkdir -pv /yangsenlin/data/sc/local01
mkdir: created directory ‘/yangsenlin’
mkdir: created directory ‘/yangsenlin/data’
mkdir: created directory ‘/yangsenlin/data/sc’
mkdir: created directory ‘/yangsenlin/data/sc/local01’
root@worker232:~/images#

root@worker233:~/images# mkdir -pv /yangsenlin/data/sc/local01
mkdir: created directory ‘/yangsenlin’
mkdir: created directory ‘/yangsenlin/data’
mkdir: created directory ‘/yangsenlin/data/sc’
mkdir: created directory ‘/yangsenlin/data/sc/local01’

5 创建pvc验证“延迟绑定”
root@master231:/manifests/local-sc# cat 03-custom-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: yangsenlin-pvc-local
spec:
accessModes:
– ReadWriteOnce
resources:
requests:
storage: 5Gi
# pvc无需关联pv,关联sc即可
storageClassName: ysl-local-sc
root@master231:/manifests/local-sc# kubectl apply -f 03-custom-pvc.yaml
persistentvolumeclaim/yangsenlin-pvc-local created
root@master231:/manifests/local-sc#

root@master231:/manifests/local-sc# kubectl get -f 03-custom-pvc.yaml
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
yangsenlin-pvc-local Pending

6 创建pod并观察pvc状态
root@master231:/manifests/local-sc# cat 04-deploy-xiuxian.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: xiuxian
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
volumes:
– name: data
persistentVolumeClaim:
claimName: yangsenlin-pvc-local
containers:
– name: c1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
ports:
– containerPort: 80
volumeMounts:
– mountPath: “/data”
name: data
root@master231:/manifests/local-sc# kubectl apply -f 04-deploy-xiuxian.yaml
deployment.apps/xiuxian created
root@master231:/manifests/local-sc#

[root@master231 local-sc]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-7df7678dcf-kv5fw 1/1 Running 0 9s 10.100.2.38 worker233
xiuxian-7df7678dcf-lcvg4 1/1 Running 0 9s 10.100.2.40 worker233
xiuxian-7df7678dcf-x28bv 1/1 Running 0 9s 10.100.2.39 worker233
[root@master231 local-sc]#
[root@master231 local-sc]# kubectl get pvc yangsenlin-pvc-local
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
yangsenlin-pvc-local Bound yangsenlin-pv-worker233 20Gi RWO ysl-local-sc 2m18s
[root@master231 local-sc]#

– 如何解决local sc的弊端呢?
CSI: Container Storage Intaerface


参考官网:
https://openebs.io/docs/concepts/architecture
32 harbor实现https
1 环境准备
10.0.0.250 harbor.ysl.com
2core 4G

2 下载harbor
wget https://github.com/goharbor/harbor/releases/download/v2.12.2/harbor-offline-installer-v2.12.2.tgz

3 创建工作目录
root@harbor:~# mkdir -pv /harbor/{softwares,logs,data}

4 解压软件包
root@harbor:~# tar xf harbor-offline-installer-v2.12.2.tgz -C /harbor/softwares/

5 安装docker环境
[root@harbor.ysl.com ~]# tar xf autoinstall-docker-docker-compose.tar.gz
[root@harbor.ysl.com ~]# ./install-docker.sh i

6 配置CA证书
6.1 创建工作目录
root@harbor:~/docker# mkdir -pv /harbor/softwares/harbor/certs/{ca,harbor-server,docker-client}

6.2 进入到harbor证书存放目录
root@harbor:/harbor/softwares/harbor/certs# ll
total 20
drwxr-xr-x 5 root root 4096 Apr 10 22:41 ./
drwxr-xr-x 3 root root 4096 Apr 10 22:41 ../
drwxr-xr-x 2 root root 4096 Apr 10 22:41 ca/
drwxr-xr-x 2 root root 4096 Apr 10 22:41 docker-client/
drwxr-xr-x 2 root root 4096 Apr 10 22:41 harbor-server/
root@harbor:/harbor/softwares/harbor/certs#

6.3 生成自建ca证书
6.3.1 创建ca的私钥
root@harbor:/harbor/softwares/harbor/certs# openssl genrsa -out ca/ca.key 4096
6.3.2 基于自建的CA私钥创建CA证书(注意,证书签发的域名范围)
root@harbor:/harbor/softwares/harbor/certs# openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj “/C=CN/ST=Sichuan/L=Sichuan/O=example/OU=Personal/CN=ysl.com” \
-key ca/ca.key \
-out ca/ca.crt

6.3.3 查看自建证书信息
root@harbor:/harbor/softwares/harbor/certs# openssl x509 -in ca/ca.crt -noout -text

7 配置harbor证书
7.1 生成harbor服务器的私钥
root@harbor:/harbor/softwares/harbor/certs# openssl genrsa -out harbor-server/harbor.ysl.com.key 4096

7.2 harbor服务器基于私钥签发证书认证请求(csr文件),让自建CA认证
root@harbor:/harbor/softwares/harbor/certs# openssl req -sha512 -new \
-subj “/C=CN/ST=Sichuan/L=Sichuan/O=example/OU=Personal/CN=harbor.ysl.com” \
-key harbor-server/harbor.ysl.com.key \

7.3 生成x509 v3的扩展文件用于认证
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=harbor.ysl.com
EOF

7.4 基于 x509 v3 的扩展文件认证签发harbor server证书
root@harbor:/harbor/softwares/harbor/certs# openssl x509 -req -sha512 -days 3650 \
-extfile harbor-server/v3.ext \
-CA ca/ca.crt -CAkey ca/ca.key -CAcreateserial \
-in harbor-server/harbor.ysl.com.csr \
-out harbor-server/harbor.ysl.com.crt

7.5 修改harbor的配置文件使用自建证书
root@harbor:/harbor/softwares/harbor/certs# vim ../harbor.yml

hostname: harbor.ysl.com
https:

certificate: /harbor/softwares/harbor/certs/harbor-server/harbor.ysl.com.crt
private_key: /harbor/softwares/harbor/certs/harbor-server/harbor.ysl.com.key

harbor_admin_password: 1

data_volume: /harbor/data/harbor


8 安装harbor环境
root@harbor:/harbor/softwares/harbor/certs# ../install.sh
…..
✔ —-Harbor has been installed and started successfully.—-

9 windows访问测试
9.1 修改windows的hosts解析

192.168.137.250 harbor.ysl.com

9.2 访问测试
https://192.168.137.250/
使用admin/1登录

10 生成docker客户端证书
root@harbor:/harbor/softwares/harbor/certs# pwd
/harbor/softwares/harbor/certs

root@harbor:/harbor/softwares/harbor/certs# openssl x509 -inform PEM -in harbor-server/harbor.ysl.com.crt -out docker-client/harbor.ysl.com.cert

root@harbor:/harbor/softwares/harbor/certs# md5sum docker-client/harbor.ysl.com.cert harbor-server/harbor.ysl.com.crt
6488a8559b05764db9af81a67590a8de docker-client/harbor.ysl.com.cert
6488a8559b05764db9af81a67590a8de harbor-server/harbor.ysl.com.crt
root@harbor:/harbor/softwares/harbor/certs#

11 拷贝docker client证书文件
root@harbor:/harbor/softwares/harbor/certs# cp ca/ca.crt harbor-server/harbor.ysl.com.key docker-client/

12 将harbor的客户端证书拷贝到k8s集群
12.1 k8s集群每个节点新建证书的目录(域名的名称和目录要一样)
root@master231:~# mkdir -pv /etc/docker/certs.d/harbor.ysl.com/
root@master232:~# mkdir -pv /etc/docker/certs.d/harbor.ysl.com/
root@master233:~# mkdir -pv /etc/docker/certs.d/harbor.ysl.com/

12.2 从harbor仓库将证书文件拷贝到k8s集群
[root@harbor.ysl.com certs]# scp docker-client/* 10.0.0.231:/etc/docker/certs.d/harbor.ysl.com/
[root@harbor.ysl.com certs]# scp docker-client/* 10.0.0.232:/etc/docker/certs.d/harbor.ysl.com/
[root@harbor.ysl.com certs]# scp docker-client/* 10.0.0.233:/etc/docker/certs.d/harbor.ysl.com/

12.3 客户端验证
root@worker231:~# echo ‘10.0.0.250 harbor.ysl.com’ >> /etc/hosts
root@worker232:~# echo ‘10.0.0.250 harbor.ysl.com’ >> /etc/hosts
root@worker233:~# echo ‘10.0.0.250 harbor.ysl.com’ >> /etc/hosts

12.4 k8s集群登录harbor仓库
root@master231:~# docker login -u admin -p 1 harbor.ysl.com
WARNING! Using –password via the CLI is insecure. Use –password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

13 推送镜像到harbor仓库

13.1 给镜像打标签
root@master231:~# docker tag crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1 harbor.ysl.com/ysl-xiuxian/apps:v1

13.2 harbor web页面新建一个项目,项目名称为ysl-xiuxian


13.3 推送镜像到harbor仓库
The push refers to repository [harbor.ysl.com/ysl-xiuxian/apps]
8e2be8913e57: Pushed
9d5b000ce7c7: Pushed
b8dbe22b95f7: Pushed
c39c1c35e3e8: Pushed
5f66747c8a72: Pushed
15d7cdc64789: Pushed
7fcb75871b21: Pushed
v1: digest: sha256:3bee216f250cfd2dbda1744d6849e27118845b8f4d55dda3ca3c6c1227cc2e5c size: 1778

13.4 到harbor web查看推送的镜像

14 k8s从harbor仓库拉取镜像
root@master231:/manifests/volumes# cat 06-deploy-xiuxian-harbor.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-harbor
spec:
replicas: 3
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
spec:
volumes:
– emptyDir: {}
name: data
containers:
– name: c1
# image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
image: harbor.ysl.com/ysl-xiuxian/apps:v1
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html

root@master231:/manifests/volumes# kubectl apply -f 06-deploy-xiuxian-harbor.yaml

root@master231:/manifests/volumes# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-xiuxian-harbor-6d99f57cb6-4p2cn 1/1 Running 0 31m
deploy-xiuxian-harbor-6d99f57cb6-fk767 1/1 Running 0 31m
deploy-xiuxian-harbor-6d99f57cb6-qwtx6 1/1 Running 0 31m

15 参考链接
https://goharbor.io/docs/1.10/install-config/configure-https/#generate-a-certificate-authority-certificate
https://www.cnblogs.com/yangsenlin/p/17153673.html

16 快速修复harbor服务
docker-compose down -t 0
docker-compose up -d
docker-compose ps -a
33 图形化管理工具
1 部署dashboard
是一款图形化管理K8S集群的解决方案。
参考链接:
https://github.com/kubernetes/dashboard/releases?page=7

1.1 下载资源清单
root@master231:~/manifests/add-ones/dashboard# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.1/aio/deploy/recommended.yaml

1.2 修改8443的svc类型为LoadBalancer

1.3 部署服务
[root@master231 dashboard]# kubectl apply -f recommended.yaml
namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created
[root@master231 dashboard]#


镜像下载地址:
http://192.168.15.253/Resources/Kubernetes/Add-ons/dashboard/
1.4 查看资源
[root@master231 dashboard]# kubectl get pods,svc -n kubernetes-dashboard
NAME READY STATUS RESTARTS AGE
pod/dashboard-metrics-scraper-799d786dbf-xqm2f 1/1 Running 0 104s
pod/kubernetes-dashboard-fb8648fd9-g6szd 1/1 Running 0 104s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/dashboard-metrics-scraper ClusterIP 10.200.4.60 8000/TCP 104s
service/kubernetes-dashboard LoadBalancer 10.200.50.252 10.0.0.152 443:14864/TCP 104s
[root@master231 dashboard]#

1.5 访问Dashboard
https://10.0.0.152/#/login
1.6 基于token登录
1.6.1 创建sa
root@master231:~/manifests/add-ones/dashboard# kubectl create serviceaccount ysl
serviceaccount/ysl created
root@master231:~/manifests/add-ones/dashboard#

1.6.2 将sa和内置集群角色绑定
root@master231:~/manifests/add-ones/dashboard# kubectl create clusterrolebinding dashboard-ysl –clusterrole=cluster-admin –serviceaccount=default:ysl -o yaml –dry-run=client
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
creationTimestamp: null
name: dashboard-ysl
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
– kind: ServiceAccount
name: ysl
namespace: default
root@master231:~/manifests/add-ones/dashboard#
root@master231:~/manifests/add-ones/dashboard# kubectl create clusterrolebinding dashboard-ysl –clusterrole=cluster-admin –serviceaccount=default:ysl
clusterrolebinding.rbac.authorization.k8s.io/dashboard-ysl created
root@master231:~/manifests/add-ones/dashboard#

1.6.3 使用token登录
root@master231:~/manifests/add-ones/dashboard# kubectl get secrets `kubectl get sa ysl -o jsonpath='{.secrets[0].name}’` -o jsonpath='{.data.token}’ |base64 -d ; echo
eyJhbGciOiJSUzI1NiIsImtpZCI6InhRdmpiTWw2WTlrVG04SjlGOTI0a0hrMXVjZUhWUmV6bDc0LVlhZll1MUEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InlzbC10b2tlbi1ucmQ5MiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ5c2wiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI0OTlhMmRjMS0wNTA5LTRkY2ItYjIwNy03MGM2OWNhMTBmYmMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp5c2wifQ.1WWAYf9i9ChqYGfbmoJSyqImw5D7hrUZYbznqWk8ExTJFoTiX5_X7ktbZoVxlRwp7oKvepiYn45I8Gw0IAxIZMriMdzAgjcxXTyvYzt4OP2CDKiCwCoGEEJ8HspBCPtXCfIyDejeOawaizDvQLqLwWT5RWg2uy7SEogZpJlfubx3tXW6Z81hoMHFhK9vTPb8BOYpmEHYLHe1ZkW89Zm21A9DKe0yFQo0mIbSvX8OQaluUlyMIKeL3kR2kkdHAbdjWJ7Vlfop5un5SJJZwLeLKlJsTobJJ2uO1FD43G0kLsIz_ITzxVVZ3IN7g0txm2ofyzh3RU2GLTYbWVM_QA0ryA

1.7 使用kubeconfig授权登录
root@master231:~/manifests/add-ones/dashboard# cat ysl-generate-tontext-conf.sh
#!/bin/bash


# 获取secret的名称
SECRET_NAME=`kubectl get sa ysl -o jsonpath='{.secrets[0].name}’`

# 指定API SERVER的地址
API_SERVER=10.0.0.231:6443

# 指定kubeconfig配置文件的路径名称
KUBECONFIG_NAME=./yangsenlin-k8s-dashboard-admin.conf

# 获取ysl用户的tocken
ysl_TOCKEN=`kubectl get secrets $SECRET_NAME -o jsonpath={.data.token} | base64 -d`

# 在kubeconfig配置文件中设置群集项
kubectl config set-cluster yangsenlin-k8s-dashboard-cluster –server=$API_SERVER –kubeconfig=$KUBECONFIG_NAME

# 在kubeconfig中设置用户项
kubectl config set-credentials yangsenlin-k8s-dashboard-user –token=$ysl_TOCKEN –kubeconfig=$KUBECONFIG_NAME

# 配置上下文,即绑定用户和集群的上下文关系,可以将多个集群和用户进行绑定哟~
kubectl config set-context yangsenlin-admin –cluster=yangsenlin-k8s-dashboard-cluster –user=ysl-k8s-dashboard-user –kubeconfig=$KUBECONFIG_NAME

# 配置当前使用的上下文
kubectl config use-context yangsenlin-admin –kubeconfig=$KUBECONFIG_NAME
root@master231:~/manifests/add-ones/dashboard# bash ysl-generate-tontext-conf.sh
Cluster “yangsenlin-k8s-dashboard-cluster” set.
User “yangsenlin-k8s-dashboard-user” set.
Context “yangsenlin-admin” created.
Switched to context “yangsenlin-admin”.
root@master231:~/manifests/add-ones/dashboard# ll
total 28
drwxr-xr-x 3 root root 4096 May 2 19:24 ./
drwxr-xr-x 5 root root 4096 May 2 11:16 ../
drwxr-xr-x 2 root root 4096 May 2 11:27 images/
-rw-r–r– 1 root root 7642 May 2 11:24 recommended.yaml
-rw——- 1 root root 1248 May 2 19:24 yangsenlin-k8s-dashboard-admin.conf
-rw-r–r– 1 root root 1063 May 2 19:23 ysl-generate-tontext-conf.sh
root@master231:~/manifests/add-ones/dashboard# cat yangsenlin-k8s-dashboard-admin.conf
apiVersion: v1
clusters:
– cluster:
server: 10.0.0.231:6443
name: yangsenlin-k8s-dashboard-cluster
contexts:
– context:
cluster: yangsenlin-k8s-dashboard-cluster
user: ysl-k8s-dashboard-user
name: yangsenlin-admin
current-context: yangsenlin-admin
kind: Config
preferences: {}
users:
– name: yangsenlin-k8s-dashboard-user
user:
token: eyJhbGciOiJSUzI1NiIsImtpZCI6InhRdmpiTWw2WTlrVG04SjlGOTI0a0hrMXVjZUhWUmV6bDc0LVlhZll1MUEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InlzbC10b2tlbi1ucmQ5MiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ5c2wiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI0OTlhMmRjMS0wNTA5LTRkY2ItYjIwNy03MGM2OWNhMTBmYmMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp5c2wifQ.1WWAYf9i9ChqYGfbmoJSyqImw5D7hrUZYbznqWk8ExTJFoTiX5_X7ktbZoVxlRwp7oKvepiYn45I8Gw0IAxIZMriMdzAgjcxXTyvYzt4OP2CDKiCwCoGEEJ8HspBCPtXCfIyDejeOawaizDvQLqLwWT5RWg2uy7SEogZpJlfubx3tXW6Z81hoMHFhK9vTPb8BOYpmEHYLHe1ZkW89Zm21A9DKe0yFQo0mIbSvX8OQaluUlyMIKeL3kR2kkdHAbdjWJ7Vlfop5un5SJJZwLeLKlJsTobJJ2uO1FD43G0kLsIz_ITzxVVZ3IN7g0txm2ofyzh3RU2GLTYbWVM_QA0ryA
root@master231:~/manifests/add-ones/dashboard#


2 kuboard
官网地址:
https://kuboard.cn/

2.1 部署kuboard
root@master231:~/manifests/add-ones/dashboard# wget https://addons.kuboard.cn/kuboard/kuboard-v3-swr.yaml
root@master231:~/manifests/add-ones/kuboard# kubectl apply -f kuboard-v3-swr.yaml
namespace/kuboard created
configmap/kuboard-v3-config created
serviceaccount/kuboard-boostrap created
clusterrolebinding.rbac.authorization.k8s.io/kuboard-boostrap-crb created
daemonset.apps/kuboard-etcd created
deployment.apps/kuboard-v3 created
service/kuboard-v3 created
root@master231:~/manifests/add-ones/kuboard#

root@master231:~/manifests/add-ones/kuboard# kubectl -n kuboard get pods

root@master231:~/manifests/add-ones/kuboard# kubectl -n kuboard get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kuboard-v3 NodePort 10.200.124.105 80:30080/TCP,10081:30081/TCP,10081:30081/UDP 2m59s

在浏览器中打开链接 http://10.0.0.233:30080

输入初始用户名和密码,并登录

用户名: admin
密码: Kuboard123

3 kubesphere
3.1 安装helm
[root@master231 kubesphere]# curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

3.2 配置helm的自动补全功能
[root@master231 kubesphere]# helm completion bash > /etc/bash_completion.d/helm
[root@master231 kubesphere]# source /etc/bash_completion.d/helm
[root@master231 kubesphere]# echo ‘source /etc/bash_completion.d/helm’ >> ~/.bashrc

3.3 在集群节点,执行以下命令安装 KubeSphere Core。
[root@master231 ~]# helm upgrade –install -n kubesphere-system –create-namespace ks-core https://charts.kubesphere.com.cn/main/ks-core-1.1.3.tgz –debug –wait


NOTES:
Thank you for choosing KubeSphere Helm Chart.

Please be patient and wait for several seconds for the KubeSphere deployment to complete.

1. Wait for Deployment Completion

Confirm that all KubeSphere components are running by executing the following command:

kubectl get pods -n kubesphere-system
2. Access the KubeSphere Console

Once the deployment is complete, you can access the KubeSphere console using the following URL:

http://10.0.0.231:30880

3. Login to KubeSphere Console

Use the following credentials to log in:

Account: admin
Password: P@88w0rd

NOTE: It is highly recommended to change the default password immediately after the first login.
For additional information and details, please visit https://kubesphere.io.


温馨提示:
如果安装失败,需要手动导入镜像。

3.4 登录kubesphere的WebUI
http://10.0.0.231:30880


34 wordpress
root@master231:~/manifests/wordpress# cat 01-deploy-mysql.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-db
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 2Gi
requests:
storage: 1Gi



apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-mysql
spec:
replicas: 1
selector:
matchLabels:
apps: db
template:
metadata:
labels:
apps: db
spec:
volumes:
– name: data
persistentVolumeClaim:
claimName: pvc-db
– name: datetime
hostPath:
path: /etc/localtime
restartPolicy: Always
hostNetwork: true
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
– matchExpressions:
– key: kubernetes.io/hostname
values:
– worker232
operator: In
containers:
– name: c1
image: harbor.ysl.com/wordpress/mysql:8.0.36-oracle
volumeMounts:
– name: datetime
mountPath: /etc/localtime
– name: data
mountPath: /var/lib/mysql
imagePullPolicy: IfNotPresent
args:
– –character-set-server=utf8
– –collation-server=utf8_bin
– –default-authentication-plugin=mysql_native_password
ports:
– containerPort: 3306
env:
– name: MYSQL_ALLOW_EMPTY_PASSWORD
value: “yes”
– name: MYSQL_DATABASE
value: ceshi
– name: MYSQL_USER
value: test
– name: MYSQL_PASSWORD
value: “123456”

root@master231:~/manifests/wordpress# cat 02-deploy-wordpress.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-wordpress
spec:
replicas: 1
selector:
matchLabels:
apps: wp
template:
metadata:
labels:
apps: wp
spec:
hostNetwork: true
restartPolicy: Always
nodeSelector:
kubernetes.io/hostname: worker233
containers:
– name: c1
image: harbor.ysl.com/wordpress/wordpress:6.7.1-php8.1-apache
ports:
– containerPort: 80
env:
– name: WORDPRESS_DB_HOST
value: 10.0.0.232
– name: WORDPRESS_DB_NAME
value: ceshi
– name: WORDPRESS_DB_USER
value: test
– name: WORDPRESS_DB_PASSWORD
value: “123456”
volumeMounts:
– name: datetime
mountPath: /etc/localtime
– name: data
mountPath: /var/www/html
volumes:
– name: data
persistentVolumeClaim:
claimName: pvc-wp
– name: datetime
hostPath:
path: /etc/localtime


apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-wp
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 500Mi
requests:
storage: 200Mi

– WordPress基于svc
[root@master231 v2]# cat 01-deploy-mysql.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-db
namespace: kube-public
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 2Gi
requests:
storage: 1Gi



apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-mysql
namespace: kube-public
spec:
replicas: 1
selector:
matchLabels:
apps: db
template:
metadata:
labels:
apps: db
spec:
volumes:
– name: data
persistentVolumeClaim:
claimName: pvc-db
– name: datetime
hostPath:
path: /etc/localtime
restartPolicy: Always
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
– matchExpressions:
– key: kubernetes.io/hostname
values:
– worker232
operator: In
containers:
– name: c1
image: harbor.ysl.com/wordpress/mysql:8.0.36-oracle
volumeMounts:
– name: datetime
mountPath: /etc/localtime
– name: data
mountPath: /var/lib/mysql
imagePullPolicy: IfNotPresent
args:
– –character-set-server=utf8
– –collation-server=utf8_bin
– –default-authentication-plugin=mysql_native_password
ports:
– containerPort: 3306
env:
– name: MYSQL_ALLOW_EMPTY_PASSWORD
value: “yes”
– name: MYSQL_DATABASE
value: ceshi
– name: MYSQL_USER
value: test
– name: MYSQL_PASSWORD
value: “123456”




apiVersion: v1
kind: Service
metadata:
name: svc-db
namespace: kube-public
spec:
type: ClusterIP
selector:
apps: db
ports:
– port: 3306


[root@master231 v2]#
[root@master231 v2]#
[root@master231 v2]#
[root@master231 v2]# cat 02-deploy-wordpress.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-wordpress
spec:
replicas: 1
selector:
matchLabels:
apps: wp
template:
metadata:
labels:
apps: wp
spec:
restartPolicy: Always
containers:
– name: c1
image: harbor.ysl.com/wordpress/wordpress:6.7.1-php8.1-apache
ports:
– containerPort: 80
env:
– name: WORDPRESS_DB_HOST
# 指定数据库svc的名称,CoreDNS组件会自动解析其对应的ClusterIP
# value: svc-db
# 如果不指定名称空间,则默认会在当前资源所属的名称空间找。
# value: svc-db.kube-public
# 当然,我们也可以配置完整的A记录格式
value: svc-db.kube-public.svc.ysl.com
– name: WORDPRESS_DB_NAME
value: ceshi
– name: WORDPRESS_DB_USER
value: test
– name: WORDPRESS_DB_PASSWORD
value: “123456”
volumeMounts:
– name: datetime
mountPath: /etc/localtime
– name: data
mountPath: /var/www/html
volumes:
– name: data
persistentVolumeClaim:
claimName: pvc-wp
– name: datetime
hostPath:
path: /etc/localtime


apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-wp
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 500Mi
requests:
storage: 200Mi



apiVersion: v1
kind: Service
metadata:
name: svc-wp
namespace: default
spec:
type: LoadBalancer
selector:
apps: wp
ports:
– port: 80
[root@master231 v2]#
35 pv的回收策略
Retain:
“保留回收”策略允许手动回收资源,删除pvc时,pv仍然存在,并且该卷被视为”已释放(Released)”。
在管理员手动回收资源之前,使用该策略其他Pod将无法直接使用。
温馨提示:
(1)在k8s1.15.12版本测试时,删除pvc发现nfs存储卷的数据并不会被删除,pv也不会被删除;

Delete:
对于支持删除回收策略的卷插件,k8s将删除pv及其对应的数据卷数据。建议使用动态存储类(sc)实现,才能看到效果哟!
对于AWS EBS, GCE PD, Azure Disk, or OpenStack Cinder等存储卷会被删除。
温馨提示:
(1)在k8s1.15.12版本测试时,在不使用sc时,则删除pvc发现nfs存储卷的数据并不会被删除;
(2)在k8s1.15.12版本测试时,在使用sc后,可以看到删除效果哟;

Recycle:
对于”回收利用”策略官方已弃用。相反,推荐的方法是使用动态资源调配。而动态存储类已经不支持该类型啦!
如果基础卷插件支持,回收回收策略将对卷执行基本清理(rm -rf /thevolume/*),并使其再次可用于新的声明。
温馨提示,在k8s1.15.12版本测试时,删除pvc发现nfs存储卷的数据被删除。

温馨提示:
对于动态存储类中的配置中,多了一个”archive”,表示归档pv。

[root@master231 csi-driver-nfs]# cat deploy/v4.9.0/storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
# server: nfs-server.default.svc.cluster.local
server: 10.0.0.231
# share: /
share: /ysl/data/nfs-server/sc
# csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume
# csi.storage.k8s.io/provisioner-secret-name: “mount-options”
# csi.storage.k8s.io/provisioner-secret-namespace: “default”
# 有效值为: delete retain archive,若不指定,则默认值为”delete”,当删除pvc时,会自动删除pv及后端的数据。
# onDelete: “archive”
# onDelete: “retain”
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
– nfsvers=4.1
[root@master231 csi-driver-nfs]#

36 名称空间
1 概述
k8s的名称空间是用来隔离K8S集群资源的。

但是有些资源不支持名称空间隔离,我们称之为全局资源,而支持名称空间的我们称之为局部资源。

2 查看资源是否支持名称空间
root@master231:~# kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND

NAMESPACED 为true的是支持名称空间的,为false是不支持名称空间的

3 查看现有的名称空间
root@master231:~# kubectl get ns
NAME STATUS AGE
default Active 11d
kube-flannel Active 11d
kube-node-lease Active 11d
kube-public Active 11d
kube-system Active 11d
kubesphere-system Active 89m

4 查看特定名称空间的资源
root@master231:~# kubectl get cm
NAME DATA AGE
game-demo 7 3d11h
kube-root-ca.crt 1 11d
nginx-subfile 2 2d11h
test-xy 4 2d11h
ysl-cm 2 2d3h
root@master231:~# kubectl get cm –namespace default
root@master231:~# kubectl get cm -n default
root@master231:~# kubectl get cm -n kube-system
root@master231:~# kubectl get cm –namespace kube-system
root@master231:~# kubectl -n kube-system get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
etcd-master231 1/1 Running 16 (3h57m ago) 11d 10.0.0.231 master231
kube-apiserver-master231 1/1 Running 17 (3h57m ago) 11d 10.0.0.231 master231
kube-controller-manager-master231 1/1 Running 16 (3h57m ago) 11d 10.0.0.231 master231
kube-proxy-9zlc6 1/1 Running 16 (3h57m ago) 11d 10.0.0.231 master231
kube-proxy-hn6g6 1/1 Running 23 (124m ago) 11d 10.0.0.233 worker233
kube-proxy-ngs5g 1/1 Running 8 (3h57m ago) 6d23h 10.0.0.232 worker232
kube-scheduler-master231 1/1 Running 16 (3h57m ago) 11d 10.0.0.231 master231

5 查看所有名称空间的资源
root@master231:~# kubectl get pods –all-namespaces

root@master231:~# kubectl get pods -A
root@master231:~# kubectl get cm -A

6 响应式创建名称空间
root@master231:~# kubectl create namespace ysl
namespace/ysl created
root@master231:~# kubectl get ns|grep ysl
ysl Active 12s

7 声明式创建名称空间
root@master231:~/manifests# cat 01-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
name: test-ns
root@master231:~/manifests# kubectl apply -f 01-ns.yaml
namespace/test-ns created
root@master231:~/manifests# kubectl get -f 01-ns.yaml
NAME STATUS AGE
test-ns Active 8s
root@master231:~/manifests#

8 删除名称空间
root@master231:~/manifests# kubectl delete ns ysl test-ns
namespace “ysl” deleted
namespace “test-ns” deleted

9 提示
当删除名称空间时,该名称空间下的所有资源都会被删除!生产环境中谨慎操作!

10 将pod放在特点的名称空间
root@master231:~/manifests/pods# cat 23-pods-ns.yaml
apiVersion: v1
kind: Pod
metadata:
name: ns-xiuxian
#资源放在特定的名称空间
namespace: kube-public
spec:
containers:
– name: c1
image: harbor.ysl.com/ysl-xiuxian/apps:v1
root@master231:~/manifests/pods# kubectl apply -f 23-pods-ns.yaml
pod/ns-xiuxian configured
root@master231:~/manifests/pods# kubectl -n kube-public get pods
NAME READY STATUS RESTARTS AGE
ns-xiuxian 1/1 Running 0 79s

11 将cm放在特定的名称空间
root@master231:~/manifests/configmaps# cat 02-cm-ns.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
namespace: kube-public
data:
player_initial_lives: “3”
ui_properties_file_name: “user-interface.properties”
xingming: zhangsan
city: Sichuan

game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
my.cnf: |
datadir=/ysl/data/mysql80
basedir=/ysl/softwares/mysql80
port=3306
socket=/tmp/mysql80.sock

root@master231:~/manifests/configmaps# kubectl apply -f 02-cm-ns.yaml
configmap/game-demo created
root@master231:~/manifests/configmaps# kubectl -n kube-public get cm
NAME DATA AGE
cluster-info 2 11d
game-demo 7 17s
kube-root-ca.crt 1 11d

12 有些资源不支持名称空间
比如pv,sc等都是不支持名称空间的,因此就算在资源清单中添加namespace字段也会被无视。

37 服务发现 Service
1 概述
服务发现包含以下四种

1.1 ClusterIP:
一般用于K8S集群内部应用服务之间的访问。

1.2 NodePort:
在CLusterIP的基础之上,对外部提供访问路由。

1.3 LoadBalancer:
一般用于云环境的K8S。

1.4 ExternalName:
一般映射K8S集群外部的服务到K8S集群内部,底层采用了CNAME技术。

1 ClusterIP
root@master231:~/manifests/services# cat 01-svc-clusterIP.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian
namespace: default
spec:
# 指定svc的类型,有效值: ExternalName, ClusterIP, NodePort, and LoadBalancer
# 若不指定,则默认值为:”ClusterIP”
type: ClusterIP
selector:
apps: v1
ports:
– name: xiuxian
port: 81
protocol: TCP
targetPort: 80
root@master231:~/manifests/services# kubectl apply -f 01-svc-clusterIP.yaml
service/svc-xiuxian configured
root@master231:~/manifests/services# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.200.0.1 443/TCP 7d23h
svc-xiuxian ClusterIP 10.200.224.60 81/TCP 5d23h

2 NodePort
root@master231:~/manifests/services# cat 02-svc-nodePort.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-nodeport
namespace: default
spec:
# 指定svc的类型,有效值: ExternalName, ClusterIP, NodePort, and LoadBalancer
# 若不指定,则默认值为:”ClusterIP”
type: NodePort
# 指定svc的网段即可,我们集群安装时指定的网段: 10.200.0.0/16
clusterIP: 10.200.0.100
selector:
apps: v1
ports:
– name: xiuxian
port: 81
protocol: TCP
targetPort: 80
# 默认的端口范围为: 30000-32767
nodePort: 30080
root@master231:~/manifests/services# kubectl apply -f 02-svc-nodePort.yaml
service/svc-xiuxian-nodeport created
root@master231:~/manifests/services# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.200.0.1 443/TCP 7d23h
svc-xiuxian ClusterIP 10.200.224.60 81/TCP 5d23h
svc-xiuxian-nodeport NodePort 10.200.0.100 81:30080/TCP 6s
root@master231:~/manifests/services#

root@master231:~/manifests/services# kubectl get svc svc-xiuxian -o yaml
root@master231:~/manifests/services# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.200.0.1 443/TCP 8d
svc-xiuxian ClusterIP 10.200.224.60 81/TCP 6d1h
svc-xiuxian-nodeport NodePort 10.200.0.100 81:30080/TCP 71m

集群外部访问三个节点的30080端口都可以
集群内部访问CLUSTER-IP的81端口即可

3 LoadBalancer

3.1 Metallb
如果我们需要在自己的Kubernetes中暴露LoadBalancer的应用,那么Metallb是一个不错的解决方案。

Metallb官网地址:
https://metallb.universe.tf/installation

3.2 修改cm配置
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e “s/strictARP: false/strictARP: true/” | \
sed -e ‘s#mode: “”#mode: “ipvs”#’ | \
kubectl apply -f – -n kube-system

3.3 删除Kube-proxy组件的pod,让cm的配置生效
root@master231:~# kubectl -n kube-system delete pods –all
root@master231:~# kubectl -n kube-system get pods

3.4 部署MetalLb
root@master231:~# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml

3.5 查看部署是否正常
root@master231:~# kubectl get pods -n metallb-system
NAME READY STATUS RESTARTS AGE
controller-7f77587954-gz425 1/1 Running 0 88s
speaker-f7bwt 1/1 Running 0 88s
speaker-p7z98 1/1 Running 0 88s
speaker-sp7fj 1/1 Running 0 88s

3.6 创建地址池
root@master231:~/manifests/metalLB# kubectl apply -f metallb-ip-pool.yaml
ipaddresspool.metallb.io/test-metallb created
l2advertisement.metallb.io/test created

3.7 创建svc
root@master231:~/manifests/services# cat 03-svc-LoadBalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-loadbalancer
namespace: default
spec:
# 指定svc的类型,有效值: ExternalName, ClusterIP, NodePort, and LoadBalancer
# 若不指定,则默认值为:”ClusterIP”
type: LoadBalancer
clusterIP: 10.200.0.200
selector:
apps: v1
ports:
– name: xiuxian
port: 81
protocol: TCP
targetPort: 80
nodePort: 30081

root@master231:~/manifests/services# kubectl apply -f 03-svc-LoadBalancer.yaml
service/svc-xiuxian-loadbalancer created
root@master231:~/manifests/services# kubectl get svc | grep load
svc-xiuxian-loadbalancer LoadBalancer 10.200.0.200 10.0.0.150 81:30081/TCP 31s

3.8 访问测试
http://10.0.0.150:81/
http://10.0.0.233:30081/


4 ExternalName
4.1 部署应用
root@master231:~/manifests/services# cat 04-svc-ExteralName.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-externalname
namespace: default
spec:
type: ExternalName
# 配置CNAME
externalName: www.baidu.com
ports:
– name: xiuxian
port: 81
protocol: TCP
targetPort: 80
nodePort: 30082
root@master231:~/manifests/services# kubectl apply -f 04-svc-ExteralName.yaml
service/svc-xiuxian-externalname created

4.2 解析测试
[root@master231 services]# dig @10.200.0.10 svc-xiuxian-externalname.default.svc.baidu.com +short

4.3 访问A记录格式
访问A记录格式: ..svc.<--service-dns-domain|zone>
举例说明:
svc-xiuxian-externalname.default.svc.baidu.com

4.4 ExternalName是不分配ClusterIP的
root@master231:~/manifests/services# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.200.0.1 443/TCP 8d
svc-xiuxian ClusterIP 10.200.224.60 81/TCP 6d6h
svc-xiuxian-externalname ExternalName www.baidu.com 81:30082/TCP 143m
svc-xiuxian-loadbalancer LoadBalancer 10.200.0.200 10.0.0.150 81:30081/TCP 147m
svc-xiuxian-nodeport NodePort 10.200.0.100 81:30080/TCP 6h39m

5 svc和CoreDNS的关系
5.1 CoreDNS为svc提供解析功能【基于svc的名称解析到对应的CLusterIP或者后端的真实IP地址】

5.2 查看DNS的服务配置
root@master231:~/manifests/services# kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide

5.3 阅读CoreDNS的资源清单
root@master231:~# cat coredns.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: coredns
namespace: kube-system

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
rules:
– apiGroups:
– “”
resources:
– endpoints
– services
– pods
– namespaces
verbs:
– list
– watch
– apiGroups:
– discovery.k8s.io
resources:
– endpointslices
verbs:
– list
– watch

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: “true”
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:coredns
subjects:
– kind: ServiceAccount
name: coredns
namespace: kube-system

apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}

apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/name: “CoreDNS”
app.kubernetes.io/name: coredns
spec:
# replicas: not specified here:
# 1. Default is 1.
# 2. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
app.kubernetes.io/name: coredns
template:
metadata:
labels:
k8s-app: kube-dns
app.kubernetes.io/name: coredns
spec:
priorityClassName: system-cluster-critical
serviceAccountName: coredns
tolerations:
– key: “CriticalAddonsOnly”
operator: “Exists”
nodeSelector:
kubernetes.io/os: linux
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
– labelSelector:
matchExpressions:
– key: k8s-app
operator: In
values: [“kube-dns”]
topologyKey: kubernetes.io/hostname
containers:
– name: coredns
image: registry.aliyuncs.com/google_containers/coredns:v1.8.6
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
args: [ “-conf”, “/etc/coredns/Corefile” ]
volumeMounts:
– name: config-volume
mountPath: /etc/coredns
readOnly: true
ports:
– containerPort: 53
name: dns
protocol: UDP
– containerPort: 53
name: dns-tcp
protocol: TCP
– containerPort: 9153
name: metrics
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
– NET_BIND_SERVICE
drop:
– all
readOnlyRootFilesystem: true
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8181
scheme: HTTP
dnsPolicy: Default
volumes:
– name: config-volume
configMap:
name: coredns
items:
– key: Corefile
path: Corefile

apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
annotations:
prometheus.io/port: “9153”
prometheus.io/scrape: “true”
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: “true”
kubernetes.io/name: “CoreDNS”
app.kubernetes.io/name: coredns
spec:
selector:
k8s-app: kube-dns
app.kubernetes.io/name: coredns
clusterIP: 10.200.0.10
ports:
– name: dns
port: 53
protocol: UDP
targetPort: 53
– name: dns-tcp
port: 53
protocol: TCP
targetPort: 53
– name: metrics
port: 9153
protocol: TCP
targetPort: 9153
root@master231:~#

root@master231:~# kubectl -n kube-system get cm coredns -o yaml
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{“apiVersion”:”v1″,”data”:{“Corefile”:”.:53 {\n errors\n health {\n lameduck 5s\n }\n ready\n kubernetes cluster.local in-addr.arpa ip6.arpa {\n fallthrough in-addr.arpa ip6.arpa\n }\n prometheus :9153\n forward . /etc/resolv.conf {\n max_concurrent 1000\n }\n cache 30\n loop\n reload\n loadbalance\n}\n”},”kind”:”ConfigMap”,”metadata”:{“annotations”:{},”name”:”coredns”,”namespace”:”kube-system”}}
creationTimestamp: “2025-04-04T11:30:50Z”
name: coredns
namespace: kube-system
resourceVersion: “619273”
uid: 38fb3251-ee68-4a93-861d-886f0c139671

5.4 查看kubelet组件
root@master231:~# cat /var/lib/kubelet/config.yaml

5.5 dnsconfig自定义DNS配置信息
root@master231:~/manifests/coreDNS# cat 01-deploy-dnsConfig.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-dnsconfig
spec:
replicas: 1
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
address: chaoyang
city: Sichuan
spec:
# 为Pod配置DNS相关信息
dnsConfig:
# 指定DNS服务器
nameservers:
– 223.5.5.5
– 223.6.6.6
# 定义搜索域
searches:
– yangsenlin.top
– baidu.com
# 配置DNS解析选项
options:
– name: edns0
value: trust-ad
– name: ndots
value: “5”
containers:
– name: c1
image: harbor.ysl.com/ysl-xiuxian/apps:v1

root@master231:~/manifests/coreDNS# kubectl apply -f 01-deploy-dnsConfig.yaml
deployment.apps/deploy-dnsconfig created

root@master231:~/manifests/coreDNS# kubectl exec -it deploy-dnsconfig-855c67c5b7-pf4kd — sh
/ # cat /etc/resolv.conf
nameserver 10.200.0.10
nameserver 223.5.5.5
nameserver 223.6.6.6
search default.svc.yangsenlin.top svc.yangsenlin.top yangsenlin.top baidu.com
options ndots:5 edns0:trust-ad

5.6 dnspolicy和hostNetwork
root@master231:~/manifests/coreDNS# cat 02-deploy-hostNetwork-dnsPolicy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-hostnetwork
spec:
replicas: 1
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
address: shahe
city: Sichuan
spec:
hostNetwork: true
containers:
– name: c1
image: harbor.ysl.com/ysl-xiuxian/apps:v1
root@master231:~/manifests/coreDNS# kubectl apply -f 02-deploy-hostNetwork-dnsPolicy.yaml
deployment.apps/deploy-hostnetwork created

root@master231:~/manifests/coreDNS# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-dnsconfig-855c67c5b7-pf4kd 1/1 Running 0 9m4s
deploy-hostnetwork-85ff5498ff-7k7qm 1/1 Running 0 65s
root@master231:~/manifests/coreDNS# kubectl exec -it deploy-hostnetwork-85ff5498ff-7k7qm — sh
/ # cat /etc/resolv.conf
nameserver 223.5.5.5
nameserver 223.6.6.6
search
/ # ping svc-xiuxian-nodeport
ping: bad address ‘svc-xiuxian-nodeport’

root@master231:~/manifests/coreDNS# kubectl delete -f 02-deploy-hostNetwork-dnsPolicy.yaml
deployment.apps “deploy-hostnetwork” deleted
root@master231:~/manifests/coreDNS# vi 02-deploy-hostNetwork-dnsPolicy.yaml
root@master231:~/manifests/coreDNS# cat 02-deploy-hostNetwork-dnsPolicy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-hostnetwork
spec:
replicas: 1
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
address: shahe
city: Sichuan
spec:
hostNetwork: true
# 配置DNS策略,有效值: ‘ClusterFirstWithHostNet’, ‘ClusterFirst’, ‘Default’ or ‘None’
# 默认值为:”ClusterFirst”
dnsPolicy: ClusterFirstWithHostNet
containers:
– name: c1
image: harbor.ysl.com/ysl-xiuxian/apps:v1
root@master231:~/manifests/coreDNS# kubectl apply -f 02-deploy-hostNetwork-dnsPolicy.yaml
deployment.apps/deploy-hostnetwork created
root@master231:~/manifests/coreDNS# kubectl exec -it deploy-hostnetwork-6f64688bbb-5n2n7 — sh
/ # cat /etc/resolv.conf
nameserver 10.200.0.10
search default.svc.yangsenlin.top svc.yangsenlin.top yangsenlin.top
options ndots:5
/ # ping svc-xiuxian-nodeport

6 无头服务
6.1 headless Service
本质上还是一个Service,只不过该Service没有ClusterIP而已。

一般会结合sts资源使用。

6.2 资源清单
[root@master231 services]# cat 05-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-headless
namespace: default
spec:
type: ClusterIP
# 若没有IP地址,则表示的是一个无头服务
clusterIP: None
selector:
apps: xiuxian
ports:
– name: xiuxian
port: 81
protocol: TCP
targetPort: 80

7 endpionts映射K8S集群外部服务
7.1 svc和ep的关系
除了ExternalName类型外,当创建其他类型的svc时,都会自动关联一个同名称的ep资源。

当删除svc时,会自动删除同名称的ep资源。
7.2 svc会自动关联ep
root@master231:~/manifests/services# kubectl apply -f 05-svc-headless.yaml
service/svc-headless created
root@master231:~/manifests/services# kubectl describe svc svc-headless
Name: svc-headless
Namespace: default
Labels:
Annotations:
Selector: apps=xiuxian
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: xiuxian 81/TCP
TargetPort: 80/TCP
Endpoints: 10.0.0.232:80,10.100.2.15:80
Session Affinity: None
Events:
root@master231:~/manifests/services#

root@master231:~/manifests/services# kubectl get ep svc-headless
NAME ENDPOINTS AGE
svc-headless 10.0.0.232:80,10.100.2.15:80 64s

7.3 将k8s外部的服务映射到k8s集群内部
root@worker233:~# docker run -d -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -e MYSQL_DATABASE=test -e MYSQL_USER=test -e MYSQL_PASSWORD=”123456″ –name mysql-server –network host harbor.ysl.com/wordpress/mysql:8.0.36-oracle
b2975312782cd0d689ec49cb38ba688674fb3f785ae68815619ed126f66addab

root@worker233:~# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b2975312782c harbor.ysl.com/wordpress/mysql:8.0.36-oracle “docker-entrypoint.s…” 22 seconds ago Up 20 seconds mysql-server
root@worker233:~# ss -ntl | grep 3306
LISTEN 0 70 *:33060 *:*
LISTEN 0 151 *:3306 *:*

7.4 k8s集群添加ep资源映射外部服务
root@master231:~/manifests/endpoints# cat 01-ep-mysql.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: harbor-mysql
subsets:
– addresses:
– ip: 10.0.0.250
ports:
– port: 3306



apiVersion: v1
kind: Service
metadata:
name: harbor-mysql
spec:
type: ClusterIP
ports:
– port: 3306
root@master231:~/manifests/endpoints# kubectl apply -f 01-ep-mysql.yaml
endpoints/harbor-mysql created
service/harbor-mysql created

[root@master231 endpoints]# kubectl describe svc harbor-mysql | grep Endpoints
Endpoints: 10.0.0.250:3306
[root@master231 endpoints]#


3.3 改写wordpress案例
[root@master231 v3]# cat deploy-wordpress.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: harbor-mysql
subsets:
– addresses:
– ip: 10.0.0.250
ports:
– port: 3306



apiVersion: v1
kind: Service
metadata:
name: harbor-mysql
spec:
type: ClusterIP
ports:
– port: 3306




apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-wordpress
spec:
replicas: 1
selector:
matchLabels:
apps: wp
template:
metadata:
labels:
apps: wp
spec:
restartPolicy: Always
containers:
– name: c1
image: harbor.ysl.com/wordpress/wordpress:6.7.1-php8.1-apache
ports:
– containerPort: 80
env:
– name: WORDPRESS_DB_HOST
value: harbor-mysql
– name: WORDPRESS_DB_NAME
value: ceshi
– name: WORDPRESS_DB_USER
value: test
– name: WORDPRESS_DB_PASSWORD
value: “123456”
volumeMounts:
– name: datetime
mountPath: /etc/localtime
– name: data
mountPath: /var/www/html
volumes:
– name: data
persistentVolumeClaim:
claimName: pvc-wp
– name: datetime
hostPath:
path: /etc/localtime


apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-wp
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 500Mi
requests:
storage: 200Mi



apiVersion: v1
kind: Service
metadata:
name: svc-wp
namespace: default
spec:
type: LoadBalancer
selector:
apps: wp
ports:
– port: 80
[root@master231 v3]#

38 kube-proxy
– kube-proxy的底层工作方式
– iptables:
随着规则的增多效率会降低。

– ipvs (推荐)
在读取规则时,其时间复杂度更低,性能更高,生产推荐使用。

root@master231:~/manifests/coreDNS# kubectl -n kube-system get ds kube-proxy -o yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
annotations:
deprecated.daemonset.template.generation: “1”
creationTimestamp: “2025-04-04T11:30:50Z”
generation: 1
labels:
k8s-app: kube-proxy
name: kube-proxy
namespace: kube-system
resourceVersion: “605353”
uid: e22a01ce-6250-4c2f-ab4f-b456c638d9af
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: kube-proxy
template:
metadata:
creationTimestamp: null
labels:
k8s-app: kube-proxy
spec:
containers:
– command:
– /usr/local/bin/kube-proxy
– –config=/var/lib/kube-proxy/config.conf
– –hostname-override=$(NODE_NAME)
env:
– name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
image: registry.aliyuncs.com/google_containers/kube-proxy:v1.23.17
imagePullPolicy: IfNotPresent
name: kube-proxy
resources: {}
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
– mountPath: /var/lib/kube-proxy
name: kube-proxy
– mountPath: /run/xtables.lock
name: xtables-lock
– mountPath: /lib/modules
name: lib-modules
readOnly: true
dnsPolicy: ClusterFirst
hostNetwork: true
nodeSelector:
kubernetes.io/os: linux
priorityClassName: system-node-critical
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: kube-proxy
serviceAccountName: kube-proxy
terminationGracePeriodSeconds: 30
tolerations:
– operator: Exists
volumes:
– configMap:
defaultMode: 420
name: kube-proxy
name: kube-proxy
– hostPath:
path: /run/xtables.lock
type: FileOrCreate
name: xtables-lock
– hostPath:
path: /lib/modules
type: “”
name: lib-modules
updateStrategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: 1
type: RollingUpdate
status:
currentNumberScheduled: 3
desiredNumberScheduled: 3
numberAvailable: 3
numberMisscheduled: 0
numberReady: 3
observedGeneration: 1
updatedNumberScheduled: 3
root@master231:~/manifests/coreDNS#

root@master231:~/manifests/coreDNS# kubectl -n kube-system get cm kube-proxy -o yaml
apiVersion: v1
data:
config.conf: |-
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
acceptContentTypes: “”
burst: 0
contentType: “”
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: 10.100.0.0/16
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: “”
enableProfiling: false
healthzBindAddress: “”
hostnameOverride: “”
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: “”
strictARP: true
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: “”
mode: “ipvs”
nodePortAddresses: null
oomScoreAdj: null
portRange: “”
showHiddenMetricsForVersion: “”
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: “”
sourceVip: “”
kubeconfig.conf: |-
apiVersion: v1
kind: Config
clusters:
– cluster:
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
server: https://10.0.0.231:6443
name: default
contexts:
– context:
cluster: default
namespace: default
user: default
name: default
current-context: default
users:
– name: default
user:
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
kind: ConfigMap
metadata:
annotations:
kubeadm.kubernetes.io/component-config.hash: sha256:aeeb159f672e219d96aa2cc4017cc8f204922445a7014c4c3e9118fe44b87345
kubectl.kubernetes.io/last-applied-configuration: |
{“apiVersion”:”v1″,”data”:{“config.conf”:”apiVersion: kubeproxy.config.k8s.io/v1alpha1\nbindAddress: 0.0.0.0\nbindAddressHardFail: false\nclientConnection:\n acceptContentTypes: \”\”\n burst: 0\n contentType: \”\”\n kubeconfig: /var/lib/kube-proxy/kubeconfig.conf\n qps: 0\nclusterCIDR: 10.100.0.0/16\nconfigSyncPeriod: 0s\nconntrack:\n maxPerCore: null\n min: null\n tcpCloseWaitTimeout: null\n tcpEstablishedTimeout: null\ndetectLocalMode: \”\”\nenableProfiling: false\nhealthzBindAddress: \”\”\nhostnameOverride: \”\”\niptables:\n masqueradeAll: false\n masqueradeBit: null\n minSyncPeriod: 0s\n syncPeriod: 0s\nipvs:\n excludeCIDRs: null\n minSyncPeriod: 0s\n scheduler: \”\”\n strictARP: true\n syncPeriod: 0s\n tcpFinTimeout: 0s\n tcpTimeout: 0s\n udpTimeout: 0s\nkind: KubeProxyConfiguration\nmetricsBindAddress: \”\”\nmode: \”ipvs\”\nnodePortAddresses: null\noomScoreAdj: null\nportRange: \”\”\nshowHiddenMetricsForVersion: \”\”\nudpIdleTimeout: 0s\nwinkernel:\n enableDSR: false\n networkName: \”\”\n sourceVip: \”\””,”kubeconfig.conf”:”apiVersion: v1\nkind: Config\nclusters:\n- cluster:\n certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n server: https://10.0.0.231:6443\n name: default\ncontexts:\n- context:\n cluster: default\n namespace: default\n user: default\n name: default\ncurrent-context: default\nusers:\n- name: default\n user:\n tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token”},”kind”:”ConfigMap”,”metadata”:{“annotations”:{“kubeadm.kubernetes.io/component-config.hash”:”sha256:aeeb159f672e219d96aa2cc4017cc8f204922445a7014c4c3e9118fe44b87345″},”creationTimestamp”:”2025-04-04T11:30:50Z”,”labels”:{“app”:”kube-proxy”},”name”:”kube-proxy”,”namespace”:”kube-system”,”resourceVersion”:”238″,”uid”:”0b0fc09d-780d-4d1e-9737-0a09a020c5e8″}}
creationTimestamp: “2025-04-04T11:30:50Z”
labels:
app: kube-proxy
name: kube-proxy
namespace: kube-system
resourceVersion: “605097”
uid: 0b0fc09d-780d-4d1e-9737-0a09a020c5e8
root@master231:~/manifests/coreDNS#


39 sts有状态服务
1.sts控制器
K8S 1.9+引入,主要作用就是部署有状态服务,自带特性:
– 1.每个Pod有独立的存储;
– 2.每个Pod有唯一的网络标识;
– 3.有顺序的启动和停止Pod;
所谓的有状态服务,指的是服务在启动时逻辑并不相同,比如部署MySQL主从,第一个启动更多Pod逻辑和第二个Pod启动逻辑并不相通。


2 sts部署mysql主从
root@master231:~/manifests/mysql-master-slave# cat 01-cm-mysql.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql80
data:
master.cnf: |
[mysqld]
server_id=111
skip-host-cache
skip-name-resolve
log-bin
character-set-server=utf8mb4
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
pid-file=/var/run/mysqld/mysqld.pid

[client]
default-character-set=utf8mb4
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/


slave.cnf: |
[mysqld]
server_id=222
skip-host-cache
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
super-read-only
character-set-server=utf8mb4
pid-file=/var/run/mysqld/mysqld.pid

[client]
default-character-set=utf8mb4
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/
root@master231:~/manifests/mysql-master-slave# cat 02-pvc-mysql.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-master
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 2Gi
requests:
storage: 1Gi



apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-slave
spec:
storageClassName: nfs-csi
accessModes:
– ReadWriteMany
resources:
limits:
storage: 2Gi
requests:
storage: 1Gi
root@master231:~/manifests/mysql-master-slave# cat 03-svc-mysql-master.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-master
spec:
type: ClusterIP
selector:
apps: master
ports:
– port: 3306
root@master231:~/manifests/mysql-master-slave# cat 04-deploy-mysql-master.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-mysql-master
spec:
replicas: 1
selector:
matchLabels:
apps: master
template:
spec:
volumes:
– name: dt
hostPath:
path: /etc/localtime
– name: master
persistentVolumeClaim:
claimName: pvc-master
– name: conf
configMap:
name: mysql80
items:
– key: master.cnf
path: my.cnf
containers:
– name: db
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/wordpress:mysql-8.0.36-oracle
env:
– name: MYSQL_ALLOW_EMPTY_PASSWORD
value: “yes”
– name: MYSQL_USER
value: test
– name: MYSQL_PASSWORD
value: yangsenlin
volumeMounts:
– name: master
mountPath: /var/lib/mysql
– name: conf
mountPath: /etc/my.cnf
subPath: my.cnf
– name: dt
mountPath: /etc/localtime
args:
– –character-set-server=utf8mb4
– –collation-server=utf8mb4_bin
– –default-authentication-plugin=mysql_native_password
metadata:
labels:
apps: master
root@master231:~/manifests/mysql-master-slave# cat 05-deploy-mysql-slave.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-mysql-slave
spec:
replicas: 1
selector:
matchLabels:
apps: slave
template:
spec:
volumes:
– name: dt
hostPath:
path: /etc/localtime
– name: slave
persistentVolumeClaim:
claimName: pvc-slave
– name: conf
configMap:
name: mysql80
items:
– key: slave.cnf
path: my.cnf
containers:
– name: db
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/wordpress:mysql-8.0.36-oracle
env:
– name: MYSQL_ALLOW_EMPTY_PASSWORD
value: “yes”
volumeMounts:
– name: slave
mountPath: /var/lib/mysql
– name: conf
mountPath: /etc/my.cnf
subPath: my.cnf
– name: dt
mountPath: /etc/localtime
args:
– –character-set-server=utf8mb4
– –collation-server=utf8mb4_bin
– –default-authentication-plugin=mysql_native_password
metadata:
labels:
apps: slave
root@master231:~/manifests/mysql-master-slave#

root@master231:~/manifests/mysql-master-slave# kubectl apply -f .
configmap/mysql80 created
persistentvolumeclaim/pvc-master created
persistentvolumeclaim/pvc-slave created
service/svc-master created
deployment.apps/deploy-mysql-master created
deployment.apps/deploy-mysql-slave created
root@master231:~/manifests/mysql-master-slave# kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-mysql-master-bbcd77749-x6ktb 0/1 ContainerCreating 0 4s
deploy-mysql-slave-5cddb648d9-r7r5q 0/1 ContainerCreating 0 4s
root@master231:~/manifests/mysql-master-slave# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-mysql-master-bbcd77749-x6ktb 1/1 Running 0 22s 10.100.2.43 worker233
deploy-mysql-slave-5cddb648d9-r7r5q 1/1 Running 1 (6s ago) 22s 10.100.2.42 worker233

root@master231:~/manifests/mysql-master-slave# kubectl exec -it deploy-mysql-master-bbcd77749-x6ktb — mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.36 MySQL Community Server – GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> show grants for ysl;
+————————————-+
| Grants for ysl@% |
+————————————-+
| GRANT USAGE ON *.* TO `ysl`@`%` |
+————————————-+
1 row in set (0.00 sec)

mysql> show master status\G;
*************************** 1. row ***************************
File: deploy-mysql-master-bbcd77749-x6ktb-bin.000003
Position: 157
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)

ERROR:
No query specified

mysql> exit
Bye
root@master231:~/manifests/mysql-master-slave# kubectl exec -it deploy-mysql-slave-5cddb648d9-r7r5q — mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.36 MySQL Community Server – GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> CHANGE MASTER TO MASTER_HOST=’svc-master’,MASTER_USER=’ysl’,MASTER_PASSWORD=’ysl’,MASTER_PORT=3306,MASTER_LOG_FILE=’deploy-mysql-master-546dcd6d79-25jq2-bin.000003′,MASTER_LOG_POS=380,MASTER_CONNECT_RETRY=3;
Query OK, 0 rows affected, 10 warnings (0.04 sec)

mysql> CHANGE MASTER TO MASTER_HOST=’svc-master’,MASTER_USER=’ysl’,MASTER_PASSWORD=’ysl’,MASTER_PORT=3306,MASTER_LOG_FILE=’deploy-mysql-master-bbcd77749-x6ktb-bin.000003′,MASTERR_LOG_POS=380,MASTER_CONNE
Query OK, 0 rows affected, 10 warnings (0.02 sec)

mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting to reconnect after a failed registration on source
Master_Host: svc-master
Master_User: ysl
Master_Port: 3306
Connect_Retry: 3
Master_Log_File: deploy-mysql-master-bbcd77749-x6ktb-bin.000003
Read_Master_Log_Pos: 380
Relay_Log_File: deploy-mysql-slave-5cddb648d9-r7r5q-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: deploy-mysql-master-bbcd77749-x6ktb-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 380
Relay_Log_Space: 157
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 13120
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 111
Master_UUID: ea116814-1de1-11f0-8d0f-d60610b71a57
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp: 250420 20:24:01
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set, 1 warning (0.00 sec)


root@master231:~/manifests/mysql-master-slave# cat sts-mysql.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql80
data:
master.cnf: |
[mysqld]
server_id=111
skip-host-cache
skip-name-resolve
log-bin=mysql-bin
character-set-server=utf8mb4
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
pid-file=/var/run/mysqld/mysqld.pid

[client]
default-character-set=utf8mb4
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/


slave.cnf: |
[mysqld]
server_id=222
skip-host-cache
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
#super-read-only
character-set-server=utf8mb4
pid-file=/var/run/mysqld/mysqld.pid

[client]
default-character-set=utf8mb4
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/



apiVersion: v1
kind: Service
metadata:
name: headless-db
spec:
ports:
– port: 3306
clusterIP: None
selector:
app: db



apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sts-mysql
spec:
selector:
matchLabels:
apps: db
serviceName: “headless-db”
replicas: 2
podManagementPolicy: OrderedReady
template:
spec:
initContainers:
– name: copy-conf
image: harbor.ysl.com/ysl-xiuxian/apps:v1
volumeMounts:
– name: conf
mountPath: /opt
– name: sub-conf
mountPath: /mnt
command:
– /bin/sh
– -c
– |
if [[ ${HOSTNAME} == sts-mysql-0 ]]
then
cp /opt/master.cnf /mnt/my.cnf
else
cp /opt/slave.cnf /mnt/my.cnf
fi
volumes:
– name: dt
hostPath:
path: /etc/localtime
– name: conf
configMap:
name: mysql80
– name: sub-conf
emptyDir: {}
#- name: master
# persistentVolumeClaim:
# claimName: pvc-master
containers:
– name: db
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/wordpress:mysql-8.0.36-oracle
env:
– name: MYSQL_ALLOW_EMPTY_PASSWORD
value: “yes”
– name: MYSQL_USER
value: test
– name: MYSQL_PASSWORD
value: yangsenlin
volumeMounts:
#- name: master
# mountPath: /var/lib/mysql
– name: sub-conf
mountPath: /root/
– name: dt
mountPath: /etc/localtime
args:
– –defaults-file=/root/my.cnf
– –character-set-server=utf8mb4
– –collation-server=utf8mb4_bin
– –default-authentication-plugin=mysql_native_password
metadata:
labels:
apps: db
root@master231:~/manifests/mysql-master-slave#
40 日志采集ElasticStack
1.什么是Operator
Operator是由CoreOS开发的,Operator是增强型的控制器(Controller),简单理解就是Operator = Controller + CRD。

Operator扩展了Kubernetes API的功能,并基于该扩展管理复杂应用程序。
– 1.Operator是Kubernetes的扩展软件, 它利用定制的资源类型来增强自动化管理应用及其组件的能力,从而扩展了集群的行为模式;
– 2.使用自定义资源(例如CRD)来管理应用程序及其组件;
– 3.将应用程序视为单个对象,并提供面向该应用程序的自动化管控操作(声明式管理),例如部署、配置、升级、备份、故障转移和灾难恢复等;

Operator也有很多镜像仓库,其中典型代表如上图所示。
https://operatorhub.io/


基于专用的Operator编排运行某个有状态应用的流程:
– 1.部署Operator及其专用的资源类型;
– 2.使用专用的资源类型,来声明一个有状态应用编排请求:

2 ECK(Elastic Cloud on Kubernetes)
2.1 创建自定义资源
root@master231:~/manifests/operator# wget https://download.elastic.co/downloads/eck/2.16.1/crds.yaml


2.2 常见operator及RBAC
root@master231:~/manifests/operator# wget https://download.elastic.co/downloads/eck/2.16.1/operator.yaml

root@master231:~/manifests/operator# ll
total 696
drwxr-xr-x 2 root root 4096 Apr 20 20:37 ./
drwxr-xr-x 28 root root 4096 Apr 20 20:35 ../
-rw-r–r– 1 root root 680855 Jan 18 10:35 crds.yaml
-rw-r–r– 1 root root 19777 Jan 18 10:35 operator.yaml

root@master231:~/manifests/operator# kubectl apply -f .

2.3 部署集群
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: quickstart
spec:
version: 8.17.2
nodeSets:
– name: default
count: 3
config:
node.store.allow_mmap: false
podTemplate:
metadata:
labels:
my.custom.domain/label: “label-value”
annotations:
my.custom.domain/annotation: “annotation-value”
spec:
tolerations:
– key: node-role.kubernetes.io/master
effect: NoSchedule

EOF
elasticsearch.elasticsearch.k8s.elastic.co/quickstart created

2.4 查找默认的用户名密码
[root@master231 operator]# kubectl get secrets quickstart-es-elastic-user -o jsonpath='{.data.elastic}’ | base64 -d |
more
1BV3oC4Rvmc388b85JrWz4c2
[root@master231 operator]#

2.5 查看集群状态
[root@master231 operator]# curl -u “elastic:1BV3oC4Rvmc388b85JrWz4c2” -k https://10.100.1.208:9200
{
“name” : “quickstart-es-default-0”,
“cluster_name” : “quickstart”,
“cluster_uuid” : “YG1f6FpuSMiNPhNr5WyUFg”,
“version” : {
“number” : “8.17.2”,
“build_flavor” : “default”,
“build_type” : “docker”,
“build_hash” : “747663ddda3421467150de0e4301e8d4bc636b0c”,
“build_date” : “2025-02-05T22:10:57.067596412Z”,
“build_snapshot” : false,
“lucene_version” : “9.12.0”,
“minimum_wire_compatibility_version” : “7.17.0”,
“minimum_index_compatibility_version” : “7.0.0”
},
“tagline” : “You Know, for Search”
}
[root@master231 operator]#
[root@master231 operator]# curl -u “elastic:1BV3oC4Rvmc388b85JrWz4c2” -k https://10.100.1.208:9200/_cat/nodes
10.100.1.208 56 75 7 0.09 0.34 0.46 cdfhilmrstw * quickstart-es-default-0
10.100.2.253 24 72 4 0.28 0.27 0.33 cdfhilmrstw – quickstart-es-default-1
10.100.0.38 44 76 8 1.48 1.12 0.86 cdfhilmrstw – quickstart-es-default-2
[root@master231 operator]#



3.优化后案例
[root@master231 operator]# cat 01-casedemo-es.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: ysl-ysl
spec:
version: 8.17.2
nodeSets:
– name: default
count: 3
config:
node.store.allow_mmap: false
podTemplate:
spec:
tolerations:
– key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
– name: elasticsearch
env:
– name: ES_JAVA_OPTS
value: “-Xms512m -Xmx512m”
resources:
limits:
cpu: 1
memory: 1024Mi
requests:
cpu: 500m
memory: 512Mi
# volumeMounts:
# – name: elasticsearch-data
# mountPath: /var/lib/elasticsearch
# volumeClaimTemplates:
# – metadata:
# name: elasticsearch-data
# spec:
# accessModes:
# – ReadWriteOnce
# resources:
# requests:
# storage: 5Gi
# storageClassName: nfs-csi
[root@master231 operator]#
[root@master231 operator]# kubectl apply -f 01-casedemo-es.yaml
elasticsearch.elasticsearch.k8s.elastic.co/ysl-ysl created
[root@master231 operator]#


3.2 查看服务
[root@master231 operator]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ysl-ysl-es-default-0 1/1 Running 0 62s 10.100.1.212 worker232
ysl-ysl-es-default-1 1/1 Running 0 62s 10.100.2.4 worker233
ysl-ysl-es-default-2 1/1 Running 0 62s 10.100.0.41 master231
[root@master231 operator]#
[root@master231 operator]# kubectl get secrets ysl-ysl-es-elastic-user -o jsonpath='{.data.elastic}’ | base64 -d |
more
WZ8Lolyd9q268uLg55p655uc
[root@master231 operator]#

3.3 测试验证
[root@master231 operator]# curl -k -u “elastic:WZ8Lolyd9q268uLg55p655uc” https://10.200.93.152:9200
{
“name” : “ysl-ysl-es-default-2”,
“cluster_name” : “ysl-ysl”,
“cluster_uuid” : “YhYv6k_9ShKiji02RrN85A”,
“version” : {
“number” : “8.17.2”,
“build_flavor” : “default”,
“build_type” : “docker”,
“build_hash” : “747663ddda3421467150de0e4301e8d4bc636b0c”,
“build_date” : “2025-02-05T22:10:57.067596412Z”,
“build_snapshot” : false,
“lucene_version” : “9.12.0”,
“minimum_wire_compatibility_version” : “7.17.0”,
“minimum_index_compatibility_version” : “7.0.0”
},
“tagline” : “You Know, for Search”
}
[root@master231 operator]#
[root@master231 operator]# curl -k -u “elastic:WZ8Lolyd9q268uLg55p655uc” https://10.200.93.152:9200/_cat/nodes
10.100.2.4 44 92 11 0.24 0.47 0.42 cdfhilmrstw – ysl-ysl-es-default-1
10.100.0.41 41 96 13 0.59 1.20 1.09 cdfhilmrstw * ysl-ysl-es-default-2
10.100.1.212 53 91 11 0.28 0.74 0.60 cdfhilmrstw – ysl-ysl-es-default-0
[root@master231 operator]#



参考链接:
https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-deploy-eck.html
https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-deploy-elasticsearch.html

– 基于operator部署kibana实战
1.部署ES集群
[root@master231 operator]# curl -u “elastic:WZ8Lolyd9q268uLg55p655uc” -k https://10.200.93.152:9200/_cat/nodes
10.100.2.4 61 92 1 0.02 0.07 0.21 cdfhilmrstw – ysl-ysl-es-default-1
10.100.0.41 48 96 1 0.56 0.64 0.63 cdfhilmrstw * ysl-ysl-es-default-2
10.100.1.212 68 92 1 0.30 0.19 0.19 cdfhilmrstw – ysl-ysl-es-default-0
[root@master231 operator]#
[root@master231 operator]# kubectl get es
NAME HEALTH NODES VERSION PHASE AGE
ysl-ysl green 3 8.17.2 Ready 171m
[root@master231 operator]#


2.部署kibana
[root@master231 operator]# cat 02-casedemo-kibana.yaml
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: ysl-ysl
spec:
version: 8.17.2
count: 1
elasticsearchRef:
name: ysl-ysl
config:
i18n.locale: zh-CN



apiVersion: v1
kind: Service
metadata:
name: svc-kibana
spec:
type: LoadBalancer
selector:
kibana.k8s.elastic.co/name: ysl-ysl
ports:
– port: 5601

[root@master231 operator]#
[root@master231 operator]# kubectl apply -f 02-casedemo-kibana.yaml
kibana.kibana.k8s.elastic.co/ysl-ysl created
service/svc-kibana created
[root@master231 operator]#


3.访问测试
[root@master231 operator]# kubectl get svc svc-kibana
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-kibana LoadBalancer 10.200.62.17 10.0.0.152 5601:30338/TCP 4m11s
[root@master231 operator]#


访问”https://10.0.0.152:5601″即可。



温馨提示:
如果要修改密码,
[root@master231 operator]# kubectl get secrets ysl-ysl-es-elastic-user -o jsonpath='{.data.elastic}’ | base64 -d ; echo
WZ8Lolyd9q268uLg55p655uc
[root@master231 operator]#


– 基于operator部署filebeat实战
1.编写资源清单
[root@master231 operator]# cat 03-casedemo-beats.yaml
apiVersion: beat.k8s.elastic.co/v1beta1
kind: Beat
metadata:
name: ysl-ysl
spec:
type: filebeat
version: 8.17.2
elasticsearchRef:
name: ysl-ysl
config:
filebeat.inputs:
– type: container
paths:
– /var/log/containers/*.log
processors:
– add_kubernetes_metadata:
in_cluster: true
output.elasticsearch:
username: elastic
password: WZ8Lolyd9q268uLg55p655uc
index: “ysl-ysl-k8s-haha-%{+yyyy.MM.dd}”
setup.ilm.enabled: false
setup.template.name: ysl-ysl-k8s
setup.template.pattern: “ysl-ysl-k8s*”
setup.template.settings:
index.number_of_shards: 5
index.number_of_replicas: 0
setup.template.overwrite: false
daemonSet:
podTemplate:
spec:
tolerations:
– key: node-role.kubernetes.io/master
effect: NoSchedule
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
securityContext:
runAsUser: 0
containers:
– name: filebeat
volumeMounts:
– name: varlogcontainers
mountPath: /var/log/containers
– name: varlogpods
mountPath: /var/log/pods
– name: varlibdockercontainers
mountPath: /var/lib/docker/containers
volumes:
– name: varlogcontainers
hostPath:
path: /var/log/containers
– name: varlogpods
hostPath:
path: /var/log/pods
– name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
[root@master231 operator]#
[root@master231 operator]# kubectl apply -f 03-casedemo-beats.yaml
beat.beat.k8s.elastic.co/ysl-ysl created
[root@master231 operator]#


镜像地址:
http://192.168.15.253/Resources/Kubernetes/Project/ElasticStack/v8.17.2/



– K8S日志采集数据到集群外部
1.k8s日志收集方案
– sidecar: 边车模式
可以在现有的业务容器注入一个Filebeat实例,和业务容器共享存储卷,从而进行日志采集。

优点:
– 1.理解起来比较简单,功能可以自定义注入的容器;
– 2.随着Pod数量的增多,一个节点可能有数百个容器,意味着要启动数个Filebeat;

– 使用ds各节点独占一个实例
在每个工作节点部署一个Filebeat实例,采集该节点的所有日志。

优点:
– 1.相当于sidecar更加节省资源;
– 2.需要创建sa和api-server通信,以获取当前节点pod信息;

– 业务人员编写日志采集的方案代码。
优点:
– 运维人员无需参与解决问题;
– 缺点就是实时难度较大,技术人员的能力水平不齐,可能会写的代码影响到正常业务;



2.编写资源清单
[root@master231 01-elasticstack]# cat 01-ep-svc-es.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: ysl-es7
subsets:
– addresses:
– ip: 10.0.0.91
– ip: 10.0.0.92
– ip: 10.0.0.93
ports:
– port: 9200



apiVersion: v1
kind: Service
metadata:
name: ysl-es7
spec:
type: ClusterIP
ports:
– port: 9200
targetPort: 9200
[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]# cat 02-cm-filebeat.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
data:
filebeat.yml: |-
filebeat.config:
inputs:
# Mounted `filebeat-inputs` configmap:
path: ${path.config}/inputs.d/*.yml
# Reload inputs configs as they change:
reload.enabled: false
modules:
path: ${path.config}/modules.d/*.yml
# Reload module configs as they change:
reload.enabled: false

output.elasticsearch:
hosts: [‘https://ysl-es7:9200’]
# hosts: [‘ysl-es7.default.svc.ysl.com:9200’]
index: ‘ysl-k8s-ds-%{+yyyy.MM.dd}’
# 跳过证书校验,有效值为: full(default),strict,certificate,none
# 参考链接:
# https://www.elastic.co/guide/en/beats/filebeat/7.17/configuration-ssl.html#client-verification-mode
ssl.verification_mode: none
username: “elastic”
password: “123456”

# 配置索引模板
setup.ilm.enabled: false
setup.template.name: “ysl-k8s-ds”
setup.template.pattern: “ysl-k8s-ds*”
setup.template.overwrite: false
setup.template.settings:
index.number_of_shards: 5
index.number_of_replicas: 0



apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-inputs
data:
kubernetes.yml: |-
– type: docker
containers.ids:
– “*”
processors:
– add_kubernetes_metadata:
in_cluster: true

[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]# cat 03-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: filebeat



apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: filebeat
subjects:
– kind: ServiceAccount
name: filebeat
namespace: default
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io



apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: filebeat
labels:
k8s-app: filebeat
rules:
– apiGroups: [“”]
resources:
– namespaces
– pods
– nodes
verbs:
– get
– watch
– list
[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]# cat 04-ds-filebeat.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
spec:
selector:
matchLabels:
k8s-app: filebeat
template:
metadata:
labels:
k8s-app: filebeat
spec:
tolerations:
– key: node-role.kubernetes.io/master
effect: NoSchedule
operator: Exists
serviceAccountName: filebeat
terminationGracePeriodSeconds: 30
containers:
– name: filebeat
# image: docker.elastic.co/beats/filebeat:7.17.26
image: harbor.ysl.com/ysl-elasitcstack/filebeat:7.17.26
args: [
“-c”, “/etc/filebeat.yml”,
“-e”,
]
securityContext:
runAsUser: 0
# If using Red Hat OpenShift uncomment this:
#privileged: true
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
volumeMounts:
– name: config
mountPath: /etc/filebeat.yml
readOnly: true
subPath: filebeat.yml
– name: inputs
mountPath: /usr/share/filebeat/inputs.d
readOnly: true
– name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
– name: config
configMap:
defaultMode: 0600
name: filebeat-config
– name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
– name: inputs
configMap:
defaultMode: 0600
name: filebeat-inputs

[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]# kubectl apply -f .
endpoints/ysl-es7 created
service/ysl-es7 created
configmap/filebeat-config created
configmap/filebeat-inputs created
serviceaccount/filebeat created
clusterrolebinding.rbac.authorization.k8s.io/filebeat created
clusterrole.rbac.authorization.k8s.io/filebeat created
daemonset.apps/filebeat created
[root@master231 01-elasticstack]#
[root@master231 01-elasticstack]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
filebeat-cshms 1/1 Running 0 22s 10.100.0.42 master231
filebeat-g5rtg 1/1 Running 0 22s 10.100.2.7 worker233
filebeat-xm5tw 1/1 Running 0 22s 10.100.1.214 worker232
[root@master231 01-elasticstack]#


41 探针
常用的探针(Probe):
livenessProbe:
健康状态检查,周期性检查服务是否存活,检查结果失败,将”重启”容器(删除源容器并重新创建新容器)。
如果容器没有提供健康状态检查,则默认状态为Success。

readinessProbe:
可用性检查,周期性检查服务是否可用,从而判断容器是否就绪。
若检测Pod服务不可用,会将Pod标记为未就绪状态,而svc的ep列表会将Addresses的地址移动到NotReadyAddresses列表。
若检测Pod服务可用,则ep会将Pod地址从NotReadyAddresses列表重新添加到Addresses列表中。
如果容器没有提供可用性检查,则默认状态为Success。

startupProbe: (1.16+之后的版本才支持)
如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。
如果启动探测失败,kubelet将杀死容器,而容器依其重启策略进行重启。
如果容器没有提供启动探测,则默认状态为 Success。

对于starup探针是一次性检测,容器启动时进行检测,检测成功后,才会调用其他探针,且此探针不在生效。


探针(Probe)检测Pod服务方法:
exec:
执行一段命令,根据返回值判断执行结果。返回值为0或非0,有点类似于”echo $?”。

httpGet:
发起HTTP请求,根据返回的状态码来判断服务是否正常。
200: 返回状态码成功
301: 永久跳转
302: 临时跳转
401: 验证失败
403: 权限被拒绝
404: 文件找不到
413: 文件上传过大
500: 服务器内部错误
502: 无效的请求
504: 后端应用网关响应超时

tcpSocket:
测试某个TCP端口是否能够链接,类似于telnet,nc等测试工具。

grpc:
k8s 1.19+版本才支持,1.23依旧属于一个alpha阶段。

参考链接:
https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/#types-of-probe


1 livenessProbe探针值exec探测方式
root@master231:~/manifests/probe# cat 01-pods-livenessProbe-exec.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-livenessprobe-exec-001
spec:
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
command:
– /bin/sh
– -c
– touch /tmp/ysl-linux-healthy; sleep 20; rm -f /tmp/ysl-linux-healthy; sleep 600
# 健康状态检查,周期性检查服务是否存活,检查结果失败,将重启容器。
livenessProbe:
# 使用exec的方式去做健康检查
exec:
# 自定义检查的命令
command:
– cat
– /tmp/ysl-linux-healthy
# 指定探针检测的频率,默认是10s,最小值为1.
periodSeconds: 1
# 检测服务失败次数的累加值,默认值是3次,最小值是1。当检测服务成功后,该值会被重置!
failureThreshold: 3
# 检测服务成功次数的累加值,默认值为1次,最小值1.
successThreshold: 1
# 指定多久之后进行健康状态检查,即此时间段内检测服务失败并不会对failureThreshold进行计数。
initialDelaySeconds: 30
# 一次检测周期超时的秒数,默认值是1秒,最小值为1.
timeoutSeconds: 1

2 livenessProbe探针值httpGet探测方式
root@master231:~/manifests/probe# cat 02-pods-livenessProbe-httpGet.yaml
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe-httpget-001
spec:
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
# 健康状态检查,周期性检查服务是否存活,检查结果失败,将重启容器。
livenessProbe:
# 使用httpGet的方式去做健康检查
httpGet:
# 指定访问的端口号
port: 80
# 检测指定的访问路径
path: /index.html
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
root@master231:~/manifests/probe#

3 livenessProbe探针值tcpSocket探测方式
[root@master231 probe]# cat 03-pods-livenessProbe-tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe-tcpsocket-001
spec:
containers:
– image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2
name: c1
command:
– /bin/sh
– -c
– nginx; sleep 10; nginx -s stop; sleep 600
#健康状态检查,周期性检查服务是否存活,检查结果失败,将重启容器
livenessProbe:
#使用tcpsocket的方式做健康检查
tcpSocket:
port: 80
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1

4 livenessProbe探针之grpc探测方式
[root@master231 probe]# cat 04-pods-livenessProbe-grpc.yaml
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe-grpc
spec:
restartPolicy: Always
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/etcd:3.5.10
name: web
imagePullPolicy: IfNotPresent
command:
– /opt/bitnami/etcd/bin/etcd
– –data-dir=/tmp/etcd
– –listen-client-urls=http://0.0.0.0:2379
– –advertise-client-urls=http://127.0.0.1:2379
– –log-level=debug
ports:
– containerPort: 2379
livenessProbe:
# 对grpc端口发起grpc调用,目前属于alpha测试阶段,如果真的想要使用,请在更高版本关注,比如k8s 1.24+
# 在1.23.17版本中,如果检测失败,会触发警告,但不会重启容器只是会有警告事件。
grpc:
port: 2379
# 指定服务,但是服务名称我是瞎写的,实际工作中会有开发告诉你
service: /health
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1

5 readlinessProbe探针exec探测方式
root@master231:~/manifests/probe# cat 05-deploy-svc-readinessprobe-livenessProbe-exec.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
command:
– /bin/sh
– -c
– touch /tmp/ysl-linux-healthy; sleep 60; rm -f /tmp/ysl-linux-healthy; sleep 600
livenessProbe:
exec:
command:
– cat
– /tmp/ysl-linux-healthy
failureThreshold: 3
initialDelaySeconds: 120
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
# 可用性检查,周期性检查服务是否可用,从而判断容器是否就绪.
readinessProbe:
# 使用exec的方式去做健康检查
exec:
# 自定义检查的命令
command:
– cat
– /tmp/ysl-linux-healthy
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1



apiVersion: v1
kind: Service
metadata:
name: ysl-readinessprobe-exec
spec:
selector:
apps: v1
ports:
– port: 80
targetPort: 80
protocol: TCP
root@master231:~/manifests/probe#

6 readinessProbe探针httpGet探测方式
root@master231:~/manifests/probe# cat 06-deploy-svc-readinessProbe-livenessProbe-httpGet.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian
spec:
replicas: 3
selector:
matchLabels:
apps: v2
template:
metadata:
labels:
apps: v2
spec:
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2
name: c1
command:
– /bin/sh
– -c
– touch /tmp/ysl-linux-healthy; sleep 30; rm -f /tmp/ysl-linux-healthy; sleep 600
livenessProbe:
exec:
command:
– cat
– /tmp/ysl-linux-healthy
failureThreshold: 3
initialDelaySeconds: 120
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
# 可用性检查,周期性检查服务是否可用,从而判断容器是否就绪.
readinessProbe:
# 使用httpGet的方式去做健康检查
httpGet:
# 指定访问的端口号
port: 80
path: /index.html
failureThreshold: 3
initialDelaySeconds: 15
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1




apiVersion: v1
kind: Service
metadata:
name: ysl-readinessprobe-httpget
spec:
clusterIP: 10.200.0.11
selector:
apps: v2
ports:
– port: 80
targetPort: 80
protocol: TCP
root@master231:~/manifests/probe#

测试方式:
[root@master231 ~]# while true;do curl 10.200.0.22;sleep 0.5;done

7 readinessProbe探针之tcpSocket探测方式
root@master231:~/manifests/probe# cat 07-deploy-svc-readinessProbe-livenessProbe-tcpSocket.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian
spec:
replicas: 3
selector:
matchLabels:
apps: v2
template:
metadata:
labels:
apps: v2
spec:
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2
name: c1
command:
– /bin/sh
– -c
– |
touch /tmp/ysl-linux-healthy
sleep 10
rm -f /tmp/ysl-linux-healthy
nginx
tail -f /etc/hosts
livenessProbe:
exec:
command:
– cat
– /tmp/ysl-linux-healthy
failureThreshold: 3
initialDelaySeconds: 120
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
# 可用性检查,周期性检查服务是否可用,从而判断容器是否就绪.
readinessProbe:
# 使用tcpSocket的方式去做健康检查
tcpSocket:
# 探测80端口是否存活
port: 80
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1



apiVersion: v1
kind: Service
metadata:
name: ysl-readinessprobe-tcpsocket
spec:
clusterIP: 10.200.0.22
selector:
apps: v2
ports:
– port: 80
targetPort: 80
protocol: TCP
root@master231:~/manifests/probe#

测试方式:
[root@master231 ~]# while true;do curl 10.200.0.22;sleep 0.5;done

8 启动探针startupProbe
root@master231:~/manifests/probe# cat 08-startupProbe-httpGet.yaml
apiVersion: v1
kind: Pod
metadata:
name: startupprobe-httpget-01
spec:
volumes:
– name: data
emptyDir: {}
initContainers:
– name: init01
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
volumeMounts:
– name: data
mountPath: /ysl
command:
– /bin/sh
– -c
– echo “liveness probe test page” >> /ysl/huozhe.html
– name: init02
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2
volumeMounts:
– name: data
mountPath: /ysl
command:
– /bin/sh
– -c
– echo “readiness probe test page” >> /ysl/ysl.html
– name: init03
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v3
volumeMounts:
– name: data
mountPath: /ysl
command:
– /bin/sh
– -c
– echo “startup probe test page” >> /ysl/start.html
containers:
– name: c1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
# 判断服务是否健康,若检查不通过,将Pod直接重启。
livenessProbe:
httpGet:
port: 80
path: /huozhe.html
failureThreshold: 3
initialDelaySeconds: 5
#initialDelaySeconds: 120
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
# 判断服务是否就绪,若检查不通过,将Pod标记为未就绪状态。
readinessProbe:
httpGet:
port: 80
path: /ysl.html
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
# 启动时做检查,若检查不通过,直接杀死容器。并进行重启!
# startupProbe探针通过后才回去执行readinessProbe和livenessProbe哟~
startupProbe:
httpGet:
port: 80
path: /start.html
failureThreshold: 3
# 尽管上面的readinessProbe和livenessProbe数据已经就绪,但必须等待startupProbe的检测成功后才能执行。
initialDelaySeconds: 35
# initialDelaySeconds: 15
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
root@master231:~/manifests/probe#
42 静态Pod
1 静态Pod概述
所谓的静态pod就是kubelet自己监视的一个目录,如果这个目录有Pod资源清单,就直接会在当前节点上创建该Pod。

也就是说不基于APIServer就可以直接创建Pod,静态Pod仅对Pod类型的资源有效,其他资源无视。

静态Pod创建的资源,后缀都会加一个当前节点的名称。

2 查看kubelet配置默认静态目录
root@master231:~/manifests/probe# grep staticPodPath /var/lib/kubelet/config.yaml
staticPodPath: /etc/kubernetes/manifests
root@master231:~/manifests/probe#

root@master231:~/manifests/probe# ll /etc/kubernetes/manifests
total 24
drwxr-xr-x 2 root root 4096 Apr 4 19:30 ./
drwxr-xr-x 4 root root 4096 Apr 4 19:30 ../
-rw——- 1 root root 2280 Apr 4 19:30 etcd.yaml
-rw——- 1 root root 4026 Apr 4 19:30 kube-apiserver.yaml
-rw——- 1 root root 3546 Apr 4 19:30 kube-controller-manager.yaml
-rw——- 1 root root 1465 Apr 4 19:30 kube-scheduler.yaml


3 修改nodePort默认端口
默认是30000-30767
修改端口范围
root@master231:~# grep -n service-node-port-range /etc/kubernetes/manifests/kube-apiserver.yaml
17: – –service-node-port-range=3000-50000
root@master231:~#

3 快速重建api-server
root@master231:~# cd /etc/kubernetes/manifests/
root@master231:/etc/kubernetes/manifests# mv kube-apiserver.yaml /opt/
root@master231:/etc/kubernetes/manifests# mv /opt/kube-apiserver.yaml ./
root@master231:/etc/kubernetes/manifests#

root@master231:/etc/kubernetes/manifests# kubectl -n kube-system get pods kube-apiserver-master231
NAME READY STATUS RESTARTS AGE
kube-apiserver-master231 1/1 Running 1 (31s ago) 2m2s


43 容器的生命周期postStart和preStop
root@master231:/manifests/pods# cat 24-pod-lifecycle-postStart-preStop.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-poststart-prestop-001
spec:
volumes:
– name: data
hostPath:
path: /ysl-linux
# 在pod优雅终止时,定义延迟发送kill信号的时间,此时间可用于pod处理完未处理的请求等状况。
# 默认单位是秒,若不设置默认值为30s。
# terminationGracePeriodSeconds: 60
terminationGracePeriodSeconds: 3
containers:
– name: c1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
volumeMounts:
– name: data
mountPath: /data
# 定义容器的生命周期。
lifecycle:
# 容器启动之后做的事情
postStart:
exec:
command:
– “/bin/sh”
– “-c”
– “sleep 30;echo \”postStart at $(date +%F_%T)\” >> /data/postStart.log”
# 容器停止之前做的事情
preStop:
exec:
command:
– “/bin/sh”
– “-c”
– “sleep 20;echo \”preStop at $(date +%F_%T)\” >> /data/preStop.log”

root@master231:/manifests/pods#
44 kubelet启动容器的原理
1 kubelet创建Pod的全流程:
– 1.kubelet调用CRI接口创建容器,底层支持docker|containerd作为容器运行时;
– 2.底层基于runc(符合OCI规范)创建容器:
– 3.优先创建pause基础镜像;
– 4.创建初始化容器
– 5.业务容器,业务容器如果定义了优雅终止,探针则顺序如下:
– 5.1 启动命令【COMMAND】
– 5.2 启动postStart;
– 5.3 Probe
– StartupProbe
– LivenessProbe | readinessProbe
– 5.4 启动PreStop
2 测试案例
root@master231:/manifests/pods# cat 25-startkubelet-workflow.yaml
apiVersion: v1
kind: Pod
metadata:
name: pods-workflow-001
spec:
volumes:
– name: data
hostPath:
path: /ysl-shaonao
initContainers:
– name: init01
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
volumeMounts:
– name: data
mountPath: /ysl
command:
– “/bin/sh”
– “-c”
– “echo \”initContainer at $(date +%F_%T)\” > /ysl/haha.log”
terminationGracePeriodSeconds: 3
containers:
– name: c1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v3
command:
– /bin/sh
– -c
– “echo \”command at $(date +%F_%T)\” >> /usr/share/nginx/html/haha.log; sleep 600″
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
– “/bin/sh”
– “-c”
– “echo \”livenessProbe at $(date +%F_%T)\” >> /usr/share/nginx/html/haha.log”
failureThreshold: 3
initialDelaySeconds: 0
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
exec:
command:
– “/bin/sh”
– “-c”
– “echo \”readinessProbe at $(date +%F_%T)\” >> /usr/share/nginx/html/haha.log”
failureThreshold: 3
initialDelaySeconds: 0
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
startupProbe:
exec:
command:
– “/bin/sh”
– “-c”
– “echo \”startupProbe at $(date +%F_%T)\” >> /usr/share/nginx/html/haha.log”
failureThreshold: 3
initialDelaySeconds: 0
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
lifecycle:
postStart:
exec:
command:
– “/bin/sh”
– “-c”
– “sleep 10;echo \”postStart at $(date +%F_%T)\” >> /usr/share/nginx/html/haha.log”
preStop:
exec:
command:
– “/bin/sh”
– “-c”
– “echo \”preStop at $(date +%F_%T)\” >> /usr/share/nginx/html/haha.log;sleep 30″
root@master231:/manifests/pods#
45 deploy的升级策略
root@master231:/manifests/deployments# cat 03-deploy-startegy-xiuxian.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-strategy
labels:
school: ysl
spec:
replicas: 5
# 定义升级策略
strategy:
# 指定更新策略的类型,有效值为: “Recreate” or “RollingUpdate”
# Recreate:
# 表示批量删除旧的Pod,重新创建新的Pod。
# RollingUpdate: (default)
# 滚动更新Pod,并不会删除所有的旧Pod。
# type: Recreate
type: RollingUpdate
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
address: shahe
class: ysl
spec:
containers:
– name: c1
# image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v22




apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian
spec:
type: ClusterIP
selector:
apps: xiuxian
ports:
– port: 80
root@master231:/manifests/deployments#

root@master231:/manifests/deployments# cat 04-deploy-strategy-RollingUpdate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-strategy
labels:
school: ysl
spec:
# replicas: 4
replicas: 5
strategy:
type: RollingUpdate
# 配置滚动更新的策略
rollingUpdate:
# 升级过程中,在原有Pod数量之上,多出来的百分比或数字。
# maxSurge: 25%
# 支持数字和百分比,此处我使用的是数字。
maxSurge: 2
# 升级过程中,最多不可用的Pod数量百分比,
# maxUnavailable: 25%
maxUnavailable: 1
selector:
matchLabels:
apps: xiuxian
template:
metadata:
labels:
apps: xiuxian
address: shahe
class: ysl
spec:
containers:
– name: c1
# image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v3
imagePullPolicy: Always




apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian
spec:
type: ClusterIP
selector:
apps: xiuxian
ports:
– port: 80
root@master231:/manifests/deployments#
46 基于operator部署prometheus实现k8s监控
1.下载源代码
wget https://github.com/prometheus-operator/kube-prometheus/archive/refs/tags/v0.11.0.tar.gz



2.解压目录
[root@master231 02-prometheus]# tar xf kube-prometheus-0.11.0.tar.gz
[root@master231 02-prometheus]#
[root@master231 02-prometheus]# cd kube-prometheus-0.11.0/
[root@master231 kube-prometheus-0.11.0]#


3.安装Prometheus-Operator
kubectl apply –server-side -f manifests/setup
kubectl wait \
–for condition=Established \
–all CustomResourceDefinition \
–namespace=monitoring
kubectl apply -f manifests/


4.检查Prometheus是否部署成功
[root@master231 kube-prometheus-0.11.0]# kubectl get pods -n monitoring -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
alertmanager-main-0 2/2 Running 0 3m34s 10.100.2.93 worker233
alertmanager-main-1 2/2 Running 0 3m34s 10.100.1.11 worker232
alertmanager-main-2 2/2 Running 0 3m34s 10.100.2.94 worker233
blackbox-exporter-746c64fd88-g7w5k 3/3 Running 0 4m40s 10.100.2.89 worker233
grafana-5fc7f9f55d-zk5tk 1/1 Running 0 4m39s 10.100.2.91 worker233
kube-state-metrics-6c8846558c-wbs66 3/3 Running 0 4m39s 10.100.2.90 worker233
node-exporter-mttjn 2/2 Running 0 4m39s 10.0.0.232 worker232
node-exporter-szr25 2/2 Running 0 4m39s 10.0.0.231 master231
node-exporter-wdkjk 2/2 Running 0 4m39s 10.0.0.233 worker233
prometheus-adapter-6455646bdc-m9qwv 1/1 Running 0 4m38s 10.100.2.92 worker233
prometheus-adapter-6455646bdc-wbjqd 1/1 Running 0 4m38s 10.100.1.9 worker232
prometheus-k8s-0 2/2 Running 0 3m33s 10.100.1.12 worker232
prometheus-k8s-1 1/2 Running 0 3m33s 10.100.2.95 worker233
prometheus-operator-f59c8b954-ttjth 2/2 Running 0 4m38s 10.100.1.10 worker232
[root@master231 kube-prometheus-0.11.0]#



5.修改Grafana的svc
[root@master231 kube-prometheus-0.11.0]# cat manifests/grafana-service.yaml
apiVersion: v1
kind: Service
metadata:

name: grafana
namespace: monitoring
spec:
type: LoadBalancer

[root@master231 kube-prometheus-0.11.0]#
[root@master231 kube-prometheus-0.11.0]# kubectl apply -f manifests/grafana-service.yaml
service/grafana configured
[root@master231 kube-prometheus-0.11.0]#
[root@master231 kube-prometheus-0.11.0]# kubectl get -f manifests/grafana-service.yaml
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana LoadBalancer 10.200.231.129 10.0.0.150 3000:37754/TCP 7m23s
[root@master231 kube-prometheus-0.11.0]#

6.访问Grafana的WebUI
http://10.0.0.150:3000/

默认的用户名和密码: admin




– 暴露Prometheus的服务
1.基于NodePort方式暴露
[root@master231 kube-prometheus-0.11.0]# cat manifests/prometheus-service.yaml
apiVersion: v1
kind: Service
metadata:

name: prometheus-k8s
namespace: monitoring
spec:
type: NodePort
ports:
– name: web
port: 9090
nodePort: 9090
targetPort: web

[root@master231 kube-prometheus-0.11.0]#
[root@master231 kube-prometheus-0.11.0]# kubectl apply -f manifests/prometheus-service.yaml
service/prometheus-k8s configured
[root@master231 kube-prometheus-0.11.0]#
[root@master231 kube-prometheus-0.11.0]# kubectl get -f manifests/prometheus-service.yaml
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
prometheus-k8s NodePort 10.200.246.30 9090:9090/TCP,8080:39234/TCP 75m
[root@master231 kube-prometheus-0.11.0]#

2.基于LoadBalancer
略。


3.基于端口转发
[root@master231 ~]# kubectl port-forward sts/prometheus-k8s 19090:9090 -n monitoring –address=0.0.0.0
Forwarding from 0.0.0.0:19090 -> 9090
Handling connection for 19090
Handling connection for 19090



– Prometheus监控云原生应用etcd案例
1.测试ectd metrics接口
1.1 查看etcd证书存储路径
[root@master231 yangsenlin]# egrep “\–key-file|–cert-file” /etc/kubernetes/manifests/etcd.yaml
– –cert-file=/etc/kubernetes/pki/etcd/server.crt
– –key-file=/etc/kubernetes/pki/etcd/server.key
[root@master231 yangsenlin]#


1.2 测试etcd证书访问的metrics接口
[root@master231 yangsenlin]# curl -s –cert /etc/kubernetes/pki/etcd/server.crt –key /etc/kubernetes/pki/etcd/server.key https://10.0.0.231:2379/metrics -k | tail
# TYPE process_virtual_memory_max_bytes gauge
process_virtual_memory_max_bytes 1.8446744073709552e+19
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code=”200″} 4
promhttp_metric_handler_requests_total{code=”500″} 0
promhttp_metric_handler_requests_total{code=”503″} 0
[root@master231 yangsenlin]#


2.创建etcd证书的secrets并挂载到Prometheus server
2.1 查找需要挂载etcd的证书文件路径
[root@master231 yangsenlin]# egrep “\–key-file|–cert-file|–trusted-ca-file” /etc/kubernetes/manifests/etcd.yaml
– –cert-file=/etc/kubernetes/pki/etcd/server.crt
– –key-file=/etc/kubernetes/pki/etcd/server.key
– –trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
[root@master231 yangsenlin]#

2.2 根据etcd的实际存储路径创建secrets
[root@master231 yangsenlin]# kubectl create secret generic etcd-tls –from-file=/etc/kubernetes/pki/etcd/server.crt –from-file=/etc/kubernetes/pki/etcd/server.key –from-file=/etc/kubernetes/pki/etcd/ca.crt -n monitoring
secret/etcd-tls created
[root@master231 yangsenlin]#
[root@master231 yangsenlin]# kubectl -n monitoring get secrets etcd-tls
NAME TYPE DATA AGE
etcd-tls Opaque 3 12s
[root@master231 yangsenlin]#


2.3 修改Prometheus的资源,修改后会自动重启
[root@master231 yangsenlin]# kubectl -n monitoring edit prometheus k8s

spec:
secrets:
– etcd-tls

[root@master231 yangsenlin]# kubectl -n monitoring get pods -l app.kubernetes.io/component=prometheus -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
prometheus-k8s-0 2/2 Running 0 74s 10.100.1.57 worker232
prometheus-k8s-1 2/2 Running 0 92s 10.100.2.28 worker233
[root@master231 yangsenlin]#


2.4.查看证书是否挂载成功
[root@master231 yangsenlin]# kubectl -n monitoring exec prometheus-k8s-0 -c prometheus — ls -l /etc/prometheus/secrets/etcd-tls
total 0
lrwxrwxrwx 1 root 2000 13 Jan 24 14:07 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root 2000 17 Jan 24 14:07 server.crt -> ..data/server.crt
lrwxrwxrwx 1 root 2000 17 Jan 24 14:07 server.key -> ..data/server.key
[root@master231 yangsenlin]#
[root@master231 yangsenlin]# kubectl -n monitoring exec prometheus-k8s-1 -c prometheus — ls -l /etc/prometheus/secrets/etcd-tls
total 0
lrwxrwxrwx 1 root 2000 13 Jan 24 14:07 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root 2000 17 Jan 24 14:07 server.crt -> ..data/server.crt
lrwxrwxrwx 1 root 2000 17 Jan 24 14:07 server.key -> ..data/server.key
[root@master231 yangsenlin]#

3.编写资源清单
[root@master231 servicemonitors]# cat 01-smon-etcd.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: etcd-k8s
namespace: kube-system
subsets:
– addresses:
– ip: 10.0.0.231
ports:
– name: https-metrics
port: 2379
protocol: TCP



apiVersion: v1
kind: Service
metadata:
name: etcd-k8s
namespace: kube-system
labels:
apps: etcd
spec:
ports:
– name: https-metrics
port: 2379
targetPort: 2379
type: ClusterIP



apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: ysl-etcd-smon
namespace: monitoring
spec:
# 指定job的标签,可以不设置。
jobLabel: kubeadm-etcd-k8s-yangsenlin
# 指定监控后端目标的策略
endpoints:
# 监控数据抓取的时间间隔
– interval: 30s
# 指定metrics端口,这个port对应Services.spec.ports.name
port: https-metrics
# Metrics接口路径
path: /metrics
# Metrics接口的协议
scheme: https
# 指定用于连接etcd的证书文件
tlsConfig:
# 指定etcd的CA的证书文件
caFile: /etc/prometheus/secrets/etcd-tls/ca.crt
# 指定etcd的证书文件
certFile: /etc/prometheus/secrets/etcd-tls/server.crt
# 指定etcd的私钥文件
keyFile: /etc/prometheus/secrets/etcd-tls/server.key
# 关闭证书校验,毕竟咱们是自建的证书,而非官方授权的证书文件。
insecureSkipVerify: true
# 监控目标Service所在的命名空间
namespaceSelector:
matchNames:
– kube-system
# 监控目标Service目标的标签。
selector:
# 注意,这个标签要和etcd的service的标签保持一致哟
matchLabels:
apps: etcd
[root@master231 servicemonitors]#

4.Prometheus查看数据
etcd_cluster_version

5.Grafana导入模板
3070



– Prometheus监控非云原生应用MySQL案例
1.编写资源清单
[root@master231 servicemonitors]# cat 02-smon-mysqld.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql80-deployment
spec:
replicas: 1
selector:
matchLabels:
apps: mysql80
template:
metadata:
labels:
apps: mysql80
spec:
containers:
– name: mysql
image: harbor.ysl.com/ysl-wordpress/mysql:8.0.36-oracle
ports:
– containerPort: 3306
env:
– name: MYSQL_ROOT_PASSWORD
value: yangsenlin
– name: MYSQL_USER
value: ysl
– name: MYSQL_PASSWORD
value: “ysl”



apiVersion: v1
kind: Service
metadata:
name: mysql80-service
spec:
selector:
apps: mysql80
ports:
– protocol: TCP
port: 3306
targetPort: 3306




apiVersion: v1
kind: ConfigMap
metadata:
name: my.cnf
data:
.my.cnf: |-
[client]
user = ysl
password = ysl

[client.servers]
user = ysl
password = ysl



apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-exporter-deployment
spec:
replicas: 1
selector:
matchLabels:
apps: mysql-exporter
template:
metadata:
labels:
apps: mysql-exporter
spec:
volumes:
– name: data
configMap:
name: my.cnf
items:
– key: .my.cnf
path: .my.cnf
containers:
– name: mysql-exporter
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/mysqld-exporter:v0.15.1
command:
– mysqld_exporter
– –config.my-cnf=/root/my.cnf
– –mysqld.address=mysql80-service.default.svc.ysl.com:3306
securityContext:
runAsUser: 0
ports:
– containerPort: 9104
#env:
#- name: DATA_SOURCE_NAME
# value: mysql_exporter:yangsenlin@(mysql80-service.default.svc.yangsenlin.com:3306)
volumeMounts:
– name: data
mountPath: /root/my.cnf
subPath: .my.cnf



apiVersion: v1
kind: Service
metadata:
name: mysql-exporter-service
labels:
apps: mysqld
spec:
selector:
apps: mysql-exporter
ports:
– protocol: TCP
port: 9104
targetPort: 9104
name: mysql80



apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: ysl-mysql-smon
spec:
jobLabel: kubeadm-mysql-k8s-yangsenlin
endpoints:
– interval: 3s
# 这里的端口可以写svc的端口号,也可以写svc的名称。
# 但我推荐写svc端口名称,这样svc就算修改了端口号,只要不修改svc端口的名称,那么我们此处就不用再次修改哟。
# port: 9104
port: mysql80
path: /metrics
scheme: http
namespaceSelector:
matchNames:
– default
selector:
matchLabels:
apps: mysqld
[root@master231 servicemonitors]#


2.Prometheus访问测试
mysql_up

3.Grafana导入模板
7362

47 helm
1 概述
helm优点类似于Linux的yum,apt工具,帮助我们管理K8S集群的资源清单。

Helm 帮助您管理 Kubernetes 应用—— Helm Chart,即使是最复杂的 Kubernetes 应用程序,都可以帮助您定义,安装和升级。

Helm Chart 易于创建、发版、分享和发布,所以停止复制粘贴,开始使用 Helm 吧。

Helm 是 CNCF 的毕业项目,由 Helm 社区维护。
官方文档:
https://helm.sh/zh/

2 安装helm
2.1 下载helm并解压
root@master231:~# wget https://get.helm.sh/helm-v3.17.1-linux-amd64.tar.gz

root@master231:~# tar xf helm-v3.17.1-linux-amd64.tar.gz -C /usr/local/bin linux-amd64/helm –strip-components=1
root@master231:~#

2.2 配置helm自动补全
root@master231:~# helm completion bash > /etc/bash_completion.d/helm
root@master231:~# source /etc/bash_completion.d/helm
root@master231:~# echo ‘source /etc/bash_completion.d/helm’ >> ~/.bashrc

3 helm的基本管理
3.1 创建chart
root@master231:~/manifests# mkdir helm
root@master231:~/manifests# cd helm/
root@master231:~/manifests/helm# helm create test-helm
Creating test-helm

3.2 查看chart
root@master231:~/manifests/helm# tree test-helm
test-helm
├── charts #包含chart依赖的其他chart
├── Chart.yaml #包含了chart信息的YAML文件
├── templates #模板目录,当和values结合时,可生成有效的kubernetes manifect文件
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt #可选,包含简要使用说明的纯文本文件
│ ├── serviceaccount.yaml
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml #默认的配置值

参考链接:
https://helm.sh/zh/docs/topics/charts/#chart-%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84

3.3 修改默认的values.yaml
root@master231:~/manifests/helm# sed -i “/repository\:/s#nginx#crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps#” test-helm/values.yaml

root@master231:~/manifests/helm# grep “repository:” test-helm/values.yaml
repository: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps

root@master231:~/manifests/helm# sed -ri ‘/tag\:/s#tag: “”#tag: v1#’ test-helm/values.yaml root@master231:~/manifests/helm# grep “tag:” test-helm/values.yaml
tag: v1

3.4 基于chart安装服务发行Release
root@master231:~/manifests/helm# helm install myapp test-helm
3.5 查看服务
root@master231:~/manifests/helm/test-helm/templates# helm list
root@master231:~/manifests/helm# kubectl get deploy,svc,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/myapp-test-helm 1/1 1 1 5m46s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/harbor-mysql ClusterIP 10.200.67.2 3306/TCP 6d4h
service/headless-apps ClusterIP None 80/TCP 6d4h
service/kubernetes ClusterIP 10.200.0.1 443/TCP 15d
service/myapp-test-helm ClusterIP 10.200.247.46 80/TCP 5m46s
service/quickstart-es-default ClusterIP None 9200/TCP 2d20h
service/quickstart-es-http ClusterIP 10.200.57.152 9200/TCP 2d20h
service/quickstart-es-internal-http ClusterIP 10.200.69.164 9200/TCP 2d20h
service/quickstart-es-transport ClusterIP None 9300/TCP 2d20h
service/svc-headless ClusterIP None 81/TCP 6d4h
service/svc-xiuxian ClusterIP 10.200.224.60 81/TCP 13d
service/svc-xiuxian-externalname ExternalName www.baidu.com 81:30082/TCP 6d21h
service/svc-xiuxian-loadbalancer LoadBalancer 10.200.0.200 10.0.0.150 81:30081/TCP 6d21h
service/svc-xiuxian-nodeport NodePort 10.200.0.100 81:30080/TCP 7d1h

NAME READY STATUS RESTARTS AGE
pod/myapp-test-helm-7d5b86dcbf-nklhf 1/1 Running 0 5m46s
pod/quickstart-es-default-0 1/1 Running 1 (96m ago) 2d20h
pod/quickstart-es-default-1 1/1 Running 1 (80m ago) 2d20h
pod/quickstart-es-default-2 1/1 Running 1 (80m ago) 2d20h
root@master231:~/manifests/helm#

root@master231:~/manifests/helm# curl 10.200.247.46

3.6 卸载服务
root@master231:~/manifests/helm# helm uninstall myapp
root@master231:~/manifests/helm# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
root@master231:~/manifests/helm#

3.7 helm架构版本选择
2019年11月Helm团队发布V3版本,相比v2版本最大变化是将Tiller删除,并大部分代码重构。

helm v3相比helm v2还做了很多优化,比如不同命名空间资源同名的情况在v3版本是允许的,我们在生产环境中使用建议大家使用v3版本,不仅仅是因为它版本功能较强,而且相对来说也更加稳定了。


官方地址:
https://helm.sh/docs/intro/install/

github地址:
https://github.com/helm/helm/releases

4 helm的两种升级方式
4.1 安装旧的服务
root@master231:~/manifests/helm# helm install myapp01 test-helm/
root@master231:~/manifests/helm# kubectl get deploy,svc,pods
root@master231:~/manifests/helm# kubectl get svc myapp01-test-helm
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp01-test-helm ClusterIP 10.200.216.101 80/TCP 112s
root@master231:~/manifests/helm# curl 10.200.216.101

4.2 修改要升级的相关参数
root@master231:~/manifests/helm# sed -i ‘/replicaCount/s#1#3#’ test-helm/values.yaml
root@master231:~/manifests/helm# grep replicaCount test-helm/values.yaml
replicaCount: 3
root@master231:~/manifests/helm# sed -i “/tag:/s#v1#v2#” test-helm/values.yaml
root@master231:~/manifests/helm# grep “tag:” test-helm/values.yaml
tag: v2

4.3 基于文件方式升级
root@master231:~/manifests/helm# helm upgrade myapp01 -f test-helm/values.yaml test-helm

4.4 结果验证
root@master231:~/manifests/helm# kubectl get deploy,svc,pods
root@master231:~/manifests/helm# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
myapp01 default 2 2025-04-24 12:52:39.161470213 +0800 CST deployed test-helm-0.1.0 1.16.0
root@master231:~/manifests/helm#

4.5 基于环境变量方式升级
root@master231:~/manifests/helm# helm upgrade myapp01 –set replicaCount=5,image.tag=v3 test-helm

4.6 再次验证升级效果
root@master231:~/manifests/helm# kubectl get deploy,svc,pods
root@master231:~/manifests/helm# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
myapp01 default 3 2025-04-24 12:55:34.585170484 +0800 CST deployed test-helm-0.1.0 1.16.0
root@master231:~/manifests/helm#

5 helm回滚
5.1 查看Release历史版本
root@master231:~/manifests/helm# helm history myapp01
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Thu Apr 24 12:31:37 2025 superseded test-helm-0.1.0 1.16.0 Install complete
2 Thu Apr 24 12:52:39 2025 superseded test-helm-0.1.0 1.16.0 Upgrade complete
3 Thu Apr 24 12:55:34 2025 deployed test-helm-0.1.0 1.16.0 Upgrade complete
root@master231:~/manifests/helm#

5.2 回滚到上一个版本
root@master231:~/manifests/helm# helm rollback myapp01
root@master231:~/manifests/helm# helm history myapp01
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Thu Apr 24 12:31:37 2025 superseded test-helm-0.1.0 1.16.0 Install complete
2 Thu Apr 24 12:52:39 2025 superseded test-helm-0.1.0 1.16.0 Upgrade complete
3 Thu Apr 24 12:55:34 2025 superseded test-helm-0.1.0 1.16.0 Upgrade complete
4 Thu Apr 24 12:59:40 2025 deployed test-helm-0.1.0 1.16.0 Rollback to 2

5.3 回滚到指定版本
root@master231:~/manifests/helm# helm rollback myapp01 1
root@master231:~/manifests/helm# helm history myapp01
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Thu Apr 24 12:31:37 2025 superseded test-helm-0.1.0 1.16.0 Install complete
2 Thu Apr 24 12:52:39 2025 superseded test-helm-0.1.0 1.16.0 Upgrade complete
3 Thu Apr 24 12:55:34 2025 superseded test-helm-0.1.0 1.16.0 Upgrade complete
4 Thu Apr 24 12:59:40 2025 superseded test-helm-0.1.0 1.16.0 Rollback to 2
5 Thu Apr 24 17:49:27 2025 deployed test-helm-0.1.0 1.16.0 Rollback to 1

6 helm公有仓库管理及es-exporter环境部署
6.1 主流的Chart仓库概述
互联网公开Chart仓库,可以直接使用他们制作好的Chart包:
微软仓库:
http://mirror.azure.cn/kubernetes/charts/

阿里云仓库:
https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

6.2 添加公有仓库
root@master231:~/manifests/helm# helm repo add azure http://mirror.azure.cn/kubernetes/charts/
“azure” has been added to your repositories
root@master231:~/manifests/helm# helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
“aliyun” has been added to your repositories
root@master231:~/manifests/helm#

6.3 查看本地的仓库列表
root@master231:~/manifests/helm# helm repo list
NAME URL
azure http://mirror.azure.cn/kubernetes/charts/
aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
root@master231:~/manifests/helm#

6.4 更新本地仓库
root@master231:~/manifests/helm# helm repo update
Hang tight while we grab the latest from your chart repositories…
…Successfully got an update from the “aliyun” chart repository
…Successfully got an update from the “azure” chart repository
Update Complete. ⎈Happy Helming!⎈
root@master231:~/manifests/helm#

6.5 搜索Chart
root@master231:~/manifests/helm# helm search repo elasticsearch
NAME CHART VERSION APP VERSION DESCRIPTION
aliyun/elasticsearch-exporter 0.1.2 1.0.2 Elasticsearch stats exporter for Prometheus
azure/elasticsearch 1.32.5 6.8.6 DEPRECATED Flexible and powerful open source, d…
azure/elasticsearch-curator 2.2.3 5.7.6 DEPRECATED A Helm chart for Elasticsearch Curator


6.6 查看Chart的详细信息
root@master231:~/manifests/helm# helm show chart aliyun/elasticsearch-exporter

6.7 查看指定版本chart
root@master231:~/manifests/helm# helm show chart aliyun/elasticsearch-exporter –version 0.1.1

6.8 拉取chart
root@master231:~/manifests/helm# helm pull aliyun/elasticsearch-exporter
root@master231:~/manifests/helm# helm pull aliyun/elasticsearch-exporter –version 0.1.1
root@master231:~/manifests/helm# ls
elasticsearch-exporter-0.1.1.tgz elasticsearch-exporter-0.1.2.tgz test-helm
root@master231:~/manifests/helm#

6.9 部署拉取的chart


6.10 删除第三方仓库
root@master231:~/manifests/helm# helm repo remove azure

root@master231:~/manifests/helm# helm repo list

7 基于helm部署Ingress-nginx
7.1 Ingress-Nginx概述
Ingress-Nginx是K8S官方写的一个Ingress Controller,而”nginx-Ingress”是Nginx官方写的资源清单。

注意,部署时要观察对比一下K8S和Ingress-Nginx对应的版本以来关系。

github地址:
https://github.com/kubernetes/ingress-nginx

安装文档:
https://kubernetes.github.io/ingress-nginx/deploy/#installation-guide

如上图所示,官方推荐了三种安装方式:
– 使用”helm”安装;
– 使用”kubectl apply”创建yaml资源清单的方式进行安装;
– 使用第三方插件的方式进行安装;

7.2 添加第三方仓库
root@master231:~/manifests/helm# helm repo add ingress https://kubernetes.github.io/ingress-nginx
[root@master231 helm]# helm repo list

7.3 搜索Ingress-nginx的chart
[root@master231 helm]# helm search repo ingress-nginx
root@master231:~/manifests/helm# helm search repo ingress-nginx
NAME CHART VERSION APP VERSION DESCRIPTION
ysl-ingress/ingress-nginx 4.12.1 1.12.1 Ingress controller for Kubernetes using NGINX a…
root@master231:~/manifests/helm#

root@master231:~/manifests/helm# helm search repo ingress-nginx -l

7.4 下载指定的chart
[root@master231 helm]# helm pull ingress/ingress-nginx –version 4.2.5

7.5 解压软件包并修改配置
[root@master231 helm]# tar xf ingress-nginx-4.2.5.tgz
[root@master231 helm]#
[root@master231 helm]# sed -i ‘/registry:/s#registry.k8s.io#registry.cn-hangzhou.aliyuncs.com#g’ ingress-nginx/values.yaml
[root@master231 helm]# sed -i ‘s#ingress-nginx/controller#yangsenlin-k8s/ingress-nginx#’ ingress-nginx/values.yaml
[root@master231 helm]# sed -i ‘s#ingress-nginx/kube-webhook-certgen#yangsenlin-k8s/ingress-nginx#’ ingress-nginx/values.yaml
[root@master231 helm]# sed -i ‘s#v1.3.0#kube-webhook-certgen-v1.3.0#’ ingress-nginx/values.yaml
[root@master231 helm]# sed -ri ‘/digest:/s@^@#@’ ingress-nginx/values.yaml
[root@master231 helm]# sed -i ‘/hostNetwork:/s#false#true#’ ingress-nginx/values.yaml
[root@master231 helm]# sed -i ‘/dnsPolicy/s#ClusterFirst#ClusterFirstWithHostNet#’ ingress-nginx/values.yaml
[root@master231 helm]# sed -i ‘/kind/s#Deployment#DaemonSet#’ ingress-nginx/values.yaml
[root@master231 helm]# sed -i ‘/default:/s#false#true#’ ingress-nginx/values.yaml

7.6 安装ingress-nginx
root@master231:~/manifests/helm# helm upgrade –install my-ingress ingress-nginx -n ingress-nginx –create-namespace

NAME: my-ingress
LAST DEPLOYED: Thu Apr 24 18:58:07 2025
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running ‘kubectl –namespace ingress-nginx get services -o wide -w my-ingress-ingress-nginx-controller’

An example Ingress that makes use of the controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
namespace: foo
spec:
ingressClassName: nginx
rules:
– host: www.example.com
http:
paths:
– pathType: Prefix
backend:
service:
name: exampleService
port:
number: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
– hosts:
– www.example.com
secretName: example-tls

If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:

apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt:
tls.key:
type: kubernetes.io/tls

7.7 验证Ingress-nginx是否安装成功
root@master231:~/manifests/helm# helm list -n ingress-nginx

root@master231:~# kubectl get ingressclass,deploy,svc,po -n ingress-nginx

8 ingress映射http
8.1 概述
NodePort在暴露服务时,会监听一个NodePort端口,且多个服务无法使用同一个端口的情况。

因此我们说Service可以理解为四层代理。说白了,就是基于IP:PORT的方式进行代理。

假设”v1.ysl.com”的服务需要监听80端口,而”v2.ysl.com”和”v3.ysl.com”同时也需要监听80端口,svc就很难实现。

这个时候,我们可以借助Ingress来实现此功能,可以将Ingress看做七层代理,底层依旧基于svc进行路由。

而Ingress在K8S是内置的资源,表示主机到svc的解析规则,但具体实现需要安装附加组件(对应的是IngressClass),比如ingress-nginx,traefik等。

IngressClass和Ingress的关系优点类似于: nginx和nginx.conf的关系。

8.2 环境准备
root@master231:~/manifests/add-ones/ingress# cat 01-deploy-svc-xiuxian.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-v1
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80


apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-v2
spec:
replicas: 3
selector:
matchLabels:
apps: v2
template:
metadata:
labels:
apps: v2
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2
ports:
– containerPort: 80


apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-v3
spec:
replicas: 3
selector:
matchLabels:
apps: v3
template:
metadata:
labels:
apps: v3
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v3
ports:
– containerPort: 80



apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-v1
spec:
type: ClusterIP
selector:
apps: v1
ports:
– port: 80



apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-v2
spec:
type: ClusterIP
selector:
apps: v2
ports:
– port: 80



apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-v3
spec:
type: ClusterIP
selector:
apps: v3
ports:
– port: 80

root@master231:~/manifests/add-ones/ingress# kubectl apply -f 01-deploy-svc-xiuxian.yaml

root@master231:~/manifests/add-ones/ingress# kubectl get pods –show-labels
NAME READY STATUS RESTARTS AGE LABELS
deploy-xiuxian-v1-686b885479-6cxwd 1/1 Running 0 2m4s apps=v1,pod-template-hash=686b885479
deploy-xiuxian-v1-686b885479-cd7dq 1/1 Running 0 2m4s apps=v1,pod-template-hash=686b885479
deploy-xiuxian-v1-686b885479-kj6cw 1/1 Running 0 2m4s apps=v1,pod-template-hash=686b885479
deploy-xiuxian-v2-58c47cb989-8lhrq 1/1 Running 0 2m4s apps=v2,pod-template-hash=58c47cb989
deploy-xiuxian-v2-58c47cb989-cn865 1/1 Running 0 2m4s apps=v2,pod-template-hash=58c47cb989
deploy-xiuxian-v2-58c47cb989-hgmt6 1/1 Running 0 2m4s apps=v2,pod-template-hash=58c47cb989
deploy-xiuxian-v3-6dc5df4467-69hrc 1/1 Running 0 2m4s apps=v3,pod-template-hash=6dc5df4467
deploy-xiuxian-v3-6dc5df4467-bnlhm 1/1 Running 0 2m4s apps=v3,pod-template-hash=6dc5df4467
deploy-xiuxian-v3-6dc5df4467-rf5xk 1/1 Running 0 2m4s apps=v3,pod-template-hash=6dc5df4467
root@master231:~/manifests/add-ones/ingress#

8.3 编写ingress规则
root@master231:~/manifests/add-ones/ingress# cat 02-ingress-xiuxian.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-xiuxian
spec:
ingressClassName: nginx
rules:
– host: v1.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v1
port:
number: 80
path: /
– host: v2.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v2
port:
number: 80
path: /
– host: v3.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v3
port:
number: 80
path: /
root@master231:~/manifests/add-ones/ingress# kubectl apply -f 02-ingress-xiuxian.yaml
ingress.networking.k8s.io/ingress-xiuxian created
root@master231:~/manifests/add-ones/ingress# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-xiuxian nginx v1.ysl.com,v2.ysl.com,v3.ysl.com 80 11s
root@master231:~/manifests/add-ones/ingress#

root@master231:~/manifests/add-ones/ingress# cat 02-ingress-xiuxian.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-xiuxian
spec:
ingressClassName: nginx
rules:
– host: v1.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v1
port:
number: 80
path: /
– host: v2.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v2
port:
number: 80
path: /
– host: v3.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v3
port:
number: 80
path: /
root@master231:~/manifests/add-ones/ingress# kubectl apply -f 02-ingress-xiuxian.yaml
ingress.networking.k8s.io/ingress-xiuxian created
root@master231:~/manifests/add-ones/ingress# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-xiuxian nginx v1.ysl.com,v2.ysl.com,v3.ysl.com 80 11s
root@master231:~/manifests/add-ones/ingress# kubectl describe ingress
Name: ingress-xiuxian
Labels:
Namespace: default
Address: 10.0.0.151
Default backend: default-http-backend:80 ()
Rules:
Host Path Backends
—- —- ——–
v1.ysl.com
/ svc-xiuxian-v1:80 (10.100.1.149:80,10.100.1.150:80,10.100.2.74:80)
v2.ysl.com
/ svc-xiuxian-v2:80 (10.100.1.152:80,10.100.2.73:80,10.100.2.75:80)
v3.ysl.com
/ svc-xiuxian-v3:80 (10.100.1.151:80,10.100.2.76:80,10.100.2.77:80)
Annotations:
Events:
Type Reason Age From Message
—- —— —- —- ——-
Normal Sync 2m46s (x2 over 3m30s) nginx-ingress-controller Scheduled for sync
Normal Sync 2m45s (x2 over 3m30s) nginx-ingress-controller Scheduled for sync
root@master231:~/manifests/add-ones/ingress#

8.5 windows添加解析
8.6 访问ingress-nginx服务
8.7 ingress和ingress class底层原理
root@master231:~/manifests/add-ones/ingress# kubectl get pods -o wide -n ingress-nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-ingress-ingress-nginx-controller-h949x 1/1 Running 3 (68m ago) 17h 10.0.0.233 worker233
my-ingress-ingress-nginx-controller-rmjjk 1/1 Running 5 (68m ago) 17h 10.0.0.232 worker232
root@master231:~/manifests/add-ones/ingress#

root@master231:~/manifests/add-ones/ingress# kubectl -n ingress-nginx exec -it my-ingress-ingress-nginx-controller-h949x — sh
/etc/nginx $ grep ysl.com /etc/nginx/nginx.conf
## start server v1.ysl.com
server_name v1.ysl.com ;
## end server v1.ysl.com
## start server v2.ysl.com
server_name v2.ysl.com ;
## end server v2.ysl.com
## start server v3.ysl.com
server_name v3.ysl.com ;
## end server v3.ysl.com

9 ingress映射https
9.1 生成证书文件
root@master231:~/manifests/add-ones/ingress/02-casedemo-https# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj “/CN=www.ysl.com”

9.2 将证书文件以secrets形式存储
root@master231:~/manifests/add-ones/ingress/02-casedemo-https# kubectl create secret tls ca-secret –cert=tls.crt –key=tls.key

[root@master231 02-casedemo-https]# kubectl get secrets ca-secret
NAME TYPE DATA AGE
ca-secret kubernetes.io/tls 2 2m37s

9.3 部署测试
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-apple
spec:
replicas: 3
selector:
matchLabels:
apps: apple
template:
metadata:
labels:
apps: apple
spec:
containers:
– name: apple
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:apple
ports:
– containerPort: 80



apiVersion: v1
kind: Service
metadata:
name: svc-apple
spec:
selector:
apps: apple
ports:
– protocol: TCP
port: 80
targetPort: 80

[root@master231 02-casedemo-https]# kubectl apply -f deploy-apple.yaml

[root@master231 02-casedemo-https]# kubectl get pods –show-labels
NAME READY STATUS RESTARTS AGE LABELS
deployment-apple-697d97ff95-gwr8v 1/1 Running 0 19s apps=apple,pod-template-hash=697d97ff95
deployment-apple-697d97ff95-lzspk 1/1 Running 0 19s apps=apple,pod-template-hash=697d97ff95
deployment-apple-697d97ff95-ppsjd 1/1 Running 0 19s apps=apple,pod-template-hash=697d97ff95
[root@master231 02-casedemo-https]#

9.4 配置ingress添加tls证书
[root@master231 02-casedemo-https]# cat ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tls-https
# 如果指定了”ingressClassName”参数,就不需要在这里重复声明啦。
# 如果你的K8S 1.22- 版本,则使用注解的方式进行传参即可。
#annotations:
# kubernetes.io/ingress.class: “nginx”
spec:
# 指定Ingress Class,要求你的K8S 1.22+
ingressClassName: nginx
rules:
– host: www.ysl.com
http:
paths:
– backend:
service:
name: svc-apple
port:
number: 80
path: /
pathType: ImplementationSpecific
# 配置https证书
tls:
– hosts:
– www.ysl.com
secretName: ca-secret
[root@master231 02-casedemo-https]#

[root@master231 02-casedemo-https]# kubectl get ingress ingress-tls-https
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-tls-https nginx www.ysl.com 80, 443 10s
[root@master231 02-casedemo-https]#

ingress-tls-https nginx www.ysl.com 10.0.0.151 80, 443 41s
[root@master231 02-casedemo-https]# kubectl describe ingress ingress-tls-https
Name: ingress-tls-https
Labels:
Namespace: default
Address: 10.0.0.151
Default backend: default-http-backend:80 ()
TLS:
ca-secret terminates www.ysl.com
Rules:
Host Path Backends
—- —- ——–
www.ysl.com
/ svc-apple:80 (10.100.1.153:80,10.100.2.78:80,10.100.2.79:80)
Annotations:
Events:
Type Reason Age From Message
—- —— —- —- ——-
Normal Sync 38s (x2 over 57s) nginx-ingress-controller Scheduled for sync
Normal Sync 38s (x2 over 57s) nginx-ingress-controller Scheduled for sync

9.5 windews添加解析
10.0.0.233 www.ysl.com

9.6 访问测试
https://www.ysl.com/

如果google浏览器自建证书不认可,可以用鼠标在空白处单击左键,而后输入:”thisisunsafe”,就会自动跳转。

10 基于helm部署trafik
参考链接:
https://doc.traefik.io/traefik/getting-started/install-traefik/#use-the-helm-chart
10.1 添加仓库
root@master231:~# helm repo add traefik https://traefik.github.io/charts

10.2 更新仓库信息
root@master231:~# helm repo update

10.3 安装traefik
root@master231:~# helm pull traefik traefik/traefik
[root@master231 helm]# tar xf traefik-35.0.1.tgz
[root@master231 helm]# helm install traefik traefik
[root@master231 helm]# helm list

10.4 查看服务
[root@master231 02-casedemo-https]# kubectl get ingress,deploy,svc,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/traefik 1/1 1 1 162m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.200.0.1 443/TCP 16d
service/traefik LoadBalancer 10.200.197.65 10.0.0.152 80:21519/TCP,443:13173/TCP 162m

NAME READY STATUS RESTARTS AGE
pod/traefik-ccd698b77-2zpbq 1/1 Running 0 162m
[root@master231 02-casedemo-https]#

10.5 创建测试案例
[root@master231 03-casedemo-http-traefik]# cat 01-deploy-svc-xiuxian.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-v1
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v1
ports:
– containerPort: 80


apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-v2
spec:
replicas: 3
selector:
matchLabels:
apps: v2
template:
metadata:
labels:
apps: v2
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2
ports:
– containerPort: 80


apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-xiuxian-v3
spec:
replicas: 3
selector:
matchLabels:
apps: v3
template:
metadata:
labels:
apps: v3
spec:
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v3
ports:
– containerPort: 80



apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-v1
spec:
type: ClusterIP
selector:
apps: v1
ports:
– port: 80



apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-v2
spec:
type: ClusterIP
selector:
apps: v2
ports:
– port: 80



apiVersion: v1
kind: Service
metadata:
name: svc-xiuxian-v3
spec:
type: ClusterIP
selector:
apps: v3
ports:
– port: 80
[root@master231 03-casedemo-http-traefik]# cat 02-ingress-xiuxian.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-xiuxian
spec:
# ingressClassName: nginx
ingressClassName: traefik
rules:
– host: v1.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v1
port:
number: 80
path: /
– host: v2.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v2
port:
number: 80
path: /
– host: v3.ysl.com
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-xiuxian-v3
port:
number: 80
path: /
[root@master231 03-casedemo-http-traefik]#

[root@master231 03-casedemo-http-traefik]# kubectl apply -f .
deployment.apps/deploy-xiuxian-v1 created
deployment.apps/deploy-xiuxian-v2 created
deployment.apps/deploy-xiuxian-v3 created
service/svc-xiuxian-v1 created
service/svc-xiuxian-v2 created
service/svc-xiuxian-v3 created
ingress.networking.k8s.io/ingress-xiuxian created
[root@master231 03-casedemo-http-traefik]#

[root@master231 03-casedemo-http-traefik]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-xiuxian traefik v1.ysl.com,v2.ysl.com,v3.ysl.com 10.0.0.152 80 28s
[root@master231 03-casedemo-http-traefik]#

[root@master231 03-casedemo-http-traefik]# kubectl describe ingress
Name: ingress-xiuxian
Labels:
Namespace: default
Address: 10.0.0.152
Default backend: default-http-backend:80 ()
Rules:
Host Path Backends
—- —- ——–
v1.ysl.com
/ svc-xiuxian-v1:80 (10.100.1.155:80,10.100.2.81:80,10.100.2.84:80)
v2.ysl.com
/ svc-xiuxian-v2:80 (10.100.1.154:80,10.100.2.82:80,10.100.2.85:80)
v3.ysl.com
/ svc-xiuxian-v3:80 (10.100.1.156:80,10.100.1.157:80,10.100.2.83:80)
Annotations:
Events:

10.6 windows添加解析
10.0.0.152 v1.ysl.com v2.ysl.com v3.ysl.com



10.7 访问测试
http://v1.ysl.com

http://v2.ysl.com

http://v3.ysl.com

11 traefik开启dashboard

11.1 拉取最新的chart
[root@master231 helm]# helm pull traefik/traefik

11.2 解压软件包
[root@master231 helm]# tar xf traefik-35.0.1.tgz

11.3 开启dashboard参数
[root@master231 helm]# vi traefik/values.yaml
187 ingressRoute:
188 dashboard:
189 # — Create an IngressRoute for the dashboard
190 #enabled: false
191 enabled: true

11.4 重新安装traefik
[root@master231 helm]# helm uninstall traefik
[root@master231 helm]# helm install mytraefik traefik

11.5 开启端口转发
[root@master231 helm]# kubectl port-forward –address=0.0.0.0 mytraefik-7f7b4f766c-zv5x5 8080:8080
Forwarding from 0.0.0.0:8080 -> 8080

11.6 访问测试traefik的WebUI
http://10.0.0.231:8080/dashboard/

12 测试cm,deploy,ingress,svc联动
12.1 编写资源清单
[root@master231 04-casedemo-games]# cat deployments.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ysl-games
spec:
replicas: 3
selector:
matchLabels:
apps: game
template:
metadata:
labels:
apps: game
spec:
volumes:
– name: conf
configMap:
name: cm-game
items:
– key: games.conf
path: games.conf
containers:
– name: c1
image: forestysl2020/ysl-games:v0.6
volumeMounts:
– name: conf
mountPath: /etc/nginx/conf.d/games.conf
subPath: games.conf
ports:
– containerPort: 81
name: game
livenessProbe:
httpGet:
port: 81
path: /index.html
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
httpGet:
port: 81
path: /index.html
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
startupProbe:
httpGet:
port: 81
path: /index.html
failureThreshold: 3
initialDelaySeconds: 3
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
[root@master231 04-casedemo-games]# cat services.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-games
spec:
type: ClusterIP
selector:
apps: game
ports:
– port: 81
[root@master231 04-casedemo-games]# cat configmaps.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-game
data:
games.conf: |
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/bird/;
server_name game01.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/pinshu/;
server_name game02.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/tanke/;
server_name game03.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/chengbao/;
server_name game04.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/motuo/;
server_name game05.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/liferestart/;
server_name game06.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/huangjinkuanggong/;
server_name game07.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/feijidazhan/;
server_name game08.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/zhiwudazhanjiangshi/;
server_name game09.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/xiaobawang/;
server_name game10.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/pingtai/;
server_name game11.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/dayu/;
server_name game12.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/maliao/;
server_name game13.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/menghuanmonizhan/;
server_name game14.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/qieshuiguo/;
server_name game15.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/wangzhezhicheng/;
server_name game16.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/zhiwuVSjiangshi/;
server_name game17.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/doudizhu/;
server_name game18.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/killbird/;
server_name game19.ysl.com;
}
server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/tankedazhan/;
server_name game20.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/buyu/;
server_name game21.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/huimiejiangshi/;
server_name game22.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/renzhegame/;
server_name game23.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/tankedazhan/;
server_name game24.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/tiaoyitiao/;
server_name game25.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/yangyang/;
server_name game26.ysl.com;
}

server {
listen 0.0.0.0:81;
root /usr/local/nginx/html/zombie-master/;
server_name game27.ysl.com;
}

[root@master231 04-casedemo-games]# cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-games
spec:
# ingressClassName: nginx
ingressClassName: mytraefik
rules:
– host: “*.ysl.com”
http:
paths:
– pathType: Prefix
backend:
service:
name: svc-games
port:
number: 81
path: /
[root@master231 04-casedemo-games]#

12.2 访问测试


13 ingress基础作用说明
Ingress-nginx 是一个基于 Kubernetes 的开源项目,它使用 NGINX 作为反向代理和负载均衡器来管理 Kubernetes 集群中的 HTTP 和 HTTPS 流量。以下是它的主要功能和作用:

### 1. **反向代理**
– **定义**:Ingress-nginx 作为反向代理,接收外部访问请求,并将请求转发到集群内的后端服务。
– **作用**:用户通过一个统一的入口访问集群内的多个服务,而无需直接暴露每个服务的 IP 地址或端口。例如,一个用户访问 `http://example.com/api`,Ingress-nginx 可以将请求转发到后端的 `api-service`。

### 2. **负载均衡**
– **定义**:Ingress-nginx 可以将流量分发到多个后端服务实例,实现负载均衡。
– **作用**:当多个后端服务实例运行时,Ingress-nginx 可以根据配置的策略(如轮询、最少连接等)将流量均匀分配到各个实例,提高系统的可用性和性能。例如,如果有三个 `web-service` 实例,Ingress-nginx 可以将流量均匀分配给这三个实例。

### 3. **基于路径和域名的路由**
– **定义**:Ingress-nginx 支持基于路径和域名的路由规则。
– **作用**:
– **基于路径**:可以根据请求的 URL 路径将流量转发到不同的后端服务。例如,`http://example.com/api` 转发到 `api-service`,`http://example.com/ui` 转发到 `ui-service`。
– **基于域名**:可以根据请求的域名将流量转发到不同的服务。例如,`api.example.com` 转发到 `api-service`,`ui.example.com` 转发到 `ui-service`。

### 4. **SSL/TLS 终止**
– **定义**:Ingress-nginx 可以管理 SSL/TLS 证书,并在入口处终止加密连接。
– **作用**:用户可以通过 HTTPS 访问集群内的服务,而无需在每个服务中单独配置 SSL/TLS。Ingress-nginx 可以解密请求,然后以明文或加密方式转发到后端服务。这简化了 SSL/TLS 的管理,提高了安全性。

### 5. **支持 WebSocket 和 gRPC**
– **定义**:Ingress-nginx 支持 WebSocket 和 gRPC 等现代协议。
– **作用**:WebSocket 用于实时通信,gRPC 用于高性能的微服务通信。Ingress-nginx 可以正确处理这些协议的流量,确保它们能够正常转发到后端服务。

### 6. **支持自定义 NGINX 配置**
– **定义**:Ingress-nginx 允许用户通过注解(Annotations)或自定义配置文件来修改 NGINX 的行为。
– **作用**:用户可以根据自己的需求调整 NGINX 的配置,例如设置超时时间、启用压缩、配置重写规则等。这提供了高度的灵活性,满足不同场景的需求。

### 7. **集成 Kubernetes 生态**
– **定义**:Ingress-nginx 是 Kubernetes 生态系统的一部分,与 Kubernetes 的其他组件(如 Service、Deployment 等)紧密集成。
– **作用**:它可以通过 Kubernetes 的 API 动态更新配置,例如当后端服务的副本数量发生变化时,Ingress-nginx 会自动更新负载均衡的配置,确保流量正确转发。

Ingress-nginx 是 Kubernetes 集群中管理外部访问流量的重要组件,它提供了强大的功能,简化了集群内服务的暴露和管理。





14 helm的chart常用字段说明
https://helm.sh/zh/docs/chart_template_guide/function_list/




15 helm的chart打包并推送到harbor仓库
15.1 打包
[root@master231 helm]# helm package ingress-nginx
Successfully packaged chart and saved it to: /manifests/helm/ingress-nginx-4.2.5.tgz
[root@master231 helm]#

15.2 推送到harbor仓库
[root@master231 helm]# helm push ysl-games-25.02.21.tgz oci://harbor.ysl.com/ysl-helm –insecure-skip-tls-verify
Pushed: harbor.ysl.com/ysl-helm/ysl-games:25.02.21
Digest: sha256:928b8f64e94b8c5fe158d582b65ee8310c8ca9d0b2c391d81a4822dc4c8adaed
[root@master231 helm]#


15.3 从harbor拉取Chart
[root@master231 tmp]# helm pull oci://harbor.ysl.com/ysl-helm/ysl-games –version 25.02.21 –insecure-skip-tls-verifyPulled: harbor.ysl.com/ysl-helm/ysl-games:25.02.21
Digest: sha256:928b8f64e94b8c5fe158d582b65ee8310c8ca9d0b2c391d81a4822dc4c8adaed
[root@master231 tmp]#

48 flannel的工作原理及优化
1 Flannel的工作模式
– udp:
早期支持的一种工作模式,由于性能差,目前官方已弃用。

– vxlan:
将源数据报文进行封装为二层报文(需要借助物理网卡转发),进行跨主机转发。

– host-gw:
将容器网络的路由信息写到宿主机的路由表上。尽管效率高,但不支持跨网段。

– directrouting:
将vxlan和host-gw工作模式工作。

2 flannel模式测试
[root@master231 flannel]# cat 01-pods-multiple-worker.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: apps-v1
spec:
replicas: 1
selector:
matchLabels:
version: v1
template:
metadata:
labels:
version: v1
spec:
nodeName: worker232
containers:
– name: c1
ports:
– containerPort: 80
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1



apiVersion: apps/v1
kind: Deployment
metadata:
name: apps-v2
spec:
replicas: 1
selector:
matchLabels:
version: v2
template:
metadata:
labels:
version: v2
spec:
nodeName: worker233
containers:
– name: c2
ports:
– containerPort: 80
image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1

Flannel实现同节点Pod数据传输cni0的工作原理:
1.假设有2个Pod,名称为p1和p2;
2.p1的eth0网卡对端设备连接在cni0的网桥设备上;
3.P2的eth0网卡对端设备也连接在cni0的网桥设备上;
4.数据传输时,可以基于cni0进行数据交换传输;


tips:
1.移除cni0网卡后,同节点的2个Pod将无法通信。
2.手动添加cni0后,虚拟网卡未能绑定到cni0上,需要手动添加(见课堂演示)

3 验证
[root@master231 flannel]# tcpdump -i eth0 -en host 10.0.0.232 and udp port 8472 | grep 2.135 -A 2 -B 2

4 修改falnnel的工作模式
[root@master231 cni]# vim kube-flannel.yml

net-conf.json: |
{
“Network”: “10.100.0.0/16”,
“Backend”: {
“Type”: “host-gw”
}
}

[root@master231 ~]# kubectl apply -f kube-flannel.yml
namespace/kube-flannel unchanged
serviceaccount/flannel unchanged
clusterrole.rbac.authorization.k8s.io/flannel unchanged
clusterrolebinding.rbac.authorization.k8s.io/flannel unchanged
configmap/kube-flannel-cfg configured
daemonset.apps/kube-flannel-ds unchanged
[root@master231 ~]#

5 测试验证
[root@master231 falnnel]# ifconfig cni0
cni0: flags=4163 mtu 1450
inet 10.100.0.1 netmask 255.255.255.0 broadcast 10.100.0.255
inet6 fe80::14d5:5dff:fefa:84be prefixlen 64 scopeid 0x20 ether 16:d5:5d:fa:84:be txqueuelen 1000 (Ethernet)
RX packets 54028 bytes 10239711 (10.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 59908 bytes 43523237 (43.5 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

[root@master231 falnnel]#
[root@master231 falnnel]# route -n | grep 10.100
10.100.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
10.100.1.0 10.100.1.0 255.255.255.0 UG 0 0 0 flannel.1
10.100.2.0 10.100.2.0 255.255.255.0 UG 0 0 0 flannel.1
[root@master231 falnnel]#

[root@master231 falnnel]# kubectl get pods -n kube-flannel -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel-ds-57zww 1/1 Running 1 (114m ago) 8d 10.0.0.233 worker233
kube-flannel-ds-5gv68 1/1 Running 1 (114m ago) 8d 10.0.0.232 worker232
kube-flannel-ds-m98sv 1/1 Running 1 (114m ago) 10d 10.0.0.231 master231
[root@master231 falnnel]#
[root@master231 falnnel]# kubectl -n kube-flannel delete pods –all
pod “kube-flannel-ds-57zww” deleted
pod “kube-flannel-ds-5gv68” deleted
pod “kube-flannel-ds-m98sv” deleted
[root@master231 falnnel]#
[root@master231 falnnel]# kubectl get pods -n kube-flannel -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel-ds-8gq28 1/1 Running 0 14s 10.0.0.232 worker232
kube-flannel-ds-kpv8b 1/1 Running 0 13s 10.0.0.233 worker233
kube-flannel-ds-p98vs 1/1 Running 0 13s 10.0.0.231 master231
[root@master231 falnnel]#
[root@master231 falnnel]# route -n | grep 10.100
10.100.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
10.100.1.0 10.0.0.232 255.255.255.0 UG 0 0 0 eth0
10.100.2.0 10.0.0.233 255.255.255.0 UG 0 0 0 eth0
[root@master231 falnnel]#

6 切换flannel的工作模式为”Directrouting”(推荐配置)
[root@master231 cni]# vim kube-flannel.yml

net-conf.json: |
{
“Network”: “10.100.0.0/16”,
“Backend”: {
“Type”: “vxlan”,
“Directrouting”: true
}
}



[root@master231 ~]#
[root@master231 ~]# kubectl apply -f kube-flannel.yml
namespace/kube-flannel unchanged
serviceaccount/flannel unchanged
clusterrole.rbac.authorization.k8s.io/flannel unchanged
clusterrolebinding.rbac.authorization.k8s.io/flannel unchanged
configmap/kube-flannel-cfg configured
daemonset.apps/kube-flannel-ds unchanged
[root@master231 ~]#


7 删除Pod测试
[root@worker233 ~]# route -n | grep 10.100
10.100.0.0 10.100.0.0 255.255.255.0 UG 0 0 0 flannel.1
10.100.1.0 10.100.1.0 255.255.255.0 UG 0 0 0 flannel.1
10.100.2.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
[root@worker233 ~]#
[root@worker233 ~]#
[root@worker233 ~]# route -n | grep 10.100
10.100.0.0 10.0.0.231 255.255.255.0 UG 0 0 0 eth0
10.100.1.0 10.0.0.232 255.255.255.0 UG 0 0 0 eth0
10.100.2.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
[root@worker233 ~]#

49 kubeapps环境部署及故障排查
– kubeapps环境部署及故障排查
推荐阅读:
https://github.com/vmware-tanzu/kubeapps/

官方的Chart【存在问题,需要去docker官方拉取数据】
https://github.com/bitnami/charts/tree/main/bitnami/kubeapps

温馨提示:
官方对于kubeapps的文档会去从docker官网拉取镜像,国内因素可能无法访问。


1.添加第三方仓库
[root@master231 helm]# helm repo add bitnami https://charts.bitnami.com/bitnami
“bitnami” has been added to your repositories
[root@master231 helm]#

2.查看仓库信息
[root@master231 helm]# helm repo list
NAME URL
ysl-ingress https://kubernetes.github.io/ingress-nginx
traefik https://traefik.github.io/charts
openebs https://openebs.github.io/openebs
bitnami https://charts.bitnami.com/bitnami
[root@master231 helm]#



3.更新repo源
[root@master231 helm]# helm repo update
Hang tight while we grab the latest from your chart repositories…
…Successfully got an update from the “openebs” chart repository
…Successfully got an update from the “bitnami” chart repository
…Successfully got an update from the “ysl-ingress” chart repository
…Successfully got an update from the “traefik” chart repository
Update Complete. ⎈Happy Helming!⎈
[root@master231 helm]#

4.搜索kubeapps
[root@master231 helm]# helm search repo kubeapps -l
NAME CHART VERSION APP VERSION DESCRIPTION

bitnami/kubeapps 12.4.12 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.11 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.10 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.9 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.8 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.7 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.6 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.5 2.8.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.4 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.3 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.2 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.4.1 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.3.3 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.3.2 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.3.1 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.2.10 2.7.0 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.2.9 2.6.4 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.2.8 2.6.4 Kubeapps is a web-based UI for launching and ma…
bitnami/kubeapps 12.2.7 2.6.4 Kubeapps is a web-based UI for launching and ma…

[root@master231 helm]#


5.拉取Chart的tar包到本地
[root@master231 helm]# helm pull bitnami/kubeapps –version 12.2.10
[root@master231 helm]#
[root@master231 helm]# ll kubeapps-12.2.10.tgz
-rw-r–r– 1 root root 221609 Feb 21 18:05 kubeapps-12.2.10.tgz
[root@master231 helm]#



5.解压tar包
[root@master231 helm]# tar xf kubeapps-12.2.10.tgz
[root@master231 helm]#
[root@master231 helm]# ll kubeapps
total 256
drwxr-xr-x 5 root root 4096 Feb 21 18:06 ./
drwxr-xr-x 8 root root 4096 Feb 21 18:06 ../
-rw-r–r– 1 root root 406 Aug 26 2023 Chart.lock
drwxr-xr-x 5 root root 4096 Feb 21 18:06 charts/
-rw-r–r– 1 root root 1764 Aug 26 2023 Chart.yaml
drwxr-xr-x 2 root root 4096 Feb 21 18:06 crds/
-rw-r–r– 1 root root 421 Aug 26 2023 .helmignore
-rw-r–r– 1 root root 136307 Aug 26 2023 README.md
drwxr-xr-x 7 root root 4096 Feb 21 18:06 templates/
-rw-r–r– 1 root root 3361 Aug 26 2023 values.schema.json
-rw-r–r– 1 root root 85725 Aug 26 2023 values.yaml
[root@master231 helm]#

6.安装kubeapps
[root@master231 helm]# helm install mykubeapps kubeapps
NAME: mykubeapps
LAST DEPLOYED: Fri Feb 21 18:10:00 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: kubeapps
CHART VERSION: 12.2.10
APP VERSION: 2.7.0** Please be patient while the chart is being deployed **

Tip:

Watch the deployment status using the command: kubectl get pods -w –namespace default

Kubeapps can be accessed via port 80 on the following DNS name from within your cluster:

mykubeapps.default.svc.cluster.local

To access Kubeapps from outside your K8s cluster, follow the steps below:

1. Get the Kubeapps URL by running these commands:
echo “Kubeapps URL: http://127.0.0.1:8080”
kubectl port-forward –namespace default service/mykubeapps 8080:80

2. Open a browser and access Kubeapps using the obtained URL.
[root@master231 helm]#


7.修改svc的类型并访问WebUI
http://10.0.0.152/#/login



8.创建sa并获取token
[root@master231 helm]# cat sa-admin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: ysl


apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-ysl
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
– kind: ServiceAccount
name: ysl
namespace: default
[root@master231 helm]#
[root@master231 helm]# kubectl apply -f sa-admin.yaml
serviceaccount/ysl unchanged
clusterrolebinding.rbac.authorization.k8s.io/cluster-ysl created
[root@master231 helm]#
[root@master231 helm]# kubectl get secrets `kubectl get sa ysl -o jsonpath='{.secrets[0].name}’` -o jsonpath='{.data.token}’ | base64 -d ;echo
eyJhbGciOiJSUzI1NiIsImtpZCI6IkZUd19obzc4VmdGM1pzbnBTazlpRGlKQU9HQnV4c2ZZNHdhQnpkLWNOa1UifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImxpbnV4OTUtdG9rZW4tdnc3aGQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoibGludXg5NSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImZhY2MyMTdlLTljNjYtNDU3NC05YWRkLWE2MjVlZWVlM2E0ZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmxpbnV4OTUifQ.K4fSPCS2VdEVEY3OCbHxY3AXqiPeiiURAMXwiQXBw7u5rCCyw0KsVI8gNMswCp5UNTzgOJBfQlOVpaLkyDMJF3U_47CuV4YrEC-Q2zY7iSv80EspWAqgN5wrgT_Wp_v52HY9wlmWfqFHqf8CilxjK0Mxp_zB-3j_nZi-HHYPaE3AXVcm23a_FeS1QI5SjzYKvJijJh9onSwN2P7OtuPo0KkconUc8y4CweQM4OFYXZln8x69MoUkST6RLNjhdJwVrqMDlpKLt3a5rfZMQHjZmbpeQjy49xKAfNkYHwm2jSt7dRZ63mP36rEZTxJhuBryPJ5bke5UjbdF8kkac0H3qg
[root@master231 helm]#


9.登录kubeapps的WebUI
使用上一步的token进行登录即可.
50 认证体系架构
1 API-Server内置的访问控制机制
API Server的访问方式:
– 集群外部: https://IP:Port
– 集群内部: https://kubernetes.default.svc


1.1 API Server内置了插件化的访问控制机制(每种访问控制机制均有一组专用的插件栈)
1.2 认证(Authentication):
核验请求者身份的合法性,进行身份识别,验证客户端身份。
身份核验过程遵循“或”逻辑,且任何一个插件核验成功后都将不再进行后续的插件验证。
均不成功,则失败,或以“匿名者”身份访问,建议禁用“匿名者”。

1.3 授权(Authorization):
核验请求的操作是否获得许可,验证客户端是否有权限操作资源对象。
鉴权过程遵循“或”逻辑,且任何一个插件对操作的许可授权后都将不再进行后续的插件验证。
均未许可,则拒绝请求的操作

1.4 准入控制(Admission Control):
检查操作内容是否合规,仅同”写”请求相关,负责实现”检验”字段类型是否合法及和补全默认字段。
内容合规性检查过程遵循“与”逻辑,且无论成败,每次的操作请求都要经由所有插件的检验。
将数据写入etcd前,负责检查内容的有效性,因此仅对“写”操作有效。
分两类:validating(校验)和 mutating(补全或订正)。

2.身份认证策略
2.1 X.509客户端证书认证:
在双向TLS通信中,客户端持有数字证书信任的CA,需要在kube-apiserver程序启动时,通过–client-ca-file选项传递。
认证通过后,客户端数字证书中的CN(Common Name)即被识别为用户名,而O(Organization)被识别为组名。
kubeadm部署的K8s集群,默认使用”/etc/kubernetes/pki/ca.crt”(各组件间颁发数字证书的CA)进行客户端认证。

2.2 持有者令牌:
– 1.静态令牌文件(Static Token File):
令牌信息保存于文本文件中,由kube-apiserver在启动时通过–token-auth-file选项加载。
加载完成后的文件变动,仅能通过重启程序进行重载,因此,相关的令牌会长期有效。
客户端在HTTP请求中,通过“Authorization: Bearer TOKEN”标头附带令牌令牌以完成认证。

– 2.Bootstrap令牌:
一般用于加入集群时使用,尤其是在集群的扩容场景时会用到。

– 3.Service Account令牌:
该认证方式将由kube-apiserver程序内置直接启用,它借助于经过签名的Bearer Token来验证请求。
签名时使用的密钥可以由–service-account-key-file选项指定,也可以默认使用API Server的tls私钥
用于将Pod认证到API Server之上,以支持集群内的进程与API Server通信。
K8s可使用ServiceAccount准入控制器自动为Pod关联ServiceAccount。

– 4.OIDC(OpenID Connect)令牌:
有点类似于”微信”,”支付宝”认证的逻辑,自建的话需要配置认证中心。
OAuth2认证机制,通常由底层的IaaS服务所提供。

– 5.Webhook令牌:
基于web的形式进行认证,比如之前配置的”钉钉机器人”,”微信机器人”等;
是一种用于验证Bearer Token的回调机制,能够扩展支持外部的认证服务,例如LDAP等。

2.3 身份认证代理(Authenticating Proxy):
由kube-apiserver从请求报文的特定HTTP标头中识别用户身份,相应的标头名称可由特定的选项配置指定。
kube-apiserver应该基于专用的CA来验证代理服务器身份。

– 匿名请求:
生产环境中建议禁用匿名认证。


3 Kubernetes上的用户
“用户”即服务请求者的身份指代,一般使用身份标识符进行识别,比如用户名,用户组,服务账号,匿名用户等。

Kubernetes系统的用户大体可分Service Account,User Account和Anonymous Account。
3.1 Service Account:
Kubernetes内置的资源类型,用于Pod内的进程访问API Server时使用的身份信息。
引用格式: “system:serviceaccount:NAMESPACE:SA_NAME”

3.2 User Account:
用户账户,指非Pod类的客户端访问API Server时使用的身份标识,一般是现实中的“人”。
API Server没有为这类账户提供保存其信息的资源类型,相关的信息通常保存于外部的文件或认证系统中。
身份核验操作可由API Server进行,也可能是由外部身份认证服务完成。
可以手动定义证书,其中O字段表示组,CN字段表示用户名。

3.3 Anonymous Account:
不能被识别为Service Account,也不能被识别为User Account的用户。
这类账户K8S系统称之为”system:anonymous”,即“匿名用户”。

4 静态令牌文件认证测试
4.1 模拟生成token
root@master231:~# echo “$(openssl rand -hex 3).$(openssl rand -hex 8)”
6e8164.d35ac8f098338c52
root@master231:~# echo “$(openssl rand -hex 3).$(openssl rand -hex 8)”
ca43c1.a0f3fe638b9b80d3
root@master231:~# echo “$(openssl rand -hex 3).$(openssl rand -hex 8)”
673877.9a3066f2a2c2d160
root@master231:~#

4.2 创建csv文件
root@master231:~# cd /etc/kubernetes/pki/
root@master231:/etc/kubernetes/pki# vi token.csv
root@master231:/etc/kubernetes/pki# cat token.csv
fd6f1d.0b58191d3d726a69,yangsenlin,10001,k8s
79ac1a.52d68499662b2b52,forest,10002,k8s
f7a5b9.132ce8cf5643cf2b,ysl,10003,k3s

文件格式为CSV,每行定义一个用户,由“令牌、用户名、用户ID和所属的用户组”四个字段组成,用户组为可选字段
具体格式: token,user,uid,”group1,group2,group3″

4.3 修改api-server参数加载token文件
root@master231:/etc/kubernetes# cat /etc/kubernetes/manifests/kube-apiserver.yaml -n
….
14 – command:
15 – kube-apiserver
16 – –token-auth-file=/etc/kubernetes/pki/token.csv
….
99 – mountPath: /etc/kubernetes/pki/token.csv
100 readOnly: true
101 hostNetwork: true

131 – hostPath:
132 path: /etc/kubernetes/pki/token.csv
133 type: File
134 name: yangsenlin-static-token-file
135 status: {}

4.4 在worker节点用kubectl使用token认证并指定api-server证书
root@worker232:/etc/kubernetes/pki# kubectl –server=https://10.0.0.231:6443 –token=fd6f1d.0b58191d3d726a69 –certificate-authority=/etc/kubernetes/pki/ca.crt get nodes
Error from server (Forbidden): nodes is forbidden: User “yangsenlin” cannot list resource “nodes” in API group “” at the cluster scope
root@worker232:/etc/kubernetes/pki# kubectl –server=https://10.0.0.231:6443 –token=79ac1a.52d68499662b2b52 –certificate-authority=/etc/kubernetes/pki/ca.crt get nodes
Error from server (Forbidden): nodes is forbidden: User “forest” cannot list resource “nodes” in API group “” at the cluster scope
root@worker232:/etc/kubernetes/pki#
root@worker232:/etc/kubernetes/pki# kubectl –server=https://10.0.0.231:6443 –token=f7a5b9.132ce8cf5643cf2b –certificate-authority=/etc/kubernetes/pki/ca.crt get nodes
Error from server (Forbidden): nodes is forbidden: User “ysl” cannot list resource “nodes” in API group “” at the cluster scope
root@worker232:/etc/kubernetes/pki#

4.5 curl 基于token认证
不加认证信息,将被识别为匿名用户
root@worker232:~# curl -k https://10.0.0.231:6443
{
“kind”: “Status”,
“apiVersion”: “v1”,
“metadata”: {},
“status”: “Failure”,
“message”: “forbidden: User \”system:anonymous\” cannot get path \”/\””,
“reason”: “Forbidden”,
“details”: {},
“code”: 403
}root@worker232:~#

root@worker232:~# curl -k -H “Authorization: Bearer 79ac1a.52d68499662b2b52” https://10.0.0.231:6443/api/v1/pods
{
“kind”: “Status”,
“apiVersion”: “v1”,
“metadata”: {},
“status”: “Failure”,
“message”: “pods is forbidden: User \”forest\” cannot list resource \”pods\” in API group \”\” at the cluster scope”,
“reason”: “Forbidden”,
“details”: {
“kind”: “pods”
},
“code”: 403

5 X509数字证书认证
5.1 基于API-Server签发
5.1.1 创建证书签署请求的秘钥
root@master231:~# openssl genrsa -out forest.key 2048
root@master231:~# ll forest.key
-rw——- 1 root root 1704 May 1 20:43 forest.key

5.1.2 创建证书签署请求
root@master231:~# openssl req -new -key forest.key -out forest.csr -subj “/CN=forest/O=yangsenlin”
root@master231:~# ll forest.*
-rw-r–r– 1 root root 915 May 1 20:45 forest.csr
-rw——- 1 root root 1704 May 1 20:43 forest.key

CN:用户
O:组

5.1.3 将证书签署请求证书使用base64编码
root@master231:~# cat forest.csr | base64 | tr -d ‘\n’;echo
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2F6Q0NBVk1DQVFBd0pqRVBNQTBHQTFVRUF3d0dabTl5WlhOME1STXdFUVlEVlFRS0RBcDVZVzVuYzJWdQpiR2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3UWd5cnJpTnlRWTZlNnZKCjZSblI3cmFVUUYrK2hMaTVmVkNyZER6cnUwMmJxL2ZTemQ4SGlUYUN0dWNUdzRWQ1JuWWloM1hiRG1zWVVLYWgKZkVabi9lcWtmZ091WE0rbUpEQVAxdkdLT1FEVktyRlY4VGVUSGZzMXdSeE9xWTZjMDVqeHQzbkxvemFZd2ZUaQpqekx1Sm4vY3ovb1dPWU54MG1iQmlwQkg1bG45Q0pNb21iMlNnaFNqZ21aS3U1WTJjQjdaZjRQQ0JTb3A3anJ4ClVTUVFNKzIwN0g4V0RpMEZUeG04S09yYnlkc2p3RXFYSkJwSHNLbVBmdUtYOEI5QzBPSjdRSWlFTng1WkN1ME4KWURDc1IxZFI1WlhLaHhUNWNUdDVkMkdOanR6bDJBY3FPNmdjczZFWnMvakN0cG9kTmlGdFFXS1I5S011OWZieQpia091TFFJREFRQUJvQUF3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUxma2hTNW8vUHlUUlRWNlUwMjJic0J5CktLdzdLcEFJOHdMNXo5Y2NKckNzTnlOTXVaWkNsQ3h3U3dGdjNZaU91a1NldDNZU2MySmpta0xSd3N3TVBHbjAKRDljZmplVG83VXlyRW45elR6QnJvZXhHVGp1ZU51UmRoMDgvZi9HbFNMRklLNGhacFRWVjFKNi9WZGFqcjhBTAo1dURSc09VNHZ6dkFXK0dHcFB1SWlnakdsMnBBdlhHekgyODM5SkUycHhEMkdkci9iamVhYXlPb2pZdXBqaWdVCmNDbVBkUGZOK1Q4ckkzb2hqb1pReVM4YnpYeGdZaWFCNTkwWFV2dW9YR1NDMkUrU0FNWVdRZUJwYkJNWGEwQ3YKdllxQzJjdS9Tc2dQWno3SCtMQkpUbG1IcnM3bFNhMlR2ME8yUDNGUnU3TS92MEtVem5EVFJXVUdLR2Z1RDgwPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K

5.1.4 收动创建csr资源
root@master231:~/manifests/auth# cat csr-forest.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: forest-csr
spec:
# 将证书签发请求使用base64编码
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2JEQ0NBVlFDQVFBd0p6RVJNQThHQTFVRUF3d0lhbUZ6YjI1NWFXNHhFakFRQmdOVkJBb01DVzlzWkdKdgplV1ZrZFRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTDY0TUwwVVJCcWh1Mi9hCkltNGJLR0paMXlVMDczcEtpU1ZZa2xuZkkyVEY0QWptMDNSWGZkRXVvYVl6NGptME1idmtyOUpQZE5sMlY4QzgKa3o5ZnBGaGhyb2svOTE0MXNPRXRyWDhrbE1QZTY4aVhHTmpWOGR0VFBQcmxyVkV4bktxbkxUT3ova3hNYTdjZgpqSjlTUzhBcWhUSUVUbWwyR2xxS21FdUVhbmZDRS83NUdJQlM0Rm5XZDVKQm8ySzIzYVpQL3BUalBhSnNQcWtWCnlPZS9vZnUzUDZnaUFJZW5JOW0yTGNIcGRXcnZFbFpmeVJqTTFxcU0vbEhYZlpsNm0zVUxVVEdiQWZIcnNBTXEKbURNQzVrL2JNeFJ2V0ZrUkRHcGdnMEJMWUhtdStBaXlGQVBuM1R0NFFla2dDY3hDOTY0MnlUQ1VjTUZNSHNwYgpRT3h2MEZjQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCdi9Zb0ZYQ0N1S3lFeFlFSzFVQmtJCmphZlM4OWt5L1ZHWlBsSENkb0pYNk1SWHJjTFB6ck1kK0NIWVAvUGNRQ1lYVTQ3Y29pOGJlZWFaeVJjZXpxcVIKWGhyWFZqZTNqcWFRMjd5ODdiRUJZRlJWdnduYjJlazFCelRvOWNHTCs3VGpjMDk5SjhPWFFVSFY5dTQ3QUY0aApWRFRrT0h3MUFTWXJLdzFmN0N6N25TbHdZOEtwMkNmcm5tWlRnRFcvTnZsRHhQMmpZWjFLeE5EMFRHVk4rMk93CmlpMEtHY1BXdXEzclhJbjgxMzJKbjJGOS8vVm5ubyswK0ZheDJZOW53ZXBzQ1drQ0FXcnpWYWJKK3QvUGo1NisKVDhKc2pRMGRaQmtlREp4ckR3Z3htZ1k5aWhCMW9hMVowMXVlM01KNDNWV3VJc2NieTlCbXB6alJDUWdnUTI0aAotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K
# 指定颁发证书的请求类型,仅支持如下三种,切均可以由kube-controllmanager中的“csrsigning”控制器发出。
# “kubernetes.io/kube-apiserver-client”:
# 颁发用于向kube-apiserver进行身份验证的客户端证书。
# 对该签名者的请求是Kubernetes控制器管理器从不自动批准。
#
# “kubernetes.io/kube-apiserver-client-kubelet”:
# 颁发kubelets用于向kube-apiserver进行身份验证的客户端证书。
# 对该签名者的请求可以由kube-controllermanager中的“csrapproving”控制器自动批准。
#
# “kubernetes.io/kubelet-serving”:
# 颁发kubelets用于服务TLS端点的证书,kube-apiserver可以连接到这些端点安全。
# 对该签名者的请求永远不会被kube-controllmanager自动批准。
signerName: kubernetes.io/kube-apiserver-client
# 指定证书的过期时间,此处我设置的是24h(3600*24=86400)
expirationSeconds: 864000
# 指定在颁发的证书中请求的一组密钥用法。
# 对TLS客户端证书的请求通常请求:
# “数字签名(digital signature)”、“密钥加密(key encipherment)”、“客户端身份验证(client auth)”。
# 对TLS服务证书的请求通常请求:
# “密钥加密(key encipherment)”、“数字签名(digital signature)”、“服务器身份验证(server auth)”。
#
# 有效值的值为: “signing”, “digital signature”, “content commitment”, “key encipherment”,”key agreement”,
# “data encipherment”, “cert sign”, “crl sign”, “encipher only”, “decipher only”, “any”, “server auth”,
# “client auth”, “code signing”, “email protection”, “s/mime”, “ipsec end system”, “ipsec tunnel”,”ipsec user”,
# “timestamping”, “ocsp signing”, “microsoft sgc”, “netscape sgc”。
usages:
– client auth
root@master231:~/manifests/auth# kubectl apply -f csr-forest.yaml
certificatesigningrequest.certificates.k8s.io/forest-csr created
root@master231:~/manifests/auth#

root@master231:~/manifests/auth# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATIO CONDITION
forest-csr 20s kubernetes.io/kube-apiserver-client kubernetes-admin 10d Pending
root@master231:~/manifests/auth#
此时状态为pending状态

5.1.5 手动签发证书
root@master231:~/manifests/auth# kubectl certificate approve forest-csr
certificatesigningrequest.certificates.k8s.io/forest-csr approved
root@master231:~/manifests/auth# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
forest-csr 107s kubernetes.io/kube-apiserver-client kubernetes-admin 10d Approved,Issued
root@master231:~/manifests/auth#

5.1.6 获取签发后的证书
root@master231:~/manifests/auth# kubectl get csr forest-csr -o jsonpath='{.status.certificate}’ | base64 -d > forest.crt
root@master231:~/manifests/auth# ll
total 16
drwxr-xr-x 2 root root 4096 May 1 20:51 ./
drwxr-xr-x 35 root root 4096 May 1 20:47 ../
-rw-r–r– 1 root root 3239 May 1 20:47 csr-forest.yaml
-rw-r–r– 1 root root 1119 May 1 20:51 forest.crt
root@master231:~/manifests/auth#

5.1.7 将证书拷贝到worker节点,便于后续使用
root@master231:~# ll forest/
total 20
drwxr-xr-x 2 root root 4096 May 1 20:52 ./
drwx—— 15 root root 4096 May 1 20:52 ../
-rw-r–r– 1 root root 1119 May 1 20:51 forest.crt
-rw-r–r– 1 root root 915 May 1 20:45 forest.csr
-rw——- 1 root root 1704 May 1 20:43 forest.key
root@master231:~# scp -r forest 10.0.0.232:~
root@master231:~# scp -r forest 10.0.0.233:~

5.1.8 客户端测试
root@worker233:~/forest# kubectl -s https://10.0.0.231:6443 –client-key forest.key –client-certificate forest.crt –insecure-skip-tls-verify get nodes
Error from server (Forbidden): nodes is forbidden: User “forest” cannot list resource “nodes” in API group “” at the cluster scope

6 kubeconfig的组成部分
6.1 概述
kubeconfig是YAML格式的文件,用于存储身份认证信息,以便于客户端加载并认证到API Server。

kubeconfig保存有认证到一至多个Kubernetes集群的相关配置信息,并允许管理员按需在各配置间灵活切换
clusters:
Kubernetes集群访问端点(API Server)列表。
users:
认证到API Server的身份凭据列表。
contexts:
将每一个user同可认证到的cluster建立关联的上下文列表。
current-context:
当前默认使用的context

6.2 为静态令牌认证的用户生成kubeconfig
6.2.1 创建一个集群
root@master231:~/forest# kubectl config set-cluster myk8s –embed-certs=true –certificate-authority=/etc/kubernetes/pki/ca.crt –server=”https://10.0.0.231:6443″ –kubeconfig=./yangsenlin-k8s.conf
Cluster “myk8s” set.
root@master231:~/forest# ll yangsenlin-k8s.conf
-rw——- 1 root root 1663 May 1 21:06 yangsenlin-k8s.conf

6.2.2 查看集群
root@master231:~/forest# kubectl config get-clusters –kubeconfig=./yangsenlin-k8s.conf
NAME
myk8s
root@master231:~/forest#

6.2.3 查看令牌文件
root@master231:~/forest# cat /etc/kubernetes/pki/token.csv
fd6f1d.0b58191d3d726a69,yangsenlin,10001,k8s
79ac1a.52d68499662b2b52,forest,10002,k8s
f7a5b9.132ce8cf5643cf2b,ysl,10003,k3s
root@master231:~/forest#

6.2.4 创建用户信息
root@master231:~/forest# kubectl config set-credentials yangsenlin –token==”fd6f1d.0b58191d3d726a69″ –kubeconfig=./yangsenlin-k8s.conf
User “yangsenlin” set.

6.2.5 查看用户信息
root@master231:~/forest# kubectl config get-users –kubeconfig=./yangsenlin-k8s.conf
NAME
yangsenlin
root@master231:~/forest#

6.2.6 定义上下文
root@master231:~/forest# kubectl config set-context yangsenlin@myk8s –user=yangsenlin –cluster=myk8s –kubeconfig=./yangsenlin-k8s.conf
Context “yangsenlin@myk8s” created.
root@master231:~/forest#

root@master231:~/forest# kubectl config set-context forest@myk8s –user=forest –cluster=myk8s –kubeconfig=./yangsenlin-k8s.conf
Context “forest@myk8s” created.

6.2.7 查看上下文
root@master231:~/forest# kubectl config get-contexts –kubeconfig=./yangsenlin-k8s.conf
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
forest@myk8s myk8s forest
yangsenlin@myk8s myk8s yangsenlin
root@master231:~/forest#

6.2.8 定义当前使用的上下文
root@master231:~/forest# kubectl config use-context yangsenlin@myk8s –kubeconfig=./yangsenlin-k8s.conf
Switched to context “yangsenlin@myk8s”.
root@master231:~/forest#

6.2.9 查看当前使用的上下文
root@master231:~/forest# kubectl config current-context –kubeconfig=./yangsenlin-k8s.conf
yangsenlin@myk8s
root@master231:~/forest#

6.2.10 打印kubeconfig信息,默认会使用“REDACTED”或者“DATA-OMITTED”关键字隐藏证书信息,使用–raw选项就可以打印出证书信息
root@master231:~/forest# kubectl config view –kubeconfig=./yangsenlin-k8s.conf
apiVersion: v1
clusters:
– cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.0.0.231:6443
name: myk8s
contexts:
– context:
cluster: myk8s
user: forest
name: forest@myk8s
– context:
cluster: myk8s
user: yangsenlin
name: yangsenlin@myk8s
current-context: yangsenlin@myk8s
kind: Config
preferences: {}
users:
– name: yangsenlin
user:
token: REDACTED
root@master231:~/forest#

root@master231:~/forest# kubectl config view –kubeconfig=./yangsenlin-k8s.conf –raw
apiVersion: v1
clusters:
– cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJMU1EUXdOREV4TXpBME1Gb1hEVE0xTURRd01qRXhNekEwTUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBT1hICkI4YU1nK3VBTFhpc2lyaloyUFBoTzY0bENpbzVvT0pMUU5EZzkzbHd4YTduQVEvNG1zY3Q3K2t3NGxEcEV4eFIKRjllUUJIVmdYVys1ZndFcVJDTXZMa2xkRW0xbEQrazNqVHM2ZHJXWEdqUGViayt1QU9Ha01MN3JlYjdpcTlIawpCdXlvUzg5eW13MkRoKzZjK3VOMjNZbWo2RGo0ZXgzUXJUVkg2a0VFeUFHODJyRlN6QzE0NTRhQjVjZ3RDUnM1CndkWVptaEYvUUxTWFBBMURFREZRVjNnYUxnSFRHNVZWQjFWV3MvVHM5YXp5Q2pIOVlwZCtxdXhTaFU1TmVyV3QKQWZ3bnFNdHVqaEV4MmR0bTlMMDVBcEJ2WlE1TURLRnFmNnBCOGhoRlVBdmtaaE5tZzk4V21hdTB0TnIvNkZENgo5TG1hcSszN3RyYkpwa2ZtMkdrQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZLT00xSkhFSFN0YmNHS0JkR1Y4Kzh5dHJ0anJNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRHJpZXFFWjJGbTNnWkoyc2RMQgpCOEZ0blMyTjdXTDdydUNxSVNSU3V1cm5MV3hXYkhDQUEvN09tU09uZE9oRG1nQ0tkQXhKY3FOQUlTd1B5NW1SCi95clA1anBYN28yWW8reFVEL3N0bGg5d2ZlRDlaWGhzbzgyVDNNVVUyQnRwMFdrb2h3OUZmYlYyakpUd3pEdUYKSlVCNXUrU0xZUG90dXZ0TStkQXRWY2Rsa0M2RjV4Z1gwdzZPOVJHdDVlYmprNnhWUUZoWmpUWGI0ZGY5Nno1UgpBV2VVc0tHcGRqdW54dzZxR21xYW51T1prUjFsZjMwckx0UVVVeWRYNW5ZMVFzZUQ2TG9ZcDM2KytmbXJjK0ZlCnIzVDhYS0J3UVA0azB3aDljQzNvY3diS2JkR1lESUFHZnBGTEI3ZFBGalFtR0cxMFBTY3p0MzZZK3FJbVlEb0wKY21ZPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
server: https://10.0.0.231:6443
name: myk8s
contexts:
– context:
cluster: myk8s
user: forest
name: forest@myk8s
– context:
cluster: myk8s
user: yangsenlin
name: yangsenlin@myk8s
current-context: yangsenlin@myk8s
kind: Config
preferences: {}
users:
– name: yangsenlin
user:
token: =fd6f1d.0b58191d3d726a69
root@master231:~/forest#

6.2.11 将kubeconfig文件拷贝到客户端
root@master231:~/forest# scp yangsenlin-k8s.conf 10.0.0.232:~/forest
root@master231:~/forest# scp yangsenlin-k8s.conf 10.0.0.233:~/forest

6.2.12 客户端进行认证
[root@worker233 ~]# kubectl get pods –kubeconfig=./yangsenlin-k8s.conf
Error from server (Forbidden): pods is forbidden: User “yangsenlin” cannot list resource “pods” in API group “” in the namespace “default”
[root@worker233 ~]#
[root@worker233 ~]# kubectl get pods –kubeconfig=./yangsenlin-k8s.conf –context=forest@myk8s
Error from server (Forbidden): pods is forbidden: User “forest” cannot list resource “pods” in API group “” in the namespace “default”
[root@worker233 ~]#

6.3 为X509数字证书的用户生成kubeconfig
6.3.1 添加证书用户
rest/forest.crt –client-key=/root/forest/forest.key –embed-certs=true –kubeconfig=./yangsenlin-k8s.conf
User “senge” set.
root@master231:~/forest#

6.3.2 查看用户列表
root@master231:~/forest# kubectl config get-users –kubeconfig=./yangsenlin-k8s.conf
NAME
senge
yangsenlin
root@master231:~/forest#

6.3.3 配置上下文
root@master231:~/forest# kubectl config set-context senge@myk8s –user=senge –cluster=myk8s –kubeconfig=./yangsenlin-k8s.conf
Context “senge@myk8s” created.
root@master231:~/forest#

6.3.4 查看上下文列表
root@master231:~/forest# kubectl config get-contexts –kubeconfig=./yangsenlin-k8s.conf
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
forest@myk8s myk8s forest
senge@myk8s myk8s senge
* yangsenlin@myk8s myk8s yangsenlin

6.3.5 查看kubeconfig信息
root@master231:~/forest# kubectl config view –kubeconfig=./yangsenlin-k8s.conf
apiVersion: v1
clusters:
– cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.0.0.231:6443
name: myk8s
contexts:
– context:
cluster: myk8s
user: forest
name: forest@myk8s
– context:
cluster: myk8s
user: senge
name: senge@myk8s
– context:
cluster: myk8s
user: yangsenlin
name: yangsenlin@myk8s
current-context: yangsenlin@myk8s
kind: Config
preferences: {}
users:
– name: senge
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
– name: yangsenlin
user:
token: REDACTED
root@master231:~/forest#

6.3.6 将kubeconfig拷贝到客户端节点
root@master231:~/forest# scp yangsenlin-k8s.conf 10.0.0.232:~/forest
root@master231:~/forest# scp yangsenlin-k8s.conf 10.0.0.233:~/forest

6.3.7 客户端测试验证
[root@worker233 ~]# kubectl get pods –kubeconfig=./yangsenlin-k8s.conf –context=senge@myk8s
Error from server (Forbidden): pods is forbidden: User “forest” cannot list resource “pods” in API group “” in the namespace “default”
[root@worker233 ~]#


7 k8s默认基于sa进行认证
7.1 为何需要service Account
Kubernetes原生(kubernetes-native)托管运行于Kubernetes之上,通常需要直接与API Server进行交互以获取必要的信息。

API Server同样需要对这类来自于Pod资源中客户端程序进行身份验证,Service Account也就是设计专用于这类场景的账号。

ServiceAccount是API Server支持的标准资源类型之一。
– 1.基于资源对象保存ServiceAccount的数据;
– 2.认证信息保存于ServiceAccount对象专用的Secret中(v1.23-版本)
– 3.隶属名称空间级别,专供集群上的Pod中的进程访问API Server时使用;


7.2 Pod使用ServiceAccount方式
在Pod上使用Service Account通常有两种方式:
自动设定:
Service Account通常由API Server自动创建并通过ServiceAccount准入控制器自动关联到集群中创建的每个Pod上。

自定义:
在Pod规范上,使用serviceAccountName指定要使用的特定ServiceAccount。

Kubernetes基于三个组件完成Pod上serviceaccount的自动化,分别对应: ServiceAccount Admission Controller,Token Controller,ServiceAccount Controller。
– ServiceAccount Admission Controller:
API Server准入控制器插件,主要负责完成Pod上的ServiceAccount的自动化。
为每个名称空间自动生成一个”default”的sa,若用户未指定sa,则默认使用”default”。

– Token Controller:
为每一个sa分配一个token的组件,已经集成到Controller manager的组件中。

– ServiceAccount Controller:
为sa生成对应的数据信息,已经集成到Controller manager的组件中。

温馨提示:
需要用到特殊权限时,可为Pod指定要使用的自定义ServiceAccount资源对象


7.3 ServiceAccount Token的不同实现方式
ServiceAccount使用专用的Secret对象(Kubernetes v1.23-)存储相关的敏感信息
– 1.Secret对象的类型标识为“kubernetes.io/service-account-token”
– 2.该Secret对象会自动附带认证到API Server用到的Token,也称为ServiceAccount Token


ServiceAccount Token的不同实现方式
– 1.Kubernetes v1.20-
系统自动生成专用的Secret对象,并基于secret卷插件关联至相关的Pod;
Secret中会自动附带Token且永久有效(安全性低,如果将来获取该token可以长期登录)。

– 2.Kubernetes v1.21-v1.23:
系统自动生成专用的Secret对象,并通过projected卷插件关联至相关的Pod;
Pod不会使用Secret上的Token,被弃用后,在未来版本就不在创建该token。
而是由Kubelet向TokenRequest API请求生成,默认有效期为一年,且每小时更新一次;

– 3.Kubernetes v1.24+:
系统不再自动生成专用的Secret对象。
而是由Kubelet负责向TokenRequest API请求生成Token,默认有效期为一年,且每小时更新一次;

7.4 创建sa并让pod引用指定的sa
root@master231:~/manifests/pods# cat 26-pods-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: yangsenlin


apiVersion: v1
kind: Pod
metadata:
name: ysl-pods-sa
spec:
serviceAccountName: yangsenlin
containers:
– name: c1
image: crpi-kxgdi0lp5jdep1gc.cn-chengdu.personal.cr.aliyuncs.com/yangsenlin/apps:v2
root@master231:~/manifests/pods# kubectl apply -f 26-pods-sa.yaml
serviceaccount/yangsenlin created
pod/ysl-pods-sa created

7.5 验证pod使用sa的验证身份
root@master231:~/manifests/pods# kubectl exec -it ysl-pods-sa sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] — [COMMAND] instead.
/ # ll /var/run/secrets/kubernetes.io/serviceaccount/
sh: ll: not found
/ # ls -l /var/run/secrets/kubernetes.io/serviceaccount/
total 0
lrwxrwxrwx 1 root root 13 May 2 02:37 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 May 2 02:37 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 May 2 02:37 token -> ..data/token
/ #
/ # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/ #
/ # curl -k -H “Authorization: Bearer ${TOKEN}” https://kubernetes
{
“kind”: “Status”,
“apiVersion”: “v1”,
“metadata”: {},
“status”: “Failure”,
“message”: “forbidden: User \”system:serviceaccount:default:yangsenlin\” cannot get path \”/\””,
“reason”: “Forbidden”,
“details”: {},
“code”: 403
}/ #

7.6 pod基于projected存储卷引用serviceaccount
Kubernetes v1.21+版本中,Pod加载上面三种数据的方式,改变为基于projected卷插件,通过三个数据源(source)分别进行
serviceAccountToken:
提供由Kubelet负责向TokenRequest API请求生成的Token。
configMap:
经由kube-root-ca.crt这个ConfigMap对象的ca.crt键,引用Kubernetes CA的证书
downwardAPI:
基于fieldRef,获取当前Pod所处的名称空间。

8 启用authorization模式
8.1 概述
在kube-apiserver上使用“–authorization-mode”选项进行定义,多个模块彼此间以逗号分隔。

如上图所示,kubeadm部署的集群,默认启用了Node和RBAC。

API Server中的鉴权框架及启用的鉴权模块负责鉴权:
支持的鉴权模块:
Node:
专用的授权模块,它基于kubelet将要运行的Pod向kubelet进行授权。
ABAC:
通过将属性(包括资源属性、用户属性、对象和环境属性等)组合在一起的策略,将访问权限授予用户。
RBAC:
基于企业内个人用户的角色来管理对计算机或网络资源的访问的鉴权方法。
Webhook:
用于支持同Kubernetes外部的授权机制进行集成。

另外两个特殊的鉴权模块是AlwaysDeny和AlwaysAllow。

参考链接:
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/

9 RBAC基础概念
实体(Entity):
在RBAC也称为Subject,通常指的是User、Group或者是ServiceAccount;

角色(Role):
承载资源操作权限的容器。

资源(Resource):
在RBAC中也称为Object,指代Subject期望操作的目标,例如Service,Deployments,ConfigMap,Secret、Pod等资源。
仅限于”/api/v1/…”及”/apis///…”起始的路径;
其它路径对应的端点均被视作“非资源类请求(Non-Resource Requests)”,例如”/api”或”/healthz”等端点;

动作(Actions):
Subject可以于Object上执行的特定操作,具体的可用动作取决于Kubernetes的定义。
资源型对象:
只读操作:get、list、watch等。
读写操作:create、update、patch、delete、deletecollection等。
非资源型端点仅支持”get”操作。

角色绑定(Role Binding):
将角色关联至实体上,它能够将角色具体的操作权限赋予给实体。

角色的类型:
Namespace级别:
称为Role,定义名称空间范围内的资源操作权限集合。
Namespace和Cluster级别:
称为ClusterRole,定义集群范围内的资源操作权限集合,包括集群级别及名称空间级别的资源对象。

角色绑定的类型:
Cluster级别:
称为ClusterRoleBinding,可以将实体(User、Group或ServiceAccount)关联至ClusterRole。

Namespace级别:
称为RoleBinding,可以将实体关联至ClusterRole或Role。
即便将Subject使用RoleBinding关联到了ClusterRole上,该角色赋予到Subject的权限也会降级到RoleBinding所属的Namespace范围之内。

10 ClusterRole
启用RBAC鉴权模块时,API Server会自动创建一组ClusterRole和ClusterRoleBinding对象

多数都以“system:”为前缀,也有几个面向用户的ClusterRole未使用该前缀,如cluster-admin、admin等。

它们都默认使用“kubernetes.io/bootstrapping: rbac-defaults”这一标签。

默认的ClusterRole大体可以分为5个类别。
API发现相关的角色:
包括system:basic-user、system:discovery和system:public-info-viewer。
面向用户的角色:
包括cluster-admin、admin、edit和view。
核心组件专用的角色:
包括system:kube-scheduler、system:volume-scheduler、system:kube-controller-manager、system:node和system:node-proxier等。
其它组件专用的角色:
包括system:kube-dns、system:node-bootstrapper、system:node-problem-detector和system:monitoring等。
内置控制器专用的角色:
专为内置的控制器使用的角色,具体可参考官网文档。

11 K8S内置的面向用户的集群角色
cluster-admin:
允许用户在目标范围内的任意资源上执行任意操作;使用ClusterRoleBinding关联至用户时,授权操作集群及所有名称空间中任何资源;使用RoleBinding关联至用户时,授权控制其所属名称空间中的所有资源,包括Namespace资源自身,隶属于”system:masters 组”。
admin:
管理员权限,主要用于结合RoleBinding为特定名称空间快速授权生成管理员用户,它能够将RoleBinding所属名称空间中的大多数资源的读/写权限授予目标用户,包括创建Role和RoleBinding的能力;但不支持对ResourceQuota及Namespace本身进行操作;
edit:
接近于admin的权限,支持对名称空间内的大多数对象进行读/写操作,包括Secret,但不允许查看或修改Role及RoleBinding;
view:
允许以只读方式访问名称空间中的大多数对象,但不包括Role、RoleBinding和Secret;

12 Role授权给一个用户类型
12.1 为授权前测试
[root@worker233 ~]# kubectl –kubeconfig=./yangsenlin-k8s.conf –context=forest@myk8s get pods
Error from server (Forbidden): pods is forbidden: User “forest” cannot list resource “pods” in API group “” in the namespace “default”
[root@worker233 ~]#

12.2 创建Role
[root@master231 rbac]# kubectl create role reader –resource=pods,services –verb=get,watch,list -o yaml –dry-run=client
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
creationTimestamp: null
name: reader
rules:
– apiGroups:
– “”
resources:
– pods
– services
verbs:
– get
– watch
– list
[root@master231 rbac]#
[root@master231 rbac]#
[root@master231 rbac]# kubectl create role reader –resource=pods,services –verb=get,watch,list
role.rbac.authorization.k8s.io/reader created
[root@master231 rbac]#
[root@master231 rbac]#


12.3 创建角色绑定
[root@master231 rbac]# kubectl create rolebinding forest-as-reader –user=forest –role=reader -o yaml –dry-run=client
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: forest-as-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: reader
subjects:
– apiGroup: rbac.authorization.k8s.io
kind: User
name: forest
[root@master231 rbac]#
[root@master231 rbac]# kubectl create rolebinding forest-as-reader –user=forest –role=reader
rolebinding.rbac.authorization.k8s.io/forest-as-reader created
[root@master231 rbac]#


12.4 授权后再次验证
[root@worker233 ~]# kubectl –kubeconfig=./yangsenlin-k8s.conf –context=forest@myk8s get po,svc
NAME READY STATUS RESTARTS AGE
pod/ysl-ysl-xiuxian 1/1 Running 0 175m
pod/ysl-pods-sa 1/1 Running 0 164m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.200.0.1 443/TCP 4d5h
[root@worker233 ~]#
[root@worker233 ~]# kubectl –kubeconfig=./yangsenlin-k8s.conf –context=forest@myk8s get cm
Error from server (Forbidden): configmaps is forbidden: User “forest” cannot list resource “configmaps” in API group “” in the namespace “default”
[root@worker233 ~]#


13 ClusterRole授权给一个用户组类型
13.1 创建集群角色
root@master231:~/forest# kubectl create clusterrole reader –resource=configmaps,pods,sc,pv,pvc –verb=get,watch,list -o yaml –dry-run=client
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: reader
rules:
– apiGroups:
– “”
resources:
– configmaps
– pods
– persistentvolumes
– persistentvolumeclaims
verbs:
– get
– watch
– list
– apiGroups:
– storage.k8s.io
resources:
– storageclasses
verbs:
– get
– watch
– list
root@master231:~/forest#

root@master231:~/forest# kubectl create clusterrole reader –resource=configmaps,pods,sc,pv,pvc –verb=get,watch,list
clusterrole.rbac.authorization.k8s.io/reader created
root@master231:~/forest#

13.2 将集群角色绑定给k3s组
root@master231:~/forest# kubectl create clusterrolebinding k8s-as-reader –clusterrole=reader –group=k8s
clusterrolebinding.rbac.authorization.k8s.io/k8s-as-reader created
root@master231:~/forest#

13.3 测试验证
13.3.1 基于kubeconfig测试
基于kubeconfig测试
[root@worker233 ~]# kubectl –kubeconfig=./yangsenlin-k8s.conf get po,svc
NAME READY STATUS RESTARTS AGE
ysl-ysl-xiuxian 1/1 Running 0 3h5m
ysl-pods-sa 1/1 Running 0 175m
Error from server (Forbidden): services is forbidden: User “yangsenlin” cannot list resource “services” in API group “” in the namespace “default”
[root@worker233 ~]#
[root@worker233 ~]#
[root@worker233 ~]# kubectl –kubeconfig=./yangsenlin-k8s.conf get po,cm
NAME READY STATUS RESTARTS AGE
pod/ysl-ysl-xiuxian 1/1 Running 0 3h6m
pod/ysl-pods-sa 1/1 Running 0 175m

NAME DATA AGE
configmap/game-demo 7 9d
configmap/haha 2 8d
configmap/kube-root-ca.crt 1 13d
configmap/nginx-subfile 2 9d
configmap/ysl-ysl 4 9d
configmap/yangsenlin-c

13.3.2 基于token测试
[root@worker233 ~]# kubectl –server=https://10.0.0.231:6443 –token=ca43c1.a0f3fe638b9b80d3 –certificate-authority=/etc/kubernetes/pki/ca.crt get po,cm
NAME READY STATUS RESTARTS AGE
pod/ysl-ysl-xiuxian 1/1 Running 0 3h8m
pod/ysl-pods-sa 1/1 Running 0 177m

NAME DATA AGE
configmap/game-demo 7 9d
configmap/haha 2 8d
configmap/kube-root-ca.crt 1 13d
configmap/nginx-subfile 2 9d
configmap/ysl-ysl 4 9d
configmap/yangsenlin-cm 2 8d
[root@worker233 ~]#
[root@worker233 ~]#
[root@worker233 ~]# kubectl –server=https://10.0.0.231:6443 –token=ca43c1.a0f3fe638b9b80d3 –certificate-authority=/etc/kubernetes/pki/ca.crt get nodes
Error from server (Forbidden): nodes is forbidden: User “forest” cannot list resource “nodes” in API group “” at the cluster scope
[root@worker233 ~]#

14 clusterrole授权给一个serviceaccount类型
14.1 安装依赖包
pip install kubernetes -i https://pypi.tuna.tsinghua.edu.cn/simple/

14.2 编写python脚本
cat > view-k8s-resources.py <
ysl-pods-sa 1/1 Running 0 3h18m 10.100.2.247 worker233
xiuxian-6dffdd86b-hstrw 1/1 Running 0 28s 10.100.2.12 worker233
[root@master231 rbac]#
[root@master231 rbac]# kubectl exec -it xiuxian-6dffdd86b-hstrw — sh
/ # python3 view-k8s-resources.py
###### Deployment列表 ######
xiuxian
###### Pod列表 ######
ysl-ysl-xiuxian
ysl-pods-sa
xiuxian-6dffdd86b-hstrw
/ #

15 kubeconfig加载的优先级

使用‘–kubeconfig’ > 环境变量‘export KUBECONFIG=/root/yangsenlin-k8s.conf’ > 默认加载路径 ‘~/.kube/config’

15 验证“/root/.kube/config”文件默认的集群角色权限
15.1 导入证书
root@master231:~/forest# kubectl config view –raw -o jsonpath='{.users[0].user.client-certificate-data}’ | base64 -d > /opt/admin.crt
root@master231:~/forest# ll /opt/admin.crt
-rw-r–r– 1 root root 1147 May 2 11:02 /opt/admin.crt
root@master231:~/forest#

15.2 查看证书信息
root@master231:~/forest# openssl x509 -noout -text -in /opt/admin.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4527849109897624662 (0x3ed626c6a0043c56)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes
Validity
Not Before: Apr 4 11:30:40 2025 GMT
Not After : Apr 4 11:30:41 2026 GMT
Subject: O = system:masters, CN = kubernetes-admin #这里是用户和组
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
….
root@master231:~/forest#

15.3 查看内置集群角色
root@master231:~/forest# kubectl get clusterrolebindings cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: “true”
creationTimestamp: “2025-04-04T11:30:48Z”
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: cluster-admin
resourceVersion: “148”
uid: 0d1acdfc-f91b-46d6-b8ee-caf8f2d56249
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
– apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:masters
root@master231:~/forest#

16 metrics-server实现HPA
部署文档
https://github.com/kubernetes-sigs/metrics-server
[root@master231 add-ons]# cd metrics-server
[root@master231 metrics-server]# ll
total 8
drwxr-xr-x 2 root root 4096 Feb 23 16:36 ./
drwxr-xr-x 8 root root 4096 Feb 23 16:36 ../
[root@master231 metrics-server]#
[root@master231 metrics-server]# wget http://192.168.15.253/Resources/Kubernetes/Add-ons/metrics-server/high-availability-1.21%2B.yaml

[root@master231 metrics-server]# kubectl apply -f high-availability-1.21+.yaml
[root@master231 metrics-server]# kubectl get pods -o wide -n kube-system -l k8s-app=metrics-server
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
metrics-server-dfb9648d6-55st9 1/1 Running 0 66s 10.100.2.19 worker233
metrics-server-dfb9648d6-nzgkx 1/1 Running 0 66s 10.100.1.145 worker232
[root@master231 metrics-server]#


镜像下载地址:
http://192.168.15.253/Resources/Kubernetes/Add-ons/metrics-server/


16.1 验证metrics组件是否正常工作
[root@master231 rbac]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master231 160m 8% 1925Mi 24%
worker232 179m 8% 2938Mi 37%
worker233 176m 8% 2583Mi 33%
[root@master231 rbac]#
[root@master231 rbac]# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
ysl-ysl-xiuxian 0m 3Mi
ysl-pods-sa 0m 4Mi
xiuxian-6dffdd86b-hstrw 0m 13Mi
[root@master231 rbac]#
[root@master231 rbac]# kubectl top pod -n kube-system
NAME CPU(cores) MEMORY(bytes)
coredns-6d8c4cb4d-2z2j8 1m 18Mi
coredns-6d8c4cb4d-jhnpg 1m 35Mi
csi-nfs-controller-5c5c695fb-6psv8 0m 34Mi
csi-nfs-node-bsmr7 1m 54Mi
csi-nfs-node-ghtvt 0m 35Mi
csi-nfs-node-s4dm5 2m 51Mi
etcd-master231 14m 90Mi
kube-apiserver-master231 83m 564Mi
kube-controller-manager-master231 9m 81Mi
kube-proxy-b855f 3m 29Mi
kube-proxy-qxhhp 3m 20Mi
kube-proxy-xlmtw 6m 36Mi
kube-scheduler-master231 1m 20Mi
[root@master231 rbac]#


16.2 验证hpa
[root@master231 horizontalpodautoscalers]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
xiuxian 1/1 1 1 56m
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# kubectl autoscale deploy xiuxian –min=2 –max=5 –cpu-percent=95 -o yaml –dry-run=client
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
creationTimestamp: null
name: xiuxian
spec:
maxReplicas: 5
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: xiuxian
targetCPUUtilizationPercentage: 95
status:
currentReplicas: 0
desiredReplicas: 0
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# kubectl autoscale deploy xiuxian –min=2 –max=5 –cpu-percent=95 -o yaml –dry-run=client >> 01-deploy-hpa.yaml

16.3 验证hpa
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# cat 01-deploy-hpa.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: stress
spec:
replicas: 1
selector:
matchLabels:
app: stress
template:
metadata:
labels:
app: stress
spec:
containers:
– image: forest2020/ysl-linux-tools:v0.1
name: ysl-linux-tools
args:
– tail
– -f
– /etc/hosts
resources:
requests:
cpu: 0.2
memory: 300Mi
limits:
cpu: 0.5
memory: 500Mi



apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: stress-hpa
spec:
maxReplicas: 5
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: stress
targetCPUUtilizationPercentage: 95
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# kubectl apply -f 01-deploy-hpa.yaml
deployment.apps/stress created
horizontalpodautoscaler.autoscaling/stress-hpa created
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
stress-5585b5ccc-6twg5 1/1 Running 0 22s 10.100.2.17 worker233
stress-5585b5ccc-7nbhc 1/1 Running 0 37s 10.100.1.144 worker232
[root@master231 horizontalpodautoscalers]#


16.4 验证hpa
[root@master231 metrics-server]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress-hpa Deployment/stress 125%/95% 2 5 4 7m56s
[root@master231 metrics-server]#
[root@master231 metrics-server]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
stress-5585b5ccc-6twg5 1/1 Running 0 9m55s 10.100.2.17 worker233
stress-5585b5ccc-b5qxr 1/1 Running 0 4m55s 10.100.2.18 worker233
stress-5585b5ccc-ccc2v 1/1 Running 0 4m55s 10.100.1.147 worker232
stress-5585b5ccc-czhg8 1/1 Running 0 4m6s 10.100.1.146 worker232
[root@master231 metrics-server]#
[root@master231 metrics-server]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress-hpa Deployment/stress 63%/95% 2 5 4 11m
[root@master231 metrics-server]#


16.5 再次压测
[root@master231 ~]# kubectl exec stress-5585b5ccc-6twg5 — stress –cpu 8 –io 4 –vm 2 –vm-bytes 128M –timeout 10m
stress: info: [44] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd


[root@master231 ~]# kubectl exec stress-5585b5ccc-b5qxr — stress –cpu 8 –io 4 –vm 2 –vm-bytes 128M –timeout 10m
stress: info: [7] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd


[root@master231 ~]# kubectl exec stress-5585b5ccc-ccc2v — stress –cpu 8 –io 4 –vm 2 –vm-bytes 128M –timeout 10m
stress: info: [7] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd


[root@master231 ~]# kubectl exec stress-5585b5ccc-czhg8 — stress –cpu 8 –io 4 –vm 2 –vm-bytes 128M –timeout 10m
stress: info: [7] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd


16.6 发现最多有5个Pod创建
[root@master231 metrics-server]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress-hpa Deployment/stress 163%/95% 2 5 5 12m
[root@master231 metrics-server]#
[root@master231 metrics-server]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
stress-5585b5ccc-6twg5 1/1 Running 0 12m 10.100.2.17 worker233
stress-5585b5ccc-b5qxr 1/1 Running 0 7m48s 10.100.2.18 worker233
stress-5585b5ccc-ccc2v 1/1 Running 0 7m48s 10.100.1.147 worker232
stress-5585b5ccc-czhg8 1/1 Running 0 6m59s 10.100.1.146 worker232
stress-5585b5ccc-z4l95 1/1 Running 0 32s 10.100.1.148 worker232
[root@master231 metrics-server]#
[root@master231 metrics-server]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress-hpa Deployment/stress 174%/95% 2 5 5 13m
[root@master231 metrics-server]#
[root@master231 metrics-server]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress-hpa Deployment/stress 200%/95% 2 5 0 5 13m
[root@master231 metrics-server]#


16.7取消压测后
需要等待5min会自动缩容Pod数量到2个。




17 hpa和vpa的区别?
– hpa:
表示Pod数量资源不足时,可以自动增加Pod副本数量,以抵抗流量过多的情况,降低负载。

– vpa:
表示可以动态调整容器的资源上线,比如一个Pod一开始是200Mi内存,如果资源达到定义的阈值,就可以扩展内存,但不会增加pod副本数量。

典型的区别在于vpa具有一定的资源上限问题,因为pod是K8S集群调度的最小单元,不可拆分,因此这个将来扩容时,取决于单节点的资源上限。

51 对接ceph
1基于Rook方式快速部署ceph集群
其他部署方式,推荐阅读:
https://rook.io/docs/rook/v1.13/Getting-Started/quickstart/#deploy-the-rook-operator


1.1 Rook概述
Rook是一个开源的云原生存储编排器,为Ceph存储提供平台、框架和支持,以便与云原生环境进行原生集成。

Ceph是一个分布式存储系统,提供文件、块和对象存储,部署在大规模生产集群中。

Rook自动化了Ceph的部署和管理,以提供自我管理、自我扩展和自我修复的存储服务。Rook操作员通过构建Kubernetes资源来部署、配置、配置、扩展、升级和监控Ceph来实现这一点。

Ceph运营商于2018年12月在Rook v0.9版本中宣布稳定,提供了多年的生产存储平台。Rook由云原生计算基金会(CNCF)托管,是一个毕业级项目。

Rook是用Golang实现的,ceph是用C++实现的,其中数据路径经过高度优化。


简而言之,Rook是一个自管理的分布式存储编排系统,可以为kubernetes提供便利的存储解决方案,Rook本身并不提供存储,而是kubernetes和存储之间提供适配层,简化存储系统的部署和维护工作。目前主要支持存储系统包括但不限于Ceph,Cassandra,NFS等。

从本质上来讲,Rook是一个可以提供ceph集群管理能力的Operator,Rook使用CRD一个控制器来对Ceph之类的资源进行部署和管理。

官网链接:
https://rook.io/

github地址:
https://github.com/rook/rook

1.2 Rook和K8S版本对应关系
我的K8S 1.23.17最高能使用的Rook版本为v1.13。

参考链接:
https://rook.io/docs/rook/v1.13/Getting-Started/Prerequisites/prerequisites/

1.3 环境准备
每个K8S节点增加2~3个块设备文件,分别对应300GB,500GB,1024GB,并重启操作系统。
root@master231:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS

sdb 8:16 0 300G 0 disk
sdc 8:32 0 500G 0 disk
sdd 8:48 0 1T 0 disk

root@master232:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS

sdb 8:16 0 300G 0 disk
sdc 8:32 0 500G 0 disk
sdd 8:48 0 1T 0 disk

root@master233:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS

sdb 8:16 0 300G 0 disk
sdc 8:32 0 500G 0 disk
sdd 8:48 0 1T 0 disk

1.4 下载指定版本Rook
root@master231:~# wget https://github.com/rook/rook/archive/refs/tags/v1.13.10.tar.gz

1.5 解压软件包
root@master231:~/manifests/preject/rook# tar xf v1.13.10.tar.gz

1.6 取消master污点
root@master231:~/manifests/preject/rook# kubectl describe nodes | grep -i taints
Taints: node-role.kubernetes.io/master:NoSchedule
Taints:
Taints:
root@master231:~/manifests/preject/rook# kubectl taint node master231 node-role.kubernetes.io/master:NoSchedule-
node/master231 untainted
root@master231:~/manifests/preject/rook# kubectl describe nodes | grep -i taints
Taints:
Taints:
Taints:
root@master231:~/manifests/preject/rook#

1.7 创建Rook
root@master231:~/manifests/preject/rook# cd rook-1.13.10/deploy/examples/

1.8 部署Ceph
[root@master231 examples]# kubectl apply -f cluster.yaml


1.9 部署Rook Ceph工具
[root@master231 examples]# kubectl apply -f toolbox.yaml


1.10 部署CephUI
[root@master231 examples]# kubectl apply -f dashboard-external-https.yaml

1.11 查看Pod列表
[root@master231 examples]# kubectl get pods,svc -n rook-ceph

1.12 查看ceph dashboard的登录密码
kubectl -n rook-ceph get secrets rook-ceph-dashboard-password -o jsonpath='{.data.password}’ | base64 -d ;echo

1.13 访问Ceph的WebUI
[root@master231 examples]# kubectl -n rook-ceph get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rook-ceph-mgr-dashboard-external-https NodePort 10.200.3.34 8443:24622/TCP 14m
rook-ceph-mon-a ClusterIP 10.200.104.17 6789/TCP,3300/TCP 109s
rook-ceph-mon-b ClusterIP 10.200.12.187 6789/TCP,3300/TCP 85s
rook-ceph-mon-c ClusterIP 10.200.33.54 6789/TCP,3300/TCP 76s
[root@master231 examples]#

https://10.0.0.233:24622/

用户名为: admin
密码: Hx46\Il]{L30|n#^_`c3

1.14 查看OSD列表信息
https://10.0.0.233:24622/#/osd

2 k8s对接ceph
2.1 ceph集群创建存储池
[root@master231 examples]# kubectl get pods -n rook-ceph -l app=rook-ceph-tools -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rook-ceph-tools-5846d4dc6c-lrgm8 1/1 Running 0 3h23m 10.100.1.175 worker232
[root@master231 examples]#
[root@master231 examples]#
[root@master231 examples]# kubectl -n rook-ceph exec -it rook-ceph-tools-5846d4dc6c-lrgm8 — bash
bash-4.4$
bash-4.4
bash-4.4$ ceph osd pool create ysl
pool ‘ysl’ created
bash-4.4$
bash-4.4$ ceph osd pool application enable ysl rbd
enabled application ‘rbd’ on pool ‘ysl’
bash-4.4$


2.在指定的存储池创建块设备
bash-4.4$ rbd create -s 2048 ysl -p ysl
bash-4.4$
bash-4.4$ rbd ls -p ysl
ysl
bash-4.4$
bash-4.4$ rbd info ysl/ysl
rbd image ‘ysl’:
size 2 GiB in 512 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 315452708a887
block_name_prefix: rbd_data.315452708a887
format: 2
features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
op_features:
flags:
create_timestamp: Mon Feb 24 06:42:32 2025
access_timestamp: Mon Feb 24 06:42:32 2025
modify_timestamp: Mon Feb 24 06:42:32 2025
bash-4.4$

3.所有节点安装ceph的客户端模块
[root@master231 ~]# apt -y install ceph-common


[root@worker232 ~]# apt -y install ceph-common

[root@worker233 ~]# apt -y install ceph-common

4.将客户端证书文件拷贝到K8S集群节点
[root@master231 volumes]# kubectl get pods -n rook-ceph -l app=rook-ceph-tools
NAME READY STATUS RESTARTS AGE
rook-ceph-tools-5846d4dc6c-lrgm8 1/1 Running 0 3h47m
[root@master231 volumes]#
[root@master231 volumes]#
[root@master231 volumes]# kubectl -n rook-ceph cp rook-ceph-tools-5846d4dc6c-lrgm8:/etc/ceph/keyring /etc/ceph/keyring
tar: Removing leading `/’ from member names
[root@master231 volumes]#
[root@master231 volumes]#
[root@master231 volumes]# ll /etc/ceph/keyring
-rw-r–r– 1 root root 62 Feb 24 15:03 /etc/ceph/keyring
[root@master231 volumes]#
[root@master231 volumes]#
[root@master231 volumes]# scp /etc/ceph/keyring 10.0.0.232:/etc/ceph/
root@10.0.0.232’s password:
keyring 100% 62 168.0KB/s 00:00
[root@master231 volumes]#
[root@master231 volumes]#
[root@master231 volumes]# scp /etc/ceph/keyring 10.0.0.233:/etc/ceph/
root@10.0.0.233’s password:
keyring 100% 62 130.3KB/s 00:00
[root@master231 volumes]#



5.编写资源清单k8s对接块设备存储卷
[root@master231 volumes]# cat 01-deploy-volumes-rbd.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: xiuxian-volume-rbd
spec:
replicas: 1
selector:
matchLabels:
app: xixi
template:
metadata:
labels:
app: xixi
spec:
volumes:
– name: data
rbd:
# 指定ceph集群地址,貌似不支持svc的名称解析,暂时写为svc的地址
monitors:
#- rook-ceph-mon-a.rook-ceph.svc.ysl.com:6789
#- rook-ceph-mon-b.rook-ceph.svc.ysl.com:6789
– 10.200.104.17:6789
– 10.200.12.187:6789
# 指定存储池
pool: ysl
# 指定块设备的名称
image: ysl
# 指定文件系统,支持”ext4″, “xfs”, “ntfs”类型,若不指定,则默认值为ext4.
fsType: xfs
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
ports:
– containerPort: 80
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
initContainers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: init
volumeMounts:
– name: data
mountPath: /ysl
command:
– /bin/sh
– -c
– echo www.ysl.com > /ysl/index.html
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-volume-rbd-54d875d5fc-smfkt 1/1 Running 0 2m23s 10.100.0.74 master231
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.0.74
www.ysl.com
[root@master231 volumes]#



– k8s基于secret存储ceph的认证信息
1.k8s所有worker移除认证信息
[root@master231 ~]# rm -f /etc/ceph/keyring

[root@worker232 ~]# rm -f /etc/ceph/keyring

[root@worker233 ~]# rm -f /etc/ceph/keyring


2.删除Pod之后将无法认证
[root@master231 volumes]# kubectl delete pods xiuxian-volume-rbd-54d875d5fc-smfkt
pod “xiuxian-volume-rbd-54d875d5fc-smfkt” deleted
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-volume-rbd-54d875d5fc-nj46n 0/1 Init:0/1 0 4s worker232
[root@master231 volumes]#
[root@master231 volumes]# kubectl describe pod xiuxian-volume-rbd-54d875d5fc-nj46n
Name: xiuxian-volume-rbd-54d875d5fc-nj46n
Namespace: default

Events:
Type Reason Age From Message
—- —— —- —- ——-
Normal Scheduled 13s default-scheduler Successfully assigned default/xiuxian-volume-rbd-54d875d5fc-nj46n to worker232
Normal SuccessfulAttachVolume 13s attachdetach-controller AttachVolume.Attach succeeded for volume “data”
Warning FailedMount 7s kubelet MountVolume.WaitForAttach failed for volume “data” : fail to check rbd image status with: (exit status 95), rbd output: (did not load config file, using default settings.
2025-02-24T15:16:11.391+0800 7f1a4d6534c0 -1 Errors while parsing config file!
2025-02-24T15:16:11.391+0800 7f1a4d6534c0 -1 can’t open ceph.conf: (2) No such file or directory
2025-02-24T15:16:11.391+0800 7f1a4d6534c0 -1 Errors while parsing config file!
2025-02-24T15:16:11.391+0800 7f1a4d6534c0 -1 can’t open ceph.conf: (2) No such file or directory
2025-02-24T15:16:11.391+0800 7f1a4d6534c0 -1 auth: unable to find a keyring on /etc/ceph/ceph.client.admin.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin: (2) No such file or directory
2025-02-24T15:16:11.391+0800 7f1a4d6534c0 -1 AuthRegistry(0x55813c13f848) no keyring found at /etc/ceph/ceph.client.admin.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin, disabling cephx
2025-02-24T15:16:11.395+0800 7f1a4d6534c0 -1 auth: unable to find a keyring on /etc/ceph/ceph.client.admin.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin: (2) No such file or directory
2025-02-24T15:16:11.395+0800 7f1a4d6534c0 -1 AuthRegistry(0x7ffcee347800) no keyring found at /etc/ceph/ceph.client.admin.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin, disabling cephx
2025-02-24T15:16:11.403+0800 7f1a4d6534c0 -1 monclient: authenticate NOTE: no keyring found; disabled cephx authentication
rbd: couldn’t connect to the cluster!
)


3.将认证信息基于secret存储
[root@master231 volumes]# cat 02-deploy-volumes-rbd-secretRef.yaml
apiVersion: v1
kind: Secret
metadata:
name: ceph-admin
type: “kubernetes.io/rbd”
stringData:
# 指定登录的认证信息,换成你ceph集群的key即可。
key: AQBL5btnoGXFDxAA2ojiKwgfI4dI42MCV70qnQ==



apiVersion: apps/v1
kind: Deployment
metadata:
name: xiuxian-volume-rbd-secretref
spec:
replicas: 1
selector:
matchLabels:
app: xixi
template:
metadata:
labels:
app: xixi
spec:
volumes:
– name: data
rbd:
# 指定ceph集群地址,貌似不支持svc的名称解析,暂时写为Pod的地址
monitors:
#- rook-ceph-mon-a.rook-ceph.svc.ysl.com:6789
#- rook-ceph-mon-b.rook-ceph.svc.ysl.com:6789
– 10.200.104.17:6789
– 10.200.12.187:6789
# 指定存储池
pool: ysl
# 指定块设备的名称
image: ysl
# 指定文件系统,支持”ext4″, “xfs”, “ntfs”类型,若不指定,则默认值为ext4.
fsType: xfs
# 指定连接集群的用户名,默认为admin
user: admin
# 一旦定义了secretRef选项,将覆盖keyring的配置,表示不在读取worker节点的认证信息。
secretRef:
name: ceph-admin
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
ports:
– containerPort: 80
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
[root@master231 volumes]#
[root@master231 volumes]# kubectl apply -f 02-deploy-volumes-rbd-secretRef.yaml
secret/ceph-admin created
deployment.apps/xiuxian-volume-rbd-secretref created
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-volume-rbd-secretref-64bd99b4b7-s6dlz 1/1 Running 0 17s 10.100.0.75 master231
[root@master231 volumes]#
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.0.75
www.ysl.com
[root@master231 volumes]#


– ceph的Dashboard实现块设备管理




– 操作etcd解决k8s资源一直处于Terminating的方案
1.问题复现”rook-ceph”名称空间一直处于”Terminating”
[root@master231 /server/kubernetes/ceph/rook-1.13.10/deploy/examples]# kubectl get ns
NAME STATUS AGE
default Active 14d
elastic-system Active 6d4h
ingress-nginx Active 4d
istio-system Active 3d6h
kube-flannel Active 14d
kube-node-lease Active 14d
kube-public Active 14d
kube-system Active 14d
kubesphere-controls-system Active 7d17h
kubesphere-system Active 7d17h
metallb-system Active 4d23h
monitoring Active 4d23h
rook-ceph Terminating 4h15m
yangsenlin Active 3d5h
[root@master231 /server/kubernetes/ceph/rook-1.13.10/deploy/examples]#



2.安装etcd的客户端
apt -y install etcd-client


3.查看数据
export ETCDCTL_API=3
etcdctl –endpoints=”10.0.0.231:2379″ –cacert=/etc/kubernetes/pki/etcd/ca.crt –cert=/etc/kubernetes/pki/etcd/server.crt –key=/etc/kubernetes/pki/etcd/server.key get /registry/namespaces/rook-ceph –prefix –keys-only

4.删除数据
[root@master231 ~]# etcdctl –endpoints=”10.0.0.231:2379″ –cacert=/etc/kubernetes/pki/etcd/ca.crt –cert=/etc/kubernetes/pki/etcd/server.crt –key=/etc/kubernetes/pki/etcd/server.key del /registry/namespaces/rook-ceph –prefix
1
[root@master231 ~]#


5.再次验证
[root@master231 /server/kubernetes/ceph/rook-1.13.10/deploy/examples]# kubectl get ns
NAME STATUS AGE
default Active 14d
elastic-system Active 6d4h
ingress-nginx Active 4d
istio-system Active 3d6h
kube-flannel Active 14d
kube-node-lease Active 14d
kube-public Active 14d
kube-system Active 14d
kubesphere-controls-system Active 7d17h
kubesphere-system Active 7d17h
metallb-system Active 4d23h
monitoring Active 4d23h
yangsenlin Active 3d5h
[root@master231 /server/kubernetes/ceph/rook-1.13.10/deploy/examples]#



– k8s对接cephFS文件系统
参考链接:
https://rook.io/docs/rook/latest/Getting-Started/example-configurations/#shared-filesystem

1.创建元数据存储池和数据存储池
bash-4.4$ ceph osd pool create ysl-cephfs-metadata
pool ‘ysl-cephfs-metadata’ created
bash-4.4$
bash-4.4$ ceph osd pool create ysl-cephfs-data
pool ‘ysl-cephfs-data’ created
bash-4.4$

2.查看ceph集群现有的文件系统
bash-4.4$ ceph fs ls
No filesystems enabled
bash-4.4$

3.创建cephFS实例
bash-4.4$ ceph fs new ysl-ysl-cephfs ysl-cephfs-metadata ysl-cephfs-data
Pool ‘ysl-cephfs-data’ (id ‘5’) has pg autoscale mode ‘on’ but is not marked as bulk.
Consider setting the flag by running
# ceph osd pool set ysl-cephfs-data bulk true
new fs with metadata pool 4 and data pool 5
bash-4.4$


4.再次查看ceph集群现有的文件系统
bash-4.4$ ceph fs ls
name: ysl-ysl-cephfs, metadata pool: ysl-cephfs-metadata, data pools: [ysl-cephfs-data ]
bash-4.4$

5.创建文件系统
[root@master231 examples]# pwd
/root/cloud-computing-stack/ysl/kubernetes/projects/03-rook/rook-1.13.10/deploy/examples
[root@master231 examples]#
[root@master231 examples]# kubectl apply -f filesystem-ec.yaml
cephfilesystem.ceph.rook.io/myfs-ec created
cephfilesystemsubvolumegroup.ceph.rook.io/myfs-csi created
[root@master231 examples]#
[root@master231 ~]# kubectl get pods -o wide -n rook-ceph # 观察是否有mds相关组件。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
csi-cephfsplugin-d8rxl 2/2 Running 0 5h23m 10.0.0.232 worker232
csi-cephfsplugin-ffms9 2/2 Running 1 (5h23m ago) 5h23m 10.0.0.233 worker233
csi-cephfsplugin-g4492 2/2 Running 0 4h53m 10.0.0.231 master231
csi-cephfsplugin-provisioner-675f8d446d-2tvj5 5/5 Running 1 (5h22m ago) 5h23m 10.100.1.172 worker232
csi-cephfsplugin-provisioner-675f8d446d-tqzjr 5/5 Running 1 (5h22m ago) 5h23m 10.100.2.35 worker233
csi-rbdplugin-9w498 2/2 Running 0 5h23m 10.0.0.232 worker232
csi-rbdplugin-fkktw 2/2 Running 0 4h53m 10.0.0.231 master231
csi-rbdplugin-j5kfd 2/2 Running 1 (5h22m ago) 5h23m 10.0.0.233 worker233
csi-rbdplugin-provisioner-dfc566599-hdpm9 5/5 Running 3 (5h22m ago) 5h23m 10.100.1.171 worker232
csi-rbdplugin-provisioner-dfc566599-snwfj 5/5 Running 1 (5h22m ago) 5h23m 10.100.2.36 worker233
rook-ceph-crashcollector-master231-84d789dc55-rr5lc 1/1 Running 0 3m36s 10.100.0.79 master231
rook-ceph-crashcollector-worker232-5b88cb5bc8-mmkxs 1/1 Running 0 3m34s 10.100.1.193 worker232
rook-ceph-crashcollector-worker233-5bf9645587-nkp54 1/1 Running 0 5h7m 10.100.2.46 worker233
rook-ceph-exporter-master231-67fff8cddb-8vtgb 1/1 Running 0 3m32s 10.100.0.80 master231
rook-ceph-exporter-worker232-5d8f7c4b55-tc4l4 1/1 Running 0 3m31s 10.100.1.194 worker232
rook-ceph-exporter-worker233-8654b9d9c4-slhdk 1/1 Running 0 5h7m 10.100.2.48 worker233
rook-ceph-mds-myfs-ec-a-5869f5c795-w5rbh 2/2 Running 0 3m36s 10.100.0.78 master231
rook-ceph-mds-myfs-ec-b-c4d98d477-knm8z 2/2 Running 0 3m35s 10.100.1.192 worker232
rook-ceph-mgr-a-75b8597954-w6825 3/3 Running 0 5h10m 10.100.1.182 worker232
rook-ceph-mgr-b-59d4b976c7-gk2bb 3/3 Running 0 5h10m 10.100.2.41 worker233
rook-ceph-mon-a-74679c68bb-pmq69 2/2 Running 0 5h15m 10.100.1.180 worker232
rook-ceph-mon-b-7c44758ffd-jxsjx 2/2 Running 0 5h15m 10.100.2.40 worker233
rook-ceph-mon-d-67f489d656-qzspd 2/2 Running 0 5h 10.100.0.73 master231
rook-ceph-operator-5f54cbd997-hq2kb 1/1 Running 0 5h28m 10.100.1.168 worker232
rook-ceph-osd-0-5fdf78969c-x6l8v 2/2 Running 0 5h7m 10.100.1.187 worker232
rook-ceph-osd-1-6cb84f5c66-ldfsd 2/2 Running 0 5h7m 10.100.2.45 worker233
rook-ceph-osd-2-7466b8f64d-4ctf4 2/2 Running 0 5h7m 10.100.2.47 worker233
rook-ceph-osd-3-76dcff98b4-z6dc5 2/2 Running 0 5h7m 10.100.1.186 worker232
rook-ceph-osd-prepare-worker232-9v5zx 0/1 Completed 0 5h7m 10.100.1.191 worker232
rook-ceph-osd-prepare-worker233-gmgg2 0/1 Completed 0 5h7m 10.100.2.49 worker233
rook-ceph-tools-5846d4dc6c-lrgm8 1/1 Running 0 5h28m 10.100.1.175 worker232
[root@master231 ~]#

6.查看cephFS的状态信息
bash-4.4$ ceph fs status ysl-ysl-cephfs
ysl-ysl-cephfs – 0 clients
========================
RANK STATE MDS ACTIVITY DNS INOS DIRS CAPS
0 active myfs-ec-a Reqs: 0 /s 10 13 12 0
POOL TYPE USED AVAIL
ysl-cephfs-metadata metadata 64.0k 759G
ysl-cephfs-data data 0 506G
MDS version: ceph version 18.2.2 (531c0d11a1c5d39fbfe6aa8a521f023abf3bf3e2) reef (stable)
bash-4.4$



7.测试验证
[root@master231 volumes]# cat 03-deploy-volumes-cephfs-secretRef.yaml
apiVersion: v1
kind: Secret
metadata:
name: ceph-admin
type: “kubernetes.io/rbd”
stringData:
# 指定登录的认证信息,换成你ceph集群的key即可。
key: AQBL5btnoGXFDxAA2ojiKwgfI4dI42MCV70qnQ==



apiVersion: apps/v1
kind: Deployment
metadata:
name: xiuxian-volume-cephfs-secretref
spec:
replicas: 3
selector:
matchLabels:
app: xixi
template:
metadata:
labels:
app: xixi
spec:
volumes:
– name: data
# 指定存储卷的类型
cephfs:
# 指定共享的文件路径
path: /
monitors:
– 10.200.104.17:6789
– 10.200.12.187:6789
user: admin
secretRef:
name: ceph-admin
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
ports:
– containerPort: 80
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-volume-cephfs-secretref-bb4cd455-9wmrc 1/1 Running 0 7s 10.100.0.81 master231
xiuxian-volume-rbd-secretref-5894f6b98c-m79ph 1/1 Running 0 84m 10.100.0.76 master231
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.0.81

403 Forbidden

403 Forbidden


nginx/1.20.1



[root@master231 volumes]#

8.修改数据
[root@master231 volumes]# kubectl exec -it xiuxian-volume-cephfs-secretref-bb4cd455-9wmrc — sh
/ # echo https://www.ysl.com > /usr/share/nginx/html/index.html
/ #
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.0.81
https://www.ysl.com
[root@master231 volumes]#

9.再次测试验证
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-volume-cephfs-secretref-bb4cd455-9fjg2 1/1 Running 0 4s 10.100.1.195 worker232
xiuxian-volume-cephfs-secretref-bb4cd455-9wmrc 1/1 Running 0 77s 10.100.0.81 master231
xiuxian-volume-cephfs-secretref-bb4cd455-cshzm 1/1 Running 0 4s 10.100.2.50 worker233
xiuxian-volume-rbd-secretref-5894f6b98c-m79ph 1/1 Running 0 85m 10.100.0.76 master231
[root@master231 volumes]#
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.1.195
https://www.ysl.com
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.2.50
https://www.ysl.com
[root@master231 volumes]#
[root@master231 volumes]# curl 10.100.0.81
https://www.ysl.com
[root@master231 volumes]#

– K8S的csi对接ceph的rbd动态存储类
1.安装rbd的sc
[root@master231 examples]# cd csi/rbd/
[root@master231 rbd]#
[root@master231 rbd]# ll
total 52
drwxrwxr-x 2 root root 4096 Jul 4 2024 ./
drwxrwxr-x 5 root root 4096 Jul 4 2024 ../
-rw-rw-r– 1 root root 489 Jul 4 2024 pod-ephemeral.yaml
-rw-rw-r– 1 root root 315 Jul 4 2024 pod.yaml
-rw-rw-r– 1 root root 266 Jul 4 2024 pvc-clone.yaml
-rw-rw-r– 1 root root 308 Jul 4 2024 pvc-restore.yaml
-rw-rw-r– 1 root root 196 Jul 4 2024 pvc.yaml
-rw-rw-r– 1 root root 578 Jul 4 2024 snapshotclass.yaml
-rw-rw-r– 1 root root 205 Jul 4 2024 snapshot.yaml
-rw-rw-r– 1 root root 3984 Jul 4 2024 storageclass-ec.yaml
-rw-rw-r– 1 root root 2441 Jul 4 2024 storageclass-test.yaml
-rw-rw-r– 1 root root 4278 Jul 4 2024 storageclass.yaml
[root@master231 rbd]#
[root@master231 rbd]# kubectl apply -f storageclass.yaml
cephblockpool.ceph.rook.io/replicapool created
storageclass.storage.k8s.io/rook-ceph-block created
[root@master231 rbd]#
[root@master231 rbd]# kubectl get sc rook-ceph-block
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate true 26s
[root@master231 rbd]#


2.创建pvc
[root@master231 rbd]# cat pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-pvc
spec:
accessModes:
– ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: rook-ceph-block
[root@master231 rbd]#
[root@master231 rbd]#
[root@master231 rbd]#
[root@master231 rbd]# kubectl apply -f pvc.yaml
persistentvolumeclaim/rbd-pvc created
[root@master231 rbd]#
[root@master231 rbd]# kubectl get pvc rbd-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
rbd-pvc Bound pvc-1f6bc1b8-1bef-4df7-a101-0ca6a2770fdb 1Gi RWO rook-ceph-block 21s
[root@master231 rbd]#
[root@master231 rbd]#
[root@master231 rbd]# kubectl describe pv pvc-1f6bc1b8-1bef-4df7-a101-0ca6a2770fdb
Name: pvc-1f6bc1b8-1bef-4df7-a101-0ca6a2770fdb
Labels:
Annotations: pv.kubernetes.io/provisioned-by: rook-ceph.rbd.csi.ceph.com
volume.kubernetes.io/provisioner-deletion-secret-name: rook-csi-rbd-provisioner
volume.kubernetes.io/provisioner-deletion-secret-namespace: rook-ceph
Finalizers: [external-provisioner.volume.kubernetes.io/finalizer kubernetes.io/pv-protection]
StorageClass: rook-ceph-block
Status: Bound
Claim: default/rbd-pvc
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 1Gi
Node Affinity:
Message:
Source:
Type: CSI (a Container Storage Interface (CSI) volume source)
Driver: rook-ceph.rbd.csi.ceph.com
FSType: ext4
VolumeHandle: 0001-0009-rook-ceph-000000000000000b-6a5f560e-98a7-4808-83dc-bcd01b0f6dda
ReadOnly: false
VolumeAttributes: clusterID=rook-ceph
imageFeatures=layering
imageFormat=2
imageName=csi-vol-6a5f560e-98a7-4808-83dc-bcd01b0f6dda
journalPool=replicapool
pool=replicapool
storage.kubernetes.io/csiProvisionerIdentity=1740367265681-724-rook-ceph.rbd.csi.ceph.com
Events:
[root@master231 rbd]#


3.测试验证
[root@master231 volumes]# cat 04-deploy-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: xiuxian-ceph-pvc
spec:
replicas: 1
selector:
matchLabels:
app: xixi
template:
metadata:
labels:
app: xixi
spec:
volumes:
– name: data
persistentVolumeClaim:
claimName: rbd-pvc
readOnly: false
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
ports:
– containerPort: 80
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
[root@master231 volumes]#
[root@master231 volumes]# kubectl apply -f 04-deploy-pvc.yaml
deployment.apps/xiuxian-ceph-pvc created
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-ceph-pvc-6fc5ff4ff6-wxrhh 1/1 Running 0 6s 10.100.0.83 master231
[root@master231 volumes]#



– K8S的csi对接ceph的cephfs动态存储类
1.创建cephFS的sc
[root@master231 examples]# cd csi/cephfs/
[root@master231 cephfs]#
[root@master231 cephfs]# ll
total 48
drwxrwxr-x 2 root root 4096 Jul 4 2024 ./
drwxrwxr-x 5 root root 4096 Jul 4 2024 ../
-rw-rw-r– 1 root root 1681 Jul 4 2024 kube-registry.yaml
-rw-rw-r– 1 root root 488 Jul 4 2024 pod-ephemeral.yaml
-rw-rw-r– 1 root root 321 Jul 4 2024 pod.yaml
-rw-rw-r– 1 root root 268 Jul 4 2024 pvc-clone.yaml
-rw-rw-r– 1 root root 310 Jul 4 2024 pvc-restore.yaml
-rw-rw-r– 1 root root 195 Jul 4 2024 pvc.yaml
-rw-rw-r– 1 root root 587 Jul 4 2024 snapshotclass.yaml
-rw-rw-r– 1 root root 214 Jul 4 2024 snapshot.yaml
-rw-rw-r– 1 root root 1751 Jul 4 2024 storageclass-ec.yaml
-rw-rw-r– 1 root root 1602 Jul 4 2024 storageclass.yaml
[root@master231 cephfs]#
[root@master231 cephfs]# kubectl apply -f storageclass-ec.yaml
storageclass.storage.k8s.io/rook-cephfs created
[root@master231 cephfs]#
[root@master231 cephfs]# kubectl get sc rook-cephfs
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
rook-cephfs rook-ceph.cephfs.csi.ceph.com Delete Immediate true 27s
[root@master231 cephfs]#


2.创建pvc
[root@master231 cephfs]# cat pvc.yaml

apiVersion: v1
[root@master231 cephfs]# cat pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cephfs-pvc
spec:
accessModes:
# – ReadWriteOnce
– ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: rook-cephfs
[root@master231 cephfs]#
[root@master231 cephfs]# kubectl apply -f pvc.yaml
persistentvolumeclaim/cephfs-pvc created
[root@master231 cephfs]#



3.查看pv对应的数据
[root@master231 cephfs]# kubectl get pvc cephfs-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
cephfs-pvc Bound pvc-6c3cce25-ff86-4706-9932-785e486488bc 1Gi RWX rook-cephfs 6s
[root@master231 cephfs]#
[root@master231 cephfs]# kubectl describe pv pvc-6c3cce25-ff86-4706-9932-785e486488bc
Name: pvc-6c3cce25-ff86-4706-9932-785e486488bc
Labels:
Annotations: pv.kubernetes.io/provisioned-by: rook-ceph.cephfs.csi.ceph.com
volume.kubernetes.io/provisioner-deletion-secret-name: rook-csi-cephfs-provisioner
volume.kubernetes.io/provisioner-deletion-secret-namespace: rook-ceph
Finalizers: [external-provisioner.volume.kubernetes.io/finalizer kubernetes.io/pv-protection]
StorageClass: rook-cephfs
Status: Bound
Claim: default/cephfs-pvc
Reclaim Policy: Delete
Access Modes: RWX
VolumeMode: Filesystem
Capacity: 1Gi
Node Affinity:
Message:
Source:
Type: CSI (a Container Storage Interface (CSI) volume source)
Driver: rook-ceph.cephfs.csi.ceph.com
FSType:
VolumeHandle: 0001-0009-rook-ceph-0000000000000002-6d666583-37c1-4af6-83a1-06e0c06f33bc
ReadOnly: false
VolumeAttributes: clusterID=rook-ceph
fsName=myfs-ec
pool=myfs-ec-erasurecoded
storage.kubernetes.io/csiProvisionerIdentity=1740367264374-8221-rook-ceph.cephfs.csi.ceph.com
subvolumeName=csi-vol-6d666583-37c1-4af6-83a1-06e0c06f33bc
subvolumePath=/volumes/csi/csi-vol-6d666583-37c1-4af6-83a1-06e0c06f33bc/2154f732-8f28-470a-8366-93b49fa7a849
Events:
[root@master231 cephfs]#


4.使用pvc
[root@master231 volumes]# cat 05-deploy-pvc-sc-cephfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: xiuxian-cephfs-pvc
spec:
replicas: 3
selector:
matchLabels:
app: xixi
template:
metadata:
labels:
app: xixi
spec:
volumes:
– name: data
persistentVolumeClaim:
claimName: cephfs-pvc
readOnly: false
containers:
– image: registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1
name: c1
ports:
– containerPort: 80
volumeMounts:
– name: data
mountPath: /usr/share/nginx/html
[root@master231 volumes]#
[root@master231 volumes]#
[root@master231 volumes]# kubectl apply -f 05-deploy-pvc-sc-cephfs.yaml
deployment.apps/xiuxian-cephfs-pvc created
[root@master231 volumes]#
[root@master231 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiuxian-cephfs-pvc-5f9775c869-6zvtx 1/1 Running 0 19s 10.100.1.196 worker232
xiuxian-cephfs-pvc-5f9775c869-bxfx8 1/1 Running 0 19s 10.100.0.85 master231
xiuxian-cephfs-pvc-5f9775c869-htc2r 1/1 Running 0 19s 10.100.2.51 worker233
[root@master231 volumes]#

52 jenkins集成k8s
– 推送代码到gitee
1.新建gitee项目
略,见视频。推荐项目名称”ysl-ysl-yiliao”。


2.配置git
[root@worker233 ~]# git config –global user.name “forestysl2020”
[root@worker233 ~]# git config –global user.email “y1053419035@qq.com”
[root@worker233 ~]#


3.项目初始化
[root@worker233 ~]# mkdir ysl-ysl-yiliao
[root@worker233 ~]# cd ysl-ysl-yiliao
[root@worker233 ysl-ysl-yiliao]# git init
hint: Using ‘master’ as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config –global init.defaultBranch
hint:
hint: Names commonly chosen instead of ‘master’ are ‘main’, ‘trunk’ and
hint: ‘development’. The just-created branch can be renamed via this command:
hint:
hint: git branch -m
Initialized empty Git repository in /root/ysl-ysl-yiliao/.git/
[root@worker233 ysl-ysl-yiliao]#

4.编写Readme文件
[root@worker233 ysl-ysl-yiliao]# cat README.md
# 1.项目介绍
“`
这是老男孩教育ysl期的Jenkins集成K8S测试项目。

“`

# 2.公司网址
“`
https://www.ysl.com
“`
[root@worker233 ysl-ysl-yiliao]#


5.上传测试代码
[root@worker233 ~]# wget http://192.168.15.253/Resources/Kubernetes/softwares/jenkins/ysl-yiliao.zip

[root@worker233 ~]# unzip ysl-yiliao.zip -d ysl-ysl-yiliao/


6.编写Dockerfile
[root@worker233 ysl-ysl-yiliao]# cat Dockerfile
FROM registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1

LABEL school=ysl \
class=ysl

COPY . /usr/share/nginx/html

EXPOSE 80
[root@worker233 ysl-ysl-yiliao]#

7.提交到本地仓库
[root@worker233 ysl-ysl-yiliao]# git add .
[root@worker233 ysl-ysl-yiliao]# git commit -m ‘first commit’

8.推送代码到gitee
[root@worker233 ysl-ysl-yiliao]# git remote add origin https://gitee.com/forestysl2020/ysl-ysl-yiliao.git
[root@worker233 ysl-ysl-yiliao]# git push -u origin “master”
Username for ‘https://gitee.com’: forestysl2020
Password for ‘https://forestysl2020@gitee.com’:
Enumerating objects: 92, done.
Counting objects: 100% (92/92), done.
Delta compression using up to 2 threads
Compressing objects: 100% (92/92), done.
Writing objects: 100% (92/92), 1.48 MiB | 3.41 MiB/s, done.
Total 92 (delta 11), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [1.1.5]
remote: Set trace flag 77436c89
To https://gitee.com/forestysl2020/ysl-ysl-yiliao.git
* [new branch] master -> master
Branch ‘master’ set up to track remote branch ‘master’ from ‘origin’.
[root@worker233 ysl-ysl-yiliao]#


9.远程仓库验证
https://gitee.com/forestysl2020/ysl-ysl-yiliao




– Jenkins环境部署
1.安装key
wget -O /usr/share/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key

2.添加jenkins的软件源
echo “deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]” \
https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null

3.安装依赖包
[root@jenkins211 ~]# apt-get -y install fontconfig


4.安装JDK
[root@jenkins211 ~]# wget http://192.168.15.253/Resources/Kubernetes/softwares/jenkins/jdk-17_linux-x64_bin.tar.gz


[root@jenkins211 ~]# mkdir -pv /ysl/softwares
mkdir: created directory ‘/ysl’
mkdir: created directory ‘/ysl/softwares’
[root@jenkins211 ~]#
[root@jenkins211 ~]# tar xf jdk-17_linux-x64_bin.tar.gz -C /ysl/softwares
[root@jenkins211 ~]#
[root@jenkins211 ~]# cat > /etc/profile.d/jenkins.sh <> /etc/hosts

7.添加shell功能编译镜像并推送代码到harbor仓库
docker build -t harbor.ysl.com/ysl-yiliao/demo:v0.1 .
docker login -u admin -p 1 harbor.ysl.com
docker push harbor.ysl.com/ysl-yiliao/demo:v0.1
docker logout harbor.ysl.com

8.harbor仓库验证
略,见视频。



课堂练习:
将医疗项目部署到K8S集群,集群外部基于8899端口访问。





– Jenkins部署服务到K8S集群实战案例
1.下载kubectl工具
[root@jenkins211 ~]# wget http://192.168.15.253/Resources/Kubernetes/softwares/jenkins/kubectl-1.23.17

2.将kubectl添加到PATH变量并授权
[root@jenkins211 ~]# mv kubectl-1.23.17 /usr/local/bin/kubectl
[root@jenkins211 ~]#
[root@jenkins211 ~]# chmod +x /usr/local/bin/kubectl
[root@jenkins211 ~]#
[root@jenkins211 ~]# ll /usr/local/bin/kubectl
-rwxr-xr-x 1 root root 45174784 Sep 4 2023 /usr/local/bin/kubectl*
[root@jenkins211 ~]#


3.拷贝认证文件
[root@jenkins211 ~]# mkdir ~/.kube
[root@jenkins211 ~]# scp 10.0.0.231:/root/.kube/config /root/.kube/

4.修改jenkins的脚本内容
docker build -t harbor.ysl.com/ysl-yiliao/demo:${version} .
docker login -u admin -p 1 harbor.ysl.com
docker push harbor.ysl.com/ysl-yiliao/demo:${version}
docker logout harbor.ysl.com
if [ `kubectl get pods -l app=yiliao | wc -l` -eq 0 ] ; then
kubectl create deployment yiliao –image=harbor.ysl.com/ysl-yiliao/demo:${version} –port=80
kubectl expose deployment yiliao –port=80 –type=NodePort
else
kubectl set image deploy yiliao demo=harbor.ysl.com/ysl-yiliao/demo:${version}
fi


5.立即构建jenkins,验证服务是否部署成功
略,见视频。


– Jenkins回滚服务
1.git参数构建
略,见视频。


2.回滚指令
kubectl set image deploy yiliao demo=harbor.ysl.com/ysl-yiliao/demo:${version}



– Jenkins的Jenkinsfile实现全流程
1.基于pipeline构建项目
pipeline {
agent any

stages {
stage(‘从gitee拉取代码’) {
steps {
git credentialsId: ‘gitee’, url: ‘https://gitee.com/forestysl2020/ysl-ysl-yiliao.git’
}
}

stage(‘编译镜像’) {
steps {
sh ‘docker build -t harbor.ysl.com/ysl-yiliao/demo:${BUILD_NUMBER} .’
}
}

stage(‘推送镜像到harbor仓库’) {
steps {
sh ”’docker login -u admin -p 1 harbor.ysl.com
docker push harbor.ysl.com/ysl-yiliao/demo:${BUILD_NUMBER}
docker logout harbor.ysl.com”’
}
}

stage(‘部署或更新医疗项目’) {
steps {
sh ”’if [ `kubectl get pods -l app=yiliao | wc -l` -eq 0 ] ; then
kubectl create deployment yiliao –image=harbor.ysl.com/ysl-yiliao/demo:${BUILD_NUMBER} –port=80
kubectl expose deployment yiliao –port=80 –type=NodePort
else
kubectl set image deploy yiliao demo=harbor.ysl.com/ysl-yiliao/demo:${BUILD_NUMBER}
fi”’
}
}

}
}


2.编译代码测试
略,见视频。





– devops架构升级到gitops实现思路



– kubeadm证书升级方案
1.kubeadm自建的CA证书有效期为10年
[root@master231 cephfs]# openssl x509 -noout -text -in /etc/kubernetes/pki/ca.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes
Validity
Not Before: Feb 10 03:55:33 2025 GMT
Not After : Feb 8 03:55:33 2035 GMT





2.kubeadm对于各组件的证书有效期为1年
[root@master231 cephfs]# openssl x509 -noout -text -in /etc/kubernetes/pki/apiserver.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4271520686627480594 (0x3b477d6ed929e412)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes
Validity
Not Before: Feb 10 03:55:33 2025 GMT
Not After : Feb 10 03:55:33 2026 GMT




3.kubeadm查看各组件及自建CA证书的有效期
[root@master231 ~]# kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster…
[check-expiration] FYI: You can look at this config file with ‘kubectl -n kube-system get cm kubeadm-config -o yaml’
W0225 17:41:49.556696 1769598 utils.go:69] The recommended value for “resolvConf” in “KubeletConfiguration” is: /run/systemd/resolve/resolv.conf; the provided value is: /run/systemd/resolve/resolv.conf

CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Feb 10, 2026 03:55 UTC 349d ca no
apiserver Feb 10, 2026 03:55 UTC 349d ca no
apiserver-etcd-client Feb 10, 2026 03:55 UTC 349d etcd-ca no
apiserver-kubelet-client Feb 10, 2026 03:55 UTC 349d ca no
controller-manager.conf Feb 10, 2026 03:55 UTC 349d ca no
etcd-healthcheck-client Feb 10, 2026 03:55 UTC 349d etcd-ca no
etcd-peer Feb 10, 2026 03:55 UTC 349d etcd-ca no
etcd-server Feb 10, 2026 03:55 UTC 349d etcd-ca no
front-proxy-client Feb 10, 2026 03:55 UTC 349d front-proxy-ca no
scheduler.conf Feb 10, 2026 03:55 UTC 349d ca no

CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Feb 08, 2035 03:55 UTC 9y no
etcd-ca Feb 08, 2035 03:55 UTC 9y no
front-proxy-ca Feb 08, 2035 03:55 UTC 9y no
[root@master231 ~]#


4.服务端证书续期
[root@master231 ~]# kubeadm certs renew all
[renew] Reading configuration from the cluster…
[renew] FYI: You can look at this config file with ‘kubectl -n kube-system get cm kubeadm-config -o yaml’
W0225 17:43:45.817175 1771510 utils.go:69] The recommended value for “resolvConf” in “KubeletConfiguration” is: /run/systemd/resolve/resolv.conf; the provided value is: /run/systemd/resolve/resolv.conf

certificate embedded in the kubeconfig file for the admin to use and for kubeadm itself renewed
certificate for serving the Kubernetes API renewed
certificate the apiserver uses to access etcd renewed
certificate for the API server to connect to kubelet renewed
certificate embedded in the kubeconfig file for the controller manager to use renewed
certificate for liveness probes to healthcheck etcd renewed
certificate for etcd nodes to communicate with each other renewed
certificate for serving etcd renewed
certificate for the front proxy client renewed
certificate embedded in the kubeconfig file for the scheduler manager to use renewed

Done renewing certificates. You must restart the kube-apiserver, kube-controller-manager, kube-scheduler and etcd, so that they can use the new certificates.
[root@master231 ~]#
[root@master231 ~]# kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster…
[check-expiration] FYI: You can look at this config file with ‘kubectl -n kube-system get cm kubeadm-config -o yaml’
W0225 17:44:12.692574 1771932 utils.go:69] The recommended value for “resolvConf” in “KubeletConfiguration” is: /run/systemd/resolve/resolv.conf; the provided value is: /run/systemd/resolve/resolv.conf

CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Feb 25, 2026 09:43 UTC 364d ca no
apiserver Feb 25, 2026 09:43 UTC 364d ca no
apiserver-etcd-client Feb 25, 2026 09:43 UTC 364d etcd-ca no
apiserver-kubelet-client Feb 25, 2026 09:43 UTC 364d ca no
controller-manager.conf Feb 25, 2026 09:43 UTC 364d ca no
etcd-healthcheck-client Feb 25, 2026 09:43 UTC 364d etcd-ca no
etcd-peer Feb 25, 2026 09:43 UTC 364d etcd-ca no
etcd-server Feb 25, 2026 09:43 UTC 364d etcd-ca no
front-proxy-client Feb 25, 2026 09:43 UTC 364d front-proxy-ca no
scheduler.conf Feb 25, 2026 09:43 UTC 364d ca no

CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Feb 08, 2035 03:55 UTC 9y no
etcd-ca Feb 08, 2035 03:55 UTC 9y no
front-proxy-ca Feb 08, 2035 03:55 UTC 9y no
[root@master231 ~]#




5.客户端证书并没有需求
[root@master231 ~]# openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 6710230616234321792 (0x5d1f87317198e780)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes
Validity
Not Before: Feb 10 03:55:33 2025 GMT
Not After : Feb 10 03:55:35 2026 GMT



6.修改静态Pod的kube-controller-manager资源清单
[root@master231 ~]# vim /etc/kubernetes/manifests/kube-controller-manager.yaml

spec:
containers:
– command:
– kube-controller-manager

# 所签名证书的有效期限。每个 CSR 可以通过设置 spec.expirationSeconds 来请求更短的证书。
– –cluster-signing-duration=87600h0m0s

# 启用controner manager自动签发CSR证书,可以不配置,默认就是启用的,但是建议配置上!害怕未来版本发生变化!
– –feature-gates=RotateKubeletServerCertificate=true


[root@master231 ~]# kubectl get pods -n kube-system kube-controller-manager-master231
NAME READY STATUS RESTARTS AGE
kube-controller-manager-master231 1/1 Running 0 12s
[root@master231 ~]#



参考链接:
https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-controller-manager/


7.要求kubelet的配置文件中支持证书滚动,默认是启用的,无需配置。
[root@worker232 ~]# vim /var/lib/kubelet/config.yaml

rotateCertificates: true


8.客户端节点修改节点的时间并重启kubelet

centos操作如下:
[root@worker232 ~]# date -s “2025-6-4”
[root@worker232 ~]#
[root@worker232 ~]# systemctl restart kubelet

ubuntu系统操作如下:
[root@worker232 ~]# timedatectl set-ntp off # 先关闭时间同步服务。
[root@worker232 ~]#
[root@worker232 ~]# timedatectl set-time ‘2026-02-09 15:30:00’ # 修改即将过期的时间的前一天
[root@worker232 ~]#
[root@worker232 ~]# date
Wed Jun 4 03:30:02 PM CST 2025
[root@worker232 ~]#
[root@worker232 ~]# systemctl restart kubelet.service
53 二进制安装k8s
1.环境准备
CPU: 2c+
Memory: 4g+
Disk: 50g+

10.0.0.41 node-exporter41
10.0.0.42 node-exporter42
10.0.0.43 node-exporter43


2.所有节点安装常用的软件包
[root@node-exporter41 ~]# apt -y install bind9-utils expect rsync jq psmisc net-tools lvm2 vim unzip rename golang-cfssl lrzsz


3.node-exporter41节点免密钥登录集群并同步数据
cat >> /etc/hosts <<'EOF' 10.0.0.240 apiserver-lb 10.0.0.41 node-exporter41 10.0.0.42 node-exporter42 10.0.0.43 node-exporter43 EOF 4.配置免密码登录其他节点 cat > password_free_login.sh <<'EOF' #!/bin/bash # auther: forest ysl ​ # 创建密钥对 ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa -q ​ # 声明你服务器密码,建议所有节点的密码均一致,否则该脚本需要再次进行优化 export mypasswd='XZnh@95599' ​ # 定义主机列表 k8s_host_list=(node-exporter41 node-exporter42 node-exporter43) ​ # 配置免密登录,利用expect工具免交互输入 for i in ${k8s_host_list[@]};do expect -c " spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$i expect { \"*yes/no*\" {send \"yes\r\"; exp_continue} \"*password*\" {send \"$mypasswd\r\"; exp_continue} }" done EOF bash password_free_login.sh ​ ​ 5 编写同步脚本 cat > /usr/local/sbin/data_rsync.sh <<'EOF' #!/bin/bash ​ # Auther: forest ysl ​ if [ $# -lt 1 ];then echo "Usage: $0 /path/to/file(绝对路径) [mode: m|w]" exit fi ​ if [ ! -e $1 ];then echo "[ $1 ] dir or file not find!" exit fi ​ fullpath=`dirname $1` ​ basename=`basename $1` ​ cd $fullpath ​ case $2 in WORKER_NODE|w) K8S_NODE=(node-exporter42 node-exporter43) ;; MASTER_NODE|m) K8S_NODE=(node-exporter42 node-exporter43) ;; *) K8S_NODE=(node-exporter42 node-exporter43) ;; esac ​ for host in ${K8S_NODE[@]};do tput setaf 2 echo ===== rsyncing ${host}: $basename ===== tput setaf 7 rsync -az $basename `whoami`@${host}:$fullpath if [ $? -eq 0 ];then echo "命令执行成功!" fi done EOF chmod +x /usr/local/sbin/data_rsync.sh data_rsync.sh /etc/hosts ​ ​ ​ 6.所有节点Linux基础环境优化 systemctl disable --now NetworkManager ufw swapoff -a && sysctl -w vm.swappiness=0 sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab free -h ln -svf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime cat >> /etc/security/limits.conf <<'EOF' * soft nofile 655360 * hard nofile 131072 * soft nproc 655350 * hard nproc 655350 * soft memlock unlimited * hard memlock unlimited EOF sed -i 's@#UseDNS yes@UseDNS no@g' /etc/ssh/sshd_config sed -i 's@^GSSAPIAuthentication yes@GSSAPIAuthentication no@g' /etc/ssh/sshd_config cat > /etc/sysctl.d/k8s.conf <<'EOF' ​ # 以下3个参数是containerd所依赖的内核参数 ​ net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv6.conf.all.disable_ipv6 = 1 fs.may_detach_mounts = 1 vm.overcommit_memory=1 vm.panic_on_oom=0 fs.inotify.max_user_watches=89100 fs.file-max=52706963 fs.nr_open=52706963 net.netfilter.nf_conntrack_max=2310720 net.ipv4.tcp_keepalive_time = 600 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.tcp_keepalive_intvl =15 net.ipv4.tcp_max_tw_buckets = 36000 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_max_orphans = 327680 net.ipv4.tcp_orphan_retries = 3 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 16384 net.ipv4.ip_conntrack_max = 65536 net.ipv4.tcp_max_syn_backlog = 16384 net.ipv4.tcp_timestamps = 0 net.core.somaxconn = 16384 EOF sysctl --system cat <> ~/.bashrc
PS1='[\[\e[34;1m\]\u@\[\e[0m\]\[\e[32;1m\]\H\[\e[0m\]\[\e[31;1m\] \W\[\e[0m\]]# ‘
EOF
source ~/.bashrc


7.所有节点安装ipvsadm以实现kube-proxy的负载均衡
apt -y install ipvsadm ipset sysstat conntrack
cat > /etc/modules-load.d/ipvs.conf << 'EOF' ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp ip_vs_sh nf_conntrack ip_tables ip_set xt_set ipt_set ipt_rpfilter ipt_REJECT ipip EOF ​ 8.重复所有节点并验证模块是否加载成功 reboot lsmod | grep --color=auto -e ip_vs -e nf_conntrack uname -r ifconfig free -h ​ ​ ​ - 1.如果有docker环境,请卸载 ./install-docker.sh r ip link del docker0 ​ ​ 2.安装containerd tar xf ysl-autoinstall-containerd-v1.7.20.tar.gz ./install-containerd.sh i ​ [root@node-exporter43 autoinstall-containerd-v1.6.36]# ./install-containerd.sh i Client: Version: v1.6.36 Revision: 88c3d9bc5b5a193f40b7c14fa996d23532d6f956 Go version: go1.22.7 ​ Server: Version: v1.6.36 Revision: 88c3d9bc5b5a193f40b7c14fa996d23532d6f956 UUID: 5e5fa4ba-9748-4f60-bbd8-2234dc1b860d ​ runc version 1.1.15 commit: v1.1.15-0-gbc20cb44 spec: 1.0.2-dev go: go1.22.3 libseccomp: 2.5.5 ​ 安装成功,欢迎下次使用! ​ ​ ​ ​ - containerd的名称空间,镜像和容器,任务管理快速入门 1.名称空间管理 1.1 查看现有的名称空间 [root@node-exporter41 ~]# ctr ns ls NAME LABELS [root@node-exporter41 ~]# ​ 1.2 创建名称空间 [root@node-exporter41 ~]# ctr ns c ysl-linux [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr ns ls NAME LABELS ysl-linux [root@node-exporter41 ~]# ​ ​ 1.3 删除名称空间 [root@node-exporter41 ~]# ctr ns rm ysl-linux ysl-linux [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr ns ls NAME LABELS [root@node-exporter41 ~]# ​ 温馨提示: 删除的名称空间必须为空,否则无法删除! ​ 2.镜像管理 2.1 拉取镜像到指定的名称空间 [root@node-exporter41 ~]# ctr image pull registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1 registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1: resolved |++++++++++++++++++++++++++++++++++++++| manifest-sha256:3bee216f250cfd2dbda1744d6849e27118845b8f4d55dda3ca3c6c1227cc2e5c: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:ff9c6add3f30f658b4f44732bef1dd44b6d3276853bba31b0babc247f3eba0dc: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:2dd61e30a21aeb966df205382a40dcbcf45af975cc0cb836d555b9cd0ad760f5: done |++++++++++++++++++++++++++++++++++++++| config-sha256:f28fd43be4ad41fc768dcc3629f8479d1443df01ada10ac9a771314e4fdef599: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:dcc43d9a97b44cf3b3619f2c185f249891b108ab99abcc58b19a82879b00b24b: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:5758d4e389a3f662e94a85fb76143dbe338b64f8d2a65f45536a9663b05305ad: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:5dcfac0f2f9ca3131599455f5e79298202c7e1b5e0eb732498b34e9fe4cb1173: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:2c6e86e57dfd729d8240ceab7c18bd1e5dd006b079837116bc1c3e1de5e1971a: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:51d66f6290217acbf83f15bc23a88338819673445804b1461b2c41d4d0c22f94: done |++++++++++++++++++++++++++++++++++++++| elapsed: 3.2 s total: 8.9 Mi (2.8 MiB/s) unpacking linux/amd64 sha256:3bee216f250cfd2dbda1744d6849e27118845b8f4d55dda3ca3c6c1227cc2e5c... done: 409.869867ms [root@node-exporter41 ~]# ctr ns ls NAME LABELS default [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr -n default i ls REF TYPE DIGEST SIZE PLATFORMS LABELS registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1 application/vnd.docker.distribution.manifest.v2+json sha256:3bee216f250cfd2dbda1744d6849e27118845b8f4d55dda3ca3c6c1227cc2e5c 9.6 MiB linux/amd64 - [root@node-exporter41 ~]# [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr i ls REF TYPE DIGEST SIZE PLATFORMS LABELS registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v1 application/vnd.docker.distribution.manifest.v2+json sha256:3bee216f250cfd2dbda1744d6849e27118845b8f4d55dda3ca3c6c1227cc2e5c 9.6 MiB linux/amd64 - [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr -n ysl-ysl image pull registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2: resolved |++++++++++++++++++++++++++++++++++++++| manifest-sha256:3ac38ee6161e11f2341eda32be95dcc6746f587880f923d2d24a54c3a525227e: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:b07c4abce9ebb6b450f348265b5d82616ca5aa7c1a975f124f97df4038275068: done |++++++++++++++++++++++++++++++++++++++| config-sha256:d65adc8a2f327feacad77611d31986381b47f3c0a1ef8ff2488d781e19c60901: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:5758d4e389a3f662e94a85fb76143dbe338b64f8d2a65f45536a9663b05305ad: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:51d66f6290217acbf83f15bc23a88338819673445804b1461b2c41d4d0c22f94: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:ff9c6add3f30f658b4f44732bef1dd44b6d3276853bba31b0babc247f3eba0dc: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:dcc43d9a97b44cf3b3619f2c185f249891b108ab99abcc58b19a82879b00b24b: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:5dcfac0f2f9ca3131599455f5e79298202c7e1b5e0eb732498b34e9fe4cb1173: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:2c6e86e57dfd729d8240ceab7c18bd1e5dd006b079837116bc1c3e1de5e1971a: done |++++++++++++++++++++++++++++++++++++++| elapsed: 0.5 s total: 0.0 B (0.0 B/s) unpacking linux/amd64 sha256:3ac38ee6161e11f2341eda32be95dcc6746f587880f923d2d24a54c3a525227e... done: 372.10925ms [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr ns ls NAME LABELS default ysl-ysl [root@node-exporter41 ~]# [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr -n ysl-ysl images ls REF TYPE DIGEST SIZE PLATFORMS LABELS registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 application/vnd.docker.distribution.manifest.v2+json sha256:3ac38ee6161e11f2341eda32be95dcc6746f587880f923d2d24a54c3a525227e 9.6 MiB linux/amd64 - [root@node-exporter41 ~]# ​ ​ ​ ​ ​ ​ 2.2 删除镜像 [root@node-exporter41 ~]# ctr -n ysl-ysl images ls REF TYPE DIGEST SIZE PLATFORMS LABELS registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 application/vnd.docker.distribution.manifest.v2+json sha256:3ac38ee6161e11f2341eda32be95dcc6746f587880f923d2d24a54c3a525227e 9.6 MiB linux/amd64 - [root@node-exporter41 ~]# [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr -n ysl-ysl i rm registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr -n ysl-ysl images ls REF TYPE DIGEST SIZE PLATFORMS LABELS [root@node-exporter41 ~]# ​ ​ 3.容器管理 3.1 运行一个容器 [root@node-exporter41 ~]# ctr run registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 haha /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh /docker-entrypoint.sh: Configuration complete; ready for start up 2025/02/26 03:00:32 [notice] 1#1: using the "epoll" event method 2025/02/26 03:00:32 [notice] 1#1: nginx/1.20.1 2025/02/26 03:00:32 [notice] 1#1: built by gcc 10.2.1 20201203 (Alpine 10.2.1_pre1) 2025/02/26 03:00:32 [notice] 1#1: OS: Linux 5.15.0-133-generic 2025/02/26 03:00:32 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1024:1024 2025/02/26 03:00:32 [notice] 1#1: start worker processes 2025/02/26 03:00:32 [notice] 1#1: start worker process 32 2025/02/26 03:00:32 [notice] 1#1: start worker process 33 2025/02/26 03:00:32 [notice] 1#1: start worker process 34 2025/02/26 03:00:32 [notice] 1#1: start worker process 35 ... ​ 3.2 查看容器列表 [root@node-exporter41 ~]# ctr c ls CONTAINER IMAGE RUNTIME haha registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 io.containerd.runc.v2 [root@node-exporter41 ~]# ​ ​ 3.3 查看正在运行的容器ID [root@node-exporter41 ~]# ctr task ls TASK PID STATUS haha 1941 RUNNING [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr t ls TASK PID STATUS haha 1941 RUNNING [root@node-exporter41 ~]# ​ ​ 3.4 连接正在运行的容器 [root@node-exporter41 ~]# ctr t exec -t --exec-id $RANDOM haha sh / # / # ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) ​ / # ​ ​ ​ ​ 温馨提示: containerd本身并不提供网络,只负责容器的生命周期。 将来网络部分交给专门的CNI插件提供。 3.5 杀死一个正在运行的容器 [root@node-exporter41 ~]# ctr t ls TASK PID STATUS haha 1941 RUNNING [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr t kill haha [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr t ls TASK PID STATUS [root@node-exporter41 ~]# ​ ​ ​ 3.6 删除容器 [root@node-exporter41 ~]# ctr c ls CONTAINER IMAGE RUNTIME haha registry.cn-hangzhou.aliyuncs.com/yangsenlin-k8s/apps:v2 io.containerd.runc.v2 [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr c rm haha [root@node-exporter41 ~]# [root@node-exporter41 ~]# ctr c ls CONTAINER IMAGE RUNTIME [root@node-exporter41 ~]# ​ ​ 更多containerd学习资料推荐: https://www.cnblogs.com/yangsenlin/p/18030527 https://www.cnblogs.com/yangsenlin/p/18058010 ​ ​ - 安装K8S程序 1.下载K8S程序包 wget https://dl.k8s.io/v1.31.6/kubernetes-server-linux-amd64.tar.gz ​ ​ ​ ​ 2.解压指定的软件包 [root@node-exporter41 ~]# tar xf kubernetes-server-linux-amd64-v1.31.6.tar.gz --strip-components=3 -C /usr/local/bin kubernetes/server/bin/kube{let,ctl,-apiserver,-controller-manager,-scheduler,-proxy} [root@node-exporter41 ~]# [root@node-exporter41 ~]# ll /usr/local/bin/kube* -rwxr-xr-x 1 root root 90542232 Feb 13 05:45 /usr/local/bin/kube-apiserver* -rwxr-xr-x 1 root root 84754584 Feb 13 05:45 /usr/local/bin/kube-controller-manager* -rwxr-xr-x 1 root root 56381592 Feb 13 05:45 /usr/local/bin/kubectl* -rwxr-xr-x 1 root root 76919128 Feb 13 05:45 /usr/local/bin/kubelet* -rwxr-xr-x 1 root root 64417944 Feb 13 05:45 /usr/local/bin/kube-proxy* -rwxr-xr-x 1 root root 63725720 Feb 13 05:45 /usr/local/bin/kube-scheduler* [root@node-exporter41 ~]# ​ 3.查看kubelet的版本 [root@node-exporter41 ~]# kubelet --version Kubernetes v1.31.6 [root@node-exporter41 ~]# ​ ​ 4.分发软件包 [root@node-exporter41 ~]# for i in `ls -1 /usr/local/bin/kube*`;do data_rsync.sh $i ;done ​ ​ ​ - 生成k8s组件相关证书 1.生成证书的CSR文件: 证书签发请求文件,配置了一些域名,公司,单位 [root@node-exporter41 pki]# mkdir -pv /ysl/certs/{pki,kubernetes} [root@node-exporter41 pki]# cat > k8s-ca-csr.json < k8s-ca-config.json < apiserver-csr.json < front-proxy-ca-csr.json < front-proxy-client-csr.json < controller-manager-csr.json < scheduler-csr.json < admin-csr.json < /etc/haproxy/haproxy.cfg <<'EOF' global maxconn 2000 ulimit-n 16384 log 127.0.0.1 local0 err stats timeout 30s ​ defaults log global mode http option httplog timeout connect 5000 timeout client 50000 timeout server 50000 timeout http-request 15s timeout http-keep-alive 15s ​ frontend monitor-haproxy bind *:9999 mode http option httplog monitor-uri /ruok ​ frontend yangsenlin-k8s bind 0.0.0.0:8443 bind 127.0.0.1:8443 mode tcp option tcplog tcp-request inspect-delay 5s default_backend yangsenlin-k8s ​ backend yangsenlin-k8s mode tcp option tcplog option tcp-check balance roundrobin default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100 server node-exporter41 10.0.0.41:6443 check server node-exporter42 10.0.0.42:6443 check server node-exporter43 10.0.0.43:6443 check EOF ​ 3.所有master节点配置keepalived 温馨提示: - 注意"interface"字段为你的物理网卡的名称,如果你的网卡是ens33,请将"eth0"修改为"ens33"哟; - 注意"mcast_src_ip"各master节点的配置均不相同,修改根据实际环境进行修改哟; - 注意"virtual_ipaddress"指定的是负载均衡器的VIP地址,这个地址也要和kubeconfig文件的Apiserver地址要一致哟; - 注意"script"字段的脚本用于检测后端的apiServer是否健康; - 注意"router_id"字段为节点ip,master每个节点配置自己的IP 具体实操: 3.1."node-exporter41"节点创建配置文件 [root@node-exporter41 ~]# ifconfig eth0: flags=4163 mtu 1500
inet 10.0.0.41 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20c:29ff:fec9:e90d prefixlen 64 scopeid 0x20 ether 00:0c:29:c9:e9:0d txqueuelen 1000 (Ethernet)
RX packets 521248 bytes 475366392 (475.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 438247 bytes 335442241 (335.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0


[root@node-exporter41 ~]#
[root@node-exporter41 ~]# cat > /etc/keepalived/keepalived.conf <<'EOF' ! Configuration File for keepalived global_defs { router_id 10.0.0.41 } vrrp_script chk_nginx { script "/etc/keepalived/check_port.sh 8443" interval 2 weight -20 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 251 priority 100 advert_int 1 mcast_src_ip 10.0.0.41 nopreempt authentication { auth_type PASS auth_pass yangsenlin_k8s } track_script { chk_nginx } virtual_ipaddress { 10.0.0.240 } } EOF ​ ​ 3.2."node-exporter42"节点创建配置文件 [root@node-exporter42 ~]# ifconfig eth0: flags=4163 mtu 1500
inet 10.0.0.42 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20c:29ff:fed2:6aeb prefixlen 64 scopeid 0x20 ether 00:0c:29:d2:6a:eb txqueuelen 1000 (Ethernet)
RX packets 438380 bytes 196700829 (196.7 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 342527 bytes 42962873 (42.9 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0


[root@node-exporter42 ~]#
[root@node-exporter42 ~]# cat > /etc/keepalived/keepalived.conf < mtu 1500
inet 10.0.0.43 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20c:29ff:fe02:429e prefixlen 64 scopeid 0x20 ether 00:0c:29:02:42:9e txqueuelen 1000 (Ethernet)
RX packets 321281 bytes 184936745 (184.9 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 220950 bytes 31132382 (31.1 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0




[root@node-exporter43 ~]#
[root@node-exporter43 ~]# cat > /etc/keepalived/keepalived.conf < /etc/keepalived/check_port.sh <<'EOF' #!/bin/bash ​ CHK_PORT=$1 if [ -n "$CHK_PORT" ];then PORT_PROCESS=`ss -lt|grep $CHK_PORT|wc -l` if [ $PORT_PROCESS -eq 0 ];then echo "Port $CHK_PORT Is Not Used,End." systemctl stop keepalived fi else echo "Check Port Cant Be Empty!" fi EOF chmod +x /etc/keepalived/check_port.sh ​ ​ ​ 4.验证haproxy服务并验证 4.1 所有节点启动haproxy服务 systemctl enable --now haproxy systemctl restart haproxy systemctl status haproxy ss -ntl | egrep "8443|9999" ​ ​ ​ 4.2 基于webUI进行验证 [root@node-exporter43 ~]# curl http://10.0.0.41:9999/ruok

200 OK

Service ready.

[root@node-exporter43 ~]#
[root@node-exporter43 ~]# curl http://10.0.0.42:9999/ruok

200 OK

Service ready.

[root@node-exporter43 ~]#
[root@node-exporter43 ~]# curl http://10.0.0.43:9999/ruok

200 OK

Service ready.

[root@node-exporter43 ~]#

5.启动keepalived服务并验证
5.1.所有节点启动keepalived服务
systemctl daemon-reload
systemctl enable –now keepalived
systemctl status keepalived

5.2 验证服务是否正常
[root@node-exporter43 ~]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:02:42:9e brd ff:ff:ff:ff:ff:ff
altname enp2s1
altname ens33
inet 10.0.0.43/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.0.0.240/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe02:429e/64 scope link
valid_lft forever preferred_lft forever
3: tunl0@NONE: mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
[root@node-exporter43 ~]#

5.3 基于telnet验证haporxy是否正常
[root@node-exporter41 ~]# telnet 10.0.0.240 8443
Tryslg 10.0.0.240…
Connected to 10.0.0.240.
Escape character is ‘^]’.
Connection closed by foreign host.
[root@node-exporter41 ~]#
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# ping 10.0.0.240 -c 3
PING 10.0.0.240 (10.0.0.240) 56(84) bytes of data.
64 bytes from 10.0.0.240: icmp_seq=1 ttl=64 time=0.218 ms
64 bytes from 10.0.0.240: icmp_seq=2 ttl=64 time=0.177 ms
64 bytes from 10.0.0.240: icmp_seq=3 ttl=64 time=0.169 ms

— 10.0.0.240 ping statistics —
3 packets transmitted, 3 received, 0% packet loss, time 2037ms
rtt min/avg/max/mdev = 0.169/0.188/0.218/0.021 ms
[root@node-exporter41 ~]#


5.4 将VIP节点的haproxy停止
[root@node-exporter43 ~]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:02:42:9e brd ff:ff:ff:ff:ff:ff
altname enp2s1
altname ens33
inet 10.0.0.43/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.0.0.240/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe02:429e/64 scope link
valid_lft forever preferred_lft forever
3: tunl0@NONE: mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
[root@node-exporter43 ~]#
[root@node-exporter43 ~]#
[root@node-exporter43 ~]# systemctl status haproxy.service
● haproxy.service – HAProxy Load Balancer
Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2025-02-26 12:18:14 CST; 5min ago
Docs: man:haproxy(1)
file:/usr/share/doc/haproxy/configuration.txt.gz
Process: 3389 ExecStartPre=/usr/sbin/haproxy -Ws -f $CONFIG -c -q $EXTRAOPTS (code=exited, status=0/SUCCESS)
Main PID: 3391 (haproxy)
Tasks: 3 (limit: 9350)
Memory: 4.0M
CPU: 57ms
CGroup: /system.slice/haproxy.service
├─3391 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
└─3393 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock

Feb 26 12:18:13 node-exporter43 systemd[1]: Starting HAProxy Load Balancer…
Feb 26 12:18:14 node-exporter43 haproxy[3391]: [WARNING] (3391) : parsing [/etc/haproxy/haproxy.cfg:33] : backend ‘yangsenlin-k8s’ :>
Feb 26 12:18:14 node-exporter43 haproxy[3391]: [NOTICE] (3391) : New worker #1 (3393) forked
Feb 26 12:18:14 node-exporter43 systemd[1]: Started HAProxy Load Balancer.
Feb 26 12:18:14 node-exporter43 haproxy[3393]: [WARNING] (3393) : Server yangsenlin-k8s/node-exporter41 is DOWN, reason: Layer4 conn>
Feb 26 12:18:17 node-exporter43 haproxy[3393]: [WARNING] (3393) : Server yangsenlin-k8s/node-exporter42 is DOWN, reason: Layer4 conn>
Feb 26 12:18:20 node-exporter43 haproxy[3393]: [WARNING] (3393) : Server yangsenlin-k8s/node-exporter43 is DOWN, reason: Layer4 conn>
Feb 26 12:18:20 node-exporter43 haproxy[3393]: [NOTICE] (3393) : haproxy version is 2.4.24-0ubuntu0.22.04.1
Feb 26 12:18:20 node-exporter43 haproxy[3393]: [NOTICE] (3393) : path to executable is /usr/sbin/haproxy
Feb 26 12:18:20 node-exporter43 haproxy[3393]: [ALERT] (3393) : backend ‘yangsenlin-k8s’ has no server available!
[root@node-exporter43 ~]#
[root@node-exporter43 ~]#
[root@node-exporter43 ~]# systemctl stop haproxy.service # 停止服务
[root@node-exporter43 ~]#
[root@node-exporter43 ~]# systemctl status haproxy.service
○ haproxy.service – HAProxy Load Balancer
Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Wed 2025-02-26 12:24:12 CST; 34s ago
Docs: man:haproxy(1)
file:/usr/share/doc/haproxy/configuration.txt.gz
Process: 3389 ExecStartPre=/usr/sbin/haproxy -Ws -f $CONFIG -c -q $EXTRAOPTS (code=exited, status=0/SUCCESS)
Process: 3391 ExecStart=/usr/sbin/haproxy -Ws -f $CONFIG -p $PIDFILE $EXTRAOPTS (code=exited, status=0/SUCCESS)
Main PID: 3391 (code=exited, status=0/SUCCESS)
CPU: 60ms

Feb 26 12:18:20 node-exporter43 haproxy[3393]: [NOTICE] (3393) : path to executable is /usr/sbin/haproxy
Feb 26 12:18:20 node-exporter43 haproxy[3393]: [ALERT] (3393) : backend ‘yangsenlin-k8s’ has no server available!
Feb 26 12:24:12 node-exporter43 systemd[1]: Stopping HAProxy Load Balancer…
Feb 26 12:24:12 node-exporter43 haproxy[3391]: [WARNING] (3391) : Exiting Master process…
Feb 26 12:24:12 node-exporter43 haproxy[3391]: [NOTICE] (3391) : haproxy version is 2.4.24-0ubuntu0.22.04.1
Feb 26 12:24:12 node-exporter43 haproxy[3391]: [NOTICE] (3391) : path to executable is /usr/sbin/haproxy
Feb 26 12:24:12 node-exporter43 haproxy[3391]: [ALERT] (3391) : Current worker #1 (3393) exited with code 143 (Terminated)
Feb 26 12:24:12 node-exporter43 haproxy[3391]: [WARNING] (3391) : All workers exited. Exiting… (0)
Feb 26 12:24:12 node-exporter43 systemd[1]: haproxy.service: Deactivated successfully.
Feb 26 12:24:12 node-exporter43 systemd[1]: Stopped HAProxy Load Balancer.
[root@node-exporter43 ~]#
[root@node-exporter43 ~]#
[root@node-exporter43 ~]# systemctl status keepalived
○ keepalived.service – Keepalive Daemon (LVS and VRRP)
Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Wed 2025-02-26 12:24:13 CST; 36s ago
Process: 3409 ExecStart=/usr/sbin/keepalived –dont-fork $DAEMON_ARGS (code=exited, status=0/SUCCESS)
Main PID: 3409 (code=exited, status=0/SUCCESS)
CPU: 573ms

Feb 26 12:20:44 node-exporter43 Keepalived_vrrp[3410]: VRRP_Script(chk_nginx) succeeded
Feb 26 12:20:48 node-exporter43 Keepalived_vrrp[3410]: (VI_1) Entering MASTER STATE
Feb 26 12:24:12 node-exporter43 systemd[1]: Stopping Keepalive Daemon (LVS and VRRP)…
Feb 26 12:24:12 node-exporter43 Keepalived[3409]: Stopping
Feb 26 12:24:12 node-exporter43 Keepalived_vrrp[3410]: VRRP_Script(chk_nginx) failed (due to signal 15)
Feb 26 12:24:12 node-exporter43 Keepalived_vrrp[3410]: (VI_1) Changing effective priority from 100 to 80
Feb 26 12:24:13 node-exporter43 Keepalived_vrrp[3410]: Stopped
Feb 26 12:24:13 node-exporter43 Keepalived[3409]: Stopped Keepalived v2.2.4 (08/21,2021)
Feb 26 12:24:13 node-exporter43 systemd[1]: keepalived.service: Deactivated successfully.
Feb 26 12:24:13 node-exporter43 systemd[1]: Stopped Keepalive Daemon (LVS and VRRP).
[root@node-exporter43 ~]#
[root@node-exporter43 ~]#
[root@node-exporter43 ~]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:02:42:9e brd ff:ff:ff:ff:ff:ff
altname enp2s1
altname ens33
inet 10.0.0.43/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe02:429e/64 scope link
valid_lft forever preferred_lft forever
3: tunl0@NONE: mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
[root@node-exporter43 ~]#

5.5 观察VIP是否漂移
[root@node-exporter42 ~]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:d2:6a:eb brd ff:ff:ff:ff:ff:ff
altname enp2s1
altname ens33
inet 10.0.0.42/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.0.0.240/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fed2:6aeb/64 scope link
valid_lft forever preferred_lft forever
3: tunl0@NONE: mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
[root@node-exporter42 ~]#

5.6 启动之前的haproxy,发现VIP并不会飘逸回来
[root@node-exporter43 ~]# systemctl start haproxy.service keepalived.service
[root@node-exporter43 ~]#
[root@node-exporter43 ~]#
[root@node-exporter43 ~]# systemctl status haproxy.service keepalived.service
● haproxy.service – HAProxy Load Balancer
Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2025-02-26 12:26:10 CST; 27s ago
Docs: man:haproxy(1)
file:/usr/share/doc/haproxy/configuration.txt.gz
Process: 4011 ExecStartPre=/usr/sbin/haproxy -Ws -f $CONFIG -c -q $EXTRAOPTS (code=exited, status=0/SUCCESS)
Main PID: 4013 (haproxy)
Tasks: 3 (limit: 9350)
Memory: 3.9M
CPU: 17ms
CGroup: /system.slice/haproxy.service
├─4013 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
└─4015 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock

Feb 26 12:26:10 node-exporter43 systemd[1]: Starting HAProxy Load Balancer…
Feb 26 12:26:10 node-exporter43 haproxy[4013]: [WARNING] (4013) : parsing [/etc/haproxy/haproxy.cfg:33] : backend ‘yangsenlin-k8s’ :>
Feb 26 12:26:10 node-exporter43 haproxy[4013]: [NOTICE] (4013) : New worker #1 (4015) forked
Feb 26 12:26:10 node-exporter43 systemd[1]: Started HAProxy Load Balancer.
Feb 26 12:26:10 node-exporter43 haproxy[4015]: [WARNING] (4015) : Server yangsenlin-k8s/node-exporter41 is DOWN, reason: Layer4 conn>
Feb 26 12:26:14 node-exporter43 haproxy[4015]: [WARNING] (4015) : Server yangsenlin-k8s/node-exporter42 is DOWN, reason: Layer4 conn>
Feb 26 12:26:17 node-exporter43 haproxy[4015]: [WARNING] (4015) : Server yangsenlin-k8s/node-exporter43 is DOWN, reason: Layer4 conn>
Feb 26 12:26:17 node-exporter43 haproxy[4015]: [NOTICE] (4015) : haproxy version is 2.4.24-0ubuntu0.22.04.1
Feb 26 12:26:17 node-exporter43 haproxy[4015]: [NOTICE] (4015) : path to executable is /usr/sbin/haproxy
Feb 26 12:26:17 node-exporter43 haproxy[4015]: [ALERT] (4015) : backend ‘yangsenlin-k8s’ has no server available!

● keepalived.service – Keepalive Daemon (LVS and VRRP)
Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2025-02-26 12:26:15 CST; 23s ago
Main PID: 4050 (keepalived)
[root@node-exporter43 ~]#
[root@node-exporter43 ~]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:02:42:9e brd ff:ff:ff:ff:ff:ff
altname enp2s1
altname ens33
inet 10.0.0.43/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe02:429e/64 scope link
valid_lft forever preferred_lft forever
3: tunl0@NONE: mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
[root@node-exporter43 ~]#




– 部署ApiServer组件
1 node-exporter41节点启动ApiServer
温馨提示:
– “–advertise-address”是对应的master节点的IP地址;
– “–service-cluster-ip-range”对应的是svc的网段
– “–service-node-port-range”对应的是svc的NodePort端口范围;
– “–etcd-servers”指定的是etcd集群地址

配置文件参考链接:
https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-apiserver/


具体实操:
1.1 创建node-exporter41节点的配置文件
cat > /usr/lib/systemd/system/kube-apiserver.service << 'EOF' [Unit] Description=forest ysl's Kubernetes API Server Documentation=https://github.com/kubernetes/kubernetes After=network.target ​ [Service] ExecStart=/usr/local/bin/kube-apiserver \ --v=2 \ --bind-address=0.0.0.0 \ --secure-port=6443 \ --allow_privileged=true \ --advertise-address=10.0.0.41 \ --service-cluster-ip-range=10.200.0.0/16 \ --service-node-port-range=3000-50000 \ --etcd-servers=https://10.0.0.41:2379,https://10.0.0.42:2379,https://10.0.0.43:2379 \ --etcd-cafile=/ysl/certs/etcd/etcd-ca.pem \ --etcd-certfile=/ysl/certs/etcd/etcd-server.pem \ --etcd-keyfile=/ysl/certs/etcd/etcd-server-key.pem \ --client-ca-file=/ysl/certs/kubernetes/k8s-ca.pem \ --tls-cert-file=/ysl/certs/kubernetes/apiserver.pem \ --tls-private-key-file=/ysl/certs/kubernetes/apiserver-key.pem \ --kubelet-client-certificate=/ysl/certs/kubernetes/apiserver.pem \ --kubelet-client-key=/ysl/certs/kubernetes/apiserver-key.pem \ --service-account-key-file=/ysl/certs/kubernetes/sa.pub \ --service-account-signing-key-file=/ysl/certs/kubernetes/sa.key \ --service-account-issuer=https://kubernetes.default.svc.ysl.com \ --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \ --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \ --authorization-mode=Node,RBAC \ --enable-bootstrap-token-auth=true \ --requestheader-client-ca-file=/ysl/certs/kubernetes/front-proxy-ca.pem \ --proxy-client-cert-file=/ysl/certs/kubernetes/front-proxy-client.pem \ --proxy-client-key-file=/ysl/certs/kubernetes/front-proxy-client-key.pem \ --requestheader-allowed-names=aggregator \ --requestheader-group-headers=X-Remote-Group \ --requestheader-extra-headers-prefix=X-Remote-Extra- \ --requestheader-username-headers=X-Remote-User ​ Restart=on-failure RestartSec=10s LimitNOFILE=65535 ​ [Install] WantedBy=multi-user.target EOF ​ ​ 1.2 启动服务 systemctl daemon-reload && systemctl enable --now kube-apiserver systemctl status kube-apiserver ss -ntl | grep 6443 ​ ​ ​ ​ 2 node-exporter42节点启动ApiServer 温馨提示: - "--advertise-address"是对应的master节点的IP地址; - "--service-cluster-ip-range"对应的是svc的网段 - "--service-node-port-range"对应的是svc的NodePort端口范围; - "--etcd-servers"指定的是etcd集群地址 ​ ​ 具体实操: 2.1 创建node-exporter42节点的配置文件 cat > /usr/lib/systemd/system/kube-apiserver.service << 'EOF' [Unit] Description=forest ysl's Kubernetes API Server Documentation=https://github.com/kubernetes/kubernetes After=network.target ​ [Service] ExecStart=/usr/local/bin/kube-apiserver \ --v=2 \ --bind-address=0.0.0.0 \ --secure-port=6443 \ --advertise-address=10.0.0.42 \ --service-cluster-ip-range=10.200.0.0/16 \ --service-node-port-range=3000-50000 \ --etcd-servers=https://10.0.0.41:2379,https://10.0.0.42:2379,https://10.0.0.43:2379 \ --etcd-cafile=/ysl/certs/etcd/etcd-ca.pem \ --etcd-certfile=/ysl/certs/etcd/etcd-server.pem \ --etcd-keyfile=/ysl/certs/etcd/etcd-server-key.pem \ --client-ca-file=/ysl/certs/kubernetes/k8s-ca.pem \ --tls-cert-file=/ysl/certs/kubernetes/apiserver.pem \ --tls-private-key-file=/ysl/certs/kubernetes/apiserver-key.pem \ --kubelet-client-certificate=/ysl/certs/kubernetes/apiserver.pem \ --kubelet-client-key=/ysl/certs/kubernetes/apiserver-key.pem \ --service-account-key-file=/ysl/certs/kubernetes/sa.pub \ --service-account-signing-key-file=/ysl/certs/kubernetes/sa.key \ --service-account-issuer=https://kubernetes.default.svc.ysl.com \ --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \ --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \ --authorization-mode=Node,RBAC \ --enable-bootstrap-token-auth=true \ --requestheader-client-ca-file=/ysl/certs/kubernetes/front-proxy-ca.pem \ --proxy-client-cert-file=/ysl/certs/kubernetes/front-proxy-client.pem \ --proxy-client-key-file=/ysl/certs/kubernetes/front-proxy-client-key.pem \ --requestheader-allowed-names=aggregator \ --requestheader-group-headers=X-Remote-Group \ --requestheader-extra-headers-prefix=X-Remote-Extra- \ --requestheader-username-headers=X-Remote-User ​ Restart=on-failure RestartSec=10s LimitNOFILE=65535 ​ [Install] WantedBy=multi-user.target EOF ​ 2.2 启动服务 systemctl daemon-reload && systemctl enable --now kube-apiserver systemctl status kube-apiserver ss -ntl | grep 6443 ​ ​ ​ 3.k8s-master03节点启动ApiServer 温馨提示: - "--advertise-address"是对应的master节点的IP地址; - "--service-cluster-ip-range"对应的是svc的网段 - "--service-node-port-range"对应的是svc的NodePort端口范围; - "--etcd-servers"指定的是etcd集群地址 ​ ​ 具体实操: 3.1 创建k8s-master03节点的配置文件 cat > /usr/lib/systemd/system/kube-apiserver.service << 'EOF' [Unit] Description=forest ysl's Kubernetes API Server Documentation=https://github.com/kubernetes/kubernetes After=network.target ​ [Service] ExecStart=/usr/local/bin/kube-apiserver \ --v=2 \ --bind-address=0.0.0.0 \ --secure-port=6443 \ --advertise-address=10.0.0.43 \ --service-cluster-ip-range=10.200.0.0/16 \ --service-node-port-range=3000-50000 \ --etcd-servers=https://10.0.0.41:2379,https://10.0.0.42:2379,https://10.0.0.43:2379 \ --etcd-cafile=/ysl/certs/etcd/etcd-ca.pem \ --etcd-certfile=/ysl/certs/etcd/etcd-server.pem \ --etcd-keyfile=/ysl/certs/etcd/etcd-server-key.pem \ --client-ca-file=/ysl/certs/kubernetes/k8s-ca.pem \ --tls-cert-file=/ysl/certs/kubernetes/apiserver.pem \ --tls-private-key-file=/ysl/certs/kubernetes/apiserver-key.pem \ --kubelet-client-certificate=/ysl/certs/kubernetes/apiserver.pem \ --kubelet-client-key=/ysl/certs/kubernetes/apiserver-key.pem \ --service-account-key-file=/ysl/certs/kubernetes/sa.pub \ --service-account-signing-key-file=/ysl/certs/kubernetes/sa.key \ --service-account-issuer=https://kubernetes.default.svc.ysl.com \ --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \ --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \ --authorization-mode=Node,RBAC \ --enable-bootstrap-token-auth=true \ --requestheader-client-ca-file=/ysl/certs/kubernetes/front-proxy-ca.pem \ --proxy-client-cert-file=/ysl/certs/kubernetes/front-proxy-client.pem \ --proxy-client-key-file=/ysl/certs/kubernetes/front-proxy-client-key.pem \ --requestheader-allowed-names=aggregator \ --requestheader-group-headers=X-Remote-Group \ --requestheader-extra-headers-prefix=X-Remote-Extra- \ --requestheader-username-headers=X-Remote-User ​ Restart=on-failure RestartSec=10s LimitNOFILE=65535 ​ [Install] WantedBy=multi-user.target EOF ​ ​ 3.2 启动服务 systemctl daemon-reload && systemctl enable --now kube-apiserver systemctl status kube-apiserver ss -ntl | grep 6443 ​ ​ ​ - 部署ControlerManager组件 1 所有节点创建配置文件 温馨提示: ​ - "--cluster-cidr"是Pod的网段地址,我们可以自行修改。 ​ 配置文件参考链接: https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-controller-manager/ ​ 所有节点的controller-manager组件配置文件相同: (前提是证书文件存放的位置也要相同哟!) cat > /usr/lib/systemd/system/kube-controller-manager.service << 'EOF' [Unit] Description=forest ysl's Kubernetes Controller Manager Documentation=https://github.com/kubernetes/kubernetes After=network.target ​ [Service] ExecStart=/usr/local/bin/kube-controller-manager \ --v=2 \ --root-ca-file=/ysl/certs/kubernetes/k8s-ca.pem \ --cluster-signing-cert-file=/ysl/certs/kubernetes/k8s-ca.pem \ --cluster-signing-key-file=/ysl/certs/kubernetes/k8s-ca-key.pem \ --service-account-private-key-file=/ysl/certs/kubernetes/sa.key \ --kubeconfig=/ysl/certs/kubeconfig/kube-controller-manager.kubeconfig \ --leader-elect=true \ --use-service-account-credentials=true \ --node-monitor-grace-period=40s \ --node-monitor-period=5s \ --controllers=*,bootstrapsigner,tokencleaner \ --allocate-node-cidrs=true \ --cluster-cidr=10.100.0.0/16 \ --requestheader-client-ca-file=/ysl/certs/kubernetes/front-proxy-ca.pem \ --node-cidr-mask-size=24 Restart=always RestartSec=10s ​ [Install] WantedBy=multi-user.target EOF ​ ​ 2.启动controller-manager服务 systemctl daemon-reload systemctl enable --now kube-controller-manager systemctl status kube-controller-manager ss -ntl | grep 10257 ​ ​ ​ - 部署Scheduler组件 1 所有节点创建配置文件 配置文件参考链接: https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-scheduler/ ​ 所有节点的controller-manager组件配置文件相同: (前提是证书文件存放的位置也要相同哟!) cat > /usr/lib/systemd/system/kube-scheduler.service <<'EOF' [Unit] Description=forest ysl's Kubernetes Scheduler Documentation=https://github.com/kubernetes/kubernetes After=network.target ​ [Service] ExecStart=/usr/local/bin/kube-scheduler \ --v=2 \ --leader-elect=true \ --kubeconfig=/ysl/certs/kubeconfig/kube-scheduler.kubeconfig ​ Restart=always RestartSec=10s ​ [Install] WantedBy=multi-user.target EOF ​ ​ 2.启动scheduler服务 systemctl daemon-reload systemctl enable --now kube-scheduler systemctl status kube-scheduler ss -ntl | grep 10259 ​ ​ ​ - 创建Bootstrapping自动颁发kubelet证书配置 1.创建bootstrap-kubelet.kubeconfig文件 温馨提示: - "--server"指向的是负载均衡器的IP地址,由负载均衡器对master节点进行反向代理哟。 - "--token"也可以自定义,但也要同时修改"bootstrap"的Secret的"token-id"和"token-secret"对应值哟; ​ ​ 1.1 设置集群 kubectl config set-cluster yangsenlin-k8s \ --certificate-authority=/ysl/certs/kubernetes/k8s-ca.pem \ --embed-certs=true \ --server=https://10.0.0.240:8443 \ --kubeconfig=/ysl/certs/kubeconfig/bootstrap-kubelet.kubeconfig ​ 1.2 创建用户 kubectl config set-credentials tls-bootstrap-token-user \ --token=ysl.forestyangsenlin \ --kubeconfig=/ysl/certs/kubeconfig/bootstrap-kubelet.kubeconfig 1.3 将集群和用户进行绑定 kubectl config set-context tls-bootstrap-token-user@kubernetes \ --cluster=yangsenlin-k8s \ --user=tls-bootstrap-token-user \ --kubeconfig=/ysl/certs/kubeconfig/bootstrap-kubelet.kubeconfig 1.4.配置默认的上下文 kubectl config use-context tls-bootstrap-token-user@kubernetes \ --kubeconfig=/ysl/certs/kubeconfig/bootstrap-kubelet.kubeconfig ​ 2.所有master节点拷贝管理证书 温馨提示: 下面的操作我以k8s-master01为案例来操作的,实际上你可以使用所有的master节点完成下面的操作哟~ 2.1 所有master都拷贝管理员的证书文件 mkdir -p /root/.kube cp /ysl/certs/kubeconfig/kube-admin.kubeconfig /root/.kube/config ​ ​ 2.2 查看master组件,该组件官方在1.19+版本开始弃用,但是在1.30.2依旧没有移除哟~ [root@node-exporter41 ~]# kubectl get cs Warning: v1 ComponentStatus is deprecated in v1.19+ NAME STATUS MESSAGE ERROR controller-manager Healthy ok scheduler Healthy ok etcd-0 Healthy ok [root@node-exporter41 ~]# ​ ​ 2.3 查看集群状态,如果未来cs组件移除了也没关系,我们可以使用"cluster-info"子命令查看集群状态 [root@node-exporter41 ~]# kubectl cluster-info Kubernetes control plane is running at https://10.0.0.240:8443 ​ To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. [root@node-exporter41 ~]# [root@node-exporter41 ~]# [root@node-exporter41 ~]# kubectl cluster-info dump { "kind": "NodeList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "EventList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [ { "metadata": { "name": "kube-controller-manager.1827aef9ccc7bf38", "namespace": "kube-system", "uid": "73e095cf-7e1c-44dd-b91f-f64b2d75316a", "resourceVersion": "399", "creationTimestamp": "2025-02-26T06:42:48Z" }, "involvedObject": { "kind": "Lease", "namespace": "kube-system", "name": "kube-controller-manager", "uid": "8ae595db-8118-4171-94e4-eb1c76f74f6d", "apiVersion": "coordination.k8s.io/v1", "resourceVersion": "397" }, "reason": "LeaderElection", "message": "node-exporter41_2b4c898b-93fc-4f06-a423-5eaa27bc65c0 became leader", "source": { "component": "kube-controller-manager" }, "firstTimestamp": "2025-02-26T06:42:48Z", "lastTimestamp": "2025-02-26T06:42:48Z", "count": 1, "type": "Normal", "eventTime": null, "reportingComponent": "kube-controller-manager", "reportingInstance": "" }, { "metadata": { "name": "kube-scheduler.1827af1b1ad7bfa7", "namespace": "kube-system", "uid": "2b0b35bb-e7e3-4ca0-bf17-66470b9a1bbc", "resourceVersion": "607", "creationTimestamp": "2025-02-26T06:45:11Z" }, "involvedObject": { "kind": "Lease", "namespace": "kube-system", "name": "kube-scheduler", "uid": "95110033-2f75-43c2-b45e-dd869e5213fe", "apiVersion": "coordination.k8s.io/v1", "resourceVersion": "605" }, "reason": "LeaderElection", "message": "node-exporter42_5144bbbd-511b-4e02-87f6-5c86a280959a became leader", "source": { "component": "default-scheduler" }, "firstTimestamp": "2025-02-26T06:45:11Z", "lastTimestamp": "2025-02-26T06:45:11Z", "count": 1, "type": "Normal", "eventTime": null, "reportingComponent": "default-scheduler", "reportingInstance": "" } ] } { "kind": "ReplicationControllerList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "ServiceList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "DaemonSetList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "DeploymentList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "ReplicaSetList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "PodList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "EventList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "ReplicationControllerList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "ServiceList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [ { "metadata": { "name": "kubernetes", "namespace": "default", "uid": "98413c86-991e-4b59-ab2a-dd570b7fc6b7", "resourceVersion": "205", "creationTimestamp": "2025-02-26T06:35:00Z", "labels": { "component": "apiserver", "provider": "kubernetes" } }, "spec": { "ports": [ { "name": "https", "protocol": "TCP", "port": 443, "targetPort": 6443 } ], "clusterIP": "10.200.0.1", "clusterIPs": [ "10.200.0.1" ], "type": "ClusterIP", "sessionAffinity": "None", "ipFamilies": [ "IPv4" ], "ipFamilyPolicy": "SingleStack", "internalTrafficPolicy": "Cluster" }, "status": { "loadBalancer": {} } } ] } { "kind": "DaemonSetList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "DeploymentList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "ReplicaSetList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "1248" }, "items": [] } { "kind": "PodList", "apiVersion": "v1", "metadata": { "resourceVersion": "1248" }, "items": [] } [root@node-exporter41 ~]# ​ ​ 3 创建bootstrap-secret授权 3.1 创建配bootstrap-secret文件用于授权 [root@k8s-node-exporter41 ~]# cat > bootstrap-secret.yaml < 4m32s v1.31.6 10.0.0.41 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
node-exporter42 NotReady 47s v1.31.6 10.0.0.42 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
node-exporter43 NotReady 46s v1.31.6 10.0.0.43 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
[root@node-exporter41 ~]#

[root@node-exporter42 ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node-exporter41 NotReady 21m v1.31.6 10.0.0.41 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
node-exporter42 NotReady 18m v1.31.6 10.0.0.42 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
node-exporter43 NotReady 18m v1.31.6 10.0.0.43 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
[root@node-exporter42 ~]#



[root@node-exporter43 ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node-exporter41 NotReady 21m v1.31.6 10.0.0.41 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
node-exporter42 NotReady 18m v1.31.6 10.0.0.42 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
node-exporter43 NotReady 18m v1.31.6 10.0.0.43 Ubuntu 22.04.4 LTS 5.15.0-133-generic containerd://1.7.20
[root@node-exporter43 ~]#



7 可以查看到有相应的csr用户客户端的证书请求
[root@node-exporter41 ~]# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-4hds8 2m46s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:ysl Approved,Issued
csr-8ggts 2m48s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:ysl Approved,Issued
csr-cnr9k 6m32s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:ysl Approved,Issued
[root@node-exporter41 ~]#






– 部署worker节点之kube-proxy服务
1.生成kube-proxy的csr文件
[root@node-exporter41 pki]# cat > kube-proxy-csr.json < /etc/kubernetes/kube-proxy.yml << EOF apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration bindAddress: 0.0.0.0 metricsBindAddress: 127.0.0.1:10249 clientConnection: acceptConnection: "" burst: 10 contentType: application/vnd.kubernetes.protobuf kubeconfig: /ysl/certs/kubeconfig/kube-proxy.kubeconfig qps: 5 clusterCIDR: 10.100.0.0/16 configSyncPeriod: 15m0s conntrack: max: null maxPerCore: 32768 min: 131072 tcpCloseWaitTimeout: 1h0m0s tcpEstablishedTimeout: 24h0m0s enableProfiling: false healthzBindAddress: 0.0.0.0:10256 hostnameOverride: "" iptables: masqueradeAll: false masqueradeBit: 14 minSyncPeriod: 0s ipvs: masqueradeAll: true minSyncPeriod: 5s scheduler: "rr" syncPeriod: 30s mode: "ipvs" nodeProtAddress: null oomScoreAdj: -999 portRange: "" udpIdelTimeout: 250ms EOF ​ ​ 6.所有节点使用systemd管理kube-proxy cat > /usr/lib/systemd/system/kube-proxy.service << EOF [Unit] Description=forest ysl's Kubernetes Proxy After=network.target ​ [Service] ExecStart=/usr/local/bin/kube-proxy \ --config=/etc/kubernetes/kube-proxy.yml \ --v=2 Restart=on-failure LimitNOFILE=65536 ​ [Install] WantedBy=multi-user.target EOF ​ 7.所有节点启动kube-proxy systemctl daemon-reload && systemctl enable --now kube-proxy systemctl status kube-proxy ss -ntl |egrep "10256|10249" ​ ​ ​ ​ ​ ​ ​ - 部署Calico 1.检查Calico对K8S版本的支持 参考链接: https://docs.tigera.io/calico/latest/getting-started/kubernetes/requirements#kubernetes-requirements 2.下载Calico的Operator [root@node-exporter41 ~]# wget https://raw.githubusercontent.com/projectcalico/calico/v3.29.2/manifests/tigera-operator.yaml ​ ​ 温馨提示: 发现"v3.29.2"该版本在1.31.6版本中不间断会重启,导致服务响应变慢。需要进一步调研。 ​ ​ ​ ​ ​ 3.创建Calico的Operator [root@node-exporter41 ~]# kubectl create -f tigera-operator.yaml namespace/tigera-operator created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgpfilters.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/tiers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/adminnetworkpolicies.policy.networking.k8s.io created customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created serviceaccount/tigera-operator created clusterrole.rbac.authorization.k8s.io/tigera-operator created clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created deployment.apps/tigera-operator created [root@node-exporter41 ~]# [root@node-exporter41 calico]# kubectl get pods -n tigera-operator -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES tigera-operator-64ff5465b7-7rqdv 1/1 Running 4 (65s ago) 5m57s 10.0.0.41 node-exporter41
[root@node-exporter41 calico]#

彩蛋:
导出镜像
[root@node-exporter41 calico]# ctr -n k8s.io i export ysl-operator-v1.36.5.tar.gz quay.io/tigera/operator:v1.36.5
[root@node-exporter41 calico]#


导入镜像:
[root@node-exporter41 calico]# ctr i import ysl-operator-v1.36.5.tar.gz
unpacking quay.io/tigera/operator:v1.36.5 (sha256:3341fa9475c0325b86228c8726389f9bae9fd6c430c66fe5cd5dc39d7bb6ad4b)…done
[root@node-exporter41 calico]#
[root@node-exporter41 calico]# ctr -n k8s.io i import ysl-operator-v1.36.5.tar.gz
unpacking quay.io/tigera/operator:v1.36.5 (sha256:3341fa9475c0325b86228c8726389f9bae9fd6c430c66fe5cd5dc39d7bb6ad4b)…done
[root@node-exporter41 calico]#

4.下载自定义资源
[root@node-exporter41 calico]# wget https://raw.githubusercontent.com/projectcalico/calico/v3.29.2/manifests/custom-resources.yaml

[root@node-exporter41 calico]# grep 192 custom-resources.yaml
cidr: 192.168.0.0/16
[root@node-exporter41 calico]#
[root@node-exporter41 calico]#
[root@node-exporter41 calico]# sed -i ‘/192/s#192.168#10.100#’ custom-resources.yaml
[root@node-exporter41 calico]#
[root@node-exporter41 calico]# grep 100 custom-resources.yaml
cidr: 10.100.0.0/16
[root@node-exporter41 calico]#
[root@node-exporter41 calico]# kubectl create -f custom-resources.yaml
installation.operator.tigera.io/default created
apiserver.operator.tigera.io/default created
[root@node-exporter41 calico]#




– 回退方案使用falnnel
1.下载资源清单
[root@node-exporter41 ~]# wget http://192.168.15.253/Resources/Kubernetes/K8S%20Cluster/kube-flannel.yml


2.部署服务
[root@node-exporter41 ~]# kubectl apply -f kube-flannel.yml
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
[root@node-exporter41 ~]#

3.补全cni插件不足的问题
wget https://github.com/containernetworking/plugins/releases/download/v1.6.2/cni-plugins-linux-amd64-v1.6.2.tgz

svip:
wget http://192.168.15.253/Resources/Kubernetes/Add-ons/cni/Flannel/cni-plugins-linux-amd64-v1.6.2.tgz
tar xf cni-plugins-linux-amd64-v1.6.2.tgz -C /opt/cni/bin/

4.开启自动补全功能
kubectl completion bash > ~/.kube/completion.bash.inc
echo “source ‘$HOME/.kube/completion.bash.inc'” >> $HOME/.bashrc
source $HOME/.bashrc





5.部署CoreDNS服务
5.1 下载资源清单
wget http://192.168.15.253/Resources/Kubernetes/Add-ons/CoreDNS/coredns.yaml.base

参考链接:
https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns/coredns

5.2 修改关键字段
__DNS__DOMAIN__
ysl.com

__DNS__MEMORY__LIMIT__
200Mi

__DNS__SERVER__
10.200.0.254

5.3 部署CoreDNS组件
[root@node-exporter41 ~]# kubectl apply -f coredns.yaml.base
serviceaccount/coredns created
clusterrole.rbac.authorization.k8s.io/system:coredns created
clusterrolebinding.rbac.authorization.k8s.io/system:coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created
[root@node-exporter41 ~]#





5.4 存在的问题
[FATAL] plugin/loop: Loop (127.0.0.1:42763 -> :53) detected for zone “.”, see https://coredns.io/plugins/loop#troubleshooting. Query: “HINFO 4217337441363791670.8544625935495254661.”



解决方案:
1.准备解析的配置文件
[root@node-exporter41 ~]# cat /etc/kubernetes/resolv.conf
nameserver 223.5.5.5
options edns0 trust-ad
search .
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# data_rsync.sh /etc/kubernetes/resolv.conf


2.kubelet指定dns文件
[root@node-exporter41 ~]# grep ^resolvConf /etc/kubernetes/kubelet-conf.yml
resolvConf: /etc/kubernetes/resolv.conf
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# data_rsync.sh /etc/kubernetes/kubelet-conf.yml

3.重启服务使得配置生效
systemctl restart kubelet.service


4.解决后续报错:

Normal SandboxChanged 0s (x2 over 3m3s) kubelet Pod sandbox changed, it will be killed and re-created.


可能跟containerd有关,建议更换containerd 1.6LTS测试。


参考命令:
./install-containerd.sh r
rm -rf *
wget http://192.168.15.253/Resources/Containerd/ysl-autoinstall-containerd-v1.6.36.tar.gz
tar xf ysl-autoinstall-containerd-v1.6.36.tar.gz
./install-containerd.sh i


5.验证DNS服务
[root@node-exporter41 ~]# kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.200.0.1 443/TCP 5h51m
kube-system kube-dns ClusterIP 10.200.0.254 53/UDP,53/TCP,9153/TCP 40m
[root@node-exporter41 ~]# dig @10.200.0.254 kube-dns.kube-system.svc.ysl.com +short
10.200.0.254
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# dig @10.200.0.254 kubernetes.default.svc.ysl.com +short
10.200.0.1
[root@node-exporter41 ~]#

mysql

# mysql数据库

# 第一章 服务概述

## 1 数据库服务分类

### 1.1 关系型数据库

“`sh
把复杂的数据结构归结为简单的二元关系(RDBMS),即二维表格形式(二维表);会注重数据存储的
持久性,但存储效率低;
此类型数据库服务,类似于excel表格的存储数据方式,多采用SQL语言方式进行操作管理;
“`

关系型数据库四层结构信息

| 序号 | 数据库结构 | 描述说明 |
| —- | ———————- | ———————————— |
| 01 | 数据库管理系统(DBMS) | 进行数据存储应用管理的操作环境或命令 |
| 02 | 数据库(DB) | 数据存储的承载环境 |
| 03 | 数据表(Table) | 数据关系的构建环境 |
| 04 | 数据字段(Field) | 实际数据信息展现形式 |

常见的关系数据库应用程序:

| 序号 | 数据库程序 | 应用说明 |
| —- | ———- | ———————————————————— |
| 01 | MySQL | 互联网公司应用最广泛 |
| 02 | Mariadb | 企业场景应用较少(20%),主要用于教学环境较多 |
| 03 | Oracle | 传统企业和部分国企应用较多,但也逐步被国产数据库替代 |
| 04 | SQLserver | 适合windows server系统环境部署的数据库服务,属于微软公司发布的数据库服务 |
| 05 | PostgreSQL | 适合于海量数据信息存储,对于金融行业数据信息分析能力将强 |

说明:关系型数据库的极致追求:数据存储的安全性,但是在某种程度会损失数据存储和读取的性能。

#### 1.2 非关系型数据库(属于数据库拆分时代)

没有具体模型的数据结构,英文简称NoSQL(Not Only SQL),意为”不仅仅是SQL”,比较注重数据读取的效率;

利用NoSQL数据库主要处理高并发应用的场景,以及海量数据存储应用的场景

常见的非关系数据库应用程序:

| 序号 | 数据库程序 | 应用说明 |
| —- | ———- | ———————————————————— |
| 01 | Redis | 可以利用内存存储数据,也可以采用磁盘存储数据,数据常见展示形式为key-value形式 |
| 02 | Memcache | 可以利用内存存储数据,也可以采用磁盘存储数据,数据常见展示形式为key-value形式 |
| 03 | Mongodb | 属于面向文档数据存储的数据库 |
| 04 | ES | 主要用于做日志数据的收集与检索的数据库(ELK ELFK) |

> 说明:非关系型数据库的极致追求:数据存储的高效性,但是在某种程序会牺牲数据存储的安全性

#### 1.3 企业型数据库(属于数据整合时代)

属于近些年,由国人研发设计出的数据库服务,可以满足很多国内高并发量网站数据存储和读取业务的需求;

常见的新型数据库应用程序:

| 序号 | 数据库程序 | 应用说明 |
| —- | ———- | ———————————————————— |
| 01 | TiDB | 开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理的融合型分布式数据库产品 |
| 02 | OceanBase | 是由蚂蚁集团完全自主研发的国产原生分布式数据库,兼顾分布式架构的扩展性与集中式架构的性能优势 |
| 03 | PolarXDB | 是由阿里巴巴自主研发的云原生分布式数据库,是一款基于云架构理念分布式数据库产品,专注海量数据处理 |
| 04 | RDS/TDSQL | 阿里云/腾讯云平台基于SaaS云计算服务环境构建的数据库产品(PolarXDB TDSQL TiDB) |

## 2 数据库服务优势特点

“`sh
– MySQL数据库服务性能卓越,服务稳定,很少出现异常宕机的情况;
– MySQL数据库服务是开放源代码且无版权制约,自主性强,且使用成本低;
– MySQL数据库服务使用历史悠久,社区及用户非常活跃,遇到问题可以获取大量帮助;
– MySQL数据库服务软件体积小,安装使用简单,并且易于维护管理,安装及维护成本低;
– MySQL数据库服务业界口碑好,使得企业无需考虑就能直接使用;
– MySQL数据库服务架构应用广泛,可以用于构建LAMP LNMP LNMT等流行web架构;
– MySQL数据库服务支持多种操作系统,提供多种API接口,支持多种开发语言利用驱动接口调用;
“`

# 第二章 安装部署

## 1 安装方式

| 序号 | 安装方式 | 特征说明 |
| —- | —————— | ———————————————————— |
| 01 | 采用二进制方式安装 | 直接解压缩二进制程序包,进行简单的配置和初始化操作即可 |
| 02 | 采用rpm包方式安装 | 需要从官方网站下载rpm程序包,并且需要考虑系统环境的兼容性,解决软件程序包依赖 |
| 03 | 采用yum源方式安装 | 需要根据官方网站说明,配置yum下载的仓库源信息,在联网情况下进行安装部署 |
| 04 | 采用源码包方式安装 | 需要从官方网站下载源码程序包,并且需要解决程序包依赖问题,以及需要采用编译安装 |

“`sh
下载地址:https://downloads.mysql.com/archives/community/
“`

## 2 安装过程

### 1 二进制安装

“`sh
一 安装前准备
1 关闭防火墙
systemctl disabled –now firewalld

2 添加hosts解析
echo ‘192.168.137.51 db01’ >> /etc/hosts

3 关闭selinux
sed -i ‘s/SELINUX=enforcing/SELINUX=disabled/g’ /etc/sysconfig/selinux

4 删除系统自带的mysql或mariadb
rpm -e `rpm -qa | egrep ‘mysql|mariadb’`

5 安装依赖
yum install -y libaio-devel

二 安装过程
1 下载上传安装包

2 解压安装包
cd /usr/local/
tar xf mysql-8.0.26-linux-glibc2.12-x86_64.tar.xz

3 创建软连接(目的:以后方便升级更换)
ln -s mysql-8.0.32-linux-glibc2.12-x86_64 mysql

4 添加环境变量
echo ‘export PATH=/usr/local/mysql/bin:$PATH’ >> /etc/profile
source /etc/profile

5 添加用户组
gropadd -g 3306 mysql
useradd -g mysql -u 3306 -M -s /sbin/nologin mysql

6 创建mysql目录
mkdir -p /data/3306/{data,logs}

7 初始化
7.1 不安全初始化
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data

7.2 安全初始化
mysqld –initialize –user=mysql –basedir=/usr/local –datadir=/data/3306/data

8 创建修改/etc/my.cnf
cat > /etc/my.cnf < shutdown |
| 07 | | mysqladmin -uroot -poldboy123 shutdown |

“`sh
1 mysqld &
[root@db01 ~]# ps -ef | grep mysql
mysql 19042 19023 15 10:17 pts/0 00:00:00 mysqld

2 mysqld_safe &
root@db01 ~]# ps -ef | grep mysql
root 19094 19023 0 10:19 pts/0 00:00:00 /bin/sh /software/mysql/bin/mysqld_safe
mysql 19208 19094 15 10:19 pts/0 00:00:00 /software/mysql/bin/mysqld –basedir=/software/mysql –datadir=/data/3306/data –plugin-dir=/software/mysql/lib/plugin –user=mysql –log-error=db01.err –pid-file=db01.pid –socket=/tmp/mysql.sock

mysqld_safe 比mysqld多了一个mysqld_safe进程
数据库服务运行启动默认包含两个进程:

– 数据库服务主进程(管理进程):mysqld_safe

利用mysqld_safe脚本信息,可以满足定制修改的需求,设置一些灵活的变量信息,支持一些高级的启动功能;

利用mysqld_safe命令启动数据库服务,可以进行特殊功能信息配置,并且可以实现数据库维护性操作,还可以设置启停重启;

– 数据库服务子进程(工作进程):mysqld

利用mysqld命令可以启动数据库服务,并显示启动的命令进程信息,但不能负责完成数据库服务的停止和重启操作;

利用mysqld命令可以启动数据库服务,有些服务功能是锁定死的,不能编辑改动(比如日志功能);

> 说明:通过以上进程信息,可以看出数据库服务可以更灵活的启动,使用mysqld和mysqld_safe命令来完成,主要用于维护操作。

“`

![image-20250117120019502](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250117120019502.png)

## 4 密码管理

### 1 密码设置

“`sh
给mysql配置登陆密码,并使用新密码进行登录数据库
[root@oldboy ~]# mysqladmin password ‘oldboy123’
或者
[root@oldboy ~]# mysqladmin -uroot -p password ‘oldboy123’
— 表示第一次登录设置密码信息

# 进行登录测试:
[root@oldboy ~]# mysql -uroot -p
Enter password:
quit
“`

### 2 修改密码

“`sh
# 利用数据库服务命令修改密码信息
[root@oldboy ~]# mysqladmin -uroot -poldboy123 password ‘oldboy’
— 将原有oldboy123密码 改为oldboy

# 进行测试登录
[root@oldboy ~]# mysql -uroot -poldboy
Welcome to the MySQL monitor. Commands end with ; or \g.

# 利用数据库服务SQL语句修改密码信息
alter user root@’localhost’ identified by ‘oldboy123’;
flush privileges;
— 适合于mysql 8.0

update mysql.user set authentication_string=PASSWORD(‘oldboy123′) where user=’root’ and host=’localhost’;
flush privileges;
— 适合于mysql 5.7

set password for ‘oldboy’@’localhost’=PASSWORD(‘oldboy123′);
flush privileges;
— 适合于mysql 5.6
“`

### 3 密码重置

“`sh
1 关闭数据库
shutdown或停止服务

2 重启数据库
mysqld_safe –skip-grant-tables –skip-networking &
— skip-grant-tables 表示忽略授权表启动
— skip-networking 忽略网络通讯方式启动

3 采用免密登录,重置密码
mysql -uroot
flush privileges;
–表示先将数据库服务授权表加载到内存中,也可以将内存中修改的授权信息存入到磁盘中
alter user root@’localhost’ identified by ‘oldboy123′;
–修改数据库服务用户密码信息

4 关闭数据库,重启数据库,使用新的密码登录

# 杀死已经运行的数据库服务进程信息
[root@oldboy ~]# pkill mysqld
[root@oldboy ~]# ps -ef|grep mysql

# 重新启动数据库服务
[root@oldboy ~]# systemctl start mysqld
[root@oldboy ~]# netstat -lntup|grep 3306

# 重新登录进行测试
[root@oldboy ~]# mysql -uroot -poldboy123
“`

## 5 用户管理

### 1 创建用户

“`sh
数据库用户创建:’用户名称信息’@’白名单信息’
— 用户名称信息:创建的用户字符串信息
— 白名单信息:网段IP地址信息或者名称信息
create user blog@’192.168.56.%’ identified by ‘oldboy123′;
# 方式一:书写方法(企业常用)
root@’192.168.30.0/24′
root@’192.168.30.0/255.255.255.0′
— 授权一个网段主机均可远程登录数据库服务,表示这个网段中192.168.30.1~192.168.30.254均可访问
— 在数据库中识别默认掩码就是/24,其他掩码信息需要具体写明,需要注意特殊VLSM子网掩码需要长格式指明,不能简写***

# 方式二:书写方法(企业常用)
root@’192.168.30.%’
— 授权一个网段主机均可远程登录数据库服务,表示这个网段中192.168.30.1~192.168.30.254均可访问

# 方式三:书写方法
root@’172.16.%’
— 授权一个更大网段主机均可远程登录数据库服务,表示这个网段中192.168.0.1~192.168.255.254均可访问

# 方式四:书写方法
root@’%’
— 授权任意主机都可以远程登录数据库服务

# 方式五:书写方法
root@’192.168.30.51′
— 授权一个具体的主机可以远程登录数据库服务,表示这个主机192.168.30.51可以访问
root@’192.168.30.5%’
— 授权多个具体的主机可以远程登录数据库服务,表示多个主机192.168.30.50~192.168.30.59均可以访问
“`

### 2 查看用户

“`sh
select user,host,authentication_string from mysql.user;
查看当前用户信息
select user();
“`

### 3 删除用户

“`sh
drop user test@’localhost’;
“`

### 4 锁定用户

“`sh
alter user test@’localhost’ account lock;
Query OK, 0 rows affected (0.00 sec)

select user,account_locked from mysql.user;
+——————+—————-+
| user | account_locked |
+——————+—————-+
| mysql.infoschema | Y |
| mysql.session | Y |
| mysql.sys | Y |
| root | N |
| test | Y |
+——————+—————-+
“`

### 5 解锁用户

“`sh
alter user test@’localhost’ account unlock;
Query OK, 0 rows affected (0.04 sec)

select user,account_locked from mysql.user;
+——————+—————-+
| user | account_locked |
+——————+—————-+
| mysql.infoschema | Y |
| mysql.session | Y |
| mysql.sys | Y |
| root | N |
| test | N |
+——————+—————-+
“`

### 6 不同版本用户管理

#### 1 创建用户并授权区别

##### 1 5.7版本

“`sh
只需要grant命令即可完成用户创建操作+用户密码设置+用户授权操作
grant all on *.* to test@’localhost’ identified by ‘123’;
“`

##### 2 8.0版本

“`sh
所有系统表都是InnoDB管理了,需要先建立用户再进行授权,并且grant命令不再支持indentified by语句
create user test1@’localhost’ identified by ‘123’;
Query OK, 0 rows affected (0.01 sec)

grant all on *.* to test1@’localhost’ ;
Query OK, 0 rows affected (0.00 sec)
“`

#### 2 用户密码插件区别

##### 1 5.7版本

“`sh
用户密码加密插件使用的早期版本时,可以保证客户端程序正常登陆,保证主从架构数据正常,保证集群通讯不受到影响;
show variables like ‘%auth%’;
+——————————-+———————–+
| Variable_name | Value |
+——————————-+———————–+
| authentication_policy | *,, |
| default_authentication_plugin | caching_sha2_password |
+——————————-+———————–+
“`

##### 2 8.0版本

“`sh
show variables like ‘%auth%’;
+——————————-+———————–+
| Variable_name | Value |
+——————————-+———————–+
| authentication_policy | *,, |
| default_authentication_plugin | caching_sha2_password |
+——————————-+———————–+
“`

##### 3 用户插件说明

“`sh
解决数据库服务升级后,用户密码加密插件影响连接建立问题,可以采取以下两种方案

– 方案一:替换原有默认密码加密插件,更换为历史版本使用的加密插件(mysql_native_passwordl) `运维职责`
– 方案二:替换客户端连接数据库服务端的驱动程序软件,使之兼容新版本加密插件功能
`开发职责’
“`

##### 4 修改用户插件

“`sh
1 创建用户过程中修改插件信息
create user test2@’localhost’ identified with mysql_native_password by ‘123’ ;
select user,plugin from mysql.user where user=’test2′;
+——-+———————–+
| user | plugin |
+——-+———————–+
| test2 | mysql_native_password |
+——-+———————–+

2 修改已创建的用户密码插件
alter user test1@’localhost’ identified with mysql_native_password by ‘123’;
select user,plugin from mysql.user where user=’test1′;
+——-+———————–+
| user | plugin |
+——-+———————–+
| test1 | mysql_native_password |
+——-+———————–+

3 修改数据库配置文件信息
cat >>/etc/my.cnf< 说明:all privileges(all)包含查看的所有权限信息,但是唯独缺了Grant option,不能授权用户,此权限只能给root@local用户

### 2 权限设置

“`sh
1 语法格式
grant all on 授权对象范围 to 用户信息

2 举例
grant all on *.* –对所有数据库的所有表进行授权
grant all on test.* –对test库中的所有表进行授权
grant all on test.test –对指定库的指定表进行授权
grant insert,select,update,delete on test.* to test@’localhost’;

3 查看某个用户权限
show grants for test@’localhost’;

4 挥手权限
revoke delete on test.* from test@’localhost’;
“`

### 3 授权思路

“`sh
对生产表授权一定要小,越小越安全,给业务用户常规的授权,包含增删改查
“`

| 序号 | 权限 | 互联网应用 |
| —- | —————— | ————————————– |
| 01 | SELECT 查询数据 | 访问网站页面时,表示浏览查看数据信息; |
| 02 | INSERT 插入数据 | 访问网站页面时,表示发表文章数据信息; |
| 03 | UPDATE 修改数据 | 访问网站页面时。表示修改文章数据信息; |
| 04 | DELETE 删除数据 | 访问网站页面时,表示删除文章数据信息; |

“`sh
生产常规授权方案
create database bbs;
create user bbs@’localhost’ identified by ‘XZnh@95599′;
grant all on bbs.* to bbs@’localhost’ with grant option;
with grant option;这个的意思是可以授予其他用户权限
特殊数据库权限授权方法:
# 授权命令语法格式
create user ‘user’@’ip’ identified by ‘password’;
grant SELECT on op_db.* to ‘user’@’ip’ with grant option;
# 授权命令实际应用
create user ‘root’@’127.0.0.1’ identified by ‘****’;
GRANT ALL PRIVILEGES ON *.* TO ‘root’@’127.0.0.1’ WITH GRANT OPTION;
flush privileges;
此句中all privileges跟 all等价,但是加了privileges更清晰,适用的版本更多

grant SELECT on op_db.* to ‘user’@’ip’ identified by ‘password’ with grant
option;
flush privileges;

说明:WITH GRANT OPTION 这个选项表示该管理用户可以将自己拥有的授权权限授权给别人。
经常有人在创建操作用户的时候不指定WITH GRANT OPTION选项,导致后来该用户不能使用GRANT命令创建用户;
或者给其它用户授权。如果不想这个用户有这个grant的权限,可以不加这句;
“`

## 7 连接管理

### 1 利用socket建立远程连接(unix 套接字文件连接)

“`sh
[root@db01 bin]# cat /etc/my.cnf
[mysql]
socket=/tmp/mysql.sock
[mysqld]
user=mysql
basedir=/software/mysql
datadir=/data/3306/data
socket=/tmp/mysql.sock

mysql -uroot -poldboy123 -S /tmp/mysql.sock
— -S指定socket的信息可以省略,因为在数据库服务配置文件的客户端已经配置过了
“`

### 2 利用TCP/IP建立远程连接(网络地址与端口)

“`sh
# 利用TCP/IP建立数据库服务连接
[root@oldboy ~]# mysql -uroot -poldboy123 -h 192.168.30.101 -P3306 -S
/var/lib/mysql/mysql.sock
说明:需要在数据库服务中授权网络白名单用户,才能实现采用TCP/IP方式登录操控数据库服务
“`

## 8 配置文件管理

### 1 配置文件书写格式规范说明

“`sh
# 通过数据库服务启动命令获取加载文件顺序
mysqld –help –verbose|grep my.cnf
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf
— 数据库服务加载配置文件顺序:
— /etc/my.cnf –> /etc/mysql/my.cnf –> /usr/local/mysql/etc/my.cnf –>
~/.my.cnf
# 数据库服务加载特定路径中的配置文件信息
配置文件特定路径举例:/opt/my.cnf, /data/3306/my.cnf, /data/3307/my.cnf,
/data/3308/my.cnf
mysqld –defaults-file=/opt/my.cnf &
mysqld_safe –defaults-file=/opt/my.cnf &
— 利用启动脚本加载参数信息,手工指定加载配置文件的路径位置信息
“`

### 2 配置文件信息结构说明

| | 配置信息 | 解释说明 |
| —- | ————————————————— | ———————————————— |
| | [mysqld] | 服务端配置标签 |
| 01 | user=mysql | 表示数据库服务管理用户信息 |
| 02 | basedir=/usr/local/mysql | 表示数据库服务程序安装路径 |
| 03 | datadir=/data/3306/data | 表示数据库服务数据存储路径 |
| 04 | server_id=6 | 表述数据库服务标识节点编号(主从复制的唯一编号) |
| 05 | port=3306 | 表示数据库服务启动端口设定 |
| 06 | socket=/tmp/mysql.sock | 表示数据库服务本地连接文件(套接字文件) |
| 07 | default_authentication_plugin=mysql_native_password | 表示数据库服务加密插件设定,用于向下兼容 |
| | [mysql] | 客户端配置标签(本地连接数据库生效) |
| 01 | socket=/tmp/mysql.sock | 表示数据库服务本地连接文件(套接字文件) |

“`sh
利用数据库服务命令启动服务加参数信息,完成初始化定制操作
mysqld_safe –skip-grant-tables –skip-networking &
“`

## 9 实例管理

### 1 概念

“`sh
一般在一个系统环境中,可以运行多个相同的服务程序信息,并且产生不同的进程和网络端口信息,就可以称为多实例概念;
“`

### 2 多实例目的

“`sh
数据库多实例是指在同一台服务器上运行多个独立的数据库实例。
每个实例都有自己的系统进程、内存结构、数据文件和日志文件,它们之间相互独立,互不干扰。
提高系统的可用性
提高系统整体性能
简化系统日常管理
可以有效节约成本
“`

### 3 多实例部署

| | 实例服务端口 | 实例存储路径 | 实例配置文件 | 套接字文件 |
| ——– | ————– | ————— | ———————- | ——————- |
| mysql-01 | 端口信息:3307 | /data/3307/data | /data/3307/data/my.cnf | /tmp/mysql3307.sock |
| mysql-02 | 端口信息:3308 | /data/3308/data | /data/3308/data/my.cnf | /tmp/mysql3308.sock |
| mysql-03 | 端口信息:3309 | /data/3309/data | /data/3309/data/my.cnf | /tmp/mysql3309.sock |

“`sh
mkdir -p /data/330{7..9}/data
chown -R mysql. /data/*
mv /etc/my.cnf /tmp
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql —
datadir=/data/3307/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql —
datadir=/data/3308/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql —
datadir=/data/3309/data
— 初始化完毕后可以检查数据库目录中,是否已经存在了数据库初始化产生的数据文件信息;
# vim /data/3307/data/my.cnf
[mysql]
socket=/tmp/mysql3307.sock
[mysqld]
user=mysql
port=3307
basedir=/usr/local/mysql
datadir=/data/3307/data
socket=/tmp/mysql3307.sock
vim /data/3308/data/my.cnf
[mysqld]
user=mysql
port=3308
basedir=/usr/local/mysql
datadir=/data/3308/data
socket=/tmp/mysql3308.sock
vim /data/3309/data/my.cnf
[mysqld]
user=mysql
port=3309
basedir=/usr/local/mysql
datadir=/data/3309/data
socket=/tmp/mysql3309.sock
mysqld_safe –defaults-file=/data/3307/data/my.cnf &
mysqld_safe –defaults-file=/data/3308/data/my.cnf &
mysqld_safe –defaults-file=/data/3309/data/my.cnf &
“`

# 第三章 数据库语句应用

## 1 概述

“`sh
关系型数据库要进行交互,就需要用到sql
有sql92 和sql99
“`

## 2 sql分类

根据sql的功能作用,划分为4个语句类型

### 1 数据定义语言(DDL)

Data Definition Language

“`sh
主要用于定义数据库、表等数据对象,其中包括create、alter、drop
? data definition;
“`

| 序号 | 语句命令 | 功能作用 |
| —- | ——– | ——————– |
| 01 | create | 用于创建数据库、表 |
| 02 | alter | 用于修改表的结构信息 |
| 03 | drop | 用于删除数据库、表 |

### 2 数据控制语言(DCL)

Data Control Language

“`sh
主要用于控制用户的访问权限,其中包括grant语句、revoke语句、commit语句和rollback语句;
? account management;
“`

| 序号 | 语句命令 | 功能作用 |
| —- | ——– | ——————– |
| 01 | grant | 用于给用户增加权限 |
| 02 | revoke | 用于收回用户的权限 |
| 03 | commit | 用于提交事务操作信息 |
| 04 | rollback | 用于撤销事务操作信息 |

### 3 数据操纵语言(DML)

Data Manipulation Language

“`sh
用于多数据库的数据进行添加、修改和删除操作,其中包含insert语句,update语句和delete语句
“`

| 序号 | 语句命令 | 功能作用 |
| —- | ——– | —————- |
| 01 | insert | 用于插入数据信息 |
| 02 | update | 用于修改数据信息 |
| 03 | delete | 用于删除数据信息 |

### 4 数据查询语言(DQL)

Data Query Language

“`sh
主要用于查询数据,也就是指select语句;通过select语句可以查询数据表中的一条或多条数据
“`

## 3 字符集

### 1 查看修改字符集

“`sh
查询数据库服务编码信息
show charset;
查看获取数据库服务默认字符编码
mysql > show variables like “%character%”;
show variables like ‘%character%’;
+————————–+—————————————————————-+
| Variable_name | Value |
+————————–+—————————————————————-+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | /usr/local/mysql-8.0.32-linux-glibc2.12-x86_64/share/charsets/ |
+————————–+—————————————————————-+
“`

| 序号 | 参数信息 | 解释说明 |
| —- | ————————– | ———————————————————— |
| 01 | `character_set_client` | 用来设置客户端使用的字符集 |
| 02 | `character_set_connection` | 用来设置连接数据库时的字符集 如果程序中没有指明连接数据库使用的字符集类型则按照这个字符集设置。 |
| 03 | `character_set_database` | 用来设置默认创建数据库的编码格式 如果在创建数据库时没有设置编码格式,就按照这个格式设置。 |
| 04 | character_set_filesystem | 文件系统的编码格式,把操作系统上的文件名转化成此字符集 即把 character_set_client转换character_set_filesystem, 默认binary是不做任何转换 |
| 05 | `character_set_results` | 数据库给客户端返回时使用的编码格式,如果没有指明,使用服务器默认的编码格式。 |
| 06 | `character_set_server` | 服务器安装时指定的默认编码格式,这个变量建议由系统自己管理,不要人为定义。 |
| 07 | character_set_system | 数据库系统使用的编码格式,这个值一直是utf8 不需要设置,它是为存储系统元数据的编码格式。 |
| 08 | character_sets_dir | 这个变量是字符集安装的目录。 |

字符编码中utf8编码和utf8mb4编码之间差异

| 序号 | 区别说明 | 解释说明 |
| —- | ——– | ——————————————————– |
| 01 | utf8 | 最多存储3字节长度字符,不能支持特殊emoji表情符号信息存储 |
| 02 | utf8mb4 | 最多存储4字节长度字符,可以支持特殊emoji表情符号信息存储 |

“`sh
修改数据库服务编码信息(配置文件)
[mysqld]
character-set-server=utf8mb4
— 设置服务端字符集编码为utf8mb4
[mysql]
socket=/tmp/mysql.sock
default-character-set=utf8mb4
— 设置客户端字符集编码为utf8mb4

修改数据库服务编码信息:(命令操作修改)
假设数据库表原有字符集为gbk,并且已经存储数据了,需要将表和数据字符集进行调整转换utf8mb4
# 方法一:
mysql > alter table t1 charset utf8mb4;
— 不严谨的方法,只会影响之后存储的数据,不会修改之前存储的数据
# 方法二:
·锁表逻辑导出数据(例如:mysqldump)
·重新创建数据空表(设置目标字符集)
·导入备份数据信息
— 严谨的方法,可以影响之后存储的数据,也会修改之前存储的数据
— 字符集转换是可以的,但是必须保证修改后的字符集是修改前的严格超集(包含)
“`

### 2 字符集校对规则

“`sh
查询数据库服务校对规则:
show collation;

一般数据库校对规则设置,与对应字符编码设置是有关联得;
其中utf8mb4字符集中,常用的排序规则有utf8mb4_unicode_ci、utf8mb4_general_ci、
utf8mb4_bin:
排序规则,就是指字符比较时按照字符编码还是直接用二进制数据比较,以及是否区分大小写。
主要可以根据校对规则定义或设置的不同:在查询数据信息时,影响数据信息的查询输出和排序效果;

“`

| 排序规则后缀 | 解释说明 |
| ———— | ———————————— |
| _ci | 不区分大小写,Case-insensitive的缩写 |
| _cs | 区分大小写,Case-sensitive的缩写 |
| _ai | 不区分重音,Accent-insensitive的缩写 |
| _as | 区分重音,Accent-sensitive的缩写 |
| _bin | 采用二进制方式存储数据信息 |

**utf8mb4_unicode_ci**

是基于标准Unicode来排序和比较,能够在各种语言之间精确排序。

且在特殊情况下,Unicode排序规则为了能够处理特殊字符的情况,实现了略微复杂的排序算法。

**utf8mb4_general_ci**

没有实现Unicode排序规则,在遇到某些特殊字符情况下,排序结果可能不一致。

但是,在绝大多数情况下,这些特殊字符的顺序并不需要那么精确。

**utf8mb4_bin**

将字符串的每个字符用二进制数据编译存储,区分大小写,而且可以存二进制的内容。

> 综合来说:
>
> utf8mb4_unicode_ci比较准确,utf8mb4_general_ci速度较快。
>
> utf8mb4_unicode_ci对于特殊字符的处理,在中文、英文应用中不会使用到;
>
> 除非你的应用有德语、法语、俄语等,则需要使用utf8mb4_unicode_ci,否则一般选用utf8mb4_general_ci就可以了。

## 4 数据类型

“`sh
使用MySQL数据库存储数据时,不同类型数据的存储格式各不相同。MySQL数据库提供了多种数据类型;

主要包括数值类型、日期和时间类型、字符串类型。
“`

### 1 数值类型

“`sh
主要包含整数类型,浮点类型
“`

#### 1 整数类型

| 数据类型 | 字节数 | 无负号取值 | 有符号取值 |
| ——— | —— | ————- | ———————– |
| tinyint | 1 | 0~255 | -128~127 |
| smallint | 2 | 0~65535 | -32768~32767 |
| mediumint | 3 | 0~16777215 | -8388608~8388607 |
| int | 4 | 0~4294967295 | -2147483648~2147483647 |
| bigint | 8 | 0~2的64次方-1 | -2的64次方~-2的63次方-1 |

#### 2 浮点数类型

“`sh
在MySQL数据库中,小数的表示分为浮点和定点数两种类型。

其中浮点数类型分为两种:单精度浮点数类型和双精度浮点数类型;

“`

| 数据类型 | 字节数 | 数据类型说明 |
| ———– | —— | ———————————————— |
| float(m,d) | 4字节 | 单精度浮点型 8位精度(4字节) m总个数,d小数位 |
| double(m,d) | 8字节 | 双精度浮点型 16位精度(8字节) m总个数,d小数位 |

### 2 时间类型

| 数据类型 | 字节数 | 取值范围 | 日期格式 |
| ——— | —— | ————————————— | ——————- |
| year | 1 | 1901~2155 | YYYY |
| date | 3 | 1000-01-01~9999-12-31 | YYYY-MM-DD |
| time | 3 | -838:59:59~838:59:59 | hh:mm:ss |
| datatime | 8 | 1000-01-01 00:00:00~9999-12-31 23:59:59 | YYYY-MM-DD hh:mm:ss |
| timestamp | 4 | 1970-01-01 00:00:01~2038-01-19 03:14:07 | YYYY-MM-DD hh:mm:ss |

### 3 字符串类型

| 序号 | 数据类型 | 类型说明 |
| —- | ——– | ———————————————————— |
| 01 | char | 表示定长的字符串类型,n表示可以存储字符的字节上限(n取值 0~255) |
| 02 | varchar | 表示变长的字符串类型,n表示可以存储字符的字节上限(n取值 0~65535) |
| 03 | enum | 枚举类型值 |

定义char和varchar的类型方式:`char(M) varchar(M)`;

定义类型中M指的是字符串的最大长度,为了更好理解char和varchar之间区别,以char(4)和varchar(4)做对比进行说明

| 插入数值 | char(4)存储情况 | varchar(4)存储情况 |
| ——– | ————— | —————— |
| ” | 4字节 | 1字节 |
| ‘ab’ | 4字节 | 3字节 |
| ‘abc’ | 4字节 | 4字节 |
| ‘abcd’ | 4字节 | 5字节 |

当数据为char(4),不管插入值的长度是多少,所占用的存储空间都是4字节;

而数据为varchar(4),对应的数据所占用的字节数为实际长度加1;

> 说明:如果插入的字符串尾部存在空格,char类型会去除空格后进行存储,而varchar类型会保留空格完整地存储字符串

## 5 约束

“`sh
通过数据类型设置的约束与属性,可以让数据库服务限制人类录入的数据信息,从而避免录入数据信息混乱的局面;
并且,通过数据类型的约束与属性设置,还可以避免数据信息输入的重复与输入数据信息不能为空;
“`

常见的约束定义:

| 序号 | 约束方法 | 解释说明 |
| —- | —————– | ———————————————- |
| 01 | PK(primary key) | 表示主键约束,非空且唯一(表中只能有一个主键) |
| 02 | UK(unique key) | 表示唯一约束 |
| 03 | NN(not null) | 表示非空约束 |
| 04 | FK(foreign key) | 表示外键约束,多表之间关联使用(了解) ??? |

常见的属性定义:

| 序号 | 属性信息 | 解释说明 |
| —- | ————– | ———————————————————— |
| 01 | default | 设定默认数据信息,可以实现自动填充 |
| 02 | auto_increment | 设定数值信息自增,可以实现数值编号自增填充(一般配合主键使用) |
| 02 | comment | 设定数据注释信息 |
| 03 | unsigned | 设定数值信息非负,可以实现数值信息列不能出现负数信息 |

## 6 外键

建库

![image-20250206174126765](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250206174126765.png)

![image-20250206174144707](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250206174144707.png)

### 1 在建表的时候增加外键

“`sh
# 创建外键语法格式
foreign key(外键字段) references 主表(主键);

# 创建外键关联的父表
create table class(
id int primary key auto_increment,
name varchar(10) not null comment “班级名字,不能为空”,
room varchar(10) comment ‘教室:允许为空’
) charset utf8;

# 创建子表使用外键
create table student(
id int primary key auto_increment,
number char(10) not null unique comment “学号:不能重复”,
name varchar(10) not null comment “姓名”,
c_id int,
foreign key(c_id) references class(id)
) charset utf8;
— 增加外键:c_id是外键字段,class是引用表(父表),id是引用字段(主键)
“`

### 2 在创建表之后增加外键

“`sh
# 创建外键语法格式
alter table 表名 add constraint 外键名 foreign key(外键字段) references 父表(主键字段)

# 创建没有外键信息的表
create table t_foreign(
id int primary key auto_increment,
c_id int
)charset utf8;

# 在没有外键的表中添加外键
alter table t_foreign add constraint class_foreign foreign key(c_id) references class(id);
外键增加条件: 外键字段必须与引用表(父表主键)的数据类型严格保持一致
“`

### 3 删除外键

“`sh
外键不能被修改,只能先删除后再新增;
# 删除外键语法格式
alter table 表名 drop foreign key 外键名;

# 删除表(t_foreign)中外键信息
alter table t_foreign drop foreign key class_foreign;
“`

### 4 外键说明

“`sh
外键也称之为外键约束,主要作用在于对数据进行约束:

约束01:外键对子表的数据写操作约束(增加和更新)

如果子表中插入的数据所对应的外键在父表不存在,创建不能成功.

select * from class;
Empty set (0.00 sec)

select * from student;
Empty set (0.00 sec)

insert into student values(null,’2023110001′,’xiaoQ’,1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`oldboy`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`))

约束02:外键对父表也有数据约束

当父表操作一个记录,但是该记录被子表所引用的时候,那么父表的操作将会被限制(更新: 主键和删除)

insert into class values (1,’Linux80′,’001′),(2,’Linux81′,’002′);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

insert into student values(null,’2023110001′,’xiaoQ’,1);
Query OK, 1 row affected (0.00 sec)

select * from student;
+—-+————+——-+——+
| id | number | name | c_id |
+—-+————+——-+——+
| 2 | 2023110001 | xiaoQ | 1 |
+—-+————+——-+——+
1 row in set (0.00 sec)

select * from class;
+—-+———+——+
| id | name | room |
+—-+———+——+
| 1 | Linux80 | 001 |
| 2 | Linux81 | 002 |
+—-+———+——+
2 rows in set (0.00 sec)

delete from class where id=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`oldboy`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`))
— 删除父表数据,数据被字表所引用,所以不能更新或者删除父行记录

“`

## 7 数据库模式概念

在数据库服务应用过程中存在SQL_mode概念(SQL模式),规范SQL执行行为和数据的准确性,能够符合数据录入常识和执行结果意义

例如:日期信息不能出现 0000-00-00 信息,月份只能是1-12,日期只能是1-31,一旦违反常识便会报错;

例如:在进行数据运算时,除法运算时,除数不能为0;

例如:当定义数据类型为char(10),不能超过字符长度,超过长度就报错;

例如:设置only_full_group_by(5.7以后的特性),禁止进行分组查询时,出现聚合信息1对多的显示输出;

获取SQLmode设置的默认信息:

“`tiki wiki
select @@sql_mode;
+———————————————————————————————————————–+
| @@sql_mode |
+———————————————————————————————————————–+
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+———————————————————————————————————————–+
1 row in set (0.00 sec)
“`

SQLmode配置参数信息解释说明:

| 序号 | 模式参数配置 | 解释说明 |
| —- | —————————- | ———————————————————— |
| 01 | `ONLY_FULL_GROUP_BY` | 对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中。 |
| 02 | `STRICT_TRANS_TABLES` | 在该模式下,如果一个值不能插入到一个事物表中,则中断当前的操作,对非事物表不做限制 |
| 03 | `NO_ZERO_IN_DATE` | 在严格模式下,不允许日期和月份为零 |
| 04 | `NO_ZERO_DATE` | 设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告 |
| 05 | `ERROR_FOR_DIVISION_BY_ZERO` | 在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时MySQL返回NULL |
| 06 | NO_ENGINE_SUBSTITUTION | 如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常 |
| 07 | NO_AUTO_VALUE_ON_ZERO | 该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户希望插入的值为0,该列又是自增长的,那么这个选项就有用了。 |
| 08 | NO_AUTO_CREATE_USER | 禁止GRANT创建密码为空的用户 |
| 09 | PIPES_AS_CONCAT | 将”\|\|”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似 |
| 10 | ANSI_QUOTES | 启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符 |

当进行数据库服务版本升级时,可能之前版本数据信息不能满足新版本数据库服务的SQL_mode信息设定,需要暂时设置SQLmode为空

“`tiki wiki
set global sql_mode=”;
— 配置完毕后,可以重新登录数据库服务进行检查确认
“`

###

# 第四章 语句应用实践

“`sh
帮助信息
\h
help contents
? contents

help contents Data Definition;
? create
? create database
“`

## 1 数据定义语言实践(DDL)

“`sh
创建数据库
mysql > create database oldboy;
mysql > create schema oldboy;
— 创建新的数据库
mysql > create database oldboy character set utf8mb4;
mysql > create database oldboy charset utf8 collate utf8_general_mysql500_ci;
— 创建新的数据库,并修改调整默认的字符编码
mysql > show databases;
— 查看是否已经创建好
mysql > show create database oldboy;
— 查看创建库的语句信息
mysql > show databases;
— 查看所有数据库信息
mysql > show databases like ‘%xiao%’;
— 检索查看指定的数据库信息
mysql > show create database oldboy;
— 查看创建库的语句信息
“`

数据库安装完毕后,默认的数据库说明:

| 序号 | 数据库名称 | 作用说明 |
| —- | —————— | —————————————————- |
| 01 | information_schema | 数据库系统运行状态,性能配置等数据信息存储的数据库 |
| 02 | mysql | 数据库用户授权权限、用户管理相关数据信息存储的数据库 |
| 03 | performance_schema | 数据库系统运行状态,性能配置等数据信息存储的数据库 |

> 说明:以上三个是数据库系统中默认的数据库,可以用于管理应用。

“`sh
mysql > use xiaoq
Database changed
— 在已有数据库之间进行切换
mysql > select database();
+————–+
| database() |
+————–+
| xiaoq |
+————–+
1 row in set (0.00 sec)
— 查看当前所在数据库信息

数据定义语句定义数据库规范说明:**

– 创建数据库名称规范:要和业务有关,不要有大写字母(为了多平台兼容),不要数字开头,不要含有系统关键字信息;
– 创建数据库明确字符:创建数据库时明确(显示)的设置字符集信息,为了避免跨平台兼容性与不同版本兼容性问题;
– 删除数据库操作慎用:在对数据库进行删除操作时,一定要经过严格审计后再进行操作,并且数据库普通用户不能有drop权限;

mysql > use mysql;
— 切换到指定数据库中
mysql > show tables;
— 查看数据库中所有表信息
mysql > desc stu1;
— 查看数据库中指定表数据结构信息
mysql > show create table stu1;
— 查看数据库中指定表创建语句信息

# 修改数据表名称信息
mysql > rename table stu1 to stu2;
或者
mysql > alter table stu2 rename stu3;
— 利用上面种方式均可修改表名称信息
mysql > show tables;
— 查看表名称信息是否修改

# 修改数据表编码信息
mysql > alter table stu1 charset utf8mb4;
— 修改表结构中字符集编码信息
mysql > show create table stu1;
— 查看表字符编码信息情况

# 数据表结构调整命令语法
mysql > alter table <表名> add column <字段名称> <数据类型> <约束与属性> [comment ‘注释’] [选项参数];
— 利用alter在数据表中添加新的表结构字段
mysql > alter table <表名> drop column <字段名称>;
— 利用alter在数据表中删除已有表结构字段
mysql > alter table <表名> modify column <字段名称> <数据类型> <约束与属性> [comment ‘注释’] [选项参数];
— 利用alter在数据表中修改已有表结构字段(数据类型 约束与属性)
mysql > alter table <表名> change column <旧字段名称> <新字段名称> <数据类型> <约束与属性> [comment ‘注释’] [选项参数];
— 利用alter在数据表中修改已有表结构字段(字段名称 数据类型 约束与属性)
mysql > alter table <表名> drop index <字段名称> ;
— 利用alter在数据表中删除已有表结构字段(约束与属性)

# 具体实际操作过程(添加新的表结构字段)
mysql > alter table stu add column telno char(11) not null unique key comment ‘手机号’;
— 在学生表中,添加新的表结构字段列(追加字段列-单列操作)
mysql > alter table stu add column wechat varchar(64) not null unique key comment ‘微信号’ after age;
— 在学生表中,添加新的表结构字段列(插入字段列-单列操作)
mysql > alter table stu add column sid int not null unique key comment ‘微信号’ first;
— 在学生表中,添加新的表结构字段列(插入首行列-单列操作)
mysql > desc stu;
— 查看表结构字段信息变化

# 具体实际操作过程(删除已有表结构字段)
mysql > alter table stu drop column sid;
— 在学生表中,删除已有表结构字段列(删除指定字段列-单列操作)

# 具体实际操作过程(修改已有表结构字段)
mysql > alter table stu modify name varchar(64);
— 在学生表中,修改已有表结构字段列(修改表结构数据类型)
mysql > alter table stu modify name varchar(64) not null comment ‘学生名’;
— 在学生表中,修改已有表结构字段列,最后带有保持原有配置的属性信息,否则其他属性信息会被还原为默认
mysql > alter table stu change name stuname varchar(64) not null comment ‘学生名’;
或者
mysql > alter table stu change column name stuname varchar(64) not null comment ‘学生名’;
— 在学生表中,修改已有表结构字段列(修改表结构字段名称)
mysql > alter table stu modify name varchar(64) not null unique comment ‘学生名称’;
— 在学生表中,修改已有表结构字段列(修改表结构属性信息)了解即可
mysql > alter table stu drop index `name`;
— 在学生表中,修改已有表结构字段列(删除表结构属性信息)了解即可
mysql > desc stu;
— 查看表结构字段信息变化

# 数据表删除命令语法
mysql > drop table <表名>;
# 具体实际操作过程
mysql > drop table stu1;
— 删除操作过程,会将定义的表结构和表中数据内容一并删除
mysql > truncate table stu1;
— 删除操作过程,只是清空表中数据内容,但保留定义的表结构信息

**数据定义语句定义数据表规范说明:**

– 创建数据表名称规范:要和业务有关(含库前缀),不要有大写字母,不要数字开头,不要含有系统关键字信息,名称不要太长;

– 创建数据表属性规范:属性信息显示设置,引擎选择InnoDB,字符集选择utf8/utf8mb4,表信息添加注释;

– 创建数据列属性规范:名称要有意义,不要含有系统关键字信息,名称不要太长;

– 创建数据类型的规范:数据类型选择合适的、足够的、简短的;

– 创建数据约束的规范:每个表中必须都要有主键,最好是和业务无关列,实现自增功能,建议每个列都非空(避免索引失效)/加注释

– 删除数据表操作规范:对于普通用户不能具有删表操作,需要操作删表时需要严格审核

– 修改数据表结构规范:在数据库8.0之前,修改数据表结构需要在业务不繁忙时进行,否则会产生严重的锁 19:00

如果出现紧急修改表结构信息需求时,可以使用工具进行调整,比如使用:pt-osc、gh-ost,从而降低对业务影响
“`

## 2 数据操作语言实践(DML)

### 1 增加数据内容信息(insert)

“`sh
insert into stu1 (字段1.。。) values (值1.。。);
# 具体实际操作过程
desc stu1;
insert into stu1(id,name,age,dept) values(1,’oldboy’,35,’net sec’);
— 插入单行信息标准方法(信息输入不要重复,且特定信息不要为空)
insert into stu1(id,name,age,dept) values(0,’oldboy’,35,’net sec’);
insert into stu1(id,name,age,dept) values(null,’oldboy’,35,’net sec’);
— 插入单行信息标准方法(自增列信息可以填入0或null,表示默认实现自增效果)

insert into stu1 values(2,’oldgirl’,25,’linux’);
— 插入单行信息可以不含有表字段信息
insert into stu1 values(03,’littlegirl’,2,’net sec’),(04,’littleboy’,1,’Linux’);
— 插入多行信息可以不含有表字段信息
insert into stu1(name,age) values(‘oldboy’,35);
— 插入当行信息可以只含部分字段信息,但是省略字段信息必须具有自增特性 或 可以为空 或有默认值输入
insert into stu1 values(6,”,32,’python,linux,net sec’);
— 插入中文信息

# 检查信息是否插入成功
select * from stu1;
“`

### 2 修改数据内容(update)

“`sh
# 数据表数据修改命令语法
update 表名 set 字段=新值,… where 条件;
— 属于表内容信息变更操作,需要按照表结构预先定义好的字段信息修改,并且按照条件修改,默认全表修改
# 具体实际操作过程
update stu1 set name=”zhangsan” where id=6;
— 修改表数据内容标准方式,修改时一定要加条件信息(条件信息建议为主键或具有唯一性信息)

# 检查信息是否修改成功
select * from stu1;
“`

### 3 删除表数据(delete)

“`sh
# 数据表数据删除命令语法
delete from 表名 where 表达式;
— 属于表内容信息变更操作,需要按照表结构预先定义好的字段信息删除,并且按照条件删除,默认全表删除
# 具体实际操作过程
delete from stu1 where id=6;
delete from stu1 where id<3; delete from stu1 where age=2 or age=1; delete from stu1; -- 删除表信息时,如果不加条件会进行逐行删除全表信息(效率比较慢) # 检查信息是否删除成功 select * from stu1; **删除数据库信息扩展:伪删除操作** 由于执行删除语句信息时,有可能会对一些业务数据造成影响,甚至可能会将表中所有数据清空,虽然可以通过日志信息恢复(闪回) 但是整体操作过程还是比较危险的,因此在进行数据信息删除操作时,可以利用伪删除操作代替真实删除操作; 一般在数据库中删除数据信息,是因为从业务层面有些数据不想被查询获取到,伪删除就是不让查询时可以获取想要删除的数据; `伪删除的本质:利用update替代delete` 可以在相应表中添加状态列信息,可以将状态列设置为:1表示存在 0表示不存在 在进行伪删除操作时,只是将状态列信息改为0,但是并没有把相应行的数据信息删除,但是在查询时可以忽略状态列为0的信息; 这样可以有效规避误删除操作对业务数据的影响,万一伪删除操作有问题,可以再将状态列信息0改为1即可 # 真实删除数据信息操作举例 delete from stu1 where id=6; # 伪删除数据信息操作举例 alter table stu1 add state tinyint not null default 1; -- 在原有表中添加新的状态列 update stu1 set state=0 where id=6; -- 将原本删除列信息的状态改为0,实现伪删除效果 select * from stu1 where state=1; -- 实现查询时不要获取状态为0的信息,即不查看获取伪删除数据信息 ``` ## 3 数据管理语言实践(DQL) ### 1 查询获取服务配置信息 ```sh select @@配置参数信息 show variables like '信息' select @@port; select database(); select @@socket; select @@innodb_flush_log_at_trx_commit; show variables like 'po%'; 数据库服务在线调整配置参数方法 set session innodb_flush_log_at_trx_commit=1 set sql_log_bin=0; -- 表示在线临时调整配置参数,并且只是当前会话生效(session是默认方式,不是所有配置都可以调整) set global innodb_flush_log_at_trx_commit=1 -- 表示在线临时调整配置参数,并且将会影响所有连接(global是全局方式,可以进行所有配置调整) 说明:数据库服务配置参数在线调整参数,只是临时生效,数据库服务重启后配置会失效,想要永 久生效需要修改配置文件信息 函数 select version(); select now(); select concat(user,"@","'",host,"'") from mysql.user; +-------------------------------+ | concat(user,"@","'",host,"'") | +-------------------------------+ | test@'%' | | testroot@'%' | | root@'192.168.137.%' | | mysql.infoschema@'localhost' | | mysql.session@'localhost' | | mysql.sys@'localhost' | | testroot@'localhost' | +-------------------------------+ 函数拼接 ``` ### 2 单表查询 ```sh 语法 select 字段1.。。 from 表名 where group by 字段1.。。 having 条件 order by 字段 limit 限制信息 ``` #### 1 select + from ```sh use world; select * from city; -- > 等价于 cat a.txt
select id,name,countrycode,district,population from city;
— 进入world数据库中,查询数据库中city表所有内容信息(企业应用不要对大表查看所有数据)
select name,population from city; — > 等价于 awk $1 $2
— 查询city表中的部分字段信息,显示查看城市名称和人口数量
“`

#### 2 select+from+where

“`sh
1 定义等值条件
#查询中国的所有城市信息,中国代码信息 ”CHN”
select * from city where countrycode=’CHN’;
# 查询中国的所有城市信息,只关注城市名称和人口数量列信息
select `Name`,Population from city where countrycode=’CHN’;

2 定义区间条件
# > < >= <= !=/<> 大于 小于 大于等于 小于等于 不等于
# 查询大于700万人的所有城市信息
select * from city where Population>=7000000;
# 查询小于等于1000人的所有城市信息
select * from city where Population<=1000; 3 定义逻辑条件 # and或&&两个条件均满足才能被查出来 # or 或|| 多个条件有一个满足就能被查出来 # not或! 取反 # 查询中国境内,大于520万人口的城市信息 select * from city where city.CountryCode='CHN' and city.Population>5200000;
# 查询中国和美国的所有城市
select * from city where city.CountryCode=’CHN’ or
city.CountryCode=’USA’;
# 查询人口数在100w到200w之间的城市信息
select * from city where city.Population>=1000000 and city.Population<=2000000; 4 定义模糊条件 #like # 查询国家代号是CH开头的城市信息 select * from city where city.CountryCode like 'CH%'; # 查询国家代号含US内容的城市信息 select * from city where city.CountryCode like '%US%'; -- 在模糊查询时,%符号在前面进行检索数据时,是不会走索引信息进行检索的,查询性能较慢 5 特殊查询条件 #配合in, not in, between and # 查询中国和美国的所有城市 select * from city where city.CountryCode in ('CHN','USA'); #查询世界上的所有城市信息,但排除中国和美国的城市不查询 SELECT * FROM city WHERE city.CountryCode NOT IN ('CHN','USA'); # 查询人口数量在50w-100w之间的城市信息 SELECT * FROM city WHERE city.Population BETWEEN 500000 AND 1000000; -- in的查询条件方式表示包含意思,实际应用更广泛 -- not in的查询条件方式表示排除意思,实际应用比较少见,因为not in不能走索引扫描,查询检索性能较慢 -- between and的查询条件方式是包含边界取值信息的,即包含50w人口的城市,也包含100w人口的城市 6 查询重复消息 #distinct SELECT DISTINCT city.CountryCode FROM city WHERE city.CountryCode='USA'; -- 列字段信息必须完全相同内容,才可以实现去重; 7 查询数据为空的内容 #is null -- 查询国家编码字段为空的信息 SELECT * FROM city WHERE city.CountryCode IS NULL; -- 查询国家编码字段为非空的信息 SELECT * FROM city WHERE city.CountryCode IS NOT NULL; #实际操作命令演示:select+from+where+group by+聚合函数(统计函数) 结合使用情况** #在利用select语句查询数据信息,结合group by子句可以实现分组查询,并且还必须配合聚合函数对分组查询的数据做相应处理; #数据库服务中常用的聚合函数(统计函数): #sum() avg() min() max() group_concat() distict #统计每个国家人口总数 select CountryCode,sum(Population) from city group by city.CountryCode; #查询统计每个省份的城市个数 select District,count(name) from city where city.CountryCode='CHN' group by district; #查询统计每个省份的城市数,以及城市名称信息(经常面试题考到) select District,count(name),name from city where CountryCode='CHN' group by District; 此sql报错 -- 由于数据库sql_mode配置了only_full_group_by,由于输出的name信息不能和district信息实现1对1关系,因此报错 select district ,count(name),group_concat(name) from city where city.CountryCode='CHN' group by district; -- 利用group_concat()就可以实现没有出现在分组和聚合函数中的字段,采取拼接整合方式显示,满足分组1对1关系 #select+from+where+group by+聚合函数+having+order by # 查询统计每个国家的人口总数,只显示人口数量超过5千万的信息,并且按照国家人口总数排序显示 select city.CountryCode,sum(city.Population) from city group by city.CountryCode having sum(city.Population)>50000000 order by sum(city.Population) desc limit 3;

# 查询统计每个国家的人口总数,只显示人口数量超过5千万的信息,并且按照国家人口总数从大到小排序,只显示三~五名
select city.CountryCode,sum(city.Population) from city group by city.CountryCode having sum(city.Population) >50000000 order by sum(city.Population) desc limit 2,3;

select city.CountryCode,sum(city.Population) from city group by city.CountryCode having sum(city.Population) >50000000 order by sum(city.Population) desc limit 3 offset 2;– 跳过前2名,显示后面的三名数据信息

SELECT:指定要查询的列或表达式。
FROM:指定查询的表。
WHERE:用于筛选满足特定条件的行。
GROUP BY:对数据进行分组。
聚合函数:对分组后的数据进行聚合计算(如 SUM()、COUNT()、AVG() 等)。
HAVING:对分组后的结果进行筛选。
ORDER BY:对结果进行排序。
LIMIT:限制返回的记录数量。

虽然查询语句的书写顺序是 SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT,但实际执行顺序是:
FROM:确定查询的表。
WHERE:筛选符合条件的行。
GROUP BY:对筛选后的数据进行分组。
聚合函数:对分组后的数据进行聚合计算。
HAVING:对聚合后的结果进行筛选。
SELECT:选择需要的列。
ORDER BY:对最终结果进行排序。
LIMIT:限制返回的记录数量
“`

### 3 多表查询

“`sh
1 多表联合查询数据-横向拼接

在对数据库中数据信息查询时,有些需求情况要获取的数据信息,是通过多个表的数据信息整合获取到的,就称为多表查询;

查询命令语法格式:

笛卡尔乘积连接多表
select * from t1,t2;

内连接查询多表
select * from t1,t2 where t1.字段= t2.字段;
select * from t1 inner jion t2 on t1.字段=t2.字段;

左外连接
select * from t1 left join t2 on t1.字段=t2.字段
右外连接
select * from t1 right join t2 on t1.字段=t2.字段

说明:多表查询的最终目的是将多张表的信息整合为一张大表显示,并将显示的结果信息可以做相应单表的操作处理;
多表查询方式类型:笛卡尔乘积
— 默认方式多表查询时,会出现组合乘积效果(4*4=16)

**多表查询方式类型:内连接(取交集)**

join,其实就是“inner join”,为了简写才写成join;内连接表示以两个表的交集为主,查出来是两个表有交集的部分,

其余没有关联就不额外显示出来,这个用的情况也是挺多的;

可以基于笛卡尔乘积方式的结果集,将有意义的信息进行展示,并且是基于两张表里的相同含义字段,进行比较后输出相等的结果信息;

`内连接查询的简单描述:两个表中有关联条件的行显示出来;`

**多表查询方式类型:外连接(应用更广泛)**

利用外连接查询时,是可以进行性能优化处理的,因为内连接在底层查询时,是逐行进行比较后输出,整体数据查询检索的效率较低;

– **外连接可以细分为:左外连接-left join on**

左连接:表1左连接表2,以左为主,表示以表1为主,关联上表2的数据,查出来的结果显示左边的所有数据,

然后右边显示的是和左边有交集部分的数据。

左外连接表示查询数据结构包含:左表所有数据行+右表满足关联条件的行;
# 左连接查询语法
a left join b on a.x = b.x
— a表示左表,b表示右表,基于左表a建立关联

# 实际操作演示过程
select * from teacher left join course on teacher.tno=course.tno;
+—–+——–+——+——–+——+
| tno | tname | cno | cname | tno |
+—–+——–+——+——–+——+
| 101 | oldboy | 1001 | linux | 101 |
| 102 | xiaoQ | 1002 | python | 102 |
| 103 | xiaoA | 1003 | mysql | 103 |
| 104 | xiaoB | NULL | NULL | NULL |
+—–+——–+——+——–+——+
4 rows in set (0.00 sec)
— 包含了左表的所有数据行信息(teacher),包含了右表的关联数据行信息(course)

– **外连接可以细分为:右外连接-right join on**

右连接:表1右连接表2,以右为主,表示以表2为主,关联查询表1的数据,查出表2所有数据以及表1和表2有交集的数据,

右外连接表示查询数据结构包含:右表所有数据行+左表满足关联条件的行;


# 右连接查询语法
a right join b on a.x = b.x
— a表示左表,b表示右表,基于右表b建立关联

# 实际操作演示过程
select * from teacher right join course on teacher.tno=course.tno;
+——+——–+——+——–+—–+
| tno | tname | cno | cname | tno |
+——+——–+——+——–+—–+
| 101 | oldboy | 1001 | linux | 101 |
| 102 | xiaoQ | 1002 | python | 102 |
| 103 | xiaoA | 1003 | mysql | 103 |
| NULL | NULL | 1004 | go | 105 |
+——+——–+——+——–+—–+
4 rows in set (0.00 sec)
— 包含了右表的所有数据行信息(course),包含了左表的关联数据行信息(teacher)

# 显示差集信息:
select * from teacher right join course on teacher.tno=course.tno where teacher.tname is null;
+——+——-+——+——-+—–+
| tno | tname | cno | cname | tno |
+——+——-+——+——-+—–+
| NULL | NULL | 1004 | go | 105 |
+——+——-+——+——-+—–+
1 row in set (0.01 sec)

外连接方式左连接与右连接区别举例:


# 会将右表作为驱动表,进行外层循环
for each row in b
for each row in a
if b.y=a.x print row
else print b.y a.null

**多表连接查询的步骤思路:**

– 进行需求分析,根据查询需求找寻所有需要的表信息;
– 找寻表的关联,根据多张表字段信息获取关联的字段;(也可以查询间接关系)
– 组合后的需求,根据多张表组合后定义查询条件信息;
“`

## 4 操作管理应用实践(获取元数据)

### 1 概念

“`sh
元(meta)一般会被翻译成中文是”关于…的…”,元数据(meta data)等价于data about data,表示关于数据的数据;

一般是元数据就是结构化数据,例如存储在数据库里的数据,规定了字段的长度。类型等;

元数据就是描述数据的数据,在MySQL中就是描述database的数据,属性,状态等相关信息;

`表示在数据库服务中有哪些数据库,库中有哪些表,表中有多少字段,字段是什么类型等等,这样的数据就是数据库的元数据;`
“`

### 2 元数据获取方法

“`sh
方法一:利用各种shwo命令获取元数据信息

方法二:利用各种select命令查看视图信息获取元数据信息

方法三:利用各种mysql数据库中的各种函数获取元数据信息

# 常用SQL语句的show命令查看元数据信息
show databases;
— 查询数据库服务中的所有数据库信息(数据库名称-元数据)

show tables;
show tables from mysql;
— 查询数据库服务中的相应数据表信息(数据表名称-元数据)

show create database <库名>;
— 查询数据库服务中的建库语句信息 (建库语句参数-元数据 建库语句就是DDL语句,定义建立数据库的属性信息)

show create table <表名>;
— 查询数据库服务中的建表语句信息 (建表语句参数-元数据 建表语句就是DDL语句,定义建立数据表的属性信息)

desc <表名>;
show columns from <表名>;
— 查询数据库服务中的数据表的结构(数据表的列定义信息-元数据)

show table status from <库名>;
— 查询数据库服务中的相应数据表状态 (数据表的状态信息/统计信息-元数据)
show table status from world like ‘city’ \G
*************************** 1. row ***************************
Name: city — 数据表名称信息
Engine: InnoDB — 使用的数据库引擎信息
Version: 10
Row_format: Dynamic
Rows: 4046 — 数据表的行数信息
Avg_row_length: 101 — 平均行长度
Data_length: 409600
Max_data_length: 0
Index_length: 114688 — 索引长度信息
Data_free: 0
Auto_increment: 4080 — 自增列的值计数
Create_time: 2022-11-04 09:13:27 — 数据表创建时间
Update_time: NULL
Check_time: NULL
Collation: utf8mb4_0900_ai_ci — 校对规则信息
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
— 查看数据库服务中的具体数据库表的状态信息(属于单库或单表查询)

show index from world.city;
— 查询数据库服务中的相应数据表的索引情况(了解即可)

show grants for root@’localhost’;
— 查询数据库服务中的用户权限属性配置信息

show [full] processlist;
— 查询数据库服务的系统状态信息,表示当前数据库的所有连接情况

show variables;
show variables like ‘%xx%’;
— 查询数据库服务的所有配置信息

show status;
show status like ‘%lock%’;
— 查询数据库服务的系统整体状态,表示当前数据库服务运行的即时状态情况

show binary logs;
— 查询数据库服务的所有二进制日志信息(binlog日志)
show master status;
— 查询数据库服务正在使用的二进制日志
show binlog events in ‘binlog.000009’;
— 查询数据库服务具体二进制日志内容事件信息

show engine innodb status \G
— 查询数据库服务存储引擎相关信息

show slave hosts;
— 在数据库服务主库查看从库信息
show slave status;
— 查询数据库服务主从状态信息

元数据获取方式二:利用库中视图获取元数据

视图概念:

`将查询基表元数据语句信息方法封装在一个变量或别名中,这个封装好的变量或别名就成为视图,视图信息都是存储在内存中的表`

元数据信息存储在系统基表中,通过一般的select命令只能查看数据信息,不能查看到系统基表,以免被随意调整篡改;

而查询基表的语句过于复杂,可以将整个查询基表语句定义为一个视图信息(等价于别名/变量),调取视图等价于调取查询基表语句;

information_schema库中的内存表都是每次数据库服务启动时生成的,里面存储了查询元数据基表的视图信息;

视图定义:

# 假设查询基表语句信息如下
select a.tname as ‘老师名’,group_concat(d.sname) as ‘不及格学生名’
from teacher as a
join course as b
on a.tno=b.tno
join sc as c
on b.cno=c.cno
join student as d
on c.sno=d.sno
where c.score<60 group by a.tno; -- 会获取如下查询后的信息 +-----------+--------------------+ | 老师名 | 不及格学生名 | +-----------+--------------------+ | xiaoQ | zhang3 | | xiaoA | li4,zh4 | +-----------+--------------------+ # 可以将复杂的查询语句定义为视图 create view tv as select a.tname as '老师名',group_concat(d.sname) as '不及格学生名' from teacher as a join course as b on a.tno=b.tno join sc as c on b.cno=c.cno join student as d on c.sno=d.sno where c.score<60 group by a.tno; # 调取视图信息等价于调取复杂的查询语句 select * from tv; +-----------+--------------------+ | 老师名 | 不及格学生名 | +-----------+--------------------+ | xiaoQ | zhang3 | | xiaoA | li4,zh4 | +-----------+--------------------+ 2 rows in set (0.00 sec) # 切换进入information_schema数据库中查看表信息 use information_schema; show tables; -- 此时看到的所有表信息,其实都是视图信息 # 查看获取视图信息创建语句 show create view tables; -- 查看tables这个视图表的创建过程 # 查看视图表信息应用 # 统计数据库资产信息(数据资产),获取每个库中表的个数和名称信息(业务相关) desc information_schema.tables; -- 查看information_scheam中的tables表的结构信息; select table_schema,count(*),group_concat(table_name) from information_schema.tables group by table_schema; -- 获取相应数据库中表的个数,与数据库中拥有的表信息 select table_schema,count(*),group_concat(table_name) from information_schema.tables where table_schema not in ('mysql','sys','performance_schema','information_') group by table_schema; # 统计数据库资产信息(数据资产),获取每个数据库数据占用磁盘空间 select table_schema,sum(table_rows*avg_row_length+index_length)/1024/1024 from information_schema.tables where table_schema not in ('mysql','sys','performance_schema','information_') group by table_schema; # 统计数据库资产信息(数据资产),获取具有碎片信息的表 select table_schema,table_name,data_free from information_schema.tables where table_schema not in ('mysql','sys','performance_schema','information_') and data_free >0 ;
— 碎片信息过多会导致索引信息失效,以及统计信息不真实的情况

# 统计数据库资产信息(数据资产),处理具有碎片信息的表
alter table t1 engine=innodb;
— 可以对已经是innodb存储引擎的表做操作,实现整理碎片功能
select concat(“alter table “,table_schema,”.”,table_name,” engine=innodb”) from information_schema.tables where table_schema not in (‘mysql’,’sys’,’performance_schema’,’information_’) and data_free >0 ;
— 可以对已经是innodb存储引擎的表做操作,实现批量整理碎片功能

# 统计数据库资产信息(数据资产),获取数据库中非innodb表信息
mysql>select table_schema,table_name,engine from information_schema.tables where table_schema not in (‘mysql’,’sys’,’performance_schema’,’information_’) and engine!=’innodb’;
— 获取非innodb数据库引擎表
use school;
create table t1 (id int) engine=myisam;
create table t2 (id int) engine=myisam;
create table t3 (id int) engine=myisam;
— 模拟创建一些myisam引擎数据表

# 统计数据库资产信息(数据资产),修改数据库中非innodb表信息替换成innodb
alter table world.t1 engine=innodb;
— 可以对不是innodb存储引擎的表做操作,实现数据表引擎修改
select concat(“alter table “,table_schema,”.”,table_name,” engine=innodb”) from information_schema.tables where table_schema not in (‘mysql’,’sys’,’performance_schema’,’information_’) and engine !=’innodb’;
select concat(“alter table “,table_schema,”.”,table_name,” engine=innodb;”) from information_schema.tables where table_schema not in (‘mysql’,’sys’,’performance_schema’,’information_’) and engine!=’innodb’ into outfile ‘/tmp/alter.sql’;
ERROR 1290 (HY000): The MySQL server is running with the –secure-file-priv option so it cannot execute this statement
vim /etc/my.cnf
[mysqld]
secure-file-priv=/tmp
— 修改配置文件参数信息,实现将数据库操作的数据信息导入到系统文件中,配置完毕重启数据库服务
source /tmp/alter.sql
— 可以对不是innodb存储引擎的表做操作,实现数据表批量化引擎修改,调用数据库脚本信息

“`

关注的视图表字段说明:

| 序号 | 字段信息 | 解释说明 |
| —- | ————– | ————————– |
| 01 | TABLE_SCHEMA | 表示数据表所属库的名称信息 |
| 02 | TABLE_NAME | 表示数据库中所有数据表名称 |
| 03 | ENGINE | 表示数据库服务中的引擎信息 |
| 04 | TABLE_ROWS | 表示数据库相应数据表的行数 |
| 05 | AVG_ROW_LENGTH | 表示数据表中每行的平均长度 |
| 06 | INDEX_LENGTH | 表示数据表中索引信息的长度 |
| 07 | DATA_FREE | 表示数据库服务碎片数量信息 |
| 08 | CREATE_TIME | 表示数据表创建的时间戳信息 |
| 09 | UPDATE_TIME | 表示数据表修改的时间戳信息 |
| 10 | TABLE_COMMENT | 表示数据表对应所有注释信息 |

说明:使用information_schema的视图查看功能,可以看到全局数据库或数据表的元数据信息,探究全局层面的元数据

### 3 元数据调取函数

利用程序代码在语句数据库交互的过程,也可以调取数据库中的相关元数据信息:

“`tiki wiki
getDatabaseProductName
— 获取数据库的产品名称
getDatabaseProductName
— 获取数据库的版本号
getUserName
— 获取数据库的用户名
getURL
— 获取数据库连接的URL
getDriverName
— 获取数据库的驱动名称
driverVersion
— 获取数据库的驱动版本号
isReadOnly
— 查看数据库是否只允许读操作
supportsTransactions
— 查看数据库是否支持事务
“`

数据库元数据信息参考资料:https://www.yisu.com/zixun/579710.html

# 第五章 日志管理

## 1 日志分类

常用日志信息介绍:

| 序号 | 日志名称 | 解释说明 |
| —- | ————– | ———————————————————— |
| 01 | general_log | 表示查询日志(通用日志),默认日志状态处于关闭,可以进行在线调整配置
作用:记录了客户端从会话连接开始,执行过的所有SQL语句信息; |
| 02 | log_error | 表示错误日志(运行日志),默认日志状态处于激活
作用:记录了数据库服务启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息; |
| 03 | log_bin | 表示二进制日志(binlog日志),默认日志状态处于激活(8.0之后)
作用:记录了所有的DDL语句和DML语句,但是不包括数据库查询语句;语句以事件的形式保存,描述了数据的更改过程,此日志对于灾难时的数据恢复起着极其重要的作用。 |
| 04 | slow_query_log | 表示慢查询日志,记录了所有执行时间超过参数long_query_time设置值并且扫描记录数小于min_examined_row_limit的所有SQL语句的日志。 |

“`sh
set global general_log=1
# 修改日志存储路径(永久配置):
[root@xiaoq ~]# vim /etc/my.cnf
log_error=/tmp/mysql3306.err
— 配置文件编写完毕后,需要重启数据库服务生效
— 根据错误日志的错误提示信息,进行错误信息进行分析,从而排查故障可能出现的原因;
##### **分类日志信息配置:二进制日志(log_bin)**

在进行增量恢复数据时,需要先了解什么是binlog日志,此日志文件其实就是用于记录对数据库进行操作更改的语句信息的;

并且记录更改的语句信息以事件形式进行记录,但是需要注意的是查询相关的语句是不会被记录的,比如:select、show;

然而作为所有对数据库的改操作事件信息都会被记录,比如:insert、update、create、drop。。。

server_id=6
— 进行主从操作时,需要进行此信息配置;
log_bin=ON
— 默认日志功能处于关闭状态
log_bin_basename=/data/3306/data/binlog
— 定义日志文件存储的路径信息,建议日志文件路径与数据存放路径进行分离;

# 配置信息简写方式:开启数据库binlog日志记录功能
[root@xiaoq ~]# vim /etc/my.cnf
— 激活binlog日志记录功能,需要对数据库服务配置文件进行编辑修改
[mysqld]
server_id=6
log_bin=/data/3306/binlog/mysql-bin
— 进行binlog日志目录路径信息修改时,需要创建指定的目录并设置权限信息,最后需要重新启动数据库服务生效;
或者
log_bin=binlog
— 只是设置日志名称信息,日志会自动保存到数据库服务指定的数据目录中;
# 未开启binlog日志功能时,查看系统binlog功能配置参数状态
show variables like ‘%log_bin%’;
— 数据库服务重启后,已经可以在数据库的数据存储目录中,看到binlog日志文件的踪影

# 参数一:sync_binlog 表示刷新日志到磁盘策略
select @@sync_binlog;
+———————+
| @@sync_binlog |
+———————+
| 1 |
+———————+
1 row in set (0.00 sec)
— 在进行主从同步过程的双一标准的其中一个1的信息配置,主要是控制缓冲区里的binlog日志信息如何刷写到磁盘中;
— 此参数信息是有三种方式进行配置的:
— 参数信息配置0:表示由操作系统缓存自己决定,什么时候刷新日志到磁盘中;
— 参数信息配置1:表示每次事务提交,立即刷新日志到磁盘中;(此方式配置更安全)
— 参数信息配置N:表示每组事务提交,按照组的事务次数定义,确定刷新日志到磁盘中的频次;(可以有效减少IO性能损耗)

# 参数二:binlog_format 定义binlog日志的格式信息
select @@binlog_format;
+————————+
| @@binlog_format |
+————————+
| ROW |
+————————+
1 row in set (0.00 sec)
— 在进行主从同步数据恢复时,此参数配置可能会影响数据恢复的一致性问题;
— 此参数信息是有三种方式进行配置的,确定了主从复制的级别,只针对DML语句的日志才有效;
— 参数信息配置 statement(SBR):语句格式记录binlog;
create database xiaoQ; — DDL DCL语句只能使用statement 表示的就是原原本本的语句信息,即做什么就记录什么;
— 参数信息配置 row(RBR):行格式记录binlog(默认模式)
update t1 set a=10 where id<10; -- 会记录行的变化信息,属于底层的记录信息,可能会有多个变化日志信息记录 -- 参数信息配置 mixed(MBR):混合格式记录binlog -- 由数据库服务自行决定,是记录语句信息,还是记录行的变化信息; ``` ## 2 sbr和rbr记录的优缺点(面试) SBR(statement-based replication)与RBR(Row-Based Replication)记录的优缺点分析:(面试常见问题) | 记录方式 | 优点说明 | 缺点说明 | | -------- | ------------------------------------------------------------ | -------------------------------------- | | SBR | 可读性强,日志量相对较少; | 数据信息可能不准确,数据一致性不足 | | RBR | 数据信息记录更准确,数据一致性更强 | 可读性弱,日志量相对较多,数据记录准确 | | 举例说明 | update t1 set a=10 where id<10000; 记录一条语句即可 | insert into 随机数函数; | | 举例说明 | update t1 set a=10 where id<10000; 记录多条语句修改信息,生成日志 | insert into 随机数函数; | ```sh bin_log 可以通过查看方式,获取binlog日志里的数据信息,一般在数据库启动时,日志记录功能就开启了; 可以利用日志中记录信息,将数据库服务的数据信息恢复到指定的时间点,同时也可以支持主从数据复制(在其它机器上回放日志); `对于binlog日志信息的查看,主要目的是为了日后日志事件信息的截取操作;` 查看方式一:确认数据库binlog日志数量 show binary logs; flush logs; Query OK, 0 rows affected (0.12 sec) -- 可以执行flush刷新命令,从而生成新的binlog日志文件,类似于实现了日志切割功能; show binlog events in 'binlog.000002'; -- binlog日志信息是以事件方式进行记录的,所以日志查看过程是查看事件信息 -- 一般binlog日志的前两行,表示日志格式头信息(日志简单的描述信息) -- 一般binlog日志中的query信息,就是对数据库的操作语句,其中包含了创建数据库的语句; ``` 具体binlog事件记录信息分析: | 列号 | 列信息 | 解释说明 | | ---- | ----------- | ---------------------------------------------------------- | | 01 | Log_name | 表示指定查看的binlog日志文件名称信息 | | 02 | Pos | 表示binlog日志事件开始的位置点,用于截取二进制日志信息标识 | | 05 | End_log_pos | 表示binlog日志事件结束的位置点,用于截取二进制日志信息标识 | | 06 | Info | 表示binlog中具体的事件内容信息 | ```sh # 筛选数据库日志方式一: [root@xiaoq data]# mysql -e "show binlog events in 'binlog.000002'"|grep "drop database" binlog.000002 722789 Query 1 722896 drop database world /* xid=5363 */ -- 获取指定事件信息产生的起点位置和终点位置信息; # 筛选数据库日志方式二: pager less -- 在数据库中定义pager功能,数据库连接会话退出即失效; show binlog events in 'binlog.000002'; -- 此时查看日志事件信息具有了翻页功能 /drop database | binlog.000002 | 722789 | Query | 1 | 722896 | drop database world /* xid=5363 */ pager grep "drop database" PAGER set to 'grep "drop database"' -- 表示开启数据库pager的过滤功能 show binlog events in 'binlog.000002'; | binlog.000002 | 722789 | Query | 1 | 722896 | drop database world /* xid=5363 */ -- 再次查看binlog事件信息时,只过滤显示删除数据库的操作事件日志 mysqlbinlog /var/lib/mysql/binlog.000001 ``` ## 3 数据库异常恢复(简单情况) ```sh 切割日志 flush logs show master status; -- 在没有进行事务提交前,操作的事务事件信息,是不会出现在binlog事件日志中的 commit; -- 对于数据库的binlog日志,只会记录事务已经提交的DML语句信息,没有提交的DML语句是不会进行记录的; -- 在日志中变化的DML语句信息是无法识别的,因为记录DML操作的语句默认是以ROW模式记录的; -- 对于数据库binlog日志信息,是无法直接查看内容信息,需要利用相关命令工具进行查看 [root@db01 data]# mysqlbinlog binlog.000017 # The proper term is pseudo_replica_mode, but we use this compatibility alias # to make the statement usable on server versions 8.0.24 and older. /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #250208 10:45:03 server id 1 end_log_pos 126 CRC32 0xcf7bbba5 Start: binlog v 4, server v 8.0.32 created 250208 10:45:03 # Warning: this binlog is either in use or was not closed properly. BINLOG ' L8WmZw8BAAAAegAAAH4AAAABAAQAOC4wLjMyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAEwANAAgAAAAABAAEAAAAYgAEGggAAAAICAgCAAAACgoKKioAEjQA CigAAaW7e88= '/*!*/; # at 126 #250208 10:45:03 server id 1 end_log_pos 157 CRC32 0x7d5528c8 Previous-GTIDs # [empty] # at 157 #250208 10:45:36 server id 1 end_log_pos 234 CRC32 0x3e25b0c0 Anonymous_GTID last_committed=0 sequence_number=1 rbr_only=no original_committed_timestamp=173898273618702immediate_commit_timestamp=1738982736187022 transaction_length=187 # original_commit_timestamp=1738982736187022 (2025-02-08 10:45:36.187022 CST) # immediate_commit_timestamp=1738982736187022 (2025-02-08 10:45:36.187022 CST) /*!80001 SET @@session.original_commit_timestamp=1738982736187022*//*!*/; /*!80014 SET @@session.original_server_version=80032*//*!*/; /*!80014 SET @@session.immediate_server_version=80032*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 234 #250208 10:45:36 server id 1 end_log_pos 344 CRC32 0xe50698f5 Query thread_id=8 exec_time=0 error_code=0 Xid = 16 SET TIMESTAMP=1738982736/*!*/; SET @@session.pseudo_thread_id=8/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1168113696/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C utf8mb4 *//*!*/; SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; /*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/; drop database oldboy /*!*/; # at 344 #250208 10:45:43 server id 1 end_log_pos 421 CRC32 0xb77d507e Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=no original_committed_timestamp=173898274306998immediate_commit_timestamp=1738982743069988 transaction_length=167 # original_commit_timestamp=1738982743069988 (2025-02-08 10:45:43.069988 CST) # immediate_commit_timestamp=1738982743069988 (2025-02-08 10:45:43.069988 CST) /*!80001 SET @@session.original_commit_timestamp=1738982743069988*//*!*/; /*!80014 SET @@session.original_server_version=80032*//*!*/; /*!80014 SET @@session.immediate_server_version=80032*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 421 #250208 10:45:43 server id 1 end_log_pos 511 CRC32 0x918fb551 Query thread_id=8 exec_time=0 error_code=0 SET TIMESTAMP=1738982743/*!*/; SET @@session.time_zone='SYSTEM'/*!*/; flush privileges /*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; [root@db01 data]# mysqlbinlog /data/3306/data/binlog.000003 # The proper term is pseudo_replica_mode, but we use this compatibility alias # to make the statement usable on server versions 8.0.24 and older. /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #250206 15:52:37 server id 1 end_log_pos 126 CRC32 0xd24df123 Start: binlog v 4, server v 8.0.32 created 250206 15:52:37 at startup ROLLBACK/*!*/; BINLOG ' RWqkZw8BAAAAegAAAH4AAAAAAAQAOC4wLjMyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAABFaqRnEwANAAgAAAAABAAEAAAAYgAEGggAAAAICAgCAAAACgoKKioAEjQA CigAASPxTdI= '/*!*/; # at 126 #250206 15:52:37 server id 1 end_log_pos 157 CRC32 0xbc193d0e Previous-GTIDs # [empty] # at 157 #250206 15:55:10 server id 1 end_log_pos 180 CRC32 0x94a43686 Stop SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; -- binlog日志文件156之前的内容是可以忽略的,表示是日志文件的头格式内容信息 -- binlog日志文件以事件形式进行记录,主要关注两个at内容之间的信息,即表示的是一个事件信息; # at 233 -- binlog日志中一个事件的开始,就表示上一个事件的结束,在binlog中记录的事件日志信息是连续的; binlog日志内容中主要关注的信息: - **通过日志信息查看DDL操作语句信息(记录方式 SBR)** **通过日志信息查看DML操作语句信息(记录方式 RBR)** mysqlbinlog --base64-output=decode-rows -vvv /data/3306/data/binlog.000003 -- 以上添加的参数信息,表示将DML的ROW格式语句信息,进行格式化处理输出; -- 利用DML语句做的插入语句信息就显示出来了 -- 以上日志记录的信息,可以用命令实现,如下: 数据库异常情况数据恢复操作: mysqlbinlog --start-position=233 --stop-position=1162 /data/3306/data/binlog.000003 >/tmp/bin.sql
— 依据binlog日志的position号码,即可获取到想要恢复数据信息;

# 根据截取的日志信息,进行数据库服务数据恢复
set sql_log_bin=0;
— 建议在进行数据日志恢复数据时,将数据恢复时执行的SQL语句信息,不做binlog日志记录;
source /tmp/bin.sql

# 查看确认数据信息是否恢复
# 方法一:
flush logs;
[root@xiaoq ~ ]# mysql -uroot -p123456 -e “flush logs”
— 滚动更新前的日志文件就会处于静止状态,不会在进行数据信息的更新

# 方式二:
[root@xiaoq ~ ]# mysqladmin -uroot -p123456 flush-logs

# 方式三:
restart;
— mysql 8.0之后支持的数据库中重启服务;之前的版本只支持shutdown关闭数据库;
[root@xiaoq ~ ]# /etc/init.d/mysqld restart

# 方式四:
select @@max_binlog_size;
+————————–+
| @@max_binlog_size |
+————————–+
| 1073741824 |
+————————–+
— 配置binlog日志最大数据存储量,默认大小为1G,到达最大日志存储量也会进行自动切割;

— 在最新数据库8.0中,可以以秒为单位进行日志信息清理,默认是30天进行日志清理,或者也可以以天为单位进行清理;
— 在最先数据库8.0前,主要是以天为单位进行清理,但默认清理功能并未激活;
— 在企业实战环境中,建议过期时间最少保留一轮全备周期以上,有条件最好是保留两轮+1;
help purge binary logs;
— 获取清理日志命令帮助信息

purge binary logs to ‘mysql-bin.010’
— 删除到指定日志文件前结束
PURGE BINARY LOGS BEFORE ‘2019-04-02 22:46:26’;
— 可以基于日志时间点信息进行日志清理

日志信息远程备份:

可以实现将数据库中(特别是主库)生成的binlog日志文件,及时备份保存到专门的日志备份服务器中,并且整个备份操作都是在线的;

mkdir -p /binlog_backup
cd /binlog_backup/
[root@xiaoQ-01 binlog_backup]# mysqlbinlog -R –host=192.168.30.101 –user=root –password=123456 –raw –stop-never binlog.000008 &
— 备份过程可以放后台一直运行,但是需要注意当连接的数据库服务器停止或重启了,也会导致备份中断;

# 数据库服务多实例情况binlog日志备份
mysqlbinlog -R –host=10.0.0.51 -P 3306 –user=root –password=123456 –raw –stop-never binlog.000002 &
mysqlbinlog -R –host=10.0.0.51 -P 3307 –user=root –password=123456 –raw –stop-never binlog.000002 &
— 需要考虑备份后日志文件名称一样的覆盖问题
“`

远程备份命令参数说明

| 参数信息 | 解释说明 |
| ——————————- | ———————————- |
| -R
–read-from-remote-server | 读取binlog日志文件从数据库服务端 |
| -h
–host | 指定binlog日志文件存储服务器地址 |
| -u
–user=name | 指定binlog日志服务器连接用户信息 |
| -p
–password[=name] | 指定binlog日志服务器连接密码信息 |
| –raw | 指定binlog日志信息记录二进制信息 |
| –stop-never | 指定binlog日志信息将会一直备份记录 |
| binlog.000008 | 代表从哪个binlog日志开始进行备份 |

## 4 慢查询

“`sh
select @@slow_query_log;
此参数配置信息,表示是否激活启动慢日志记录功能,默认处于关闭状态
select @@slow_query_log_file;
— 此参数配置信息,表示慢日志文件保存的路径信息;建议日志文件路径与数据存放路径进行分离;
select @@long_query_time;
— 此参数信息配置,表示记录慢日志的条件,默认是大于10s执行的语句,就会记录为慢查询语句;(测试时建议时间为0.01~0.1)
select @@log_queries_not_using_indexes;
— 此参数信息配置,表示慢日志中会记录没有使用索引的语句信息;

设置
set global slow_query_log=1;
set global long_query_time=0.01;
set global log_queries_not_using_indexes=1;
set global slow_query_log_file=/data/3306/data/mysql-slow.log;

也可以放入my.cnf
slow_query_log_file=/data/3306/logs/mysqld.slow.log
slow_query_log = 1
log_queries_not_using_indexes = 1
log_slow_admin_statements = 1
log_throttle_queries_not_using_indexes = 10

慢查询日志分析方法
mysqldumpslow -s c -t 3 /data/3306/data/xiaoQ-01-slow.log
— 按照慢查询语句的重复执行次数(c)进行排序(-s),取出其中靠前(t)的前三名慢查询语句
— 还可以扩展使用pt-query-digest更好的分析慢查询日志,支持图形化展示
— what to sort by (al, at, ar, c, l, r, t), ‘at’ is default
al: average lock time
ar: average rows sent
at: average query time
c: count
l: lock time
r: rows sent
t: query time
“`

## 5 数据库数据异常恢复数据

### 1 数据库数据异常恢复(痛点情况)

“`sh
**情况一:日志文件被清理过,可能建库语句所在日志已经丢失;**(在后面课程章节处理)

项目背景:一个数据库三年前就创建了,但是日志信息只记录一个月,这个库被误删除了;

解决方案:

A计划:最近一次全备+全备之后,误删除之前所有binlog,进行一同恢复;(`全备数据+增量数据`)

B计划:利用延时从库,进行数据恢复;

**情况二:所需日志跨越多个文件,如何进行日志信息的截取;**

解决方案:

A计划:只有position号的方式,可以进行分段截取,进行分段恢复数据;

B计划:根据Datatime时间信息方式,可能会出现准确性不高的情况(因为每一秒可能有多个事件产生);

C计划:启用GTID(全局事务ID)方式,无论跨越多少个日志文件,每个事务操作的事件ID信息都是唯一且递增的(5.6+引入);

实践操作:

**C计划:基于GTID方式对binlog进行管理(利用GTID实现日志截取)**

数据库异常恢复情况环境准备:

# 刷新新的binlog日志进行操作
flush logs;
— 生成新的binlog日志信息

# 确认新的日志编号是否是连续的
create database test5;
show binlog events in “binlog.000004”
— 可以看出新的binlog日志文件中,记录的gtid编号信息是延续了上一个binlog日志gtid集合信息,继续连续进行记录;

# 进行基本的数据库SQL语句操作:
create database gtdb;
use gtdb;
create table t1(id int);
insert into t1 values(1);
commit;
insert into t1 values(2);
commit;
insert into t1 values(3);
commit;

# 进行binlog事件信息查看
show binlog events in ‘binlog.000004’;
— 可以获取以上的数据操作事件信息,
drop database gtdb;
— 模拟破坏性操作,删除数据库

# 根据日志信息查看相关的事件情况(获取GTID编号范围)
show binlog events in ‘binlog.000004′;

# 需要恢复建库开始,删除之前的所有操作(即所有binlog日志信息),实现日志信息的截取
[root@oldboyxiaoq ~]# mysqlbinlog –include-gtids=’7afe4f8c-5e36-11ed-b083-000c29d44f34:3-7′ /data/3306/data/binlog.000004 >/tmp/gtid.sql
— 依据binlog日志的GTID信息,即可获取到想要恢复数据信息;

# 根据截取的日志信息,进行数据库服务数据恢复
set sql_log_bin=0;
— 建议在进行数据日志恢复数据时,将数据恢复时执行的SQL语句信息,不做binlog日志记录;恢复后别忘在改为1;
source /tmp/gtid.sql
— 默认此时报错恢复失败,因为GTID截取的日志恢复数据时,具有幂等性,由于binlog中已经记录了3-7的GTID事件信息
show master status;
+—————+———-+————–+——————+——————————————+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+—————+———-+————–+——————+——————————————+
| binlog.000004 | 1905 | | | 7afe4f8c-5e36-11ed-b083-000c29d44f34:1-8 |
+—————+———-+————–+——————+——————————————+
1 row in set (0.00 sec)
— 通过查看确认,核实清楚binlog中已经记录了3-7的GTID事件信息

# 利用GTID日志信息恢复报错处理方式一:将系统中日志中的GTID信息清除掉(不建议)
# 利用GTID日志信息恢复报错处理方式二:删除与幂等性冲突的记录信息
[root@oldboyxiaoq ~]# mysqlbinlog –skip-gtids –include-gtids=’7afe4f8c-5e36-11ed-b083-000c29d44f34:3-7′ /data/3306/data/binlog.000004 binlog.000005 binlog.000006>/tmp/gtid.sql
— 表示跳过gtid的检查过程,即截取的日志中不再含有GTID的配置语句信息,自然解决了幂等性冲突问题;
— 开启了GTID之后,依然可以使用pos方式进行日志信息截取与恢复;

# 查看确认数据信息是否恢复
use gtdb;
show tables;
select * from t1;
— 查看test1数据库中的t1表的数据信息是否恢复

# 操作扩展:可以实现排除指定gtid信息不做日志记录截取
[root@oldboyxiaoq ~]# mysqlbinlog –exclude-gtids=’7afe4f8c-5e36-11ed-b083-000c29d44f34:4′ –include-gtids=’7afe4f8c-5e36-11ed-b083-000c29d44f34:3-7′ /data/3306/data/binlog.000004

# 操作扩展:跨多日志文件信息截取
[root@oldboyxiaoq ~]# mysqlbinlog –skip-gtids –include-gtids=’7afe4f8c-5e36-11ed-b083-000c29d44f34:1-10’ /data/3306/data/binlog.000001 /data/3306/data/binlog.000002 /data/3306/data/binlog.000003 >/tmp/gtid.sql
“`

### 2 GTID(全局事务ID)

#### 1 概念介绍

“`sh
GTID(global transation id)称为全局事务(事件)ID,标识binlog日志记录的唯一性;

GTID信息的表示方式:
“`

| 表现形式 | 关键列 | 解释说明 |
| ————- | ———– | ——————————————————– |
| server_uuid:N | server_uuid | 表示数据库初始化启动之后,自动生成的随机数信息(唯一的) |
| | N | 表示第几个相关的事务或事件信息,会不断进行自增 |

“`sh
select @@server_uuid;– 表示数据库每次初始化之后自动生成,不建议手工进行修改;
cat /data/3306/data/auto.cnf– 在数据库的数据目录文件中也可以查询到
“`

#### 2 功能作用

“`sh
利用GTID方式管理binlog,实质上就是对于数据库的每个事务产生事件信息打上唯一标识信息(id号);

利用GTID方式管理binlog,主要目的是处理数据库主从问题,解决主从数据库的数据一致性问题;

简单描述:标识事务的唯一性,保证日志恢复时的一致性,并且具备”幂等性”;
“`

#### 3 功能配置

“`sh
select @@gtid_mode;
— 设置是否开启显示gtid信息功能(在5.7之后是有个匿名的gtid,是数据库系统自己维护的)
select @@enforce_gtid_consistency;
— 设置是否开启GTID强制一致性功能
— 对某些 SQL 会有限制,例如 CREATE TABLE … SELECT 必须得分成两条语句执行。
— OFF: 表示事务允许违反 GTID 一致性。
— ON: 表示事务不允许违反 GTID 一致性,有相关 SQL 会直接返回异常。
— WARN:表示事务允许违反 GTID 一致性,但会将警告信息记录到 ERROR LOG。
select @@log_slave_updates;
— 和配置主从有关(在8.0.26开始 推荐配置log_replica_updates替代log_slave_updates参数)
— 此参数表示从服务器从主服务器接收的更新信息,是否也会记录在从服务器本地的二进制文件中
[root@xiaoq ~]# vim /etc/my.cnf
[mysqld]
gtid_mode=on
enforce_gtid_consistency=1
log_slave_updates=on
— 配置文件信息修改完毕后,重启数据库服务使配置生效

gtid信息查看
show master status
— 在GTID功能被激活后,就会在Executed_Gtid_Set列中显示GTID集合信息;
create database test3;
— 模拟创建数据库,产生新的事件信息
show master status;
— GTID信息随着新的事件产生,随之发生变化
create database test4;
— 模拟创建数据库,产生新的事件信息
show master status;
— GTID信息随着新的事件产生,随之发生变化
show binary logs;
–查看所有二进制日志
show binlog events in ‘binlog.000004’;
— 在每个数据库操作事件之前,会显示GTID的唯一标识信息
“`

### 3 从日志文件中恢复单库、单表、或部分行数据

“`sh
A计划:可以利用命令单独截取某个数据库的日志信息;`mysqlbinlog -d world xxx > xxxx`

B计划:可以借助第三方工具实现单表或部分数据恢复;`binlog2sql(python)` 过滤指定表数据或过滤指定表的部分数据;

实战操作:

**A计划:单库日志信息截取,企业实战过程**:

数据库异常恢复情况环境准备:

# 查看获取当前binlog日志状态信息
show master status;
# 进行基本的数据库SQL语句操作:
create database test1;
use test1
create table t1 (id int);
insert into t1 values(1);
insert into t1 values(2);
commit;
select * from t1;

— 创建了一个test1数据库,并在数据库中创建了一个表,在表中插入了一些数据信息
create database test2;
use test2;
create table t2 (id int);
insert into t2 values(1);
insert into t2 values(2);
commit;
— 创建了一个test2数据库,并在数据库中创建了一个表,在表中插入了一些数据信息
use test1;
insert into t1 values(3);
insert into t1 values(4);
use test2;
insert into t2 values(3);
insert into t2 values(4);
commit;
select * from test1.t1;
select * from test2.t2;
— 通过操作不同的数据库,以及不同的数据表,实现binlog日志事件信息的交叉

数据库模拟异常情况破坏操作:
drop database test1;
— 模拟破坏性操作,删除数据库

数据库异常情况数据恢复操作:
# 根据日志信息查看相关的事件情况
show binlog events in ‘binlog.000003′;

# 需要恢复建库开始,删除之前的所有操作(即所有binlog日志信息),实现日志信息的截取
mysqlbinlog –start-position=1346 –stop-position=4116 -d test1 /data/3306/data/binlog.000003 >/tmp/bin.sql
— 依据binlog日志的position号码,即可获取到想要恢复数据信息,并利用-d参数导出指定数据库相关数据;

# 根据截取的日志信息,进行数据库服务数据恢复
set sql_log_bin=0;
— 建议在进行数据日志恢复数据时,将数据恢复时执行的SQL语句信息,不做binlog日志记录;恢source /tmp/bin.sql

# 查看确认数据信息是否恢复
use test1;
show tables;
select * from t1;
— 查看test1数据库中的t1表的数据信息是否恢复
use test2;
show tables;
select * from t2;
— 查看test2数据库中的t2表的数据信息是否破坏

**B计划:可以借助第三方工具实现单表或部分数据恢复;**

利用binlog2sql工具可以处理上面的企业需求,此软件是利用python语言开发的,主要用来处理binlog日志信息;

从软件应用方面来说主要包含两个核心功能:

– 可以友好的展示或者管理二进制日志信息(binlog),进而可以过滤出单独表的信息,甚至表中指定行的信息;
– 可以快速的实现DML操作语句的闪回功能,即实现通过日志信息翻转方式,进行数据信息的恢复;

> 说明:binlog2sql工具是模拟了一个从库,进行日志信息分析,需要保证数据库服务启动状态,且不支持离线方式分析日志内容;
数据库异常恢复情况环境准备:

# 下载第三方日志分析工具
cd /opt/
git clone https://github.com/danfengcao/binlog2sql.git
cd /opt/binlog2sql
— 此工具在mariadb中可以通过打补丁方式,进行部署安装;但是在mysql 8.0中暂时还没有集成,需要单独安装

# 部署第三方工具运行环境
yum install -y python3
pip3 install -r requirements.txt
pip3 show pymysql
pip3 install –upgrade pymysql (此步骤可以忽略)
— 以上pip3下载软件缓慢,可以优化pip3下载源
— 下载源优化方法:https://developer.aliyun.com/mirror/pypi?spm=a2c6h.13651102.0.0.3e221b11H9Q7La

# 在指定数据库中创建多个数据表
use test1;
create table t11 (id int);
insert into t11 values (1),(2);
commit;
数据库日志信息工具分析查看:(解析日志事件SQL)

python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –start-file=’binlog.000003′
INSERT INTO `test1`.`t1`(`id`) VALUES (1); #start 1460 end 1704 time 2022-11-21 22:16:32 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (2); #start 1735 end 1979 time 2022-11-21 22:16:35 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (3); #start 2939 end 3183 time 2022-11-21 22:20:53 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (4); #start 3214 end 3458 time 2022-11-21 22:22:19 gtid
python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t11 –start-file=’binlog.000003′
INSERT INTO `test1`.`t11`(`id`) VALUES (1); #start 4704 end 4954 time 2022-11-21 23:47:51 gtid
INSERT INTO `test1`.`t11`(`id`) VALUES (2); #start 4704 end 4954 time 2022-11-21 23:47:51 gtid
— 表的数据信息导出后,可以直接复制命令信息恢复,或者导出sql文件进行导入恢复;

数据库模拟异常情况破坏操作:
# 在指定数据库的相应数据表中做修改操作
use test1;
update t1 set id=10 where id=1;
commit;

# 在指定数据库的相应数据表中做删除操作
use test1;
delete from t1 where id=3;
commit;
数据库日志信息工具分析查看:(解析日志事件SQL)

python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –start-file=’binlog.000003′
INSERT INTO `test1`.`t1`(`id`) VALUES (1); #start 1460 end 1704 time 2022-11-21 22:16:32 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (2); #start 1735 end 1979 time 2022-11-21 22:16:35 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (3); #start 2939 end 3183 time 2022-11-21 22:20:53 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (4); #start 3214 end 3458 time 2022-11-21 22:22:19 gtid
UPDATE `test1`.`t1` SET `id`=10 WHERE `id`=1 LIMIT 1; #start 4985 end 5244 time 2022-11-21 23:52:33 gtid
DELETE FROM `test1`.`t1` WHERE `id`=3 LIMIT 1; #start 5275 end 5519 time 2022-11-21 23:54:17 gtid

# 只想查看删除操作信息
python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=delete –start-file=’binlog.000003′
DELETE FROM `test1`.`t1` WHERE `id`=3 LIMIT 1; #start 5275 end 5519 time 2022-11-21 23:54:17 gtid
— sql-type参数只能过滤DML类型语句信息,一般常见过滤的是 insert update delete

# 只想查看修改操作信息
python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=update –start-file=’binlog.000003′
UPDATE `test1`.`t1` SET `id`=10 WHERE `id`=1 LIMIT 1; #start 4985 end 5244 time 2022-11-21 23:52:33 gtid

# 只想查看插入操作信息
python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=insert –start-file=’binlog.000003′
INSERT INTO `test1`.`t1`(`id`) VALUES (1); #start 1460 end 1704 time 2022-11-21 22:16:32 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (2); #start 1735 end 1979 time 2022-11-21 22:16:35 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (3); #start 2939 end 3183 time 2022-11-21 22:20:53 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (4); #start 3214 end 3458 time 2022-11-21 22:22:19 gtid

数据库日志信息工具回滚操作:(生成指定事件回滚语句-闪回操作)

假设在某个企业的应用场景中,有3000万行数据,占用200G的存储空间,其中误删除了10行数据信息,请问如何进行恢复数据?

# 误删除操作语句反转操作
python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=delete –start-file=’binlog.000003′
DELETE FROM `test1`.`t1` WHERE `id`=3 LIMIT 1; #start 5275 end 5519 time 2022-11-21 23:54:17 gtid
— 获取删除操作语句信息

python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=delete –start-file=’binlog.000003′ -B
INSERT INTO `test1`.`t1`(`id`) VALUES (3); #start 5275 end 5519 time 2022-11-21 23:54:17 gtid
— 在获取删除操作语句命令后加 -B 参数,正好获得了反转语句的操作信息

# 误修改操作语句反转操作
python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=update –start-file=’binlog.000003′
UPDATE `test1`.`t1` SET `id`=10 WHERE `id`=1 LIMIT 1; #start 4985 end 5244 time 2022-11-21 23:52:33 gtid
— 获取修改操作语句信息

python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=update –start-file=’binlog.000003′ -B
UPDATE `test1`.`t1` SET `id`=1 WHERE `id`=10 LIMIT 1; #start 4985 end 5244 time 2022-11-21 23:52:33 gtid
— 在获取修改操作语句命令后加 -B 参数,正好获得了反转语句的操作信息

# 误插入操作语句反转操作
python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=insert –start-file=’binlog.000003′
INSERT INTO `test1`.`t1`(`id`) VALUES (1); #start 1460 end 1704 time 2022-11-21 22:16:32 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (2); #start 1735 end 1979 time 2022-11-21 22:16:35 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (3); #start 2939 end 3183 time 2022-11-21 22:20:53 gtid
INSERT INTO `test1`.`t1`(`id`) VALUES (4); #start 3214 end 3458 time 2022-11-21 22:22:19 gtid
— 获取插入操作语句信息

python3 binlog2sql.py -h 10.0.0.101 -P3306 -uroot -p123456 -d test1 -t t1 –sql-type=insert –start-file=’binlog.000003’ -B
DELETE FROM `test1`.`t1` WHERE `id`=4 LIMIT 1; #start 3214 end 3458 time 2022-11-21 22:22:19 gtid
DELETE FROM `test1`.`t1` WHERE `id`=3 LIMIT 1; #start 2939 end 3183 time 2022-11-21 22:20:53 gtid
DELETE FROM `test1`.`t1` WHERE `id`=2 LIMIT 1; #start 1735 end 1979 time 2022-11-21 22:16:35 gtid
DELETE FROM `test1`.`t1` WHERE `id`=1 LIMIT 1; #start 1460 end 1704 time 2022-11-21 22:16:32 gtid
— 在获取插入操作语句命令后加 -B 参数,正好获得了反转语句的操作信息
“`

# 第六章 备份恢复

## 1 物理备份

“`sh
找个业务不忙的时间段停机停业务
cp或者tar命令备份或打包,或者nbu备份
当企业数据库服务产生的需要备份的数据量在50G以上,可以选择物理备份(xtrabackup);
“`

## 2 逻辑备份

可以采用以SQL语句形式把数据库的数据导出保存备份为数据库文件(xxx.sql),文件中会含有大量SQL语句信息;

可以在任意时间节点在不停机不停止业务时

### 1 mysqldump

“`sh
主要的备份逻辑是将建库、建表、数据插入语句信息导出,实现数据的备份操作;

基于mysqldump备份数据的逻辑原理,对于数据量比较小的场景(单表数据行百万以内),mysqldump备份工具做备份会更适合些;

在跨平台或跨版本进行数据库数据信息迁移时,mysqldump备份工具做备份也会比较适合,可以避免物理备份的兼容性问题;

> 说明:在一般情况下,对数据库进行数据恢复的时间耗费,大约是数据库进行数据备份的时间耗费的3~5倍。
mysqldump -uroot -p [参数] >备份文件.sql
— 在执行mysqldump命令时,也会用到数据库连接登录的基础参数:-u -p -S -h -P
“`

工具命令常用参数:

| 序号 | 参数信息 | 官方说明 | 解释说明 |
| —- | ——– | ———————————————- | ——————————– |
| 01 | -A | Dump all the databases | 表示备份所有库中数据信息 |
| 02 | -B | Dump several databases. | 表示备份指定库中数据信息 |
| 03 | -F | Flush logs file in server before starting dump | 表示在备份启动前自动刷新日志文件 |

“`sh
1 全部备份(-A)
mkdir -p /database_backup
mysqldump -uroot -p123456 -A >/database_backup/all_database.sql
ll -h /database_backup/all_database.sql
说明:利用-A创建数据库备份数据时,在备份数据中会含有 create建库语句和use切换库语句,可以直接进行恢复操作即可;
单个数据库进行备份(-B)
mysqldump -uroot -p123456 -B oldboy >/database_backup/oldboy.sql
egrep -vi ‘^-|^/\*|^$|lock’ /databases_backup/oldboy.sql
恢复
source /database_backup/oldboy.sql;
mysql -uroot -p123456 oldboy /database_backup/oldboy_world.sql

# 过滤部分内容后查看备份数据库文件信息:
[root@xiaoQ ~]# egrep -vi ‘^-|^/\*|^$|lock’ /database_backup/oldboy_world.sql

> 说明:利用-B创建数据库备份数据时,在备份数据中会含有 create建库语句和use切换库语句,可以直接进行恢复操作即可;

– 单个数据表进行备份**

# 备份指定数据库中的单个数据表:
[root@xiaoQ ~]# mysqldump -uroot -poldboy123 oldboy stu1 >/databases_backup/oldboy_tables_stu1.sql

# 恢复指定数据库中的单个数据表:
[root@xiaoQ ~]# mysql -uroot -poldboy123 oldboy /database_backup/world_tables_city_country.sql

# 恢复指定数据库中的多个数据表:
[root@xiaoQ ~]# mysql -uroot -poldboy123 world 说明:数据库单表或多表进行数据备份时,在备份数据中不含有create建库语句和use切换库语句,需要建库并指定库再恢复数据;

现数据库信息备份备份:
# 进行数据库数据复原恢复操作:
# 方式一:在数据库系统中加载数据库备份文件
source /database_backup/oldboy.sql;

# 方式二:在操作系统命令行执行数据恢复命令
[root@xiaoQ ~]# mysql -uroot -p123456 oldboy /backup/backup.sql

实现数据库信息远程备份:

mysqldump -uroot -p123456 -h数据库服务IP地址 -P数据库服务端口 [备份参数] >/backup/backup.sql

> 说明:可以利用第三方远程连接数据库工具,也可以实现数据备份

数据库数据备份进阶方式一:利用命令参数 –single-transaction
利用–single-transaction参数进行数据备份,就等价于在备份的时候给数据库的数据拍了照,备份时候数据库可以继续更新;

–single-transaction
通过在单个事务中备份所有表时,会创建一致性快照
仅适用于存储在支持多版本控制的存储引擎中的表(目前只有InnoDB)
对于InnoDB,会利用MVCC中一致性快照进行备份;
当–single-transaction参数应用在备份进程中时,确保备份文件的有效性
在进行备份数据期间,不要出现相关DDL的操作信息,导致备份数据不一致;
Option automatically turns off –lock-tables.

在 MySQL 8.0.26 及更高版本中,–master-data 参数已被重命名为 –source-data。这两个参数的作用相同,都是用于在导出的 SQL 文件中包含主服务器(或源服务器)的二进制日志(binlog)信息,以便在主从复制环境中使用。
参数作用
–source-data 或 –master-data:
在导出的 SQL 文件中包含当前服务器的二进制日志文件名和位置信息。
这些信息用于主从复制的搭建,帮助从服务器(slave)从指定的二进制日志位置开始复制。
参数值
–source-data=1 或 –master-data=1:
在导出的文件中包含未注释的 CHANGE MASTER TO 语句。在从服务器导入时,该语句会直接生效。
–source-data=2 或 –master-data=2:
在导出的文件中包含注释的 CHANGE MASTER TO 语句。在从服务器导入时,需要手动取消注释后才能生效。
使用场景
主从复制:
在主服务器上使用 –source-data 或 –master-data 参数导出数据,然后将导出的文件导入到从服务器。从服务器会根据导出文件中的二进制日志信息开始复制。
增量恢复:
在全量备份后,可以使用二进制日志进行增量恢复。
示例命令
MySQL 8.0.26 及更高版本:
bash复制
mysqldump -uroot -p –all-databases –source-data=2 > backup.sql
MySQL 8.0.26 之前的版本:
bash复制
mysqldump -uroot -p –all-databases –master-data=2 > backup.sql
注意事项
确保二进制日志已启用,否则该参数无效。
使用该参数时,可能会自动启用 –lock-all-tables,除非同时使用了 –single-transaction。
如果你正在使用 MySQL 8.0.26 或更高版本,建议使用 –source-data 参数。如果你使用的是更早的版本,则需要使用 –master-data。
在这种情况下,全局读锁只在备份开始时占用很短的时间
mysqldump -u -p -h -P -S -A/-B –source-data=1 –single-transaction
mysqldump -uroot -poldboy123 –master-data=2 –single-transaction -A -B|gzip >/tmp/bak.sql.gz
gzip -d /tmp/bak.sql.gz

库数据备份进阶方式三:利用命令参数 -R -E –triggers
mysqldump -uroot -poldboy123 -B mdb –master-data=2 –single-transaction -R -E –triggers >/databases_backup/oldboy_`date +%F`.sql
“`

以上mysqldump备份中的特殊参数说明:

| 序号 | 参数信息 | 官方说明 | 解释说明 |
| —- | ———- | ———————————————– | ————————– |
| 01 | -R | Dump stored routines (functions and procedures) | 表示进行数据库存储过程备份 |
| 02 | -E | Dump events | 表示进行数据库事件信息备份 |
| 03 | –triggers | Dump triggers for each dumped table. | 表示进行触发器信息备份 |

“`sh
数据备份进阶方式四:利用命令参数 –max_allowed_packet=64M**

此参数表示数据库服务端与客户端在一次传送数据包的过程中,最大允许进行传输的数据包大小;

在某些时候如果备份的数据为大表数据,需要调整此参数信息;

如果没有正确的设置此参数信息,可能会导致备份大表数据时,会出现数据备份失败的情况;

应用场景:

– 有时候业务的需要,可能会存在某些字段数据长度非常大,造成插入和更新数据库会被max_allowed_packet 参数限制掉;

导致数据库操作失败。

– 将本地数据库迁移到远程数据库时运行sql错误。错误信息是max_allowed_packet

以上问题出现,经常出现的错误提示如下:

Packet for query is too large (20682943>1048576).
You can change this value on the server by setting the max_allowed_packet’ variable.

结合以上参数信息,进行标准化数据备份操作:

mysqldump -uroot -p123456 -A –master-data=2 –single-transaction -R -E –triggers –max_allowed_packet=64M >/database_backup/full_`date +%F`
vim /database_backup/full_2022-11-26.sql
SET @@GLOBAL.GTID_PURGED=/*!80000 ‘+’*/ ‘9d14be39-6423-11ed-bb21-000c2996c4f5:1-6′;
— 表示在进行数据恢复操作时,会将gtid1-6的事件信息删除掉,因为在之前备份数据中已经有了1-6的事件数据信息;
— 因此,从GTID的编号来看,可以从编号7事件开始进行数据增量恢复;
CHANGE MASTER TO MASTER_LOG_FILE=’binlog.000013’, MASTER_LOG_POS=1312;
— 输出信息表示增量数据的临界点在binlog.000013日志文件的1312位置,同时是备份结束时的位置点;

参数说明
-uroot
指定数据库用户为 root。
-p123456
指定数据库用户的密码为 123456。注意,直接在命令中明文写入密码可能存在安全风险。建议在生产环境中使用更安全的方式,如配置 .my.cnf 文件或使用 –prompt 参数。
-A
等同于 –all-databases,表示导出所有数据库。
–master-data=2
将当前的二进制日志文件名和位置写入导出文件中。这对于主从复制环境非常有用,可以确保备份文件中包含足够的信息用于恢复。
–single-transaction
启动一个事务,确保在导出过程中数据库的状态保持一致。适用于使用事务存储引擎(如 InnoDB)的数据库,不会锁定表。
-R
等同于 –routines,表示导出存储过程和函数。
-E
等同于 –events,表示导出事件调度器中的事件。
–triggers
表示导出表的触发器。
–max_allowed_packet=64M
设置最大允许的数据包大小为 64MB。这可以防止在导出大表时出现 max_allowed_packet 错误。
>/database_backup/full_date +%F“
将备份文件输出到 /database_backup 目录,并以当前日期(格式为 YYYY-MM-DD)命名备份文件。

使用mysqldump备份test1库中的t2表和test2库中的t1表
mysqldump -u root -p –single-transaction test1 t2 test2 t1 > backup.sql

mysqldump备份多个库所有表
mysqldump -u root -p –single-transaction test1 test2 > backup.sql
“`

### 2 mysqldump总结

“`sh
备份全库
mysqldump -uroot -p123456 -A –master-data=2 –single-transaction -R -E –triggers –max_allowed_packet=64M >/database_backup/full_`date +%F`
备份不同库中的一些表
mysqldump -u root -p –single-transaction test1 t2 test2 t1 > backup.sql
mysqldump备份多个库所有表
mysqldump -u root -p –single-transaction test1 test2 > backup.sql

“`

## 3 逻辑备份应用案例

“`sh
模拟企业生产场景,数据库管理人员误删除了数据库数据信息,通过mysqldump全备的部分数据信息,进行部分数据信息恢复;

再结合binlog日志文件增量数据信息,实现数据库增量数据恢复,最终实现数据库全部数据的完整复原。

– **项目故障说明:**

在某周周三下午14点左右,由于开发人员连接数据库实例错误,导致企业数据库服务生产数据被误删除了,亟待相关人员解决;

**01 模拟时间-某周周一~周二,正常网站用户访问网站进行数据库信息录入**

flush logs;
— 将binlog日志文件进行刷新,创建一个新的日志文件
create database mdb;
use mdb;
— 模拟创建用户存储数据的数据库信息
create table t1 (id int);
create table t2 (id int);
— 模拟创建用户存储数据的数据表信息
insert into t1 values(1),(2),(3);
insert into t2 values(1),(2),(3);
commit;
— 模拟用户向数据表中添加新的数据
select * from t1;
select * from t2;
— 检查用户创建的数据信息是否生成

**02 模拟时间-某周周二晚零点,企业数据库管理员进行一次数据库服务数据全备操作**

[root@xiaoQ ~]# mysqldump -uroot -p -A –master-data=2 –single-transaction -R -E –triggers –max_allowed_packet=64M >/database_backup/full_`date +%F`.sql

以上mysqldump备份中的特殊参数说明:

| 序号 | 参数信息 | 官方说明 | 解释说明 |
| —- | ———- | ———————————————– | ————————– |
| 01 | -R | Dump stored routines (functions and procedures) | 表示进行数据库存储过程备份 |
| 02 | -E | Dump events | 表示进行数据库事件信息备份 |
| 03 | –triggers | Dump triggers for each dumped table. | 表示进行触发器信息备份 |

**03 模拟时间-某周周二晚零点之后,模拟用户继续访问网站业务产生了增量的数据信息**

use mdb;
create table t3 (id int);
insert into t3 values(1),(2),(3);
insert into t2 values(4),(5),(6);
commit;

**04 模拟时间-某周周三下午14点,模拟系统相关技术人员误删除了数据库,并且已紧急跑路**

drop database mdb;

– **项目实战复原:**

**01 修复操作-查看找寻数据库服务全备数据,并进行全备数据恢复**

[root@xiaoQ-01 database_backup]# ll
-rw-r–r– 1 root root 51256606 11月 26 01:53 full_2022-11-26.sql
[root@xiaoQ ~]# mysql -uroot -p123456
source /database_backup/full_2022-11-26.sql
— 强调说明 强调说明 强调说明,此步骤操作了解作用后,请在后面进行操作,不要在此步骤就进行数据恢复

use mdb;
show tables;
+——————–+
| Tables_in_mdb |
+——————–+
| t1 |
| t2 |
+——————–+
2 rows in set (0.00 sec)
— 查看全备的数据是否恢复成功

**02 修复操作-查看找寻数据库服务增量备份,并进行增量数据恢复**

# 检索恢复binlog临界位置
[root@xiaoQ ~]# vim /database_backup/full_2022-11-26.sql
SET @@GLOBAL.GTID_PURGED=/*!80000 ‘+’*/ ‘9d14be39-6423-11ed-bb21-000c2996c4f5:1-6′;
— 表示在进行数据恢复操作时,会将gtid1-6的事件信息删除掉,因为在之前备份数据中已经有了1-6的事件数据信息;
— 因此,从GTID的编号来看,可以从编号7事件开始进行数据增量恢复;
CHANGE MASTER TO MASTER_LOG_FILE=’binlog.000013’, MASTER_LOG_POS=1312;
— 输出信息表示增量数据的临界点在binlog.000013日志文件的1312位置,同时是备份结束时的位置点;

# 检索查看binlog日志文件获取误删除操作前的GTID
ll /data/3306/data/binlog.*
-rw-r—– 1 mysql mysql 1833 11月 26 01:55 /data/3306/data/binlog.000013
-rw-r—– 1 mysql mysql 64 11月 26 01:50 /data/3306/data/binlog.index
— 具体binlog日志是哪个,以企业具体情况而定,不一定是binlog.000013
show binlog events in ‘binlog.000013’;
+——————+——-+——————+————-+—————–+————————————————–+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+——————+——-+——————+————-+—————–+————————————————–+
| binlog.000013 | 2060 | Gtid | 1 | 2137 | SET @@SESSION.GTID_NEXT= ‘9d14be39-6423-11ed-bb21-000c2996c4f5:10′ |
| binlog.000013 | 2137 | Query | 1 | 2238 | drop database mdb /* xid=840 */ |
+——————+——-+——————+————-+—————–+————————————————–+
— 需要将GTID编号10的误删除数据库事件信息忽略,然后再进行数据信息的恢复

# 移动迁移binlog文件位置
[root@xiaoQ ~]# cp /var/lib/mysql/binlog.* /databases_backup/

# 操作截取binlog文件信息
[root@xiaoQ ~]# mysqlbinlog –skip-gtids –include-gtids=’9d14be39-6423-11ed-bb21-000c2996c4f5:7-9’ /data/3306/data/binlog.000013 >/database_backup/add_bin.sql
— include-gtids是指定前面临界位置点,截取之后的日志文件信息

# 增量恢复binlog数据信息
set sql_log_bin=0;
— 建议在进行数据日志恢复数据时,将数据恢复时执行的SQL语句信息,不做binlog日志记录;恢复后别忘在改为1;
source /database_backup/add_bin.sql
— 完成数据信息的增量恢复

**03 修复操作-进行测试核验数据信息是否完全恢复,并进行最终全量备份**

# 核验检查恢复后的数据信息
use mdb;
show tables;
select * from t1;
select * from t2;
select * from t3;

# 完成核验之后数据完整备份
[root@xiaoQ ~]# mysqldump -uroot -p -A –master-data=2 –single-transaction -R -E –triggers –max_allowed_packet=64M >/database_backup/full_`date +%F`.sql

> 说明:数据库数据修复复原完毕后,别忘让开发人员或测试人员进行业务功能测试,最终让运维人员恢复业务上线。
“`

## 4 物理备份实践

“`sh
在数据库服务运行使用过程中,除了上面介绍的逻辑备份数据方法,还可以采用物理方式备份数据信息;

物理备份数据方式又可以细分为`冷备份和热备份`两种,和逻辑备份相比,它的最大优点是备份和恢复的速度更快;

因为物理备份的原理都是基于文件的cp。
“`

### 1 物理冷备份

“`sh
冷备份其实就是停掉数据库服务,cp数据文件的方法;这种方法对MyISAM和InnoDB存储引擎都合适,但是一般很少使用,

因为很多应用是不允许长时间停机的。

– 进行备份的操作过程:

停掉MySQL服务,在操作系统级别备份MySQL的数据文件和日志文件到备份目录;

– 进行恢复的操作过程:

停掉MySQL服务,在操作系统级别恢复MySQL的数据文件,然后重启MySQL服务,使用mysqlbinlog工具恢复增量数据日志;
“`

### 2 物理热备份

“`sh
– 数据库存储引擎应用:MyISAM

MyISAM存储引擎的热备份有很多方法,本质其实就是将要备份的表加读锁,然后再cp数据文件到备份目录:
**方法一:使用mysqlhotcopy工具**

mysqlhotcopy是MySQL自带的一个热备份工具,使用方法很简单:

​“`tiki wiki
[root@xiaoQ ~]# mysqlhotcopy db_name [/path/to/new_directory]
— mysqlhotcopy有很多选项,具体可以使用–help查看帮助信息;
​“`

**方法二:手工锁表copy**

在mysqlhotcopy使用不熟悉的情况下,可以手工来做热备份,操作步骤如下:

​“`tiki wiki
# 对数据库中所有表加读锁:
mysql> flush tables for read;
— 然后cp数据文件到备份目录即可;
​“`

– 数据库存储引擎应用:InnoDB

Xtrabackup(PXB)是Percona公司CTO Vadim参与开发的一款基于InnoDB的在线热备工具,属于物理备份数据工具;

具有开源、免费、支持在线热备、备份恢复速度快、占用磁盘空间小等特点,并且支持不同情况下的多种备份形式。

官方软件下载链接:https://www.percona.com/downloads/

对于数据库8.0.20版本,需要使用PXB 8.0.12+以上版本,对于数据库8.0.11~8.0.19,可以使用PXB 8.0正式版本;

PXB 8.0只能备份MySQL 8.0版本数据,不能备份低版本数据信息;如果想备份数据库服务低版本程序数据,需要下载使用PXB 2.4版本;

xtrabackup包含两个主要的工具:xtrabackup和innobackupex

– xtrabackup 只能备份InnoDB和XtraDB两种类型的数据表,而不能备份MyISAM类型数据表;
– innobackupex 是一个封装了xtrabackup的perl脚本,支持同时备份InnoDB和MyISAM,但对MyISAM备份时需要加全局读锁;

由于PXB属于第三方软件工具程序,因此需要进行单独下载安装:
# 进行软件程序上传
wget https://downloads.percona.com/downloads/Percona-XtraBackup-8.0/Percona-XtraBackup-8.0.35-31/binary/redhat/7/x86_64/percona-xtrabackup-80-debuginfo-8.0.35-31.1.el7.x86_64.rpm?_gl=1*5s32hw*_gcl_au*MTM1NzMzMDIzMi4xNzM5MTU5ODYz

# 进行软件程序安装
[root@xiaoQ-01 local]# yum install -y percona-xtrabackup-80-8.0.13-1.el7.x86_64.rpm
— 利用yum方式安装本地的rpm包程序,可以有效解决软件依赖的问题;
**Xtrabackup数据备份方式01:实现全量备份**

​“`tiki wiki
# 全量备份操作:
mkdir /data/backup/full -p
— 进行物理备份的目标目录不能存在数据信息,需要指定一个空目录进行备份
xtrabackup –defaults-file=/etc/my.cnf –host=192.168.30.101 –user=root –password=123456 –port=3306 –backup –target-dir=/data/backup/full
或者使用参数–datadir替换掉参数–defaults-file
xtrabackup –datadir=/data/3306/data –user=root –password=123456 –port=3306 –backup –target-dir=/data/backup/full
— backup参数信息表示进行全备操作
# 物理备份命令执行输出信息说明:
221127 02:46:11 >> log scanned up to (277574297)
— 记录日志位置点信息,表示进行拷贝数据的checkpoint的SN号码,相当于磁盘当前数据页的SN号码;
Using undo tablespace ‘./undo_001’.
Using undo tablespace ‘./undo_002’.
Opened 2 existing undo tablespaces.
221127 02:46:11 [01] Copying ./ibdata1 to /data/backup/full/ibdata1
221127 02:46:11 [01] …done
221127 02:46:11 [01] Copying ./sys/sys_config.ibd to /data/backup/full/sys/sys_config.ibd
221127 02:46:11 [01] …done
221127 02:46:11 [01] Copying ./mysql.ibd to /data/backup/full/mysql.ibd
… 省略部分信息…
— 进行相关数据文件、日志文件、共享表空间文件、数据表空间文件等文件的拷贝,并且拷贝过程是不会进行锁表操作的;
— 数据表空间信息备份完毕后,会有提示字段信息,并且此时会锁定binlog日志文件,并将binlog日志文件复制到备份目录;
— 在进行binlog日志文件备份时,会生成xtrabackup_binlog_info文件信息,用于记录物理备份后的二进制日志位置点;
— 二进制日志文件备份完毕后,会释放binlog日志文件锁定状态,并再次检查checkpoint的SN号码,确认redo日志是否变化;

[root@xiaoQ-01 backup]# ll /data/backup/full/
— 可以看到将原有数据库的数据目录信息,已经基本迁移到指定的物理备份目录中;
​“`

Xtrabackup数据备份工具在热备操作后产生的特殊数据文件说明:

| 序号 | 文件名称 | 解释说明 |
| —- | ———————- | ———————————————————— |
| 01 | xtrabackup_binlog_info | 表示用于存储备份时的binlog位置点信息 |
| 02 | xtrabackup_checkpoints | 表示用于记录备份时的数据页LSN信息,主要用于接下一次备份,需要保证连续性; |
| 03 | xtrabackup_info | 表示整体物理备份信息的总览 |
| 04 | xtrabackup_logfile | 表示存储在备份数据期间产生的新的的redo日志的信息; |
| 05 | xtrabackup_tablespaces | 表示用于存储表空间的其余信息 |

**Xtrabackup数据恢复方式01:全量备份恢复**

模拟进行数据库数据破坏性操作:

​“`tiki wiki
[root@xiaoQ ~]# pkill mysqld
[root@xiaoQ ~]# rm -rf /data/3306/data/*
[root@xiaoQ ~]# rm -rf /data/3306/logs/*
[root@xiaoQ ~]# rm -rf /data/3306/binlog/*
​“`

进行数据库数据恢复的操作过程:

​“`tiki wiki
[root@xiaoQ ~]# xtrabackup –prepare –target-dir=/data/backup/full
…忽略部分信息…
Shutdown completed; log sequence number 19214860
221127 16:31:58 completed OK!
— 表示模拟CR过程,将redo日志进行前滚,undo日志进行回滚,让恢复数据信息保持一致性状态

[root@xiaoQ ~]# xtrabackup –copy-back –target-dir=/data/backup/full
— 将进行物理备份后的数据,再次进行还原恢复到备份前的目录中(拷贝回数据)
xtrabackup –copy-back –target-dir=/data/backup/full –datadir=/data/3306/data/
[root@xiaoQ ~]# chown -R mysql.mysql /data/*
[root@xiaoQ ~]# /etc/init.d/mysqld start
— 重新设置数据目录权限,并重新启动恢复数据库业务
​“`

“`

xtrabackup下载流程

https://www.percona.com/

![image-20250211105006345](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250211105006345.png)

点击mysql–software

![Image 1](C:\Users\Administrator\Desktop\Image 1.png)

![2025-02-11 10 54 07](C:\Users\Administrator\Desktop\2025-02-11 10 54 07.png)

![image-20250211105614431](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250211105614431.png)

根据版本选择下载

## 5 克隆备份

“`sh
在数据库MySQL 8.0(8.0.17+)版本中,引入了数据库的克隆功能,主要是借助clone-plugin实现的,是对数据页底层克隆;

克隆的数据是InnoDB存储引擎中的物理快照信息,包括schemas, tables, tablespaces, and data dictionary metadata;

在数据库中出现克隆功能,主要是为了满足目前云原生的技术应用场景,同时也是为了海量数据备份而诞生的;

在数据库中实现克隆功能应用有两种方式:
**本地克隆(Local Cloning):**

启动克隆操作的MySQL数据库服务器实例中的数据,将会克隆到同服务器或同节点上的一个目录里;
**远程克隆(Remote Cloning)**:

默认情况下,远程克隆操作会删除接受者(recipient)数据目录中的数据,并将其替换为捐赠者(donor)的克隆数据;

也可以将数据克隆到接受者的其他目录中,以避免删除现有数据;(属于可选操作);

主要用于实现数据远程的快速热迁移操作,在迁移过程中,除了DDL操作情况,其他操作都不会出现阻塞情况;

还可以利用远程克隆技术,实现快速构建数据库的主从架构环境,实现主从数据信息快速复制同步;

数据库克隆原理说明**

在进行数据库克隆操作时,会经历几个重要的过程或步骤:

**01 Page copy:**

在进行数据页复制操作时,会涉及到两个操作动作:

开启redo archiving功能,从当前点开始存储新增的redo_log,这样从当前位置点开始所有的增量修改都不会丢失;

同时上一步在page track的page被发送到目标端,确保当前位置点之前所有做的变更一定发送到目标端;

关于redo archiving实际上这是官方早就存在的功能,主要用于官方的企业级备份工具,clone利用了该特性来维持记录增量产生的redo

在开始克隆前会做一次checkpoint;

对于redo archiving功能应用,会开启一个后台线程log_archiver_thread()来做日志归档;

当有新的写入时(notify_about_advanced_write_lsn),也会通知线程去进行归档,当arch_log_sys处于活跃状态时,

线程会控制日志写入以避免未归档的日志被覆盖(log_write_wait_on_archiver),注意如果log_write等待时间过长的话,

archive任务会被中断掉;

**02 Redo copy:**

停止redo archiving功能,所有归档的日志被发送到目标端,这些日志包含了从page copy阶段开始到现在的所有日志;

另外可能还需要记下当前的复制点,例如:最后一个事务提交时的binlog位置点或者gtid信息,在系统页中可以找到;

**03 Done:**

目标端重启实例,通过crash recovery将redo log应用上去;

克隆原理过程分析参考链接:https://zhuanlan.zhihu.com/p/437760913

> 说明:整个克隆过程都会以事件信息记录,可以很清晰的看到克隆的流程,如果克隆过程中断,也会以追加方式进行继续克隆;

在进行克隆功能应用时,也是存在一些限制性操作的:(结合官方列出的限制)

– 对于MySQL 8.0.27之前版本,在进行克隆操作期间,是不允许在捐赠者和接受者上进行DDL操作,包括:truncate table操作;

对于MySQL 8.0.27之后版本,在捐赠者上默认允许并发DDL操作,对于捐赠者上并发DDL的支持由clone_block_DDL变量控制;

– 对于不同版本的MySQL数据库实例之间,是不能进行克隆操作的。对于捐赠者和接受者必须是确切相同数据库服务版本;

例如:你不能克隆数据在between MySQL 5.7 and MySQL 8.0, or between MySQL 8.0.19 and MySQL 8.0.20;

这个克隆功能只支持在数据库8.0.17版本或之后的版本

参考官方链接说明:https://dev.mysql.com/doc/refman/8.0/en/clone-plugin-limitations.html

**实现本地克隆操作过程:**

克隆需求:实现快速创建和源数据库服务一模一样的多实例服务程序;

克隆操作步骤01:加载克隆插件信息

​“`tiki wiki
# 进行克隆插件加载配置
mysql> INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;
或者
[mysqld]
plugin-load-add=mysql_clone.so
clone=FORCE_PLUS_PERMANENT

# 查看克隆插件加载情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = ‘clone’;
+——————+———————-+
| PLUGIN_NAME | PLUGIN_STATUS |
+——————+———————-+
| clone | ACTIVE |
+——————+———————-+
1 row in set (0.00 sec)
​“`

克隆操作步骤02:创建克隆专用用户

​“`tiki wiki
mysql> create user clone_user@’%’ identified by ‘password’;
mysql> grant backup_admin on *.* to ‘clone_user’;
— backup_admin权限是mysql 8.0才有的备份导出的权限;
​“`

克隆操作步骤03:进行本地克隆操作

​“`tiki wiki
mkdir -p /data/test
chown -R mysql.mysql /data/
mysql -uclone_user -ppassword
mysql> clone local data directory = ‘/data/test/clonedir’;
— 完成本地数据库目录的克隆操作,如果出现异常需要删除克隆目录,在进行重新克隆操作
​“`

克隆操作步骤04:观测本地克隆状态(另开窗口使用管理员用户查看)

​“`tiki wiki
mysql> select stage,state,end_time from performance_schema.clone_progress;
+—————+—————-+———————————–+
| stage | state | end_time |
+—————+—————-+———————————–+
| DROP DATA | Completed | 2022-11-28 01:11:17.715901 |
| FILE COPY | Completed | 2022-11-28 01:11:17.752819 |
| PAGE COPY | Completed | 2022-11-28 01:11:17.756830 |
| REDO COPY | Completed | 2022-11-28 01:11:17.757802 |
| FILE SYNC | Completed | 2022-11-28 01:11:17.912679 |
| RESTART | Not Started | NULL |
| RECOVERY | Not Started | NULL |
+—————+—————-+———————————–+
7 rows in set (0.00 sec)
— 当克隆数据量比较大的时候,可以使用此SQL语句进行克隆状态查看
​“`

克隆操作步骤05:实现克隆日志观测

​“`tiki wiki
mysql> set global log_error_verbosity=3;
tail -f db01.err
clone local data directory = ‘/data/test/clonedir’
​“`

克隆操作步骤06:启动运行克隆实例

​“`tiki wiki
mysqld_safe –datadir=/data/test/clonedir –port=3333 –socket=/tmp/mysql3333.sock –user=mysql –mysqlx=off &
netstat -lntup|grep 3333
tcp6 0 0 :::3333 :::* LISTEN 52674/mysqld

# 核实查看克隆后数据库信息
mysql -uroot -p123456 -S /tmp/mysql3333.sock
mysql> show databases;
​“`

**实现远程克隆操作过程:**

在进行实现远程克隆操作步骤之前,可以利用虚拟软件再次克隆出一台新的数据库8.0版本的服务器主机;

克隆操作步骤01:克隆操作环境准备

​“`tiki wiki
# 在克隆接收者主机上清理数据库服务环境:
pkill mysqld
rm -rf /data/3306/data/*
rm -rf /data/3306/binlog/*
rm -rf /data/3306/logs/*

# 在克隆接收者主机上进行实例初始化操作:
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data
vim /etc/my.cnf
[mysqld]
server_id=16
— 修改克隆接收者主机上的server_id的配置信息

# 在克隆接收者主机上进行实例的运行操作:
/etc/init.d/mysqld start
​“`

克隆操作步骤02:加载克隆插件信息

​“`tiki wiki
# 进行克隆插件加载配置
mysql> INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;
或者
[mysqld]
plugin-load-add=mysql_clone.so
clone=FORCE_PLUS_PERMANENT
— 克隆插件信息需要在克隆主机的捐赠者和接受者上都进行安装

# 查看克隆插件加载情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = ‘clone’;
+——————+———————-+
| PLUGIN_NAME | PLUGIN_STATUS |
+——————+———————-+
| clone | ACTIVE |
+——————+———————-+
1 row in set (0.00 sec)
— 克隆插件信息需要在克隆主机的捐赠者和接受者上都进行安装后确认
​“`

克隆操作步骤03:创建克隆专用用户

​“`tiki wiki
# 在克隆捐赠者主机上进行授权(数据库01主机上设置)
mysql> create user test_jz@’%’ identified by ‘password’;
mysql> grant backup_admin on *.* to test_jz@’%’ ;
— backup_admin权限是mysql 8.0才有的备份导出的权限;

# 在克隆接收者主机上进行授权(数据库02主机上设置)
mysql> create user test_js@’%’ identified by ‘password’;
mysql> grant clone_admin on *.* to test_js@’%’ ;
— clone_admin权限是mysql 8.0才有的克隆同步数据的权限;
​“`

> 说明:可以在克隆捐赠者主机上和接收者主机上均创建两个用户信息,防止克隆同步数据后,接收者主机上不再含有接收用户信息;

克隆操作步骤04:进行远程克隆操作

​“`tiki wiki
# 在克隆接收者主机上进行设置
mysql> set global clone_valid_donor_list=’10.0.0.51:3306′;
— 设置克隆同步数据的信任列表

# 在克隆接收者主机上进行克隆
mysql -utest_js -ppassword -h192.168.30.102 -P3306
mysql> clone instance from test_jz@’192.168.30.101′:3306 identified by ‘password’;
— 在接收者主机上实现远程克隆操作
​“`

克隆操作步骤05:观测本地克隆状态

​“`tiki wiki
mysql> select stage,state,end_time from performance_schema.clone_progress;
+—————+—————-+———————————–+
| stage | state | end_time |
+—————+—————-+———————————–+
| DROP DATA | Completed | 2022-11-29 00:15:34.002378 |
| FILE COPY | Completed | 2022-11-29 00:15:35.218397 |
| PAGE COPY | Completed | 2022-11-29 00:15:35.225659 |
| REDO COPY | Completed | 2022-11-29 00:15:35.229777 |
| FILE SYNC | Completed | 2022-11-29 00:15:35.773431 |
| RESTART | Completed | 2022-11-29 00:15:39.189607 |
| RECOVERY | Completed | 2022-11-29 00:15:39.978301 |
+—————+—————-+———————————–+
7 rows in set (0.00 sec)
— 当克隆数据量比较大的时候,可以使用此SQL语句进行克隆状态查看,在克隆接收者主机上进行查看
mysql> show databases;
— 此时克隆接收者主机上查看到的数据信息,与克隆捐赠者主机上查看到的数据信息一致,即远程克隆操作完成
​“`

###
“`

## 6 数据库备份总结

“`sh
数据库备份恢复管理 (进阶)
逻辑方式备份数据信息 mysqldump 参数应用
扩展应用参数 –master-data(source-data)
功能作用:
1)可以实现对数据表信息进行锁定
2)会在备份文件中生成备份数据结束的位置点信息 –master-data=1(默认–没有注释显示change master命令信息) –master-data=2(含有注释显示change master命令信息 ???)
CHANGE MASTER TO MASTER_LOG_FILE=’bin-log.000025′, MASTER_LOG_POS=137469;
— 可以区分全量备份数据和增量数据 可以用于从库进行数据同步 ???

扩展应用参数 –single-transaction
功能作用:
1)在进行备份时,会完成一次语句信息提交操作
2)可以实现生成数据快照信息,从而避免利用锁机制保证数据一致性,影响业务

扩展应用参数 –max-allowed-packet=128M
功能作用:
1)影响客户端的DML语句的执行操作
2)影响数据库服务备份恢复操作
PS:在备份时应用此参数信息,可以在恢复数据信息,恢复大表的大量数据信息
若不配置此参数,在早期5.6 5.5 数据库中,恢复大表数据时,会出现以下报错信息
ERROR 1301 (HY000): Result of repeat() was larger than max_allowed_packet (1024) – truncated

Packet for query is too large (20682943>1048576).
You can change this value on the server by setting the max_allowed_packet’ variable.

扩展应用参数 -R -E –triggers
-R 备份数据库存储过程信息 (开发相关) 开发代码 SQL语句 C客户端 – 传参信息 网络(带宽固定)-》 mysql server (脚本信息-注册脚本 登录脚本 — 存储过程)
-E 备份数据库事件信息 (开发相关) 数据库中可以实现自动执行语句的定时任务信息(银行卡利息)
–triggers 备份数据库触发器信息 (开发相关) 当执行增 删 改时,会自动完成一些列操作

mysqldump -uroot -p123456 -A –source-data –single-transaction –max-allowed-packet=64M -R -E –triggers >/backup/all.sql
— 以上mysqldump操作命令备份数据库所有数据,是最全最合理备份方式

物理方式备份数据信息:(进阶-热备)
应用第三方软件:xtrabackup

部署安装/应用 xbk工具:
步骤一:下载xbk软件程序包
MySQL 高于8.0.19版本 应用xbk软件版本 对应数据库版本 (MySQL 8.0.32 )
MySQL 8.0.11~8.0.19 应用xbk软件版本 PXB 8.0
MySQL 低于8.0.11版本 应用xbk软件版本 PXB 2.4

步骤二:安装xbk软件程序包
yum localinstall -y percona-xtrabackup-80-8.0.32-26.1.el7.x86_64.rpm

步骤三:应用xbk软件进行备份恢复(物理备份/恢复)
备份过程–全量备份
mkdir -p /backup/full — 空目录
xtrabackup –defaults-file=/etc/my.cnf –host=10.0.0.51 –port=3306 –user=root –password=123 –backup –target-dir=/backup/full
–defaults-file — 加载需要备份数据的实例信息(datadir 加载数据目录信息)

2025-01-20T06:12:42.807871+08:00 0 [Note] [MY-011825] [Xtrabackup] completed OK!
— 以上备份操作成功,会看到命令执行后最后的输出信息为 OK

或者使用参数–datadir替换掉参数–defaults-file
xtrabackup –datadir=/data/3306/data –host=10.0.0.51 –port=3306 –user=root –password=123 –backup –target-dir=/backup/full
PS:利用xbk工具只能实现本地数据库数据信息备份
备份数据特点:xbk可以将备份开始前的所有磁盘文件数据保存备份,也可以将备份期间增量数据做备份

恢复过程–全量恢复
步骤一:需要停止数据库服务
/etc/init.d/mysql.server stop

步骤二:清理原有数据目录信息
cp -a /data/3306/data/ /backup/data-02
rm -rf /data/3306/data/*
rm -rf /data/3306/log/*

步骤三:恢复数据信息
xtrabackup –prepare –target-dir=/backup/full — 将内存部分数据恢复
[Note] [MY-011825] [Xtrabackup] completed OK!
xtrabackup –copy-back –target-dir=/backup/full — 将磁盘文件部分恢复
[Note] [MY-011825] [Xtrabackup] completed OK!

chown -R mysql.mysql /data/3306/data/
chown -R mysql.mysql /data/3306/log/

步骤四:启动恢复数据库服务/测试数据信息
/etc/init.d/mysql.server start

备份过程–增量备份
步骤一:创建备份数据的目录
mkdir -p /backup/full — 周日做的全量备份数据保存目录
mkdir -p /backup/week-01 — 周一做的增量备份数据保存目录
mkdir -p /backup/week-02 — 周二做的增量备份数据保存目录

步骤二:实现数据备份操作
xtrabackup –defaults-file=/etc/my.cnf –host=10.0.0.51 –user=root –password=123 –port=3306 –backup –parallel=4 –target-dir=/backup/full
— 以上备份操作,表示第一次的全量备份 (参数–parallel=4 在进行备份数据时开启的线程数量 可以提高备份数据效率)

创建周一的增量数据
mysql> create database test10;
Query OK, 1 row affected (0.03 sec)

mysql> use test10;
Database changed
mysql> create table t1 (id int);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t1 values (1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0

xtrabackup –defaults-file=/etc/my.cnf –host=10.0.0.51 –user=root –password=123 –port=3306 –backup –parallel=4 –target-dir=/backup/week-01 –incremental-basedir=/backup/full
— 以上备份操作,表示第一次的增量备份 (–incremental-basedir 加载识别上一次备份数据目录信息)

创建周二的增量数据
mysql> create database test11;
Query OK, 1 row affected (0.03 sec)

mysql> use test11;
Database changed
mysql> create table t1 (id int);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t1 values (1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0

xtrabackup –defaults-file=/etc/my.cnf –host=10.0.0.51 –user=root –password=123 –port=3306 –backup –parallel=4 –target-dir=/backup/week-02 –incremental-basedir=/backup/week-01
— 以上备份操作,表示第二次的增量备份 (–incremental-basedir 加载识别上一次备份数据目录信息)

恢复过程–增量恢复
步骤一:需要停止数据库服务
/etc/init.d/mysql.server stop

步骤二:清理原有数据目录信息
cp -a /data/3306/data/ /backup/data-02
rm -rf /data/3306/data/*
rm -rf /data/3306/log/*

步骤三:恢复数据信息
xtrabackup –prepare –apply-log-only –target-dir=/backup/full
— 以上操作,表示加载全量数据目录中信息 (加载全量数据目录中内存数据信息 加载磁盘数据信息)
xtrabackup –prepare –apply-log-only –target-dir=/backup/full –incremental-dir=/backup/week-01
xtrabackup –prepare –apply-log-only –target-dir=/backup/full –incremental-dir=/backup/week-02
— 以上操作,表示加载全量数据目录中信息 (加载增量数据目录中内存数据信息 加载磁盘数据信息)
xtrabackup –prepare –target-dir=/backup/full
— 将全量和增量整合后的内存信息进行恢复

xtrabackup –datadir=/data/3306/data –copy-back –target-dir=/data/backup/full
或者
xtrabackup –copy-back –target-dir=/backup/full
— 将全量和增量整合后的磁盘信息进行恢复

–apply-log-only
— 表示不会在恢复数据过程中,触发回滚操作

chown -R mysql.mysql /data/3306/data/
chown -R mysql.mysql /data/3306/log/

步骤四:启动恢复数据库服务/测试数据信息
/etc/init.d/mysql.server start
“`

# 第七章 主从

## 1 主从复制扩展应用:延时从库

“`sh
#### 主从复制扩展应用:延时从库

**概念介绍说明:**

表示人为主动方式将一个从库进行配置,使从库可以按照指定的时间延时后,再进行和主库完成相应数据信息同步;

**功能作用说明:**

通常对于数据库服务中的数据信息产生损坏,可能有两方面因素造成:

物理损坏:主机故障、磁盘异常、数据文件损坏…,可以利用传统主从复制方式,规避此类问题,利用从库替代主库工作任务;

逻辑损坏:误删除操作(drop truncate delete),可以利用备份数据+binlog日志方式,可以实现数据信息的修复,但是代价比较高;

利用延时从库同步功能,主要是对逻辑原因造成的数据损坏进行弥补修复,从而避免全备数据恢复业务产生的代价较高问题;

当出现逻辑损坏操作时,可以利用延时从库的延时同步特性,将异常操作不做同步,将从库未做破坏的数据信息恢复到主库中;
“`

“`sh
**功能应用实践:**

① 创建新的从库环境

​“`tiki wiki
mysql -S /tmp/mysql3309.sock
mysql> set global server_id=9;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@server_id;
+————-+
| @@server_id |
+————-+
| 9 |
+————-+
1 row in set (0.00 sec)
— 调整从库server_id信息,避免和主库产生冲突

# 可以将主库上的部分数据在从库上先进行同步
mysqldump -uroot -A -S /tmp/mysql3307.sock –master-data=2 –single-transaction >/tmp/full.sql
— 在3307主库上进行数据的全备(模拟企业环境的历史数据全备)
mysql -S /tmp/mysql3309.sock
mysql> source /tmp/full.sql;
— 在3309从库上进行数据的恢复(模拟企业环境的历史数据恢复)
— 将原有主机的数据先备份,然后从库中进行恢复一部分数据,随后再进行数据信息同步追加
— 可以利用同步方式有很多:mysqldump xtrabackup clone_plugin

# 设置从库连接主库信息,定义从库连接主库同步位置点自动复制
mysql> create user repl@’%’ identified by ‘XZnh@95599′;
Query OK, 0 rows affected (0.00 sec)

mysql> grant all on *.* to repl@’%’;
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> help change master to
— 获取连接主库,以及定义同步位置点的数据库配置模板信息
vim /tmp/full.sql
— CHANGE MASTER TO MASTER_LOG_FILE=’binlog.000004′, MASTER_LOG_POS=156;
— 通过备份文件获取同步位置点信息
mysql> CHANGE MASTER TO
MASTER_HOST=’192.168.137.51′,
MASTER_USER=’repl’,
MASTER_PASSWORD=’XZnh@95599′,
MASTER_PORT=3307,
MASTER_LOG_FILE=’binlog.000004′,
MASTER_LOG_POS=156,
MASTER_CONNECT_RETRY=10;
— 以上配置主从同步信息在从库进行执行;

# 利用相应线程实现主从数据库的数据同步复制
mysql> start slave;
— 在从库上激活数据复制同步功能

# 进行核实主从同步功能是否实现
mysql -S /tmp/mysql3307.sock
mysql> create database xiaoh;
— 在主库模拟创建数据信息
mysql -S /tmp/mysql3307.sock
mysql> show databases;
— 在从库模拟查看数据信息(确认是否同步数据)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.30.101
Master_User: repl
Master_Port: 3307
Connect_Retry: 10
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 347
Relay_Log_File: xiaoQ-01-relay-bin.000002
Relay_Log_Pos: 512
Relay_Master_Log_File: binlog.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
— 从库上查看数据同步状态情况,看到上面的两个Yes信息,就表示主从数据同步功能设置成功了
​“`

② 配置延时从库功能

​“`tiki wiki
# 在从库上配置应用延时同步功能
mysql> stop slave;
mysql> change master to master_delay=300;
mysql> start slave;
mysql> show slave status\G
*************************** 1. row ***************************
SQL_Delay: 300
SQL_Remaining_Delay: NULL
— 设置延时时间为300s后同步数据(生产建议延时3~6小时),以及最近事件要做同步的延时剩余时间;
​“`

③ 延时从库应用过程

延时从库的应用思路分析:

延时的根本效果是主库执行操作完成后,会经过指定的时间后,从库在执行主库曾经执行的操作;

基于主从同步原理分析,延时同步效果是在SQL线程上进行控制实现的,并非在IO线程上进行控制实现的;

SQL线程的延时控制机制,主要是需要识别同步操作任务的时间戳信息,根据时间戳和延时时间信息结合,判断相关任务是否同步执行;

> 简述:基于主从同步原理,IO线程同步主库操作事件是持续同步的,只是SQL线程在进行事件信息回放时,进行了延时控制;

企业应用延时从库事件模拟:

| 事件序号 | 操作语句 | 解释说明 |
| ——– | ————— | ———————————————– |
| 01 | 插入语句 insert | 假设在09:59时,持续有插入操作行为,需要进行同步 |
| 02 | 删除语句 drop | 假设在10:00时,产生了删除操作行为,需要避免同步 |

企业异常情况处理过程说明:

1)网站页面需要挂维护页面进行说明;

2)从库服务关闭SQL线程,停止事件任务回放;

3)将从库出现故障前的数据信息,即由于延时配置没有执行的操作回放,到出现故障点的时刻停止回放;

​“`tiki wiki
# 核实当前主从同步是完整状态
mysql> show master status;
+——————+———–+——————-+———————–+————————+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+——————+———–+——————-+———————–+————————+
| binlog.000004 | 347 | | | |
+——————+———–+——————-+———————–+————————+
1 row in set (0.00 sec)
— 核实主库应用日志文件和事件位置点情况;
mysql> show slave status\G
*************************** 1. row ***************************
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 347
Relay_Log_File: xiaoQ-01-relay-bin.000003
Relay_Log_Pos: 277
— 核实从库应用日志文件和事件位置点情况,确认和主库应用日志信息和事件位置点情况一致;

# 延时从库应用效果环境模拟
mysql > create database relaydb;
mysql > use relaydb;
mysql > create table t1 (id int);
mysql > insert into t1 values(1),(2),(3);
mysql > commit;
mysql > insert into t1 values(11),(12),(13);
mysql > commit;
mysql > insert into t1 values(111),(112),(113);
mysql > commit;
mysql > drop database relaydb;
— 以上操作语句在主库上进行执行;
mysql> show master status;
+——————+———–+——————-+———————–+————————+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+——————+———–+——————-+———————–+————————+
| binlog.000004 | 1793 | | | |
+——————+———–+——————-+———————–+————————+
1 row in set (0.00 sec)
— 核实主库应用日志文件和事件位置点情况;
mysql> show slave status\G
*************************** 1. row ***************************
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 1793
Relay_Log_File: xiaoQ-01-relay-bin.000003
Relay_Log_Pos: 277
SQL_Delay: 300
SQL_Remaining_Delay: 91
— 核实从库应用日志文件和事件位置点情况,

# 数据信息修复方式一:手工截取日志信息进行回放数据,恢复业务;
# 操作过程01:停止从库SQL线程回放日志事件
mysql > stop slave sql_thread;
— 停止从库SQL线程,终止持续同步操作,使从库不再回放同步数据;
mysql > show slave status\G
*************************** 1. row ***************************
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 3239
Relay_Log_File: xiaoQ-01-relay-bin.000003
Relay_Log_Pos: 1723
Slave_IO_Running: Yes
Slave_SQL_Running: No
SQL_Delay: 300
SQL_Remaining_Delay: N
— 核实从库SQL线程状态是否为NO,以及获取读取的relay_log日志文件信息

# 操作过程02:根据relaylog起点信息以及异常操作位置点信息,截取日志内容信息
起点信息:
Relay_Log_File: xiaoQ-01-relay-bin.000003
Relay_Log_Pos: 1723

mysql> show relaylog events in ‘xiaoQ-01-relay-bin.000003’;
.. 省略部分…
| xiaoQ-01-relay-bin.000003 | 3056 | Query | 1 | 3239 | drop database relaydb /* xid=745 */
— 获取终点信息 3056
cd /data/3309/data/
[root@xiaoQ-01 data]# mysqlbinlog –start-position=1723 –stop-position=3056 xiaoQ-01-relay-bin.000003 >/tmp/relay.sql
— 在从库服务器上完成日志信息的截取操作

# 操作过程03:从库中恢复截取日志数据
mysql> set sql_log_bin=0;
mysql> source /tmp/relay.sql;
mysql> show databases;
+——————–+
| Database |
+——————–+
| relaydb |
+——————–+
— 核实数据库以及数据表信息已恢复,并且原有主从关系已经彻底奔溃,需要进行主从关系重构
mysql> stop slave;
mysql> reset slave all;
— 从库身份解除

# 数据信息修复方式二:持续延时从库数据回放同步过程,但同步过程停止在异常操作前;
# 操作过程01:停止从库SQL线程回放日志事件
mysql > stop slave sql_thread;
— 停止从库SQL线程,终止持续同步操作,使从库不再回放同步数据;
mysql > show slave status\G
*************************** 1. row ***************************
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 4685
Relay_Log_File: xiaoQ-01-relay-bin.000003
Relay_Log_Pos: 3169
Slave_IO_Running: Yes
Slave_SQL_Running: No
SQL_Delay: 300
SQL_Remaining_Delay: NULL
— 核实从库SQL线程状态是否为NO,以及获取读取的relay_log日志文件信息

# 操作过程02:回放日志事件在异常操作位置点前
mysql> show relaylog events in ‘xiaoQ-01-relay-bin.000003’;
+———————————-+——+——————-+———–+—————–+——————————————+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+———————————-+——+——————-+———–+—————–+——————————————+
…忽略部分..
| xiaoQ-01-relay-bin.000003 | 4394 | Xid | 1 | 4495 | COMMIT /* xid=757 */ |
| xiaoQ-01-relay-bin.000003 | 4425 | Anonymous_Gtid | 1 | 4572 | SET @@SESSION.GTID_NEXT= ‘ANONYMOUS’ |
| xiaoQ-01-relay-bin.000003 | 4502 | Query | 1 | 4685 | drop database relaydb /* xid=759 */ |
+———————————-+——+——————-+———–+—————–+——————————————+
— 获取异常操作日志文件信息和事件位置点信息,其中位置点信息以Pos列显示的为准,并且是提前一个事务位置点;
mysql > change master to master_delay=0;
— 在从库重启进行日志回放操作前,关闭从库延迟回放的功能
mysql > start slave until relay_log_file=”log_name”, relay_log_pos=log_pos;
mysql > start slave until relay_log_file=’xiaoQ-01-relay-bin.000003′, relay_log_pos=4425;
— 启动日志信息回放功能,直到指定位置点结束日志信息回放
mysql > start slave until sql_before_gtids=”xxxx3:4″;
— 如果开启了GTID功能,也可以按照GTID位置点进行数据信息回放(参考)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: No
Until_Log_File: xiaoQ-01-relay-bin.000003
Until_Log_Pos: 4425
— 从库重新回放操作恢复数据后,从库状态信息中SQL还是为NO,是正常的,因为直到指定位置点就终止回放;

# 操作过程03:核实异常数据信息是否恢复
mysql > show databases;
+——————–+
| Database |
+——————–+
| relaydb |
+——————–+
— 核实数据库以及数据表信息已恢复,并且原有主从关系已经彻底奔溃,需要进行主从关系重构
mysql> stop slave;
mysql> reset slave all;
— 从库身份解除
— 参考官方资料:https://dev.mysql.com/doc/refman/8.0/en/start-replica.html
​“`

####
“`

## 2 主从复制扩展应用:过滤复制

“`sh
主库上有多个数据库业务,希望将不同的数据库业务同步到不同的从库上,实现数据库业务分离;

为了满足以上需求,就可以利用过滤复制功能,将指定的数据信息复制到指定从库上,而不是全备方式同步数据;
“`

![image-20250212170016745](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250212170016745.png)

“`sh
**实现工作机制:**

– 解决方案一:在主库上进行限制

在主库上进行复制同步数据时,主库上存在A、B、C三个数据库信息,若只想复制其中A数据库的数据信息;

可以让数据库服务只记录A数据库的事件日志信息,对于B和C数据库信息进行不写入日志操作;

但是利用这种方法实现主从信息同步的过滤,可能会导致B和C库数据一旦损坏,由于没有记录日志,无法进行恢复的情况;

– 解决方案二:在从库上进行限制

在从库上进行复制同步数据时,利用从库上的SQL线程进行控制,只回放同步过来的A库数据信息,屏蔽其他数据库的信息不做回放;

利用从库进行同步数据过滤,不能减轻主库同步数据的压力,但可以减轻从库进行数据回放的压力;

**功能应用实践:**

① 查看主从限制过滤参数信息

​“`tiki wiki
# 查看主库复制过滤限制参数信息(了解即可)
mysql> show master status;
+——————+———–+——————-+———————–+————————-+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+——————+———–+——————-+———————–+————————-+
| binlog.000004 | 4685 | | | |
+——————+———–+——————-+———————–+————————-+
1 row in set (0.00 sec)
— 主库状态信息中,Binlog_Do_DB表示同步复制白名单过滤设置,Binlog_Ignore_DB表示同步复制黑名单过滤设置
— 过滤白名单表示会记录事件日志信息,过滤黑明白表示不会记录事件日志信息,一般选择其一进行应用即可
— 可以应用主库的过滤同步功能,实现数据库中默认库的同步复制限制;

# 查看从库复制过滤限制参数信息
mysql> show slave status\G
*************************** 1. row ***************************
Replicate_Do_DB: xiaoQ
Replicate_Ignore_DB: xiaoA
— 表示库级别的过滤操作,白名单设置表示回放库级别操作,黑名单设置表示忽略库级别操作

Replicate_Do_Table: xiaoQ.t1
Replicate_Ignore_Table: xiaoA.t1
— 表示表级别的过滤操作,白名单设置表示回放表级别操作,黑名单设置表示忽略表级别操作

Replicate_Wild_Do_Table: xiaoQ.t%
Replicate_Wild_Ignore_Table: xiaoA.t%
— 表示模糊级别的过滤操作,主要是可以针对多表信息,配置白名单或黑名单;
— 以上在从库上线实现数据同步过滤机制的参数信息有6个,主要可以分为3组,一般应用使用一个参数即可;
​“`

② 数据同步复制过滤效果配置

​“`tiki wiki
# 编写配置文件实现过滤
vim /data/3309/my.cnf
replicate_do_db=ppt
replicate_do_db=word

# 在线调整参数实现过滤
mysql> help change replication filter
mysql> stop slave sql_thread;
mysql> CHANGE REPLICATION FILTER REPLICATE_DO_DB = (word, ppt);
mysql> start slave sql_thread;
— 一般编写配置文件和在线配置都会进行,可以不重启数据库服务生效过滤机制,日后重启数据库后过滤机制依然生效;

# 查看获取从库过滤配置
mysql> show slave status\G
Replicate_Do_DB: word,ppt
Replicate_Ignore_DB:
​“`

③ 进行同步复制过滤效果测试

​“`tiki wiki
# 在主库上进行数据库创建模拟
mysql> create database word;
mysql> show slave status\G
*************************** 1. row ***************************
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 4870
— 从库日志信息同步查看
mysql> show databases;
+——————–+
| Database |
+——————–+
| word |
+——————–+
— 查看从库数据同步情况

mysql> create database ppt;
mysql> show slave status\G
*************************** 1. row ***************************
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 5052
— 从库日志信息同步查看
mysql> show databases;
+——————–+
| Database |
+——————–+
| ppt |
+——————–+
— 查看从库数据同步情况

mysql> create database xiaoA;
mysql> show slave status\G
*************************** 1. row ***************************
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 5240
— 从库日志信息同步查看
mysql> show databases;
+——————–+
| Database |
+——————–+
| |
+——————–+
— 查看从库数据同步情况,并未实现xiaoA数据库的复制,即实现了数据同步过滤效果;
​“`

####
“`

## 3 半同步复制

“`sh
在MySQL5.5版本之前,数据库的复制是异步操作,主库和从库的数据之间存在一定的延迟,这样就存在数据存储不一致的隐患;

假设当主库上写入一个事务并提交成功, 而从库尚未得到主库推送的binlog日志时,主库宕机了;

例如主库可能因磁盘损坏、内存故障等造成主库上该事务binlog丢失,此时从库就可能损失这个事务,从而造成主从不一致;

为了解决这个问题,数据库服务引入了半同步复制机制。

当采用异步方式同步数据,由于从库异常宕机情况出现,造成主从数据不一致情况出现,还会有以下影响情况:

– 会造成从库可能创建语句没有执行,后续的插入语句也必然失败,形成SQL线程运行故障;

– 由于主从数据信息不一致,在架构设计上在读取从库数据信息时,就会读取数据信息异常;

> 说明:利用半同步复制机制,主要是用于解决主从数据复制不一致的问题,即解决主从数据一致性问题,也可以避免SQL线程故障;
半同步复制技术与传统主从复制技术不同之处:

– 在主库提交操作时候会受到阻塞,等待从库IO线程返回ack确认信号后,才能使主库提交操作成功;

– 从库IO线程接收到binlog日志信息,当日志信息写入到磁盘上的relaylog文件时,会给主库返回ack信号;

在主库上会利用ack_receiver线程接收返回的ack信号;

– 当主库上的ack_receiver线程接收到ack信号信息时,会产生事件触发机制,告诉主库事务提交操作成功了;

– 如果在接收ack信号时,等待信号时间超过了预设值的超时时间,半同步复制会切换为原始的异步复制方式;

预设的等待超时时间的数值,由参数rpl_semi_sync_master_timeout设置的毫秒数决定
“`

![1689180659727](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/1689180659727.png)

“`sh
**功能应用实践:**

① 主从数据库安装半同步功能插件:

​“`tiki wiki
# 进行主从同步重构
mysqldump -uroot -A -S /tmp/mysql3307.sock –master-data=2 –single-transaction >/tmp/full.sql
grep “\– CHANGE” /tmp/full.sql
— CHANGE MASTER TO MASTER_LOG_FILE=’binlog.000004′, MASTER_LOG_POS=5240;
— 在主库进行数据备份,并获取备份位置点信息
mysql> stop slave;
mysql> reset slave all;
mysql> CHANGE MASTER TO
MASTER_HOST=’192.168.30.101′,
MASTER_USER=’repl’,
MASTER_PASSWORD=’123456′,
MASTER_PORT=3307,
MASTER_LOG_FILE=’binlog.000004′,
MASTER_LOG_POS=5240,
MASTER_CONNECT_RETRY=10;
mysql> start slave;
— 实现从库数据库同步功能重构

# 主库安装半同步插件(3307)
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME ‘semisync_master.so’;
或者
[mysqld]
plugin_dir=/usr/local/mysql/lib/plugin
plugin-load=rpl_semi_sync_master=semisync_master.so
— 主库利用插件控制ack_receiver线程接收ack确认信息,并且会控制commit阻塞,实现半同步复制功能
mysql> show plugins;
+———————————+———-+——————–+————————–+———-+
| Name | Status | Type | Library | License |
+———————————+———-+——————–+————————–+———-+
| rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL |
+———————————+———-+——————–+————————–+———-+
— 查看插件是否进行加载

# 从库安装半同步插件(3309)
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME ‘semisync_slave.so’;
或者
[mysqld]
plugin_dir=/usr/local/mysql/lib/plugin
plugin-load=rpl_semi_sync_slave=semisync_slave.so
— 从库利用插件控制IO线程发送ack确认信息;
mysql> show plugins;
+———————————+———-+——————–+————————–+———-+
| Name | Status | Type | Library | License |
+———————————+———-+——————–+————————–+———-+
| rpl_semi_sync_slave | ACTIVE | REPLICATION | semisync_slave.so | GPL |
+———————————+———-+——————–+————————–+———-+
— 查看插件是否进行加载
​“`

> 说明:一般在高可用数据库架构环境中,可以在高可用的两台主机上均安装好主库插件和从库插件;

② 主从数据库启动半同步插件功能:

​“`tiki wiki
# 主库启动半同步功能
mysql> set global rpl_semi_sync_master_enabled =1;

# 从库启动半同步功能
mysql> set global rpl_semi_sync_slave_enabled =1;

# 重启从库上的IO线程
mysql> stop slave IO_THREAD;
mysql> start slave IO_THREAD;

# 核实确认半同步功能状态:
mysql> show status like ‘rpl_semi_sync_master_status’;
+————————————–+——-+
| Variable_name | Value |
+————————————–+——-+
| Rpl_semi_sync_master_status | ON |
+————————————–+——-+
1 row in set (0.01 sec)
— 核实主库半同步功能是否激活

mysql> show status like ‘rpl_semi_sync_slave_status’;
+————————————–+——-+
| Variable_name | Value |
+————————————–+——-+
| Rpl_semi_sync_slave_status | ON |
+————————————–+——-+
1 row in set (0.00 sec)
— 核实从库半同步功能是否激活
​“`

③ 主从数据库半同步功能永久配置:

​“`tiki wiki
# 在数据库配置文件中编写以下参数
rpl_semi_sync_master_enabled=on
— 主库半同步功能启停设置,on为激活设置
rpl_semi_sync_master_timeout=1000
— 主库接收从库确认信息的超时时间设置(单位毫秒)
rpl_semi_sync_master_trace_level=32
— 用于开启半同步复制模式时的调试级别,默认是32
rpl_semi_sync_master_wait_for_slave_count=1
— 用于控制在主库需要从库确认的数量,默认为1
rpl_semi_sync_master_wait_no_slave=on
— 是否允许每个事物的提交都要等待slave的信号
— on为每一个事物都等待,除非超过等待时间
— off表示master发现Rpl_semi_sync_master_clients小于rpl_semi_sync_master_wait_for_slave_count,则master立即转为异步模式
rpl_semi_sync_master_wait_point=after_sync
— 用来控制半同步模式下主库在返回给session事物成功之前的事务提交方式
— after_sync (新版半同步复制同步机制)
— 主服务器将每个事务写入其二进制日志和从服务器,并将二进制日志同步到磁盘。同步后,主设备等待从设备确认事务接收。在收到确认后,主服务器将事务提交给存储引擎,并将结果返回给客户端,然后客户端可以继续。
— after_commit (旧版半同步复制同步机制)
— 主服务器将每个事务写入其二进制日志和从服务器,同步二进制日志,并将事务提交给存储引擎。主提交后等待从服务器确认事务接收。在收到确认后,主将结果返回给客户端,然后客户端可以继续。
binlog_group_commit_sync_delay=1
— 等待多少微秒后才进行fsync
binlog_group_commit_sync_no_delay_count=1000
— 达到等待的事务数量后调用fsync操作
— 实现事务组提交方式,将多个事务合并成组推送到从库上,避免dump线程采用串型方式提交事务,造成主从同步延时;
https://blog.csdn.net/yaoxie1534/article/details/126259320

rpl_semi_sync_slave_enabled=on
— 从库半同步功能启停设置,on为激活设置
rpl_semi_sync_slave_trace_level=32
​“`

当半同步功能配置完毕后,需要重启主从数据库服务,重启后slave会在master上注册为半同步复制的slave角色;

这时候在master数据库的错误日志中会看到以下日志信息:

​“`
2017-04-19 11:09:26 28300 [Note] Semi-sync replication switched ON with slave (server_id: 28703307) at (mysql-bin.000002, 510)
2017-04-19 11:09:26 28300 [Note] Start semi-sync binlog_dump to slave (server_id: 28703307), pos(mysql-bin.000002, 510)
2017-04-19 11:09:26 28300 [Note] Stop asynchronous binlog_dump to slave (server_id: 28703307)
​“`

半同步复制配置参数参考链接:

https://www.cnblogs.com/konggg/p/12205505.html

半同步复制和增强半同步复制配置区别:

半同步复制主从配置:

​“`tiki wiki
# 数据库配置信息:
plugin_load = “rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so”
rpl_semi_sync_master_enabled=1
rpl_semi_sync_slave_enabled=1
rpl_semi_sync_master_timeout=1000
rpl_semi_sync_master_wait_for_slave_count=1

STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

# 查看半同步是否在运行:
# 主库执行:
mysql> show status like ‘Rpl_semi_sync_master_status’;
# 从库执行:
mysql> show status like ‘Rpl_semi_sync_slave_status’;
— 这两个变量常用来监控主从是否运行在半同步复制模式下。

# 主库执行
mysql> show status like ‘%semi%’;
Rpl_semi_sync_master_status
— 指示主服务器使用的是异步复制模式,还是半同步复制模式。
Rpl_semi_sync_master_clients:
— 显示有多少个从服务器配置成了半同步复制模式。
Rpl_semi_sync_master_yes_tx:
— 显示从服务器确认的成功提交数量。
Rpl_semi_sync_master_no_tx:
— 显示从服务器确认的不成功提交数量。
​“`

增强半同步复制主从配置:(在MySQL5.7.2版本之后,官方推出了增强型半同步复制技术;)

​“`tiki wiki
# 数据库配置信息:
plugin_load = “rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so”
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_slave_enabled = 1
rpl_semi_sync_master_timeout = 5000
–超过5s不返回信息就降为半同步复制
rpl_semi_sync_master_wait_point = AFTER_SYNC
rpl_semi_sync_master_wait_for_slave_count = 1
​“`

参考链接资料:https://blog.csdn.net/HD243608836/article/details/118220422

配置参数信息补充说明:rpl_semi_sync_master_wait_point

当参数信息配置为:AFTER_COMMIT(5.6默认值)

master将每个事务写入binlog ,传递到slave 刷新到磁盘(relay log),同时主库提交事务;

master等待slave 反馈收到relay log,只有收到ACK后master才将commit OK结果反馈给客户端。

即主库commit时,先保证了binlog日志写入了从库中继日志后主库才提交binlog落盘OK给客户端;

当参数信息配置为:AFTER_SYNC(5.6默认值)

master 将每个事务写入binlog , 传递到slave 刷新到磁盘(relay log)。

master等待slave 反馈接收到relay log的ack之后,再提交事务并且返回commit OK结果给客户端。

即使主库crash,所有在主库上已经提交的事务都能保证已经同步到slave的relay log中。

此方法中存储引擎可以批量提交,降低了对主库性能的影响.
“`

## 4 主从同步的三种机制

“`sh
异步复制:(Asynchronous replication)

MySQL主从同步数据时,默认使用的复制数据机制就是异步的;

简单理解:主库在执行完客户端提交的事务后会立即将结果返给客户端,并不关心从库是否已经接收并处理;

同步痛点:若主库宕机了,此时主上已经提交的事务可能并没有传到从上,此时若从被提升为主,可能导致新主上的数据不完整;

全同步复制(Fully synchronous replication)

指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端;

写主库的时候,同步写从库,如果有多个从库,那么需要多个从库都成功,主库才能写成功;

因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会受到严重的影响。

一看就知道慢,但能达到实时同步,强一致性

面试问题:异步复制 半同步复制 增强型半同步复制区别;

异步复制:

客户端发起数据更新操作请求,主库执行更新操作完成后立即向客户端发起响应,然后再向从库发起数据同步;

主库执行更新操作不需要等待从库的响应,因此主库对于客户端的响应较快,但是数据同步到从库并不是实时同步的;

所以主从延迟情况下,主库发生故障可能会导致主从数据不一致;

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/数据库同步方式图示-异步方式.png)

半同步复制:(Semisynchronous replication)

客户端发起数据更新操作请求,主库执行更新操作完成后立即向从库复制数据,从库接受到数据写入relay log后;

从库会向主库返回ack确认,然后主库收到从库的ack确认后向客户端发起响应;

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/数据库同步方式图示-半同步复制方式.png)

半同步复制关键配置项:

​“`mysql
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_master_wait_for_slave_count=1
rpl_semi_sync_master_wait_point=after_commit
​“`

半同步复制缺陷:

– 出现幻读

当用户发起一个事务,该事务已经写入redo日志和binlog日志,但该事务还没写入从库,此时处在waiting slave dump处;

此时另一个用户可以读取到这条数据,而当前事务会话本身却不能;

– 数据丢失

一个事务在waiting slave dump处崩溃后或者超过等待时间后,主库将比从库多一条数据,造成主从数据不一致;

> 说明:复制发生异常时,复制方式会降为异步复制,复制恢复时会自动切换为半同步;

增强型半同步:(Enhanced Semisynchronous replication)

客户端发起数据更新操作请求,主库执行更新操作完成后,立即向从库复制数据,从库接收到数据并执行完成后;

会向主库返回ack确认,主库必须接收到从库的ack确认后,才向客户端进行响应;

从而实现了主从复制的实时性,所以在很大程度上保证了主从数据的一致性,但主库的每次操作依赖于从库的操作成功写入;

可能会影响主库的正常操作,所以一般是一主两从,避免一台故障影响主库的正常操作;

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/数据库同步方式图示-增强型半同步复制方式.png)

半同步复制关键配置项:

​“`mysql
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_master_wait_no_slave=1
rpl_semi_sync_master_wait_point=after_sync
​“`

增强半同步复制优势:

– 避免幻读问题

当用户发起一个事务,该事务写入二进制后,便向从库进行同步,此时其他并行会话用户无法读取到该数据,解决了幻读;

– 避免数据丢失

一个事务在waiting slave dump处崩溃掉后,可以通过观察从库上是否存在主库的last gtid值,

如果存在,这条数据正常恢复,如果不存在则删除主库的那条多余的GTID值,然后恢复,保证了数据的完整性;

增强半同步应用痛点:

当启用增强型半同步复制时,主库会等待至少一个备库确认已经接收到事务的复制数据后,才认为事务提交成功;

如果启用了增强半同步且延迟过大,可能会导致以下问题:

– **写入延迟增加:**

由于主数据库必须等待备库的确认,如果延迟过大,主数据库的写入操作可能会受到阻塞,从而增加写入延迟;

– **主库性能下降:**

如果增强半同步延迟过大,主库在等待备库确认时,可能无法及时释放资源,导致主库的性能下降;

– **可用性降低:**

如果主库发生故障或不可用,而延迟过大的备库无法及时成为新的主库,可能导致整个系统的可用性下降;

– **数据不一致:**

增强半同步的目的是提供更高的数据一致性,但是如果延迟过大,可能导致备库无法及时复制主库的所有事务;

从而导致主从之间数据不一致的情况;

因此,延迟过大可能会影响到系统的性能、可用性和数据一致性。为了避免延迟过大的问题,建议进行以下操作:

– [ ] 优化网络连接带宽:确保主库与备库之间的网络连接畅通,并具备足够的带宽来传输复制数据。
– [ ] 优化备份库的性能:确保备库具备足够的处理能力和资源,以便及时接收和处理主库发送的复制数据。
– [ ] 监控优化调整配置:定期监控复制延迟,并根据情况调整配置,如调整主库和备库的硬件配置、调整复制线程数等。

通过合理的优化和配置,可以减小增强半同步的延迟,并提高系统的性能和可靠性。

> 说明:
>
> 如果增强半同步的延迟变得非常大,超过了设定的阈值,MySQL 的增强半同步机制将会切换为异步模式。
>
> 在异步模式下,主数据库不再等待备库的确认,而是立即提交事务,从而降低了延迟,但也带来了一定的数据风险。
“`

## 5 GTID复制

“`sh
**概念介绍说明:**

GTID(global transaction id)是对于一个已提交事务的唯一编号,并且是一个全局唯一编号(主从复制过程);

是数据库5.6版本开始的一个功能新特性,主要是用于解决主从复制的一致性问题;

**复制原理机制:**

– master节点在更新数据的时候,会在事务前产生GTID信息,一同记录到binlog日志中;
– slave节点的io线程将主库推送的binlog写入到本地relay log中;
– 然后SQL线程从relay log中读取GTID,设置gtid_next的值为该gtid,然后对比slave端的binlog是否有记录;
– 如果有记录的话,说明该GTID的事务已经运行,slave会忽略;
– 如果没有记录的话,slave就会执行该GTID对应的事务,并记录到binlog中。
“`

![1670602175403](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/1670602175403.png)

**功能应用实践:**

① 主从复制GTID功能实现环境:

为了实现GTID机制的主从复制,需要准备好主从架构环境:

| 主机角色 | 主机名称 | 地址信息 |
| ———- | ——– | ————– |
| 主库服务器 | db-01 | 192.168.10.101 |
| 从库服务器 | db-02 | 192.168.10.102 |
| 从库服务器 | db-03 | 192.168.10.103 |

对原有数据库服务环境清理:

“`tiki wiki
# 在所有主从节点均进行清理操作:
pkill mysqld
rm -rf /data/3306/*
rm -rf /data/binlog/*
mv /etc/my.cnf /tmp
mkdir -p /data/3306/data /data/binlog
chown -R mysql.mysql /data/*
— 所有数据库主从节点均进行以上清理操作;
“`

② 主从复制GTID功能配置编写

“`tiki wiki
# 配置参数信息
gtid-mode=on
— 启用gtid复制方式,默认采用传统的复制方式
enforce-gtid-consistency=true
— 开启gtid所有节点的强制一致性,主要会限制 CREATE TABLE … SELECT 类似语句的执行;
log-slave-updates=1
— 定义slave更新是否记入二进制日志,从而增强数据一致性,是在高可用架构中重要配置环节

# 主库db01配置文件编写
cat >/etc/my.cnf <
EOF

# 主库db02配置文件编写
cat >/etc/my.cnf <
EOF

# 主库db03配置文件编写
cat >/etc/my.cnf <
EOF

# 进行数据库所有节点初始化操作
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data

# 启动数据库所有节点服务
/etc/init.d/mysqld start
/etc/init.d/mysqld start
/etc/init.d/mysqld start
“`

③ 主从复制GTID配置重构主从

“`tiki wiki
# 重构主从关系-主库操作
create user repl@’192.168.30.%’ identified with mysql_native_password by ‘123456’;
Query OK, 0 rows affected (0.01 sec)
grant replication slave on *.* to repl@’192.168.30.%’;
Query OK, 0 rows affected (0.00 sec)
— 主库上创建主从复制用户信息

# 重构主从关系-从库操作
change master to
master_host=’192.168.30.101′,
master_user=’repl’,
master_password=’123456′,
master_auto_position=1;
— 表示让从库自己找寻复制同步数据的起点;
— 在第一次启动gtid功能时,会读取从库中的binlog日志信息,根据主库uuid信息,获取从库中执行过的主库gtid信息
— 从从库中没有执行过的主库gtid信息之后进行进行数据同步操作
start slave;
— 其他从库一并操作
“`

**知识扩展:实现自动获取同步位置点**

主从同步获取主库的gtid信息,获取同步位置点,并且不断更新位置点:

“`tiki wiki
show master status;
+———————–+———–+——————-+———————–+——————————————————-+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+———————–+———–+——————-+———————–+——————————————————-+
| mysql-bin.000002 | 681 | | | 3cfa5898-771a-11ed-b8d7-000c2996c4f5:1-2 |
+———————–+———–+——————-+———————–+——————————————————-+
1 row in set (0.00 sec)
— 主库查看状态信息,获取gtid同步信息,gtid信息将会存储的位置:binlog、relaylog、master-info(uuid)

show master status;
+———————–+———–+——————-+———————–+——————————————————-+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+———————–+———–+——————-+———————–+——————————————————-+
| mysql-bin.000002 | 695 | | | 3cfa5898-771a-11ed-b8d7-000c2996c4f5:1-2 |
+———————–+———–+——————-+———————–+——————————————————-+
1 row in set (0.00 sec)
show master status;
+———————–+———–+——————-+———————–+——————————————————-+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+———————–+———–+——————-+———————–+——————————————————-+
| mysql-bin.000002 | 695 | | | 3cfa5898-771a-11ed-b8d7-000c2996c4f5:1-2 |
+———————–+———–+——————-+———————–+——————————————————-+
1 row in set (0.00 sec)
— 从库查看状态信息,获取gtid同步信息;gtid信息将会存储的位置:binlog、relaylog、master-info(uuid)
— show binlog events in ‘mysql-bin.000002’ 获取从库自己的binlog信息,得到gitd同步的位置点;
“`

**知识扩展:进行全备恢复数据时不要加 set-gtid-purged参数**

如果是已经运行很久的数据库,需要构建主从,都是需要备份恢复主库数据后,再开启实现主从功能的;

在mysqldump进行备份数据时,不要加set-gtid-purged参数,否则会造成从库依旧从第一个gtid信息开始同步数据;

造成主从同步数据信息冲突,影响主从构建过程,导致主从同步过程失败;

“`tiki wiki
# 未加set-gtid-purged参数实现的数据备份效果
mysqldump -A –master-data=2 –single-transaction >/tmp/full.sql
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don’t want to restore GTIDs, pass –set-gtid-purged=OFF. To make a complete dump, pass –all-databases –triggers –routines –events.

# 备份警告信息解释说明
A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions,
— 默认情况下,来自具有GTID的服务器的部分备份数据信息将包括所有事务的GTID,
even those that changed suppressed parts of the database.
— 即使是那些更改了的部分也会抑制数据库。
If you don’t want to restore GTIDs, pass –set-gtid-purged=OFF.
— 如果您不想还原GTID,请传递–set-gtid-purged=OFF。
To make a complete dump, pass –all-databases –triggers –routines –events.
— 要进行完整的转储,请传递–all-database–trigger–例程–events。

vim /tmp/full.sql
SET @@GLOBAL.GTID_PURGED=/*!80000 ‘+’*/ ‘3cfa5898-771a-11ed-b8d7-000c2996c4f5:1-2’;
— 表示让从库删除1-2的集合信息,即通过备份文件已经恢复了1-2的数据,可以从1-2之后进行数据信息同步;

# 已加set-gtid-purged参数实现的数据备份效果
mysqldump -A –master-data=2 –single-transaction –set-gtid-purged=OFF >/tmp/full02.sql
vim /tmp/full.sql
SET @@GLOBAL.GTID_PURGED=/*!80000 ‘+’*/ ‘3cfa5898-771a-11ed-b8d7-000c2996c4f5:1-2’;
SET SQL_LOG_BIN=0;
— 以上信息不会出现在备份文件中
— 表示会让从库把备份文件中的操作语句,再次根据gtid请求执行一遍,容易产生异常冲突问题;
“`

`–set-gtid-purged=on/auto` 此为默认参数,即使在备份命令中不写,依旧生效;

它的效果是在mysqldump输出的备份文件中生成 `SET@@GLOBAL.GTID_PURGED`语句;备份文件中的这条语句记录了GTID号。

– **参数应用场景-主从复制:**

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/3f3d36bb5e1a45bba03d2ff6fcd6abcf.png)

当需要构建主从的时候,主库上有许多数据需要先备份出来并恢复到从库上,以此来保持两个库没有差异,然后再去配置主从。

这种场景下一定要用on;想要基于GTID实现主从复制,从库是基于MASTER_AUTO_POSITION=1自动获取并应用GTID的。

因此如果再主库导出的备份文件中没有GTID,那么从库无法自动获取并应用GTID。

设为`–set-gtid-purged=OFF`时,在`mysqldump`输出中不包含`SET@@GLOBAL.GTID_PURGED`语句;

**参数应用场景-普通备份(避免幂等性):**

在GTID开启的情况下,MySQL通过binlog恢复时,若有匹配到重复,相同的GTID日志记录,则会直接跳过;

所以,在截取binlog时,需要忽略原日志中的GTID,如果不忽略,则在恢复时就会因为GTID相同而跳过,导致恢复失败;

在执行恢复前,同样需要执行sql_log_bin=0,因为原binlog文件中已有记录,无需再次记录。

## 6 克隆复制

“`sh
**概念介绍说明:**

利用clone plugin方式可以实现数据迁移备份恢复操作,同样也可以利用克隆技术实现主从数据同步操作,即完成快速构建从库;

主要应用于运行一段时间的数据库,需要进行主从架构环境的构建时,可以实现主库数据信息的快速迁移;

利用克隆复制备份恢复迁移数据信息,可以使备份恢复数据的效率提升;

**功能应用实践:**

① 主从复制克隆功能实现环境:

为了实现克隆机制的主从复制,需要准备好主从架构环境:

| 主机角色 | 主机名称 | 地址信息 |
| ———- | ——– | ————– |
| 主库服务器 | db-01 | 192.168.10.101 |
| 从库服务器 | db-03 | 192.168.10.103 |

对原有数据库服务环境清理:

​“`tiki wiki
# 清理原有从库配置应用(db03)
stop slave;
reset slave all;

# 准备数据库空白的节点
pkill mysqld
rm -rf /data/3306/*
rm -rf /data/binlog/*
mv /etc/my.cnf /tmp
mkdir -p /data/3306/data /data/binlog
chown -R mysql.mysql /data/*
— 在新的数据库节点进行以上清理操作;

cat >/etc/my.cnf <
EOF
— 从库db03配置文件编写

mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data
— 进行数据库所有节点初始化操作

/etc/init.d/mysqld start
— 启动数据库相应节点服务
​“`

② 主从复制克隆环境功能配置:

​“`tiki wiki
# 实现免交互方式安装插件和创建用户(主库操作)
mysql -e “INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;create user test@’%’ identified by ‘123456’;grant backup_admin on *.* to ‘test’@’%’;”

# 实现免交互方式安装插件和创建用户(从库操作)
mysql -e “INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;create user test@’%’ identified by ‘123456’;grant clone_admin on *.* to ‘test’@’%’;set global clone_valid_donor_list=’192.168.30.101:3306′;”
​“`

③ 主从复制克隆功能应用启动:

​“`tiki wiki
# 从库上启用克隆功能
mysql -utest -p123456 -h192.168.30.103 -P3306 -e “clone instance from test@’192.168.30.101′:3306 identified by ‘123456’;”

# 实现克隆状态情况监控(可以实现每秒监控)
mysql -e “select stage,state,end_time from performance_schema.clone_progress;”
+———–+———–+—————————-+
| stage | state | end_time |
+———–+———–+—————————-+
| DROP DATA | Completed | 2022-12-11 23:58:04.373236 |
| FILE COPY | Completed | 2022-12-11 23:58:05.772489 |
| PAGE COPY | Completed | 2022-12-11 23:58:05.781343 |
| REDO COPY | Completed | 2022-12-11 23:58:05.784746 |
| FILE SYNC | Completed | 2022-12-11 23:58:06.123775 |
| RESTART | Completed | 2022-12-11 23:58:07.796073 |
| RECOVERY | Completed | 2022-12-11 23:58:08.819861 |
+———–+———–+—————————-+
— 可以实现每秒关注监控输出的结果信息,最后看到RECOVERY,并且状态为Completed,表示克隆完毕
​“`

④ 主从复制克隆完毕实现主从:

​“`tiki wiki
# 主从方式构建一:利用position
mysql -e “select binlog_file,binlog_position from performance_schema.clone_status;”
+——————+—————–+
| binlog_file | binlog_position |
+——————+—————–+
| mysql-bin.000002 | 1210 |
+——————+—————–+

# 主从方式构建二:利用gtid
mysql -e “change master to master_host=’192.168.30.101′,master_user=’repl’,master_password=’123456′,master_auto_position=1;start slave”

# 核实展示最后主从状态结果
mysql -e “show slave status\G”|grep “Running:”
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
​“`

> 说明:利用clone功能实现主从,可以利用脚本自动化完成,并且可以实现主从的自愈能力,为实现主从功能上云提供方便;
“`

## 7 数据组复制(MGR)

“`sh
在MGR出现之前,用户常见的MySQL高可用方式,无论怎么变化架构,本质就是Master-Slave架构。

MySQL 5.7.17版本开始支持无损半同步复制(lossless semi-syncreplication),从而进一步提升数据复制的强一致性。

MySQL Group Replication(MGR)是MySQL官方在5.7.17版本引进的一个数据库高可用与高扩展的解决方案,以插件形式提供。

MGR基于分布式paxos协议,实现组复制,保证数据一致性。

MGR采用多副本,在2N+1个节点集群中,集群只要N+1个节点还存活着,数据库就能稳定的对外提供服务;

`数据库组复制功能,可以理解为是数据库主从关系的高可用环境,一般需要三个数据库实例,构成一个具有高可用、高一致性的复制环境`

主要涉及的功能应用包含:

– 具有多节点之间互相通过投票的方式进行监控功能;(基于paxos协议)

– 具有内置故障检测和自动选主功能,只要不是集群中的大多数节点都宕机,就可以继续正常工作;

\- 如果主节点异常,会自动选举新节点实现故障转移

\- 如果从节点异常,会自动将从节点从复制节点踢除

– 提供单主模式与多主模式,多主模式支持多点写入;

“`

**应用模式说明:**

– **MGR单主模式(single-primary mode)**

在这种模式下,组具有设置为读写模式的单主服务器,该组中的所有其他成员都设置为只读模式(这会自动发生);

主服务器通常是引导该组的第一台服务器,所有其它加入的服务器会自动了解主服务器,并设置为只读;

MGR单主模式选举原理

单主模式下,如果主节点挂了,那么其他的成员会自动选举出新的主成员,成员之间可以通过配置权重来确定下一个主成员是谁,

如果没有配置权重,则会对所有在线成员的UUID进行排序,然后选取UUID最小的成员作为主成员。

![1670949237999](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/1670949237999.png)

– **MGR多主模式(multi-primary mode)**

在多主的模式下,没有单个主概念。无需进行节点选举,因为没有服务器扮演任何特殊角色,所有服务器均设置为读写模式。

MGR多主模式选举原理

多主模式,所有的组内成员对外提供读写服务,是真正意义上的并发,MGR对于高并发有很好的的处理能力。

多主模式下,组内所有成员没有主从之分,对用户来说,就像在操作一个MySQL一样。

所以在多主模式下,不存在选举主节点,因为所有节点都是主节点。

![1670949335470](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/1670949335470.png)

利用MGR工作模式可以实现业务架构的读写分离需求,应用MySQL原生态的router功能即可实现,并且原生态router技术更兼容MGR;

因为,当MGR中主节点出现异常下线后,会选举出现的主节点,原生态router技术可以自动识别新的主节点,做读写分离的写库;

将MySQL MGR + MySQL Router + MySQL Shell = InnoDB Cluster

![1670925420469](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/1670925420469.png)

官方扩展学习资料链接:https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-innodb-cluster.html

“`sh
**工作机制原理:**

组复制是一种可用于实现容错系统的技术,复制组是一个通过消息传递实现相互交互的server集群;

复制组由多个server成员组成,如下图master01、master02、master03,所有成员独立完成各自的事务;

1. 当客户端发起一个更新事务时,该事务先在本地执行,执行完成之后就要发起对事务的提交操作;

2. 在还没有真正提交之前,需要将产生的复制写集广播出去,复制到其它所有成员节点;

主库事务提交时,会将事务修改记录相关的信息和事务产生的binlog事件打包生成一个写集,将写集发送给所有节点;

3. 如果冲突检测成功,组内决定该事务可以提交,其它成员可以应用,否则就回滚;

冲突检测成功的标准是:至少半数以上个节点投票通过才能事务提交成功;

4. 最终,所有组内成员以相同的顺序接收同一组事务;

因此,组内成员以相同的顺序应用相同的修改,保证组内数据强一致性(采用了分布式事务特性)

![1670867803361](D:/学习//4_数据库/视频和笔记/系统运维95期-Day08-数据库服务主从同步/课程笔记目录/MySQL中级数据库课程-14章-数据库主从同步应用/课件配图资料/1670867803361.png)

**功能应用实践:**

① MGR复制同步功能实现环境:

为了实现MGR复制的主从同步,需要准备好主从架构环境:

| 主机角色 | 主机名称 | 地址信息 |
| ———- | ————– | ——– |
| 主库服务器 | 192.168.30.101 | 3306 |
| 从库服务器 | 192.168.30.102 | 3306 |
| 从库服务器 | 192.168.30.103 | 3306 |

对原有数据库服务环境清理:(基于GTID环境构建)

​“`tiki wiki
# 在所有主从节点均进行清理操作:
pkill mysqld
rm -rf /data/13306/*
rm -rf /data/binlog/*
\mv /etc/my.cnf /tmp
mkdir -p /data/13306/data /data/13306/binlog
chown -R mysql.mysql /data/*
— 所有数据库主从节点均进行以上清理操作;

# 获取随机数信息充当uuid信息
cat /proc/sys/kernel/random/uuid
eb8441e9-8aef-4a86-a4bc-5beea315f04f
— 借助随机数文件生成uuid信息,因为组复制过程也是通过GTID的uuid号码,达到复制环境中的事务一致性
— 这里采用内部GTID功能,也就是组复制的各个节点通过同一个GTID的标识,进行事务管理,所以需要给组复制设置唯一号码

# 主库db01配置文件编写
cat >/etc/my.cnf <
EOF

# 从库db02配置文件编写
cat >/etc/my.cnf <
EOF

# 从库db03配置文件编写
cat >/etc/my.cnf <
EOF

# 进行数据库所有节点初始化操作
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/13306/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/13306/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/13306/data

# 启动数据库所有节点服务
/etc/init.d/mysqld start
/etc/init.d/mysqld start
/etc/init.d/mysqld start
​“`

异常配置信息参数说明:

group_replication变量使用的loose-前缀是指server启用时尚未加载复制插件也将继续启动

| num | conf_info |
| —- | ———————————————————— |
| 01 | transaction_write_set_extraction=XXHASH64
指示server为每个事务收集写集合,并使用XXHASH64哈希算法将其编码为散列 |
| 02 | loose-group_replication_group_name=”eb8441e9-8aef-4a86-a4bc-5beea315f04f”
表示将加入或创建的复制组命名为eb8441e9-8aef-4a86-a4bc-5beea315f04f
可以自定义或者通过cat /proc/sys/kernel/random/uuid获取 |
| 03 | loose-group_replication_start_on_boot=OFF
表示设置server启动时不自动启动组复制 |
| 04 | loose-group_replication_local_address=”192.168.30.101:33061″
表示绑定本地的192.168.30.101:33061端口接受其他组成员的连接,IP地址必须为其他组成员可正常访问 |
| 05 | loose-group_replication_group_seeds=”192.168.30.101:33061,192.168.30.102:33062,192.168.30.103:33063″
表示告诉服务器在加入组时,应当连接到这些种子服务器进行配置。本设置可以不是全部的组成员服务地址 |
| 06 | loose-group_replication_bootstrap_group=OFF
表示配置是否自动引导组 |
| 07 | loose-group_replication_ip_whitelist=”10.30.0.0/16,10.31.0.0/16,10.27.0.0/16″
表示配置白名单,默认情况下只允许192.168.30.101/102/103连接到复制组,如果是其他IP则需要配置 |

② MGR复制同步功能配置过程:

MGR单主模式配置过程:

​“`tiki wiki
# 设置本地root用户密码和密码插件(所有节点)
mysql -S /tmp/mysql13306.sock -e “alter user ‘root’@’localhost’ identified with mysql_native_password by ‘XZnh@95599’;”

# 安装部署MGR组复制功能插件(所有节点)
mysql -uroot -p123 -S /tmp/mysql13306.sock -e “install plugin group_replication SONAME ‘group_replication.so’;”

# 设置创建MGR组复制功能账号(所有节点)
mysql -uroot -p123 -S /tmp/mysql13306.sock
set sql_log_bin=0;
create user repl@’%’ identified by ‘123’;
create user repl@’localhost’ identified by ‘123’;
create user repl@’127.0.0.1′ identified by ‘123’;
grant replication slave,replication client on *.* to repl@’%’;
grant replication slave,replication client on *.* to repl@’localhost’;
grant replication slave,replication client on *.* to repl@’127.0.0.1′;
flush privileges;
set sql_log_bin=1;

# 启动MGR单主模式:启动MGR引导节点(在主库上执行)
change master to master_user=’repl’,master_password=’XZnh@95599′ for channel ‘group_replication_recovery’;
set global group_replication_bootstrap_group=ON;
start group_replication;
set global group_replication_bootstrap_group=OFF;
— 相当于创建一个组复制集群,并指定集群中的引导节点
select * from performance_schema.replication_group_members;
— 查看集群节点状态信息,以及集群成员信息
select * from performance_schema.replication_group_members;
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| group_replication_applier | f90d44f9-7b94-11ed-ab2d-000c2996c4f5 | 192.168.30.101 | 13306 | ONLINE | PRIMARY | 8.0.26 |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
1 row in set (0.00 sec)

# 其他几点加入MGR(在所有从库上执行)
reset master;
— 表示清除从库上所有日志信息,重新做日志信息的复制或生成;
change master to master_user=’repl’,master_password=’123′ for channel ‘group_replication_recovery’;
start group_replication;
— 将指定从库节点加入到组复制集群中(企业中最好先备份恢复一定的数据,在进行组复制应用)
select * from performance_schema.replication_group_members;
— 查看集群节点状态信息,以及集群成员信息
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| group_replication_applier | f90d44f9-7b94-11ed-ab2d-000c2996c4f5 | 192.168.30.101 | 13306 | ONLINE | PRIMARY | 8.0.26 |
| group_replication_applier | fe73f0b4-7b94-11ed-96ea-000c2961cd06 | 192.168.30.102 | 13306 | ONLINE | SECONDARY | 8.0.26 |
| group_replication_applier | 0a09b03e-7b95-11ed-9af8-000c29f5669f | 192.168.30.103 | 13306 | ONLINE | SECONDARY | 8.0.26 |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
3 rows in set (0.00 sec)
— 此时可以看到3个节点状态为online,并且主节点为192.168.30.101,只有主节点可以写入,其他节点只读,MGR单主模式搭建成功
show variables like ‘%only%’;
+—————————————-+——-+
| Variable_name | Value |
+—————————————-+——-+
| read_only | ON |
| super_read_only | ON |
+—————————————-+——-+
— 此时所有从库节点只能实现只读操作,只有主库可以进行写操作

# 遇到集群构建异常,可以进行重置操作
stop group_replication;
reset master;
set sql_log_bin=0;
change master to master_user=’repl’,master_password=’123′ for channel ‘group_replication_recovery’;
start group_replication;
​“`

MGR多主模式配置过程:从单主模式切换到多主模式

MGR切换模式需要重新启动组复制,因此需要在所有节点上先关闭组复制,设置group_replication_single_primary_mode=OFF参数

再重新启动组复制功能

​“`tiki wiki
# 多主模式需要的参数信息
group_replication_single_primary_mode=0
— 设置参数表示关闭掉单master模式
group_replication_enforce_update_everywhere_checks=1
— 这个参数设置表示多主模式下,各个节点进行严格一致性检查

# 多主模式功能配置(在所有节点上执行)
stop group_replication;
set global group_replication_single_primary_mode=OFF;
set global group_replication_enforce_update_everywhere_checks=1;
select @@group_replication_single_primary_mode,@@group_replication_enforce_update_everywhere_checks;
— 检查参数配置信息是否生效
set global group_replication_bootstrap_group=ON;
start group_replication;
set global group_replication_bootstrap_group=OFF;
— 重新启动MGR组复制功能,是多主模式生效(主节点操作)
start group_replication;
— 重新启动MGR组复制功能,是多主模式生效(从节点操作)
select * from performance_schema.replication_group_members;
— 查看集群节点状态信息,以及集群成员信息
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| group_replication_applier | 0a09b03e-7b95-11ed-9af8-000c29f5669f | 192.168.30.103 | 13306 | ONLINE | PRIMARY | 8.0.26 |
| group_replication_applier | f90d44f9-7b94-11ed-ab2d-000c2996c4f5 | 192.168.30.101 | 13306 | ONLINE | PRIMARY | 8.0.26 |
| group_replication_applier | fe73f0b4-7b94-11ed-96ea-000c2961cd06 | 192.168.30.102 | 13306 | ONLINE | PRIMARY | 8.0.26 |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
3 rows in set (0.00 sec)

# 修改从库只读功能配置(在所有从库上执行)
set global read_only=0;
set global super_read_only=0;
— 默认启动组复制功能都是单master模式,从库节点都是自动设置read_only super_read_only这两个参数,需要手工修改
​“`

完成上面的配置后就可以执行多点写入了,多点写入会存在冲突检查,这对数据库性能耗损是挺大的,官方建议采用网络区分功能,

在程序端把相同的业务定位到同一节点,尽量减少冲突发生的几率;

​“`tiki wiki
# 停止组复制功能(在所有节点执行)
stop group_replication;
set global group_replication_single_primary_mode=OFF;
set global group_replication_enforce_update_everywhere_checks=ON;

# 随便选择某个节点执行操作
set global group_replication_bootstrap_group=ON;
start group_replication;
set global group_replication_bootstrap_group=OFF;

# 其他节点执行
start group_replication;

# 查看组信息,所有节点的member_role 都为primary;
select * from performance_schema.replication_group_members;
​“`

MGR多主模式配置过程:从多主模式切换到单主模式

​“`tiki wiki
# 所有节点执行以下操作
stop group_replication;
set global group_replication_enforce_update_everywhere_checks=OFF;
set global group_replication_single_primary_mode=ON;

# 在主节点执行以下操作
set global group_replication_bootstrap_group=ON;
start group_replication;
set global group_replication_bootstrap_group=OFF;

# 在从节点执行以下操作
start group_replication;

# 查看MGR组信息:
select * from performance_schema.replication_group_members;
​“`

③ MGR复制同步功能运维管理:

​“`tiki wiki
# MGR日常管理监控操作:
select * from performance_schema.replication_group_members;
— 根据命令信息输出,获取各个节点主机的状态情况;

# MGR故障模拟操作过程:
/etc/init.d/mysqld stop
select * from performance_schema.replication_group_members;
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| group_replication_applier | 0a09b03e-7b95-11ed-9af8-000c29f5669f | 192.168.30.103 | 13306 | ONLINE | PRIMARY | 8.0.26 |
| group_replication_applier | fe73f0b4-7b94-11ed-96ea-000c2961cd06 | 192.168.30.102 | 13306 | ONLINE | SECONDARY | 8.0.26 |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
2 rows in set (0.00 sec)
— 模拟主节点宕掉,会自动选举新的主节点

/etc/init.d/mysqld start
start group_replication;
select * from performance_schema.replication_group_members;
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
| group_replication_applier | 0a09b03e-7b95-11ed-9af8-000c29f5669f | 192.168.30.103 | 13306 | ONLINE | PRIMARY | 8.0.26 |
| group_replication_applier | f90d44f9-7b94-11ed-ab2d-000c2996c4f5 | 192.168.30.101 | 13306 | ONLINE | SECONDARY | 8.0.26 |
| group_replication_applier | fe73f0b4-7b94-11ed-96ea-000c2961cd06 | 192.168.30.102 | 13306 | ONLINE | SECONDARY | 8.0.26 |
+—————————+————————————–+—————-+————-+————–+————-+—————-+
3 rows in set (0.00 sec)
— 立刻恢复宕机节点,恢复节点自动成为从节点

# 通过克隆功能添加新的节点
pkill mysqld
rm -rf /data/13306/*
rm -rf /data/binlog/*
\mv /etc/my.cnf /tmp
mkdir -p /data/13306/data /data/13306/binlog
chown -R mysql.mysql /data/*
— 初始化新的节点

cat >/etc/my.cnf <
EOF
— 编写新的节点配置文件

mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/13306/data
— 进行数据库所有节点初始化操作

/etc/init.d/mysqld start
— 启动数据库所有节点服务

mysql -S /tmp/mysql13306.sock -e “alter user ‘root’@’localhost’ identified with mysql_native_password by ‘123’;”
— 设置本地root用户密码和密码插件(所有节点)

mysql -uroot -p123 -S /tmp/mysql13306.sock -e “install plugin group_replication SONAME ‘group_replication.so’;”
— 安装部署MGR组复制功能插件(所有节点)

mysql -uroot -p123 -S /tmp/mysql13306.sock -e “INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;create user test@’%’ identified by ‘123’;grant backup_admin on *.* to ‘test’@’%’;”
— 在数据库服务正常节点上,创建克隆捐赠者用户信息

mysql -uroot -p123 -S /tmp/mysql13306.sock -e “INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;create user test1@’%’ identified by ‘123’;grant clone_admin on *.* to ‘test1’@’%’;set global clone_valid_donor_list=’192.168.30.103:13306′;”
mysql -utest1 -p123 -h192.168.30.101 -P13306 -e “clone instance from test@’192.168.30.103′:13306 identified by ‘123’;”
— 在新添加节点上,创建克隆接收者用户信息
mysql -uroot -p123 -S /tmp/mysql13306.sock -e “select stage,state,end_time from performance_schema.clone_progress;”
— 检查克隆是否完毕

change master to master_user=’repl’,master_password=’123′ for channel ‘group_replication_recovery’;
start group_replication;
— 将新节点加入到组复制集群中

select * from performance_schema.replication_group_members;
— 查看组复制成员状态信息
​“`

**应用限制说明:**

在应用MGR组复制功能时,也存在一些应用的限制条件:

– 仅支持innodb存储引擎应用组复制功能;

MGR集群中只支持innodb存储引擎,能够创建非innodb引擎的表,但是无法写入数据,向非innodb表写入数据直接报错;

– 数据表中必须有主键,或者非null的唯一键;

MGR集群中只支持innodb存储引擎,并且该表必须有显示的主键,或者非null的唯一键,否则即使能够创建表,也无法向表中写数据

– 组复制存在网络限制,MGR组通信引擎目前仅支持IPv4网络,并且对节点间的网络性能要求较高;

对于低延迟、高带宽的网络是部署MGR集群的基础;

– 组复制功能会自动忽略表锁和命名锁,在MGR中lock tables、unlock tables、get_lock、release_lock等这些表锁和命名锁将忽略

– MGR多主模式中,默认不支持 SERIALIZABLE 隔离级别,建议使用RC隔离级别;

– 组复制多主模式中,对同一个对象进行并发是有冲突的,ddl和dml操作导致这种冲突在部分成员节点中无法检测到;

最终可能导致数据不一致

– 组复制多主模式中,不支持级联约束的外键,可能造成有冲突的操作无法检查;

– 组复制功能不支持超大事务同步;

– 组复制多主模式下可能导致死锁,比如select … for update在不同节点执行,由于多节点锁无法共享,很容易导致死锁;

– 组复制是不支持复制过滤的,如果有节点设置了复制过滤功能,将影响节点间决议的达成;

– 组复制功能最多支持9个节点,当大于9个节点,将拒绝新节点的加入;

“`

## 8 主从复制总结

“`sh
02 数据库服务同步扩展
数据库服务克隆同步
数据库服务事务同步(GTID 事件唯一编号)
数据库服务半同步 (异步方式 半同步(普通半同步 增强半同步) 全同步)
数据库服务过滤同步

课程任务安排:
企业恢复数据情况01:有些需要恢复数据的binlog文件被清理了
企业恢复数据情况02:需要恢复的数据信息分不在不同binlog文件中 备份数据恢复
企业恢复数据情况03:只是误操作影响了部分行的数据 1000w行 误操作影响4行数据,如何将误操作的数据修改
delete from t1 where name in (‘李四’,’张三’,’王五’)

02 数据库服务同步扩展

– 数据库服务延时同步
应用作用:可以利用延时从库,恢复主库误操作数据
构建过程:
步骤一:创建两个数据库实例
10.0.0.51 3306 主库
10.0.0.52 3306 从库(延时)

步骤二:实现主从同步配置
主库进行数据备份 并 创建同步用户
从库恢复数据信息
从库做主从配置 change master to
启动主从同步关系 start slave

步骤三:将从库设置为延时同步
stop slave sql_thread;
change master to master_delay=300; — 设置延时300s
start slave sql_thread;

show slave status\G
SQL_Delay: 300 — 开启了延时功能
SQL_Remaining_Delay: 258 — 显示延时同步倒计时信息

应用延时从库恢复数据:
步骤一:模拟企业操作管理主库信息
主库写操作
— 正常的写操作
insert into test01.t1 values (4),(5),(6);
— 错误的写操作(误操作)
drop database world;

步骤二:利用从库恢复数据信息

– 只是不会回放错误数据,正确回放合理的SQL语句
– 将从库上正确数据保存备份,导入到主库中恢复数据

stop slave sql_thread;
定位错误信息的位置点 db02-relay-bin.000002 993

1)在从库上回放正确数据信息
change master to master_delay=0;
start slave until relay_log_file=”db02-relay-bin.000002″, relay_log_pos=993;

数据库服务克隆同步 (主库-物理主机 从库–云主机)
克隆数据应用方式:
方式一:本地克隆备份数据
方式二:远程克隆迁移数据

方式一:本地克隆备份数据
步骤一:创建一个数据库实例
10.0.0.51 3306

步骤二:在数据库中安装克隆插件
INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;
或者
[mysqld]
plugin-load-add=mysql_clone.so
clone=FORCE_PLUS_PERMANENT
PS:以上安装克隆插件方式,都是表示永久配置

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = ‘clone’;
+————-+—————+
| PLUGIN_NAME | PLUGIN_STATUS |
+————-+—————+
| clone | ACTIVE |
+————-+—————+

步骤三:创建克隆数据使用的用户信息
create user clone_user@’%’ identified by ‘password’;
grant backup_admin on *.* to ‘clone_user’;

步骤四:实现数据本地克隆备份
mkdir -p /data/test
chown -R mysql.mysql /data/
mysql -uclone_user -ppassword
clone local data directory = ‘/data/test/clonedir’;

mysql> select stage,state,end_time from performance_schema.clone_progress; — 可以查看本地克隆进度情况

方式二:远程克隆迁移数据 (ECS RDS)
步骤一:安装数据库实例环境
10.0.0.51 主库
10.0.0.52 从库/备份 清理数据

步骤二:在数据库服务中安装克隆插件
INSTALL PLUGIN clone SONAME ‘mysql_clone.so’;
— 在数据捐赠主机和接收主机都安装

SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = ‘clone’;

步骤三:创建克隆所需的用户信息

# 在克隆捐赠者主机上进行授权(数据库01主机上设置)

mysql> create user test_jz@’%’ identified by ‘password’;
mysql> grant backup_admin on *.* to test_jz@’%’ ;
— backup_admin权限是mysql 8.0才有的备份导出的权限;

# 在克隆接收者主机上进行授权(数据库02主机上设置)

mysql> create user test_js@’%’ identified by ‘password’;
mysql> grant clone_admin on *.* to test_js@’%’ ;
— clone_admin权限是mysql 8.0才有的克隆同步数据的权限;

步骤四:实现数据远程克隆操作
set global clone_valid_donor_list=’10.0.0.51:3307′;
— 在接收者数据库主机上配置克隆白名单

mysql -utest_js -ppassword -h10.0.0.52 -P3306
clone instance from test_jz@’10.0.0.51′:3307 identified by ‘password’;

select stage,state,end_time from performance_schema.clone_progress;
— 在数据克隆过程中,只能在捐赠者数据库中进行查看克隆进度

远程克隆完毕,如何建立主从关系
方式一:利用pos位置点信息,进行主从建立
需要在主库binlog文件中,查看相关事件信息,通过事件信息和克隆后从库数据最对比,找到位置点
CHANGE MASTER TO
MASTER_HOST=’10.0.0.51′,
MASTER_USER=’repl’,
MASTER_PASSWORD=’123456′,
MASTER_PORT=3307,
MASTER_LOG_FILE=’binlog.000002′,
MASTER_LOG_POS=157,
MASTER_CONNECT_RETRY=10;

方式二:利用GTID方式实现主从同步(可以自动识别位置点)
步骤一:需要克隆前配置gtid功能
vim /etc/my.cnf
— 以下配置信息,需要在主库和从库配置文件都编写
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

步骤二:完成数据目录克隆
省略

步骤三:建立主从同步(云数据库 -从 — 物理数据库 — 主)
CHANGE MASTER TO
MASTER_HOST=’10.0.0.51′,
MASTER_USER=’repl’,
MASTER_PASSWORD=’123456′,
MASTER_PORT=3307,
master_auto_position=1,
MASTER_CONNECT_RETRY=10;

数据库服务事务同步 (基于GTID方式建立主从)
GTID功能概念
GTID(global transaction id)是对于一个已提交事务的唯一编号,并且是一个全局唯一编号(主从复制过程);
是数据库5.6版本开始的一个功能新特性,主要是用于解决主从复制的一致性问题;

GTID同步原理

– master节点在更新数据的时候,会在事务前产生GTID信息,一同记录到binlog日志中;
– slave节点的io线程将主库推送的binlog写入到本地relay log中;
– 然后SQL线程从relay log中读取GTID,设置gtid_next的值为该gtid,然后对比slave端的binlog是否有记录;
– 如果有记录的话,说明该GTID的事务已经运行,slave会忽略;
– 如果没有记录的话,slave就会执行该GTID对应的事务,并记录到binlog中

GTID主从建立
步骤一:创建两个数据库实例
10.0.0.51 3307 主节点 有数据
10.0.0.52 3306 从节点

步骤二:配置开启GTID功能
gtid-mode=on
— 启用gtid复制方式,默认采用传统的复制方式
enforce-gtid-consistency=true
— 开启gtid所有节点的强制一致性,主要会限制 CREATE TABLE … SELECT 类似语句的执行;

log-slave-updates=1
— 定义slave更新是否记入二进制日志,从而增强数据一致性,是在高可用架构中重要配置环节

vim /etc/my.cnf
— 以下配置信息,需要在主库和从库配置文件都编写

gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

mysql> show master status;
+—————-+———-+————–+——————+——————————————+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+—————-+———-+————–+——————+——————————————+
| bin-log.000035 | 388 | | | cd3cc675-bd25-11ef-bd84-000c29141679:1-3 |
+—————-+———-+————–+——————+——————————————+

mysql> show binlog events in ‘bin-log.000034’;
+—————-+—–+—————-+———–+————-+——————————————————————-+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+—————-+—–+—————-+———–+————-+——————————————————————-+
| bin-log.000034 | 4 | Format_desc | 1 | 126 | Server ver: 8.0.32, Binlog ver: 4 |
| bin-log.000034 | 126 | Previous_gtids | 1 | 157 | |
| bin-log.000034 | 157 | Gtid | 1 | 234 | SET @@SESSION.GTID_NEXT= ‘cd3cc675-bd25-11ef-bd84-000c29141679:1’ |
| bin-log.000034 | 234 | Query | 1 | 348 | create database test31 /* xid=4 */ |
| bin-log.000034 | 348 | Gtid | 1 | 425 | SET @@SESSION.GTID_NEXT= ‘cd3cc675-bd25-11ef-bd84-000c29141679:2’ |
| bin-log.000034 | 425 | Query | 1 | 539 | create database test32 /* xid=6 */ |
| bin-log.000034 | 539 | Rotate | 1 | 584 | bin-log.000035;pos=4 |
+—————-+—–+—————-+———–+————-+——————————————————————-+
7 rows in set (0.02 sec)

步骤三:将主库数据进行备份,并将数据导入到从库
mysqldump -uroot -p123456 -h10.0.0.51 -P3307 -A –source-data >/backup/all.sql
mysql start slave;

步骤五:检查主从同步状态/检查同步数据

# mysqldump -uroot -p123456 -h10.0.0.51 -P3307 -A –source-data >/backup/all.sql

mysqldump: [Warning] Using a password on the command line interface can be insecure.
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions,
even those that changed suppressed parts of the database.
If you don’t want to restore GTIDs, pass –set-gtid-purged=OFF. To make a complete dump, pass –all-databases –triggers –routines –events.

–set-gtid-purged=ON (默认) — 为了实现主从同步
表示会记录gtid事务编号信息(在备份文件中)
主要利用备份文件可以实现主从建立,从库加载恢复备份文件,会将事务编号记录到从库中

–set-gtid-purged=OFF — 可以应用修复数据
表示不会记录gtid事务编号信息(在备份文件中)
gtid备份的数据信息,当备份文件中具有gtid编号信息时,再恢复数据时,会具有幂等性问题(程序代码可以多次执行)

数据库服务半同步

– 异步方式: 不会确认dump线程发送binlog信息,是否在从库接收到
实现异步方式:利用pos位置点实现同步 利用gtid事务编号实现同步

– 半同步方式
· 普通半同步方式 会确认dump线程发送binlog信息,在IO线程存储relay log后, 会返回确认消息给dump线程
· 增强半同步方式 会确认dump线程发送binlog信息,在SQL线程回放relay log后,会返回确认消息给dump线程

实现方法:
步骤一:安装半同复制插件
主库安装的半同步插件:master
INSTALL PLUGIN rpl_semi_sync_master SONAME ‘semisync_master.so’;
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = ‘rpl_semi_sync_master’;

从库安装的半同步插件:slave
INSTALL PLUGIN rpl_semi_sync_slave SONAME ‘semisync_slave.so’;
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = ‘rpl_semi_sync_slave’;

步骤二:启动半同步复制功能
主库需要启动插件功能:
— 临时激活插件功能:
set global rpl_semi_sync_master_enabled=1;
— 永久激活插件功能:
[mysqld]
rpl_semi_sync_master_enabled=ON

从库需要启动插件功能:
— 临时激活插件功能:
set global rpl_semi_sync_slave_enabled=1;
— 永久激活插件功能:
[mysqld]
rpl_semi_sync_slave_enabled=ON

set global rpl_semi_sync_master_timeout=10000; (1000毫秒=1s)
— 主节点进行半同步超时时间设置

半同步复制有关扩展知识:
1)配置参数信息
rpl_semi_sync_master_trace_level=32
— 以上设置项表示,是否将半同步复制过程产生信息记录到错误日志中;
rpl_semi_sync_master_wait_for_slave_count=1
— 用于控制在主库需要从库确认的数量,默认为1(多个从库同步数据)
rpl_semi_sync_master_wait_no_slave=on
— 是否允许每个事物的提交都要等待slave的信号
— on为每一个事物都等待,除非超过等待时间
— off表示master发现Rpl_semi_sync_master_clients小于rpl_semi_sync_master_wait_for_slave_count,则master立即转为异步模式
Rpl_semi_sync_master_clients — 状态变量 显示从库数量信息
rpl_semi_sync_master_wait_point=after_sync *****
after_commit :此时半同步复制为普通半同步 5.6版本 默认是普通半同步
AFTER_SYNC :此时半同步复制为增强半同步 5.7版本 默认是增强半同步

– 全同步方式 主从数据库会对执行的操作进行投票机制(投票允许过半,就完成事件操作,投票失败过半,就自动进行回滚操作)

数据库服务过滤同步:
功能应用:可以灵活控制主库同步到从库的数据信息

方式一:在主库上,利用binlog文件实现同步过滤
控制binlog文件记录的内容

– 白名单设置:binlog_do_db
[mysqld]
binlog_do_db=xiaoJ

mysql> create database xiaoJ;
Query OK, 1 row affected (0.00 sec)

mysql> create database xiaoQ;
Query OK, 1 row affected (0.00 sec)

mysql> create database xiaoK;
Query OK, 1 row affected (0.00 sec)

mysql> show master status;
+—————-+———-+————–+——————+——————————————–+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+—————-+———-+————–+——————+——————————————–+
| bin-log.000036 | 385 | xiaoJ | | cd3cc675-bd25-11ef-bd84-000c29141679:1-352 |
+—————-+———-+————–+——————+——————————————–+
1 row in set (0.01 sec)

mysql> show binlog events in ‘bin-log.000036’;
+—————-+—–+—————-+———–+————-+———————————————————————+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+—————-+—–+—————-+———–+————-+———————————————————————+
| bin-log.000036 | 4 | Format_desc | 1 | 126 | Server ver: 8.0.32, Binlog ver: 4 |
| bin-log.000036 | 126 | Previous_gtids | 1 | 197 | cd3cc675-bd25-11ef-bd84-000c29141679:1-351 |
| bin-log.000036 | 197 | Gtid | 1 | 274 | SET @@SESSION.GTID_NEXT= ‘cd3cc675-bd25-11ef-bd84-000c29141679:352′ |
| bin-log.000036 | 274 | Query | 1 | 385 | create database xiaoJ /* xid=18 */ |
+—————-+—–+—————-+———–+————-+———————————————————————+
4 rows in set (0.00 sec)

– 黑名单设置:binlog_ignore_db
[mysqld]
binlog_ignore_db=xiaoQ
binlog_ignore_db=xiaoK

mysql> show master status;
+—————-+———-+————–+——————+——————————————–+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+—————-+———-+————–+——————+——————————————–+
| bin-log.000038 | 197 | | xiaoQ,xiaoK | cd3cc675-bd25-11ef-bd84-000c29141679:1-356 |
+—————-+———-+————–+——————+——————————————–+
1 row in set (0.00 sec)

思考问题:
1)在白名单和黑名单中都配置了xiaoQ数据库信息,数据库信息会不会记录
2)在白名单和黑名单中都没配置了xiaoQ数据库信息,数据库信息会不会记录

方式二:在从库上,利用SQL线程实现同步过滤
过滤数据库
— 白名单 :replicate_do_db:
[mysqld]
replicate_do_db=xiaoQ

Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: xiaoQ

— 黑名单 :replicate_ignore_db:
[mysqld]
replicate_ignore_db=xiaoQQ;

过滤数据表
— 白名单 :replicate_do_table:
[mysqld]
replicate_do_table=xiaoQ.t1

— 黑名单 :replicate_ignore_table:
[mysqld]
replicate_ignore_table=xiaoQ.t2;

进行模糊匹配过滤
— 白名单 :replicate_wild_do_table:
[mysqld]
replicate_wild_do_table=xiaoQ.t%

— 黑名单 :replicate_wild_ignore_table:
[mysqld]
replicate_wild_ignore_table=xiaoQ.t%

课程任务安排:
企业恢复数据情况01:有些需要恢复数据的binlog文件被清理了
方式一:利用延时从库修复数据
方式二:利用全备数据+binlog增量数据
步骤一:默认日常存储数据
create database oldboy01; — bin-log.000039
create table student (id int,name char(5),age tinyint); — bin-log.000039

mysql> insert into student values (1,’xiaoA’,18); — bin-log.000040
Query OK, 1 row affected (0.01 sec)
mysql> insert into student values (1,’xiaoB’,20);
Query OK, 1 row affected (0.01 sec)
mysql> insert into student values (1,’xiaoC’,20);
Query OK, 1 row affected (0.01 sec)

mysqldump -uroot -p123456 -B oldboy01 –set-gtid-purged=OFF >/backup/oldboy01.sql

mysql> flush logs;
mysql> insert into student values (1,’xiaoD’,20); — bin-log.000041
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values (1,’xiaoE’,20);
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values (1,’xiaoF’,20);

步骤二:模拟数据损坏操作
drop database oldboy01;

步骤三:恢复数据信息
mysql -uroot -p123456 /backup/add.sql
mysqlbinlog –skip-gtids –include-gtids=cd3cc675-bd25-11ef-bd84-000c29141679:372-374 bin-log.000041 >/backup/add.sql

mysql -uroot -p123456 /backup/oldboy03.sql
mysql -uroot -p123456 xxxx`
方式二:利用第三方工具读取binlog文件,实现数据闪回功能

步骤一:安装数据闪回工具
unzip binlog2sql-master.zip

yum install -y python3
pip3 install -r requirements.txt
pip3 show pymysql
pip3 install –upgrade pymysql

步骤二:利用软件工具恢复数据
mysql> delete from city where id=1;
Query OK, 1 row affected (0.03 sec)

mysql> delete from city where id=2;
Query OK, 1 row affected (0.00 sec)

mysql> delete from city where id=3;
Query OK, 1 row affected (0.00 sec)

python3 binlog2sql.py -h 10.0.0.51 -P3307 -uroot -p123456 -d world -t city –start-file=’bin-log.000044′ –sql-type=delete -B
INSERT INTO `world`.`city`(`CountryCode`, `District`, `ID`, `Name`, `Population`) VALUES (3, ‘Herat’, ‘AFG’, ‘Herat’, 186800); #start 2108 end 2310 time 2024-12-19 18:14:00 gtid
INSERT INTO `world`.`city`(`CountryCode`, `District`, `ID`, `Name`, `Population`) VALUES (2, ‘Qandahar’, ‘AFG’, ‘Qandahar’, 237500); #start 1790 end 1998 time 2024-12-19 18:13:59 gtid
INSERT INTO `world`.`city`(`CountryCode`, `District`, `ID`, `Name`, `Population`) VALUES (1, ‘Kabul’, ‘AFG’, ‘Kabol’, 1780000); #start 1478 end 1680 time 2024-12-19 18:13:55 gtid

INSERT INTO `world`.`city` VALUES (3, ‘Herat’, ‘AFG’, ‘Herat’, 186800); #start 2108 end 2310 time 2024-12-19 18:14:00 gtid
INSERT INTO `world`.`city` VALUES (2, ‘Qandahar’, ‘AFG’, ‘Qandahar’, 237500); #start 1790 end 1998 time 2024-12-19 18:13:59 gtid
INSERT INTO `world`.`city` VALUES (1, ‘Kabul’, ‘AFG’, ‘Kabol’, 1780000); #start 1478 end 1680 time 2024-12-19 18:13:55 gtid

01:数据库服务高可用MHA
“`

# 第八章 数据库冗余架构

“`sh
数据库中的高可用功能,主要是用于避免数据库服务或数据信息的损坏问题,其中数据损坏的类型有:

– 数据物理损坏:磁盘、主机、程序实例、数据文件误删除
– 数据逻辑损坏:drop update …

其中,数据库高可用技术的出现主要解决的是物理损坏的业务中断问题,而主从架构技术主要解决的是数据物理损坏问题;

数据库高可用解决方案选型依据:(全年无故障率)
“`

| 无故障率 | 故障时间 | 解决方案 |
| ——– | ——————– | ———————————————————— |
| 99.9% | 0.1%(525.6min) | keepalived+双主架构,但需要人为干预 |
| 99.99% | 0.01%(52.56min) | MHA ORCH TMHA,具有自动监控,自动切换,自动数据补偿,但还是属于半自动化
比较适合非金融类互联网公司 eg: facebook taobao前端-TMHA–>polaradb |
| 99.999% | 0.001%(5.256min) | PXC MIC MGC,数据是高一致性
比较适合金融类互联网公司 |
| 99.9999% | 0.0001%(0.5256min) | 自动化、云计算化、平台化,仍然属于概念阶段 |

## 1 高可用环境构建

“`sh
#### 1.15.2 数据库服务高可用软件介绍

MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton研发,

此人目前就职于Facebook公司,MHA是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。

MySQL进行故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换过程中;

MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。

MHA主要有两部分组成:

**MHA Manager(管理节点)**

可以单独部署在一台独立的机器上管理多个master-slave集群,也可以部署在一台slave上。

**MHA Node(数据节点)**

运行在每台MySQL服务器上

MHA Manager 会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master;

然后将所有其他的slave重新指向新的master,整个故障转移过程对应用程序是完全透明的;

MHA软件结构介绍:(MHA中的所有组件就是perl语言编写的功能脚本)

| 节点信息 | 软件组件 | 作用介绍 |
| ———————– | ———————– | —————————————————– |
| MHA Manager(管理节点) | masterha_manger | 用于启动MHA |
| | masterha_check_ssh | 用于检查MHA的SSH配置互信状况 |
| | masterha_check_repl | 用于检查MySQL复制状态,以及配置信息 |
| | masterha_master_monitor | 用于检测master是否宕机 |
| | masterha_check_status | 用于检测当前MHA运行状态 |
| | masterha_master_switch | 用于控制故障转移(自动或者手动) |
| | masterha_conf_host | 添加或删除配置的server信息 |
| MHA Node(数据节点) | save_binary_logs | 保存和复制master的二进制日志 |
| | apply_diff_relay_logs | 识别差异的中继日志事件并将其差异的事件应用于其他slave |
| | purge_relay_logs | 清除中继日志(不会阻塞SQL线程) |

#### 1.15.3 数据库服务高可用环境构建

① MHA高可用架构基础环境:

为了实现MHA高可用架构构建,需要准备好三节点数据库+GTID复制环境:

| 主机角色 | 主机名称 | 地址信息 |
| ———- | —————————- | ——– |
| 主库服务器 | 192.168.30.101 | 3306 |
| 从库服务器 | 192.168.30.102 | 3306 |
| 从库服务器 | 192.168.30.103(兼做管理节点) | 3306 |

对原有数据库服务环境清理:(基于GTID环境构建)

​“`tiki wiki
# 在所有主从节点均进行清理操作:
pkill mysqld
rm -rf /data/3306/*
rm -rf /data/binlog/*
mkdir -p /data/3306/data /data/binlog
chown -R mysql.mysql /data/*
— 所有数据库主从节点均进行以上清理操作;

# 主库db01配置文件编写
cat >/etc/my.cnf <
EOF

# 从库db02配置文件编写
cat >/etc/my.cnf <
EOF

# 从库db03配置文件编写
cat >/etc/my.cnf <
EOF

# 进行数据库所有节点初始化操作
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data
mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data

# 启动数据库所有节点服务
/etc/init.d/mysqld start
/etc/init.d/mysqld start
/etc/init.d/mysqld start

# 重构主从关系-主库操作
create user repl@’192.168.30.%’ identified with mysql_native_password by ‘123456’;
Query OK, 0 rows affected (0.01 sec)
grant replication slave on *.* to repl@’192.168.30.%’;
Query OK, 0 rows affected (0.00 sec)
— 主库上创建主从复制用户信息

# 重构主从关系-从库操作
change master to
master_host=’10.0.0.51′,
master_user=’repl’,
master_password=’123456′,
master_auto_position=1;
— 表示让从库自己找寻复制同步数据的起点;
— 在第一次启动gtid功能时,会读取从库中的binlog日志信息,根据主库uuid信息,获取从库中执行过的主库gtid信息
— 从从库中没有执行过的主库gtid信息之后进行进行数据同步操作
start slave;
— 其他从库一并操作
​“`

② MHA高可用软件安装部署:

​“`tiki wiki
# 创建程序命令软链接
ln -s /usr/local/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql
— 所有节点均执行以上操作,因为MHA程序加载数据库命令,会默认在/usr/bin下面进行加载(会影响数据补偿和监控功能)

# 配置各节点互信
rm -rf /root/.ssh
ssh-keygen
cd /root/.ssh
mv id_rsa.pub authorized_keys
scp -r /root/.ssh 192.168.30.102:/root
scp -r /root/.ssh 192.168.30.103:/root
ssh 192.168.30.101 date
ssh 192.168.30.102 date
ssh 192.168.30.103 date
— 各节点验证

# 安装软件程序
yum install perl-DBD-MySQL -y
rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm
— 所有节点安装Node软件依赖包
yum install -y perl-Config-Tiny epel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes
yum install -y mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
— Manager软件安装(db03)

# 在db01主库中创建mha需要的用户
create user mha@’192.168.30.%’ identified with mysql_native_password by ‘mha’;
grant all privileges on *.* to mha@’192.168.30.%’;
— 在主库创建完毕后,主从复制功能,核实所有从库也都有mha用户信息

# Manager配置文件准备(db03)
mkdir -p /etc/mha
— 创建配置文件目录
mkdir -p /var/log/mha/app1
— 创建日志目录

cat > /etc/mha/app1.cnf < /var/log/mha/app1/manager.log 2>&1 &

# 查看MHA状态
[root@db03 ~]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 (pid:30770) is running(0:PING_OK), master:192.168.30.101
— 显示以上提示信息,表示MHA基础环境搭建成功了,但还不能在生产环境使用,还需要有后续的操作配置
​“`

####
“`

## 2 工作原理

![image-20250217114058534](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250217114058534.png)

| 功能 | 实现 |
| ——– | —————————————- |
| 监控 | 发现主库服务程序产生了运行异常 |
| 选主 | 找到可以替代主库的服务器主机进行切换 |
| 数据补偿 | 新的主库接管后可以保证与原有主库数据一致 |
| 应用透明 | 将应用程序的读写请求对接切换到新的主库上 |
| 报警 | 及时向管理员发起告知提醒使之进行修复 |
| 额外补偿 | 当整体主库系统环境都异常时实现数据的补偿 |
| 异常自愈 | 主库服务器的异常情况进行原有主库修复 |

### 1 mha的设计原理分析(failover过程)

“`sh
01 MHA软件启动

根据启动命令,分析MHA软件启动原理:

​“`tiki wiki
nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1 &
​“`

根据以上启动命令,需要先调取MHA启动脚本文件`masterha_manager` ,然后在调取加载MHA软件的配置文件`–conf=…/app1.cnf`

会根据加载的MHA的配置文件不同,实现管理多个高可用架构环境,进行高可用业务的架构环境的区分;

`–remove_dead_master_conf`参数表示在主节点出现宕机情况时,将会从集群中被踢出,即从配置文件中删除掉故障节点;

`–ignore_last_failover` 默认MHA服务是不能频繁进行故障切换的,需要有一定的间隔时间,加此参数表示忽略切换的间隔时间;

最后将MHA启动运行的信息放入到日志文件中即可 `/var/log/mha/app1/manager.log 2>&1`

> 补充说明:–ignore_last_failover
>
> 【官方解释】
>
> If the previous failover failed, MHA does not start failover because the problem might happen again.
>
> 如果上一次高可用功能失败,MHA不会再启动高可用功能,因为这个问题可能会再次出现
>
> The normal step to start failover is manually remove failover error file
>
> 后续再想启动故障转移的正常步骤是手动删除故障转移错误文件
>
> which is created under (manager_workdir)/(app_name).failover.error .
>
> 错误文件会在manager_workdir目录下,创建一个名为app_name.failover.error的文件
>
> By setting –ignore_last_failover, MHA continues failover regardless of the last failover status.
>
> 对于设置–ignore_last_failover,表示无论上次故障切换状态如何,MHA都会继续进行启动故障切换功能
>
> 【博文参考】
>
> 在缺省情况下,如果 MHA 检测到连续发生宕机,且两次宕机间隔不足 8 小时的话,则不会进行 Failover;
>
> 之所以这样限制是为了避免 ping-pong 效应。该参数代表忽略上次 MHA 触发切换产生的文件;
>
> 默认情况下,MHA 发生切换后会在日志记录,在日志目录中会生成 app1.failover.complete 文件;
>
> 下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后删除该文件;

02 MHA实现监控

利用MHA启动脚本文件`masterha_manager`会自动调用监控脚本文件`masterha_master_monitor`,并且每隔配置文件指定时间;

`ping_interval=2` 进行脚本监控一次,从而判断主节点是否处于存活状态,连续4次还没有主库心跳,即说明主库宕机;

​“`tiki wiki
# 监控脚本验证主节点存活方法
[root@xiaoQ-03 ~]# mysql -umha -pmha -h192.168.30.101 -e “select user();”
mysql: [Warning] Using a password on the command line interface can be insecure.
+——————-+
| user() |
+——————-+
| mha@xiaoQ-03 |
+——————-+
​“`

03 MHA选主过程

在MHA中进行选主时,根据选主源码文件信息分析,主要会利用到四个数组:alive latest pref bad,并且会识别节点编号信息;

在进行选主时,主要会关注竞选新主节点的日志量、以及是否设置candidate_master参数配置信息;

| 数组信息 | 简述 | 作用说明 |
| ——– | ——– | ———————————————————— |
| alive | 存活数组 | 主要用于探测存活的节点状态;当主库宕机后,探测的就是两个从库节点 |
| latest | 最新数组 | 表示获取日志最新的从库信息,即数据量最接近主库的从库(根据GTID信息 或 position信息) |
| pref | 备选数组 | 在数组中具有candidate_master参数判断条件,此参数可以放入配置文件节点中,便于节点优先选择为新主 |
| bad | 不选数组 | 如果设定了参数:no_master=1,表示相应节点不参与竞选主;
如果设定了参数:log_bin=0(二进制日志没开),表示相应节点不参与竞选主;
如何设定了参数:check_slave_delay,检查从库延迟主库100M数据信息日志量,表示节点不参与竞选主 |

MHA选主判断总结(利用if判断选主的情况)

– 循环对比latest数组和pref数组的slave,如果存在相同的slave,并且这个slave不在bad数组当中,该slave会被推选为新的master

DB02节点即满足latest数组信息,又满足perf数组信息,但不满足bad数据信息,即会被选为新主,有多个按照号码顺序选举;

– 如果pref和bad数组当中的个数为0,则选择latest数组当中的第一个slave为master;

DB02节点没有candidate_master参数配置,又没有不选数组里的三种情况配置,即db02恰好是latest,为新主;

– 循环对比alive数组和pref数组当中的slaves,如果有一个slave相同,并且不在bad数组当中,该节点就会成为新的master;

DB02节点即不满足latest,也不满足bad,但是满足pref,也会被选择作为新主;

– 循环latest数组,如果又循环到slave不在bad数组当中,这个slave就会成为master,就算添加了candidate_master=1参数;

该slave也不一定会成为主库;

DB02节点即满足latest数组,不是bad数组,也会成为新的主;

– 从活着的slave当中进行循环,如果循环到slave不在bad数组当中,那么这个slave就会成为主库;

DB02节点是活着的,不满足bad,也可以成为新的主;

– 如果进行了多次选择都找不到主库,那么主库选择失败,failover失败;

选主策略简述表:

| 优先级 | alive数组 | latest数组 | pref数组 | bad数组 | 选主策略 | 多个选择情况 |
| —— | ——— | ———- | ——– | ——- | ———— | ——————– |
| 01 | `满足` | `满足` | `满足` | 不满足 | 优选选择 | 按照节点号码顺序选择 |
| 02 | `满足` | `满足` | 不满足 | 不满足 | 优选选择 | 按照节点号码顺序选择 |
| 03 | `满足` | 不满足 | `满足` | 不满足 | 优选选择 | 按照节点号码顺序选择 |
| 04 | `满足` | 不满足 | 不满足 | 不满足 | 优选活着节点 | 按照节点号码顺序选择 |

> 说明:在进行手工指定切换新主时,即应用了prio_new_master_host参数信息时,会最优先选择相应节点为新主;

04 MHA数据补偿

在进行数据补偿之前,需要让新主库与原有宕机主库进行对比,获悉需要补偿的数据量情况,即对比差的数据日志量信息;

然后可以从binlog日志中,进行补充数据信息的截取,随之进行数据信息补偿,但是有种特殊情况,若原有主库无法访问了;

所以进行数据补偿操作,也需要分各种情景进行处理:

– 原主库SSH连接正常:

各个从节点自动调用:`save_binary_logs`脚本文件,立即保存缺失部分的bin_log,到各节点/var/tmp/目录;

– 原主库SSH连接异常:

各个从节点自动调用:`apply_diff_relay_logs`脚本文件,进行relay_log日志差异信息补偿;

– 额外特殊数据补充:(利用主库日志冗余机制)

MHA提供了binlog_server功能,可以实时拉取主库的binlog日志到备份节点,从而进行数据额外补偿;

05 MHA业务切换

自动解除原有的主从关系,实现新的主从关系的建立;

​“`tiki wiki
# 所有从库解除主从关系操作
stop slave;
reset slave;

# 所有从库重构主从关系操作
change master to …
​“`

06 MHA应用透明

实现MHA的VIP功能,利用脚本实现,上传mha_script.tar文件到/usr/local/bin目录中,然后进行解压处理;

​“`tiki wiki
# 上传MHA所需的脚本文件
[root@xiaoQ-03 ~]# cd /usr/local/bin/
[root@xiaoQ-03 bin]# chmod +x /usr/local/bin/*

# 修改MHA脚本文件的信息
[root@xiaoQ-03 bin]# cp master_ip_failover master_ip_failover.bak
[root@xiaoQ-03 bin]# dos2unix /usr/local/bin/*
[root@xiaoQ-03 bin]# vim master_ip_failover
13 my $vip = ‘192.168.30.110/24’;
14 my $key = ‘1’;
15 my $if = ‘eth0’;
16 my $ssh_start_vip = “/sbin/ifconfig $if:$key $vip”;
17 my $ssh_stop_vip = “/sbin/ifconfig $if:$key down”;
18 my $ssh_Bcast_arp= “/sbin/arping -I $if -c 3 -A 192.168.30.110”;

# 修改配置文件
[root@xiaoQ-03 ~]# vim /etc/mha/app1.cnf
master_ip_failover_script=/usr/local/bin/master_ip_failover

# 重启MHA服务
[root@xiaoQ-03 bin]# masterha_stop –conf=/etc/mha/app1.cnf
[root@xiaoQ-03 bin]# nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

# 手工在主库上添加VIP
[root@xiaoQ-03 bin]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 (pid:103046) is running(0:PING_OK), master:192.168.30.101
— 核实此时的MHA的主库节点
ifconfig eth0:1 192.168.30.110/24
— 在主库节点手工添加vip地址信息

# 进行VIP地址连接测试
— 可以使用navcat软件,连接MHA的vip地址,查看所连主机信息是否为主节点,当故障转移后可以核实VIP地址是否持续连接;
​“`

> 说明:进行MHA的VIP地址漂移时,只能在局域网环境进行漂移,不能实现跨网段的VIP地址漂移;

07 MHA故障报警

实现MHA的报警功能,利用脚本实现,上传mha_script.tar文件到/usr/local/bin目录中,然后进行解压处理;

​“`tiki wiki
# 准备脚本文件
[root@xiaoQ-03 bin]# cp send_report send_report.bak
28 my $smtp=’smtp.qq.com’;
— smtp服务器地址域名
29 my $mail_from=’330882721@qq.com’;
— 发件箱信息配置
30 my $mail_user=’330882721′;
— 用户名 QQ号
31 my $mail_pass=’ypokkranqlgkcbba’;
— 邮箱授权码
32 my $mail_to=’330882721@qq.com’;
or
my $mail_to=[‘to1@qq.com’,’to2@qq.com’];
— 收件箱信息配置

# 修改配置文件
[root@xiaoQ-03 ~]# vim /etc/mha/app1.cnf
report_script=/usr/local/bin/send_report

# 重启MHA服务
[root@xiaoQ-03 bin]# masterha_stop –conf=/etc/mha/app1.cnf
[root@xiaoQ-03 bin]# nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
​“`

08 MHA额外补偿

利用binlog_server作为额外的日志补偿的冗余方案,即实时保存主库的bin_log日志文件到特定节点目录中;

​“`tiki wiki
# 创建日志存放目录
[root@xiaoQ-03 ~]# mkdir -p /data/binlog_server/
[root@xiaoQ-03 ~]# chown -R mysql.mysql /data/*
[root@xiaoQ-03 ~]# cd /data/binlog_server
[root@xiaoQ-03 binlog_server]# mysql -e “show slave status\G”|grep “Master_Log”
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 1201
Relay_Master_Log_File: mysql-bin.000002
Exec_Master_Log_Pos: 1201
— 拉取日志的起点,需要按照目前从库的已经获取到的二进制日志点为起点
[root@xiaoQ-03 binlog_server]# mysqlbinlog -R –host=192.168.30.101 –user=mha –password=mha –raw –stop-never mysql-bin.000002 &

# 编写配置文件信息
[root@xiaoQ-03 ~]# vim /etc/mha/app1.cnf
[binlog1]
no_master=1
— 不存于竞选
hostname=192.168.30.103
— 将日志额外补偿到哪个主机上
master_binlog_dir=/data/binlog_server/
— 日志额外补偿的存储目录

# 重启MHA服务
[root@xiaoQ-03 bin]# masterha_stop –conf=/etc/mha/app1.cnf
[root@xiaoQ-03 bin]# nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
​“`

####
“`

## 3 高可用切换

“`sh
模拟进行指定主库节点故障情况,检查核实MHA相应功能脚本是否能够正确运行:

​“`tiki wiki
# 确认目前的MHA的状态是良好的
[root@db03 ~]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 (pid:30770) is running(0:PING_OK), master:192.168.30.101

# 模拟DB01数据库节点宕机
[root@xiaoQ-01 ~]# /etc/init.d/mysqld stop
Shutting down MySQL……….. SUCCESS!

# 监控DB03日志信息的变化
[root@xiaoQ-03 ~]# tail -f /var/log/mha/app1/manager
Mon Jan 2 15:32:26 2023 – [warning] Got error on MySQL select ping: 1053 (Server shutdown in progress)
Mon Jan 2 15:32:26 2023 – [info] Executing SSH check script: exit 0
Mon Jan 2 15:32:26 2023 – [info] HealthCheck: SSH to 192.168.30.101 is reachable.
Mon Jan 2 15:32:28 2023 – [warning] Got error on MySQL connect: 2003 (Can’t connect to MySQL server on ‘192.168.30.101’ (111))
… 省略部分信息…
​“`

**实现MHA高可用切换的六个步骤:**

01 MHA健康检查报错,显示主数据库节点无法正常连接

​“`tiki wiki
# 日志信息分析
[waring] Got error on MySQL connect: 2003 (Can’t connect to MySQL server on ‘192.168.30.101’ (111))
[waring] Connection failed 2 time(s)..
[waring] Got error on MySQL connect: 2003 (Can’t connect to MySQL server on ‘192.168.30.101’ (111))
[waring] Connection failed 3 time(s)..
[waring] Got error on MySQL connect: 2003 (Can’t connect to MySQL server on ‘192.168.30.101’ (111))
[waring] Connection failed 4 time(s)..
[waring] Master is not reachable from health checker!
[waring] Master 192.168.30.101(192.168.30.101:3306) is not reachable!
— 对故障主节点进行4次健康检查,主节点数据库服务仍旧无法连接,即判定主节点故障
​“`

02 MHA进行重新选主,根据数组信息选择合适的备用新主节点

​“`tiki wiki
[info] Connecting to a master server failed. Reading configuration file /etc/masterha_default.cnf and /etc/mha/app1.cnf again, and trying to connect to all servers to check server status..
[info] Reading application default configuration from /etc/mha/app1.cnf
….
[info] Starting master failover
….
[info] ** Phase 1: Configuration Check Phase completed.
​“`

03 MHA进行节点关闭,选择完新的主节点后会将原有主节点的VIP地址消除

​“`tiki wiki
[info] * Phase 2: Dead Master Shutdown Phase..
[info] Forcing shutdown so that applications never connect to the current master..
Disabling the VIP on old master: 192.168.30.101
​“`

04 MHA进行节点切换,在新的主节点上进行非同步数据信息的补偿,

​“`tiki wiki
[info] * Phase 3: Master Recovery Phase..
[info] * Phase 3.1: Getting Latest Slaves Phase..
….
[info] * Phase 3.3: Determining New Master Phase..
[info] New master is 192.168.30.102(192.168.30.102:3306)
[info] Starting master failover..
[info] * Phase 3.3: New Master Recovery Phase..
[info] Executing binlog save command: save_binary_logs –command=save –start_file=mysql-bin.000002 –start_pos=1201 –output_file=/var/tmp/saved_binlog_binlog1_20230102153233.binlog –handle_raw_binlog=0 –skip_filter=1 –disable_log_bin=0 –manager_version=0.58 –oldest_version=8.0.26 –binlog_dir=/data/binlog_server/
[info] Additional events were not found from the binlog server. No need to save.
Enabling the VIP – 192.168.30.110/24 on the new master – 192.168.30.102
Mon Jan 2 15:32:36 2023 – [info] OK.
Mon Jan 2 15:32:36 2023 – [info] ** Finished master recovery successfully.
[info] * Phase 3: Master Recovery Phase completed.
​“`

05 MHA进行主从重构,将从库连接到新的主库上

​“`tiki wiki
[info] * Phase 4: Slaves Recovery Phase..
[info] * Phase 4.1: Starting Slaves in parallel..
[info] Resetting slave 192.168.30.103(192.168.30.103:3306) and starting replication from the new master 192.168.30.102(192.168.30.102:3306)..
[info] Executed CHANGE MASTER.
[info] Slave started.
[info] All new slave servers recovered successfully.
​“`

06 MHA切换完毕过程,架构故障转移切换完毕后做清理阶段,并进行最终汇报

​“`tiki wiki
[info] * Phase 5: New master cleanup phase..
—– Failover Report —–
Master failover to 192.168.30.102(192.168.30.102:3306) completed successfully.
Mon Jan 2 15:32:37 2023 – [info] Sending mail..
​“`

**实现MHA高可用切换的最终结果:**

01 MHA故障节点转移后,邮件信息提示:

02 核实MHA的VIP地址已经发生漂移:

03 核实MHA进行切换的新主从关系,以及配置文件中的故障节点信息已经踢除:

​“`tiki wiki
# 获取新主从关系
[root@xiaoQ-03 ~]# mysql -e “show slave status\G”
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.30.102
Master_User: repl
Master_Port: 3306

# 查看MHA配置文件信息
[root@xiaoQ-03 ~]# cat /etc/mha/app1.cnf
[binlog1]
hostname=192.168.30.103
master_binlog_dir=/data/binlog_server/
no_master=1

[server default]
manager_log=/var/log/mha/app1/manager
manager_workdir=/var/log/mha/app1
master_binlog_dir=/data/binlog
master_ip_failover_script=/usr/local/bin/master_ip_failover
password=mha
ping_interval=2
repl_password=123456
repl_user=repl
report_script=/usr/local/bin/send_report
ssh_user=root
user=mha

[server2]
hostname=192.168.30.102
port=3306

[server3]
hostname=192.168.30.103
port=3306
— 故障节点信息已从配置文件中清理
​“`

04 MHA程序终止(管理程序manager终止)

以上故障模拟操作完成后,查看MHA程序进程已经终止:

​“`tiki wiki
[root@xiaoQ-03 binlog_server]# ps -ef|grep mha
root 109328 1798 0 15:48 pts/0 00:00:00 grep –color=auto mha
[root@xiaoQ-03 ~]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 is stopped(2:NOT_RUNNING).
​“`

####
“`

## 4 高可用修复

“`sh
MHA故障通用修复方法步骤:`(前提是MHA进行正常故障切换,通过日志可以检查是否进行正常的故障转移)`

01 检查节点状态:

​“`tiki wiki
# 检查节点数据库运行状态
[root@xiaoQ-01 ~]# /etc/init.d/mysqld status
ERROR! MySQL is not running
— 发现数据库服务有异常节点进行恢复
[root@xiaoQ-01 ~]# /etc/init.d/mysqld start
Starting MySQL. SUCCESS!
— 恢复DB01异常数据库服务节点
​“`

在实际生产环境中,如果主库异常无法实现重新启动修复,可能就需要准备一台新的节点主机,重新构建1主2从的架构;

但是如果使用新的节点主机,进行主从架构重构,修复高可用环境,就需要考虑新主机的在恢复数据的时间损耗;

总之,需要将新节点的数据信息进行同步后,再将新节点变为新的从库,从而修复高可用主从关系,具体如何修复数据需要考虑实际情况

02 检查主从关系:

​“`tiki wiki
[root@xiaoQ-03 ~]# mysql -e “show slave status\G”|grep “Master_Host”
Master_Host: 192.168.30.102
— 确认切换后的新主库信息
[root@xiaoQ-02 ~]# /etc/init.d/mysqld status
SUCCESS! MySQL running (27332)
— 在DB02上核实节点运行的状态
[root@xiaoQ-01 ~]# mysql -e “show slave status\G”|grep “Master_Host”
— 在DB01上无法获取主从关系信息,需要修复DB01主从,最终实现1主2从效果
​“`

03 修复主从关系:

​“`tiki wiki
# 在DB01上修复主从:
[root@xiaoQ-01 ~]# mysql
db02 [(none)]>change master to
master_host=’192.168.30.102′,
master_user=’repl’,
master_password=’123456′,
master_auto_position=1;
db02 [(none)]> start slave;

# 在DB01上核实主从关系
[root@xiaoQ-01 ~]# mysql -e “show slave status\G”|grep “Master_Host”
Master_Host: 192.168.30.102
​“`

04 检查虚拟地址:

​“`tiki wiki
[root@xiaoQ-02 ~]# ip a s eth0
2: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:61:cd:06 brd ff:ff:ff:ff:ff:ff
inet 192.168.30.102/24 brd 192.168.30.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 192.168.30.110/24 brd 192.168.30.255 scope global secondary eth0:1
valid_lft forever preferred_lft forever
inet6 fe80::560c:13cd:6107:b0de/64 scope link tentative noprefixroute dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::727b:5d03:94c0:9382/64 scope link noprefixroute
valid_lft forever preferred_lft forever

ifconfig eth0:1 192.168.30.110/24
— 如果上面vip漂移失败,出现问题可以手工添加VIP
​“`

05 恢复日志同步:

​“`tiki wiki
# 检查binlog_server状态
[root@xiaoQ-03 ~]# ps -ef|grep mysqlbinlog
— binlog_server日志同步进程消失

# 修复binlog_server状态
[root@xiaoQ-03 ~]# rm -rf /data/binlog_server/*
[root@xiaoQ-03 ~]# cd /data/binlog_server/
[root@xiaoQ-03 binlog_server]# mysql -e “show slave status\G”|grep “Master_Log”
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 1229
Relay_Master_Log_File: mysql-bin.000002
Exec_Master_Log_Pos: 1229
[root@xiaoQ-03 binlog_server]# mysqlbinlog -R –host=192.168.30.102 –user=mha –password=mha –raw –stop-never mysql-bin.000002 &
[root@xiaoQ-03 binlog_server]# ll
总用量 4
-rw-r—– 1 root root 1229 1月 2 16:28 mysql-bin.000002
​“`

06 调整配置文件:

​“`tiki wiki
# 确认核实配置文件中三个节点信息
[root@xiaoQ-03 binlog_server]# cat /etc/mha/app1.cnf
[binlog1]
hostname=192.168.30.103
master_binlog_dir=/data/binlog_server/
no_master=1

[server default]
manager_log=/var/log/mha/app1/manager
manager_workdir=/var/log/mha/app1
master_binlog_dir=/data/binlog
master_ip_failover_script=/usr/local/bin/master_ip_failover
password=mha
ping_interval=2
repl_password=123456
repl_user=repl
report_script=/usr/local/bin/send_report
ssh_user=root
user=mha

[server2]
hostname=192.168.30.102
port=3306

[server3]
hostname=192.168.30.103
port=3306

[server1]
hostname=192.168.30.101
port=3306
— 添加DB01故障节点到配置文件中

[root@xiaoQ-03 ~]# masterha_conf_host –command=add –conf=/etc/mha/app1.cnf –hostname=192.168.30.101 –block=server1 –params=”port=3306″
— 利用命令脚本添加新的节点信息
[root@xiaoQ-03 ~]# masterha_conf_host –command=delete –conf=/etc/mha/app1.cnf –bl =server1
— 利用命令脚本删除指定的节点信息
​“`

07 核实互信情况:

​“`tiki wiki
[root@xiaoQ-03 ~]# masterha_check_ssh –conf=/etc/mha/app1.cnf
Mon Jan 2 16:42:35 2023 – [info] All SSH connection tests passed successfully.
[root@xiaoQ-03 binlog_server]# masterha_check_repl –conf=/etc/mha/app1.cnf
MySQL Replication Health is OK.
​“`

08 恢复启动MHA:

​“`tiki wiki
[root@xiaoQ-03 ~]# nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
[root@xiaoQ-03 ~]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 (pid:109463) is running(0:PING_OK), master:192.168.30.102
​“`

####
“`

## 5 高可用维护

“`sh
**实现MHA高可用主节点在线切换(手工操作)**

可以在主库没有故障的情况下,利用手工方式将主库业务切换到其它的从库节点上,从而解放原有主库节点(维护性操作时应用);

​“`tiki wiki
# 关闭MHA服务程序
masterha_stop –conf=/etc/mha/app1.cnf
— 关闭mha程序是保证手工切换时,不会受到mha自动切换的影响

# 执行MHA手工切换
masterha_master_switch –conf=/etc/mha/app1.cnf –master_state=alive –new_master_host=192.168.30.101 –orig_master_is_new_slave –running_updates_limit=10000
…省略部分信息…
It is better to execute FLUSH NO_WRITE_TO_BINLOG TABLES on the master before switching. Is it ok to execute on 192.168.30.102(192.168.30.102:3306)? (YES/no):
— 以上说明信息,表示在进行切换之前,在原有主库节点执行FLUSH NO_WRITE_TO_BINLOG TABLES这个命令
— 此命令表示,关闭所有打开的表,强制关闭所有正在使用的表,刷新binlog日志信息,确保完整日志信息推送到从库;

# 关闭原主库的写入功能(暂时不让主库进行binlog日志记录)
db02 [(none)]>FLUSH NO_WRITE_TO_BINLOG TABLES;
Query OK, 0 rows affected (0.01 sec)

It is better to execute FLUSH NO_WRITE_TO_BINLOG TABLES on the master before switching. Is it ok to execute on 192.168.30.102(192.168.30.102:3306)? (YES/no): yes

Starting master switch from 192.168.30.102(192.168.30.102:3306) to 192.168.30.101(192.168.30.101:3306)? (yes/NO): yes
— 进行再一次核实确认,是否进行手工切换

master_ip_online_change_script is not defined. If you do not disable writes on the current master manually, applications keep writing on the current master. Is it ok to proceed? (yes/NO): yes
— 表示master_ip_online_change_script此脚本没有定义,如果没有禁止当前主库写入的禁止,业务应用仍旧访问当前主库
— 因为此时VIP还没有进行转移;
[info] Switching master to 192.168.30.101(192.168.30.101:3306) completed successfully.
— 提示切换完成

# 进行MHA切换核验
[root@xiaoQ-03 ~]# nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
— 重新启动MHA程序

[root@xiaoQ-03 ~]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 is stopped(2:NOT_RUNNING).
[1]+ 退出 1 nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null > /var/log/mha/app1/manager.log 2>&1
— 检查状态失败,mha没有启动成功,因为vip信息并没有进行有效漂移

masterha_master_switch –conf=/etc/mha/app1.cnf –master_state=alive –new_master_host=192.168.30.102 –orig_master_is_new_slave –running_updates_limit=10000
— 临时先切换回原有主节点,恢复MHA服务状态

[root@xiaoQ-03 ~]# nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
[1] 65799
[root@xiaoQ-03 ~]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 (pid:65799) is running(0:PING_OK), master:192.168.30.102
— mha服务状态恢复
​“`

执行切换命令参数信息说明:

| 序号 | 参数信息 | 解释说明 |
| —- | ————————– | ———————————————————— |
| 01 | –master_state | 执行手工切换的状态,alive表示主节点存活状态进行切换 |
| 02 | –new_master_host | 指定切换后的新主库节点的地址信息 |
| 03 | –orig_master_is_new_slave | 将原有主库指定为新的从库角色 |
| 04 | –running_updates_limit | 指定切换过程的时间限制,超过指定时间未完成切换,即切换失败,单位毫秒 |

在进行MHA高可用节点在线手工切换时,有以下信息需要注意:

– 在进行MHA高可用手工切换时,无法自动调整原有主库的binlog_server,需要手工重新拉取新主库的binlog;
– 在进行MHA高可用手工切换时,无法进行触发邮件脚本功能,邮件发送功能只能在MHA产生故障转移时触发;
– 在进行MHA高可用手工切换时,需要进行架构主从关系的切换,以及可以调整转移VIP地址信息;
– 在进行MHA高可用手工切换时,需要对切换前的主库进行锁定(FTWRL flush tables with read lock),避免数据不一致

**进行MHA手工在线切换的合理操作:**

**01 应用master_ip_online_change_script功能脚本**

功能描述:此脚本可以在线进行切换时,自动锁定原主库,以及将原主库VIP地址进行自动飘移;

编写应用切换脚本文件信息:

​“`tiki wiki
# 编写MHA手工切换脚本文件:
[root@xiaoQ-03 ~]# cd /usr/local/bin/
[root@xiaoQ-03 bin]# cp master_ip_online_change master_ip_online_change.bak
[root@xiaoQ-03 bin]# vim master_ip_online_change
21 my $vip = “192.168.30.110”;
22 my $key = “1”;
23 my $ssh_start_vip = “/sbin/ifconfig eth0:$key $vip”;
24 my $ssh_stop_vip = “/sbin/ifconfig eth0:$key $vip down”;
25 my $ssh_Bcast_arp= “/sbin/arping -I eth0 -c 3 -A 192.168.30.110”;

# 修改MHA服务程序配置文件:
[root@xiaoQ-03 ~]# vim /etc/mha/app1.cnf
master_ip_online_change_script=/usr/local/bin/master_ip_online_change

# 关闭MHA服务程序进行核查:
[root@xiaoQ-03 ~]# masterha_stop –conf=/etc/mha/app1.cnf
[root@xiaoQ-03 ~]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 is stopped(2:NOT_RUNNING).
[root@xiaoQ-03 ~]# masterha_check_repl –conf=/etc/mha/app1.cnf
MySQL Replication Health is OK.

# 进行MHA服务手工在线切换:
[root@xiaoQ-03 ~]# masterha_master_switch –conf=/etc/mha/app1.cnf –master_state=alive –new_master_host=192.168.30.101 –orig_master_is_new_slave –running_updates_limit=10000
…省略部分信息…
It is better to execute FLUSH NO_WRITE_TO_BINLOG TABLES on the master before switching. Is it ok to execute on 192.168.30.102(192.168.30.102:3306)? (YES/no): yes
— FLUSH NO_WRITE_TO_BINLOG TABLES 命令在原有主库节点需要再执行一次;
Starting master switch from 192.168.30.102(192.168.30.102:3306) to 192.168.30.101(192.168.30.101:3306)? (yes/NO): yes
Sat Jan 7 13:48:50 2023 – [info] Switching master to 192.168.30.101(192.168.30.101:3306) completed successfully.

# 重构binlogserver功能
[root@xiaoQ-03 ~]# cd /data/binlog_server/
[root@xiaoQ-03 binlog_server]# rm -rf ./*
[root@xiaoQ-03 binlog_server]# mysql -e “show slave status\G”|grep “Master_Log”
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 236
Relay_Master_Log_File: mysql-bin.000005
Exec_Master_Log_Pos: 236
[root@xiaoQ-03 binlog_server]# mysqlbinlog -R –host=192.168.30.101 –user=mha –password=mha –raw –stop-never mysql-bin.000005 &
— 此功能不进行重新配置,会导致MHA服务无法正常启动(若已经启动过,可以将进程杀死,重新启动)

# 进行MHA服务手工切换核验:
[root@xiaoQ-03 ~]# nohup masterha_manager –conf=/etc/mha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &
— 重新启动MHA程序
[root@xiaoQ-03 binlog_server]# masterha_check_status –conf=/etc/mha/app1.cnf
app1 (pid:17462) is running(0:PING_OK), master:192.168.30.101
​“`

##
“`

# 第九章 读写分离

“`sh
读写分离架构最终目的:实现业务写的请求到达主库,实现业务读的请求到达从库,从而减少主库的压力,实现不同请求的压力分担;

可以利用读写分离中间件实现以上的功能需求:atlas(360公司出品) `proxySQL`

利用读写分离中间件的设置,当业务请求有select查询时,将请求发送给从库,当业务请求有update insert等修改时,将请求发送给主库
“`

![1673922233191](D:/学习//4_数据库/视频和笔记/系统运维95期-Day11-数据库服务读写分离架构-PrxoySQL/课程笔记目录/MySQL中级数据库课程-16章-数据库读写分离架构/课件配图资料/1673922233191.png)

“`sh
proxySQL是基于MySQL的一款开源的中间件的产品,是一个灵活的MySQL代理层,可以实现读写分离:

– proxySQL数据库中间件支持Query路由功能;
– pxoxySQL数据库中间件支持动态指定某个SQL进行缓存;
– proxySQL数据库中间件支持动态加载配置信息(无需重启ProxySQL服务)
– proxySQL数据库中间件支持故障切换和SQL的过滤功能(安全机制)

ProxySQL的参考网站连接:

ProxySQL

https://github.com/sysown/proxysql/releases

步骤一:读写分离架构部署环境规划

为了实现读写分离架构构建,需要准备好三节点数据库+GTID复制环境+MHA环境(`普通主从环境也可以构建`);

| 主机角色 | 主机名称 | 地址信息 |
| ———- | —————————- | ——– |
| 主库服务器 | 192.168.30.101 | 3306 |
| 从库服务器 | 192.168.30.102 | 3306 |
| 从库服务器 | 192.168.30.103(兼做管理节点) | 3306 |

步骤二:读写分离架构软件下载安装

通过官方网站或者github可以下载proxySQL软件程序,并上传到数据库服务器中进行安装;

​“`tiki wiki
# 上传安装软件程序
[root@xiaoQ-03 ~]# rpm -ivh proxysql-2.4.6-1-centos7.x86_64.rpm
警告:proxysql-2.4.6-1-centos7.x86_64.rpm: V4 RSA/SHA512 Signature, 密钥 ID 8217c97e: NOKEY
准备中… ################################# [100%]

# 启动运行软件程序
[root@xiaoQ-03 ~]# systemctl start proxysql
[root@xiaoQ-03 ~]# netstat -lntup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:6032 0.0.0.0:* LISTEN 83020/proxysql
tcp 0 0 0.0.0.0:6033 0.0.0.0:* LISTEN 83020/proxysql
— 启动生成的6032端口为管理端口,用于配置数据库中间件的功能信息连接此端口
— 启动生成的6033端口为访问端口,用于提供对外的业务访问此端口
​“`

步骤三:读写分离架构软件管理配置

在连接进入6032端口之后,表示进行proxysql的管理终端环境,终端环境中会加载五个重要的功能库:

| 序号 | 库信息 | 配置信息 | 解释说明 |
| —- | ————- | —————————- | —————————————————— |
| 01 | `main` | mysql_servers | 表示后端可以连接mysql服务器的列表 |
| | | mysql_users | 表示配置后端数据库的连接账号和监控账号 |
| | | mysql_query_rules | 表示指定query路由到后端不同服务器的规则列表 |
| | | mysql_replication_hostgroups | 表示节点分组配置信息,可以配置多个写或读节点到一个组中 |
| 02 | disk | | 表示持久化的磁盘配置信息 |
| 03 | `stats` | | 表示统计信息的汇总 |
| 04 | `monitor` | | 表示监控收集的信息,比如数据库的监控状态等 |
| 05 | stats_history | | 表示收集的有关软件内部功能的历史指标 |

> 说明:一般服务是通过配置文件保存功能配置信息,proxySQL是通过数据库中的表进行配置信息的存储设置;

​“`tiki wiki
# 连接进入到proxySQL管理终端
[root@xiaoQ-03 ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.30 (ProxySQL Admin Module)

# 查看proxySQL终端数据库信息
>show databases;
+—–+—————–+———————————————-+
| seq | name | file |
+—–+—————–+———————————————-+
| 0 | main | |
| 2 | disk | /var/lib/proxysql/proxysql.db |
| 3 | stats | |
| 4 | monitor | |
| 5 | stats_history | /var/lib/proxysql/proxysql_stats.db |
+—–+—————–+———————————————-+
5 rows in set (0.00 sec)
— 不需要use到相应数据库中进行操作,可以操作的数据表信息如下

# 查看proxySQL终端数据表信息
>show tables ;
+—————————————————————–+
| tables
+—————————————————————–+
| global_variables
| mysql_aws_aurora_hostgroups
| mysql_collations
| mysql_firewall_whitelist_rules
| mysql_firewall_whitelist_sqli_fingerprints
| mysql_firewall_whitelist_users
| mysql_galera_hostgroups
| mysql_group_replication_hostgroups
| mysql_query_rules
| mysql_query_rules_fast_routing
| mysql_replication_hostgroups
| mysql_servers
| mysql_users
| proxysql_servers
| restapi_routes
| runtime_checksums_values
| runtime_global_variables
| runtime_mysql_aws_aurora_hostgroups
| runtime_mysql_firewall_whitelist_rules
| runtime_mysql_firewall_whitelist_sqli_fingerprints
| runtime_mysql_firewall_whitelist_users
| runtime_mysql_galera_hostgroups
| runtime_mysql_group_replication_hostgroups
| runtime_mysql_query_rules
| runtime_mysql_query_rules_fast_routing
| runtime_mysql_replication_hostgroups
| runtime_mysql_servers
| runtime_mysql_users
| runtime_proxysql_servers
| runtime_restapi_routes
| runtime_scheduler
| scheduler
+—————————————————————–+
32 rows in set (0.00 sec)
— 表名以runtiem_开头的表示proxySQL服务中当前运行的配置内容,不能直接修改,不带runtime是下文图中mem相关的配置
​“`

**ProxySQL管理接口的多层配置关系:**

ProxySQL整套配置系统分为三层:

**第一层:RUNTIME:**

代表proxySQL当前正在使用的配置,无法直接修改此配置,必须要从下一层(MEM层)load加载进来;

**第二层:MEMORY(主要修改的配置表)**

memory层上面连接runtime层,下面连接disk持久化存储层;

在这层可以在线操作ProxySQL配置,随意进行修改,不会影响生产环境,确认正常之后再加载到runtime和持久化保存到磁盘上

具体修改操作方法为:insert、update、delete、select;

**第三层:DISK/CFG FILE**

持久化配置信息,重启时可以从磁盘快速加载回来;

ProxySQL不同层次间移动配置信息:

为了将配置持久化到磁盘或者应用到runtime,在管理接口下有一系列管理命令来实现相关功能配置:

​“`tiki wiki
# 01 user相关配置
LOAD MYSQL USERS TO RUNTIME;
— MEM加载到runtime
SAVE MYSQL USERS TO MEMORY;
— RUNTIME保存至MEM
LOAD MYSQL USERS FROM DISK;
— DISK加载到MEM
SAVE MYSQL USERS TO DISK;
— MEM保存至DISK
LOAD MYSQL USERS FROM CONFIG
— CFG加载到MEM

# 02 server相关配置
LOAD MYSQL SERVERS TO RUNTIME;
— MEM加载到RUNTIME
SAVE MYSQL SERVERS TO MEMORY;
— RUNTIME保存至MEM
LOAD MYSQL SERVERS FROM DISK;
— DISK加载到MEM
SAVE MYSQL SERVERS TO DISK;
— MEM保存至DISK
LOAD MYSQL SERVERS FROM CONFIG
— CFG加载到MEM

# 03 MYSQL QUERY RULES相关配置
LOAD MYSQL QUERY RULES TO RUNTIME;
— MEM加载到RUNTIME
SAVE MYSQL QUERY RULES TO MEMORY;
— RUNTIME保存至MEM
LOAD MYSQL QUERY RULES FROM DISK;
— DISK加载到MEM
SAVE MYSQL QUERY RULES TO DISK;
— MEM保存至DISK
LOAD MYSQL QUERY RULES FROM CONFIG
— CFG加载到MEM

# 03 MYSQL VARIABLES相关配置
LOAD MYSQL VARIABLES TO RUNTIME;
— MEM加载到RUNTIME
SAVE MYSQL VARIABLES TO MEMORY;
— RUNTIME保存至MEM
LOAD MYSQL VARIABLES FROM DISK;
— DISK加载到MEM
SAVE MYSQL VARIABLES TO DISK;
— MEM保存至DISK
LOAD MYSQL VARIABLES FROM CONFIG
— CFG加载到MEM
​“`

需要注意:只有load到runtime状态时才会验证配置,在保存到mem或disk时,都不会发生任何警告或错误;

当load到runtime时,如果出现了错误信息,将恢复为之前保存的状态,这时可以根据错误日志信息做检查;

> 总结:日常配置过程大部分时间是在mem中进行配置,然后load到runtime,或者save到disk中,对于cfg很少使用;

**ProxySQL基于SQL语句进行读写分离实践配置:**

①. 在mysql_replication_hostgroup表中,配置读写组编号:

proxySQL会根据server的read only的取值将服务器进行分组:

– read_only=0的server,即master会被分到编号为10的写组;
– read_only=1的server,即slave会被分到编号为20的读组;(`所以需要将从库设置:set global read_only=1`)

​“`SQL
db03 [(none)]>insert into mysql_replication_hostgroups(writer_hostgroup,reader_hostgroup,comment) values(10,20,’proxy’);
Query OK, 1 row affected (0.00 sec)

db03 [(none)]>save mysql servers to disk;
Query OK, 0 rows affected (0.01 sec)

db03 [(none)]>load mysql servers to runtime;
Query OK, 0 rows affected (0.00 sec)

db03 [(none)]>select * from mysql_replication_hostgroups\G
*************************** 1. row ***************************
writer_hostgroup: 10
reader_hostgroup: 20
check_type: read_only
comment: proxy
1 row in set (0.00 sec)
​“`

② 添加主机到ProxySQL

​“`sql
db03 [(none)]>insert into mysql_servers(hostgroup_id,hostname,port) values (10,’192.168.137.51′,3306);
Query OK, 1 row affected (0.00 sec)

db03 [(none)]>insert into mysql_servers(hostgroup_id,hostname,port) values (20,’192.168.137.52′,3306);
Query OK, 1 row affected (0.00 sec)

db03 [(none)]>insert into mysql_servers(hostgroup_id,hostname,port) values (20,’192.168.137.53′,3306);
Query OK, 1 row affected (0.00 sec)

db03 [(none)]>save mysql servers to disk;
Query OK, 0 rows affected (0.01 sec)

db03 [(none)]>load mysql servers to runtime;
Query OK, 0 rows affected (0.00 sec)

db03 [(none)]>select * from mysql_servers\G;
*************************** 1. row ***************************
hostgroup_id: 20
hostname: 192.168.30.102
port: 3306
gtid_port: 0
status: ONLINE
weight: 1
compression: 0
max_connections: 1000
max_replication_lag: 0
use_ssl: 0
max_latency_ms: 0
comment:
*************************** 2. row ***************************
hostgroup_id: 20
hostname: 192.168.30.103
port: 3306
gtid_port: 0
status: ONLINE
weight: 1
compression: 0
max_connections: 1000
max_replication_lag: 0
use_ssl: 0
max_latency_ms: 0
comment:
*************************** 3. row ***************************
hostgroup_id: 10
hostname: 192.168.30.110
port: 3306
gtid_port: 0
status: ONLINE
weight: 1
compression: 0
max_connections: 1000
max_replication_lag: 0
use_ssl: 0
max_latency_ms: 0
comment:
3 rows in set (0.00 sec)
​“`

③ 创建监控用户,并开启监控

利用监控用户对后端节点的运行情况进行监控数据同步,一旦后端节点出现数据同步异常,就不要再向故障节点发送相应业务请求;

​“`tiki wiki
# 主库创建监控用户
db01 [(none)]>create user monitor@’%’ identified with mysql_native_password by ‘123’;
Query OK, 0 rows affected (0.02 sec)
db01 [(none)]>grant replication client on *.* to monitor@’%’;
Query OK, 0 rows affected (0.01 sec)

# 在proxysql中修改variables表配置信息
db03 [(none)]>set mysql-monitor_username=’monitor’;
Query OK, 1 row affected (0.00 sec)

db03 [(none)]>set mysql-monitor_password=’123′;
Query OK, 1 row affected (0.00 sec)
— 以上变量信息修改为方法一

db03 [(none)]>update global_variables set variable_value=’monitor’ where variable_name=’mysql-monitor_username’;
Query OK, 1 row affected (0.00 sec)

db03 [(none)]>update global_variables set variable_value=’123′ where variable_name=’mysql-monitor_password’;
Query OK, 1 row affected (0.00 sec)
— 以上变量信息修改为方法二

db03 [(none)]>load mysql variables to runtime;
Query OK, 0 rows affected (0.01 sec)

db03 [(none)]>save mysql variables to disk;
Query OK, 154 rows affected (0.00 sec)

# 检查核实配置信息
db03 [(none)]>select @@mysql-monitor_username\G
*************************** 1. row ***************************
@@mysql-monitor_username: monitor
1 row in set (0.00 sec)

db03 [(none)]>select @@mysql-monitor_password\G
*************************** 1. row ***************************
@@mysql-monitor_password: 123
1 row in set (0.00 sec)

# 查询监控日志信息
db03 [(none)]>select * from mysql_server_connect_log;
+——————-+——+————————-+———————————+—————————————-+
| hostname | port | time_start_us | connect_success_time_us | connect_error |
+——————-+——+————————-+———————————+—————————————-+
| 192.168.30.110 | 3306 | 1674026545375939 | 2831 | NULL |
| 192.168.30.103 | 3306 | 1674026546137911 | 1480 | NULL |
| 192.168.30.102 | 3306 | 1674026546899730 | 3781 | NULL |
— 检查确认所有节点的连接访问情况

db03 [(none)]>select * from mysql_server_ping_log;
+——————-+——+————————-+—————————–+—————+
| hostname | port | time_start_us | ping_success_time_us | ping_error |
+——————-+——+————————-+—————————–+—————+
| 192.168.30.102 | 3306 | 1674026696004217 | 1139 | NULL |
| 192.168.30.103 | 3306 | 1674026696095455 | 194 | NULL |
| 192.168.30.110 | 3306 | 1674026696186794 | 1466 | NULL |
— 检查确认所有节点的网络连通情况

db03 [(none)]>select * from mysql_server_read_only_log limit 3;
+——————-+——+————————-+———————-+————-+——–+
| hostname | port | time_start_us | success_time_us | read_only | error |
+——————-+——+————————-+———————-+————-+——–+
| 192.168.30.110 | 3306 | 1674027579464285 | 1325 | 0 | NULL |
| 192.168.30.102 | 3306 | 1674027579479777 | 1743 | 1 | NULL |
| 192.168.30.103 | 3306 | 1674027579494993 | 308 | 1 | NULL |
— 检查确认所有节点的只读状态信息(获取主库或从库主机信息)

db03 [(none)]>select * from mysql_server_replication_lag_log;
Empty set (0.00 sec)
— 检查确认所有节点的主从延时情况
​“`

④ 创建应用用户信息

创建数据库应用用户信息,利用应用用户,可以使proxySQL进行数据库节点的操作管理;

​“`tiki wiki
# 主库创建应用用户
db01 [(none)]>create user root@’%’ identified with mysql_native_password by ‘123’;
Query OK, 0 rows affected (0.00 sec)

db01 [(none)]>grant all on *.* to root@’%’;
Query OK, 0 rows affected (0.00 sec)

# 在proxysql中添加数据库节点的管理用户信息
db03 [(none)]>insert into mysql_users(username,password,default_hostgroup) values(‘root’,’123′,10);
Query OK, 1 row affected (0.00 sec)

db03 [(none)]>load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

db03 [(none)]>save mysql users to disk;
Query OK, 0 rows affected (0.00 sec)

# 早期版本,需要开启事务的持续化(忽略)
update mysql_users set transaction_persistent=1 where username=’root’;
load mysql users to runtime;
save mysql users to disk;
— 事务路由分配持续性,同一个事务的语句不会被分配到不同的组
​“`

⑤ 实用的读写规则配置

​“`sql
> insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values (1,1,’^select.*for update$’,10,1);
> insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values (2,1,’^select’,20,1);
— 其余数据库操作语句信息,默认路由放置到主节点进行执行

> load mysql query rules to runtime;
> save mysql query rules to disk;
​“`

select … for update规则的rule_id必须要小于普通的select规则的rule_id,proxySQL是根据rule_id的顺序进行规则匹配的;

⑥ 测试读写分离效果

​“`tiki wiki
[root@xiaoQ-03 ~]# mysql -uroot -p123 -P6033 -h127.0.0.1 -e “begin;select @@server_id;commit”
+—————–+
| @@server_id |
+—————–+
| 51 |
+—————–+
— 非查询操作走的是主节点

[root@xiaoQ-03 ~]# mysql -uroot -p123 -P6033 -h127.0.0.1 -e “select @@server_id;”
+—————–+
| @@server_id |
+—————–+
| 52 |
+—————–+
[root@xiaoQ-03 ~]# mysql -uroot -p123 -P6033 -h127.0.0.1 -e “select @@server_id;”
+—————–+
| @@server_id |
+—————–+
| 53 |
+—————–+
— 查询操作走的是从节点

>select * from stats_mysql_query_digest\G
— 这个表对于分析SQL语句至关重要,是分析语句性能、定制路由规则指标的最主要来源
​“`

读写分离配置过程总结:

| 步骤 | 操作说明 | 涉及数据表信息 | 涉及操作信息 |
| —- | ——————————— | ——————————- | ———— |
| 01 | 设置从库只读模式 | | read_only=1 |
| 02 | 添加主机组信息 | mysql_replication_hostgroups | |
| 03 | 添加主机组节点信息 | mysql_servers | |
| 04 | 添加用户信息(监控用户 应用用户) | global_variables
mysql_users | |
| 05 | 添加读写分离规则 | mysql_query_rules | |

步骤四:读写分离架构软件配置扩展

① 基于端口进行读写分离路由

​“`tiki wiki
# 修改proxySQL监听SQL流量的端口号,监听多端口信息
> set mysql-interfaces=’0.0.0.0:6033;0.0.0.0:6034′

# 使监听端口配置信息生效
> save mysql variables to disk;
[root@xiaoQ-03 ~]# systemctl restart proxysql

# 设定相应读写分离路由规则
> delete from mysql_query_rules;
— 为了测试效果,先清空已有规则信息
> insert into mysql_query_rules(rule_id,active,proxy_port,destination_hostgroup,apply) values(1,1,6033,10,1),(2,1,6034,20,1);
> load mysql query rules to runtime;
> save mysql query rules to disk;
— 除了基于端口进行分离,还可以基于监听地址(修改字段proxy_addr即可),也可以基于客户端地址(修改字段client_addr字段即可);
​“`

② 基于用户进行读写分离路由

​“`sql
> insert into mysql_users(username,password,default_hostgroup) values (‘write’,’123′,10),(‘reader’,’123′,20);
> load mysql users to runtime;
> save mysql users to disk;

> delete from mysql_query_rules;
— 为了测试效果,先清空已有规则信息
> insert into mysql_query_rules(rule_id,active,username,destination_hostgroup,apply) values (1,1,’write’,10,1),(2,1,’reader’,20,1);
> load mysql users to runtime;
> save mysql users to disk;
​“`

###
“`

![image-20250217124159058](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250217124159058.png)

# 第十章 索引

## 1 概念

“`sh
#### 1.6.1 数据库索引相关概念

数据库中的索引类似一本书的目录,如果希望快速了解这本书特定的章节内容,则可以通过目录查找指定章节对应页码;

根据页码快速找到需要的信息。

索引是数据库中用来提高数据读取性能的常用工具,所有mysql列类型都可以被索引,对相关列使用索引;

可以是提高select操作性能的最佳途径,可以尽可能快的锁定要查询数据的范围,从而达到加速查询的目的(减少IO消耗);

一般索引设置都是应用在比较大的数据表上,比如百万级别、千万级别或亿级别的数据表中,从而完成一些针对性优化;

`可以简单理解:数据库索引相当于书的目录,可以借助索引有针对的查看相应数据的信息,避免了全盘检索带来的工作量;`

主要利用MySQL中的索引,可以快速锁定查询范围,mysql索引比较适合范围查找数据;

#### 1.6.2 数据库索引模型介绍

在使用常规索引类型时,对应的索引创建后,也会在内存中构建索引模型结构,可以利用模型结构来理解数据检索过程;

在MySQL数据库服务中,是有很多种索引类型模型的,但是比较常用的索引类型模型主要有:

索引树结构模型可视化网站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

| 序号 | 类型 | 说明 |
| —— | ——– | ————————————– |
| 类型01 | `B+Tree` | 默认类型索引(擅于等值和区间查询数据) |
| 类型02 | Hash | 算法类型索引(擅于等值查询数据) |
| 类型03 | RTree | 空间类型索引(擅于区间查询数据) |
| 类型04 | Fulltext | 全文类型索引(擅于过滤查询数据) |

##### 01 索引模型类型一:B+Tree

在讲解B+Tree之前先了解一下树的整体结构,无非就是二叉树、红黑树、Btree、B+tree等;

而树的查找性能取决于树的高度,让树尽可能平衡是为了降低树的高度。

为什么MySQL会选用B+树的结构,可以先来看看其他的树形结构:

– **二叉树**

二叉树的每一个节点都只有两个子节点,当需要向其插入更多的数据的时候,就必须要增加树的高度,而增加树的高度会导致IO消耗大;

对于二叉树而言,它的查找操作的时间复杂度就是树的高度,树的高度越高查询性能就会随着数据的增多越来越低。

二叉树节点中,还存在非正常的倾斜(比如ID自增的情况)的二叉树,查询一次数据就相当于全表搜索,因此二叉树的查询性能特别差
“`

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/1682955300451.png)

“`sh
从磁盘物理硬件角度分析,利用二叉树的方案调取数据性能也是最差的,因为索引不止存在内存中,还要写到磁盘上。

你可以想象一下一棵 100 万节点的平衡二叉树,假设树高 20。一次查询可能需要访问 20 个数据块。

在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。

也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10 ms 的时间,这个查询可真够慢的。

为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。

那么,我们就不应该使用二叉树,而是要使用“N 叉”树。

N 叉树由于在读写上的性能优点,以及适配磁盘的访问模式,已经被广泛应用在数据库引擎中了。

一颗空树或者满足以下性质的二叉树被称之为二叉搜索树:

– 如果左子树不为空,则左子树所有节点值都小于根节点的值;
– 如果右子树不为空,则右子树所有节点值都大于根节点的值;
– 任意一棵子树也是一棵二叉搜索树

> 说明:查找时间复杂度是O(logn),但在极端情况下会出现时间复杂度是O(n)的情况

– **红黑树:**

在原本二叉搜索树结构中进行数据查询时,利用其结构特性可以更快的进行数据的查询;

但是一旦二叉树讲解为链表结构后,查询效率会严重降低;

因此,在二叉搜索树实际应用过程会有所缺陷,为了弥补这个缺陷,就出现了平衡二叉搜索树结构(AVL树-属于平衡树);

平衡树(Balance Tree BT)

– 任意节点的子树的高度差都小于等于1;
– 常见的平衡树包括B树(MySQL中的索引)、AVL树-作者Adelson-Velskii,Landis等;

平衡二叉搜索树(AVL树 作者Adelson-Velskii,Landis)

– 同时满足二叉搜索树以及平衡树特点
– 可以有效的减少二叉树的深度,从而提高了查询的效率
– 严格平衡,代价高

红黑树(Red Black Tree R-B Tree)

1972年的Rudolf Bayer发明,称为平衡二叉B树(symmetric binary B-trees)

1978年被Leo J.Guibas和Robert Sedgewick 修改为 “红黑树”

红黑树属于一种平衡二叉树,会应用复杂的定义和规则都是为了保证树的平衡性;

红黑树属于一种特化的AVL树,在插入和删除时通过特定操作保持二叉查找树的相对平衡,从而获得较高的查找性能;

不是严格的AVL树,只是黑色平衡

– 根节点P的左子树显然比右子树高
– 但左子树和右子树的黑节点的层数是相等的

简单理解:可以将插入的连续有序数值信息,在排序后进行逐一的颜色划分,并且连续的数据需要红黑交替标记颜色;
“`

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/Image 047.png)

“`sh
红黑树特点:(符合二叉搜索树基本特征)

– 节点非黑即红(每个节点要么是黑色,要么是红色)
– 其根节点是黑色
– 叶子节点是黑色(为了简单理解,一般会省略该节点)
– 相邻节点不同为红色(红色节点子节点必是黑色)
– 从一个节点到该节点的下叶子节点的所有路径上包含的黑节点数量相等(这一点是平衡的关键)

> 说明:黑根黑叶红不邻,同祖等高只数黑

– **BTree:改造后的二叉树**

MySQL的数据是存储在磁盘文件中的,查询处理数据时,需要先把磁盘中的数据加载到内存中,磁盘IO操作非常耗时;

因此需要日常对数据库优化的重点就是尽量减少磁盘IO操作,而访问二叉树的每个节点就会发生一次IO,如果想要减少IO(降低高度);

假设:key(字段)数据类型为bigint占用8字节,每个节点要有两个指针,每个指针占用4字节,一个节点占用的空间为16字节;

因为在MySQL中的InnoDB存储引擎一次IO会读取一页(默认1页16K)的数据量;

若二叉树一次IO有效数据量只有16字节,空间利用率较低;

为了最大化利用一次IO空间,一个简单的想法是在每个节点存储多个元素,即在每个节点尽可能多的存储数据;

每个节点可以存储1000个索引数据(16k/16=1000),这样就将二叉树改造成了多叉树,通过增加树的分支,将树的高瘦结构变为矮胖;

一般构建100万条记录,树的高度只需2层就可以(1000*1000=100万),也就是说只需要2次磁盘IO就可以查询到数据;

磁盘IO次数变少了,查询数据的效率也就提高了;

这种方式构造的存储数据结构称为BTree,B树是一种多叉平衡查找树,如下图所示;
“`

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/索引树结构-BTree.png)

“`sh
利用数据树形结构查询数据:

假如查询值等于10的数据。查询路径磁盘块10->磁盘块20->磁盘块31。

第一次磁盘IO:将磁盘块1加载到内存中,在内存中从头遍历比较,10<15,走左路,到磁盘寻址磁盘块2。 第二次磁盘IO:将磁盘块2加载到内存中,在内存中从头遍历比较,7<10,到磁盘中寻址定位到磁盘块5。 第三次磁盘IO:将磁盘块5加载到内存中,在内存中从头遍历比较,10=10,找到10,取出data; ① 如果data存储的行记录,取出data,查询结束。 ② 如果存储的是磁盘地址,还需要根据磁盘地址到磁盘中取出数据,查询终止。 相比二叉平衡查找树,在整个查找过程中,虽然数据的比较次数并没有明显减少,但是磁盘IO次数会大大减少。 同时,由于我们的比较是在内存中进行的,比较的耗时可以忽略不计。 B树的高度一般2至3层就能满足大部分的应用场景,所以使用B树构建索引可以很好的提升查询的效率。 此种树形结构特点: - B树的节点中存储着多个元素,每个内节点有多个分叉; - 节点中的元素包含键值和数据,节点中的键值从大到小排列。也就是说所有的节点都储存数据。 - 父节点当中的元素不会出现在子节点中。 - 所有的叶子结点都位于同一层,叶节点具有相同的深度,叶节点之间没有指针连接。 看到这里一定觉得B树很理想了,但是B树不支持范围查询的快速查找; 如果想查询15-30之间的数据,查到15之后,我们还要返回根节点重新遍历查找下一个数据,直到全部遍历找到。 如果data存储的是行记录,行的大小随着列数的增多,所占空间会变大。 这时一个页中可存储的数据量就会变少,树相应就会变高,磁盘IO次数就会变大。 **对于B+tree算法的底层算法逻辑理解:** 利用Btree算法还是快速锁定100个盒子中,有代金券的盒子编号,如下图所示: - 将需要存储的数据信息,均匀分配保存到对应页当中,最终数据信息的均匀存储(落盘) - 根据页节点存储的数据信息,取出页节节点最小数据信息,并将每个叶节点最小数据信息进行汇总整合,生成相应内部节点数据; 实质上存储的是下层页节点的区间范围,以及与之对应的指针信息,最后构建出内部节点信息; - 根据内部节点存储的数据信息,取出内部节点最小数据信息,并将每个内部节点最小值信息进行汇总整合,生成相应根节点数据; 根节点只能有占用一个页区域,如果一个页区域空间不够,需要进行内部节点层次扩展,但是尽量要保证层次越少越好; 实质上存储的是下层内部节点的区域范围,以及与之对应的指针信息,最后构建出独立且唯一的根节点信息; - 整个树形结构,越向上节点存储数据的范围越大,然后依次再分发数据到下面的小范围,最终形成多叉树; 由于出现了多叉树,就表示全部数据分布在多个链表上,避免了单条链表存储数据,同时可以实现并发的访问数据 - 对于加号表示增强,其中增强表示在整个链表上,增加了同级相邻节点之间的双向指针,从而实现相邻节点相互跳转 ``` ![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/1667936870251.png) ```sh 利用数据树形结构查询数据: 假如想要查找9和26之间的数据。查找路径是磁盘块1->磁盘块2->磁盘块6->磁盘块7。

① 查找值等于9的数据,将值等于9的数据缓存到结果集。这一步和前面等值查询流程一样,发生了三次磁盘IO。

② 查找到15之后,底层的叶子节点是一个有序列表,我们从磁盘块6,键值9开始向后遍历筛选所有符合筛选条件的数据。

③ 第四次磁盘IO:根据磁盘6后继指针到磁盘中寻址定位到磁盘块7,将磁盘7加载到内存中;

​ 在内存中从头遍历比较,9<25<26,9<26<=26,将data缓存到结果集。 主键具备唯一性(后面不会有<=26的数据),不需再向后查找,查询终止。将结果集返回给用户 此种树形结构特点: - B+树的节点中可存N个key,N个key划分出N个区间,树的高度是相对矮的。 - 所有父节点都会重复出现在子节点中,从左到右依次递增 - 非叶子结点只起索引作用, 叶子结点包含信息。 - 非叶子结点可能在内存中缓存 - 所有的叶子结点都位于最后一层,叶节点之间首尾连接,所有key值都在子节点中存在,且最大为key **根据以上B+Tree的结构说明,假设现在需要查找54这个数据值信息所在的数据页:等值查询** - 根据定义查找的数值信息,首先在根节点中获取数值所在的区间范围和相应指针信息,从而找到下层对应的内部节点信息; - 根据定义查找的数据信息,其次在枝节点中获取数值所在的区域范围和相应指针信息,从而找到下层对应的叶子节点信息; - 根据定义查找的数据信息,最后在叶子节点中获取最终的数据信息,结果结合上图经历三步完成了数据查找(3*16=48kB); 在利用BTree查找数据信息时,会结合树形层次结构,来决定查询数据的步骤过程,并且理论上每个数据查找过程步骤相同; > 总结:B代表的平衡含义就是,每次查找数据消耗的IO数量是一致的,并且读取的页数量也是一致的,查找时间复杂度是一致的;

**根据以上B+Tree的结构说明,假设现在需要查找大于90这个数据值信息所在的数据页:不等值查询**

– 根据定义查找的数值信息,首先在根节点中获取首个大于指定数值的区间范围和相应指针信息,从而找到下层对应的内部节点信息;
– 根据定义查找的数据信息,其次在枝节点中获取数值所在的区域范围和相应指针信息,并且结合双向指针进行预读;
– 根据定义查找的数据信息,最后在叶子节点中获取最终的数据信息,并且结合双向指针进行预读,查询其余大于90的数值;

在利用BTree查找数据信息时,由于存在双向指针概念,可以避免重复从根查找问题,减少IO消耗,结合预读快速调取数据到内存中

> 总结:在BTree中的双向链接增强特性和预读功能,可以根据簇(64page)读取数据,可以使数据信息的范围查找变得更加方便高效

##### **02 索引模型类型二:Hash(哈希表)**

此种索引方式是一种以键-值(key-value)存储数据的结构,只要输入待查找的键即key,就可以找到其对应的值即value;

哈希索引的思路很简单,就是把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置;

不可避免地多个key值经过哈希函数的换算,会出现同一值的情况,处理方法是拉出一个链表;

假设,现在维护着一个身份证信息和姓名的表,需要根据身份证号查找对应的名字,这时对应的哈希索引的示意图如下所示:
“`

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/1692005069389.png)

“`sh
图中,User2 和 User4 根据身份证号算出来的值都是 N,但没关系,后面还跟了一个链表。

假设,这时候你要查 ID_card_n2 对应的名字是什么;

处理步骤就是:

– 首先,将 ID_card_n2 通过哈希函数算出 N;
– 然后,按顺序遍历,找到 User2。

> 需要注意:
>
> 图中四个 ID_card_n 的值并不是递增的,这样做的好处是增加新的 User 时速度会很快,只需要往后追加。
>
> 但缺点是,因为不是有序的,所以哈希索引做区间查询的速度是很慢的。

你可以设想下,如果你现在要找身份证号在[ID_card_X, ID_card_Y]这个区间的所有用户,就必须全部扫描一遍了。

所以,哈希表这种结构适用于只有等值查询的场景,比如 Memcached 及其他一些 NoSQL 引擎。

##### **03 索引模型类型三:R+Tree**

空间索引是检索空间数据集合的”目录”。它不同于图书的目录,在进行图书内容检索时,目录对应的书本内容是不变的;

而空间索引是根据空间数据的变化而变化的,包括数据的创建、修改、删除等基本操作都会重新建立新的索引;

R-tree的特点:

– 多维空间数据支持:R-tree支持多维空间数据的索引,适用于地理信息系统(GIS)等领域的应用。
– 空间查询效率高:R-tree可以快速定位和访问空间数据,提高查询效率。
– 空间数据动态更新:R-tree支持空间数据的动态更新,可以在线添加、删除和修改数据。

##### **04 索引模型类型四:FULLTEXT**

全文搜索的类型为FULLTEXT,表示在定义索引的列上支持值的全文查找,允许在这些索引列中插入重复值和空值;

全文搜索主要用来查找文本中的关键字,而不是直接与索引中的值相比较;

全文索引与其它索引大不相同,它更像是一个搜索引擎,而不是简单的WHERE语句的参数匹配。

#### 1.6.3 数据库索引应用类型

数据库服务在进行BTree索引构建时,是比较重要的知识点,因为最终还是会应用BTree算法知识进行索引的构建,常用方法有:

**索引方式一:聚簇索引(集群索引/聚集索引)**

聚簇索引主要是:将多个簇(区-64个数据页-1M)聚集在一起就构成了所谓聚簇索引,也可以称之为主键索引;

聚簇索引作用是:用来组织存储表的数据行信息的,也可以理解为数据行信息都是按照聚簇索引结构进行存储的,即按区分配空间的;

聚簇索引的存储:聚簇是多个簇,簇是多个连续数据页(64个),页是多个连续数据块(4个),块是多个连续扇区(8个);

> 总结:利用聚簇索引可以实现从物理上或逻辑上,都能满足数据存储的连续性关系,方便进行数据查找的有序性IO;(IOT组织表)

聚簇索引的构建方式:

– 数据表创建时,显示的构建了主键信息(pk),主键(pk)就是聚簇索引;
– 数据表创建时,没有显示的构建主键信息时,会将第一个不为空的UK的列做为聚簇索引;
– 数据表创建时,以上条件都不符合时,生成一个6字节的隐藏列作为聚簇索引;

结合下图信息,可以看出聚簇索引组织存储数据过程与加速查询过程原理:
“`

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/1668072355146.png)

“`sh
以上图信息为例,若显示创建ID列为pk自增列:

① 按照ID逻辑顺序,在同一个区中连续的数据页上,有序存储数据行;

② 数据行所在的数据页,作为聚簇索引的叶子节点(叶子节点就是所有数据行);

③ 叶子节点构建完后,可以构建no-left(支节点),用于保存的是leaf节点中的ID范围和指针信息;

④ 支节点构建完后,可以构建root(根节点),用于保存的是no-leaf节点中的ID范围和指针信息;

⑤ 并且leaf节点和no-leaf相邻数据页之间都具有双向指针,从而加速数据的范围查找;

**索引方式二:辅助索引**

辅助索引主要是:主要用于辅助聚簇索引查询的索引,一般按照业务查找条件,建立合理的索引信息,也可以称之为一般索引;

辅助索引作用是:主要是将需要查询的列信息可以和聚合索引信息建立有效的关联,从而使数据查询过程更高效,节省IO和CPU消耗

辅助索引的存储:调取需要建立的辅助索引列信息,并加上相应主键列的所有信息,存储在特定的数据页中;

> 总结:利用辅助索引与聚合索引建立的关联,先经过辅助索引的查询获取对应聚簇索引,在经过聚簇索引回表查询获取详细数据;

辅助索引的构建方式:

– 数据表创建时,显示的构建了一般索引信息(mul),一般索引信息(mul)就是辅助索引;

– 数据表创建时,没有显示的构建一般索引信息时,在查询检索指定数据信息,会进行全表扫描查找数据;

结合下图信息,可以看出辅助索引组织存储数据过程与加速查询过程原理:
“`

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/1668091064864.png)

“`sh
以上图信息为例,若显示创建name列为mul查询列:

① 调取需要建立的辅助索引列信息,并加上相应主键列的所有信息,存储在特定的内存区域中;

② 根据调取的辅助索引列信息,进行字符的顺序排序,便于形成范围查询的区间,并将排序后的数据信息存储在特定数据页中;

③ 叶子节点构建完后,可以构建no-left(支节点),用于保存的是leaf节点中的字符范围和指针信息;

④ 支节点构建完后,可以构建root(根节点),用于保存的是no-leaf节点中的字符范围和指针信息;

⑤ 找到相应辅助索引的数据信息后,在根据辅助索引与聚簇索引的对应关系,获取到相应的主键信息,从而获取相应其他数据信息

​ 在利用聚簇索引获取其他数据信息的过程,也可以称之为回表查询过程;

#### 1.6.4 数据库索引应用方法

##### **01 数据库索引信息创建**

索引的创建方式有多种,主要由数据库的功能决定,索引由DBA或表的拥有者负责创建和撤销;

创建索引类型一:普通索引、唯一索引和主键索引

– **普通索引:**

普通索引是MySQL中的最基础索引类型,允许对创建索引的列中插入重复值和空值;

创建普通索引的操作方法:

01 直接创建索引,语句格式如下:

​“`mysql
mysql> create index index_name on table(column(length))
​“`

02 以修改表结构的方式添加索引,语句格式如下:

​“`mysql
mysql> alter table table_name add index idx_name(column(length));
mysql> alter table table_name add index idx_name on (column(length));
​“`

03 创建表的同时创建索引,语句格式如下:

​“`mysql
mysql> create table table_name (….,index index_name(column(length))
mysql> create table author(
id char(6) not null,
name char(6) not null,
brief varchar(128),
primary key(id),index author_name(name(length))
);
​“`

– **唯一索引:**

唯一索引指索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一;

创建唯一索引的操作方法:

01 直接创建索引,语句格式如下:

​“`mysql
mysql> create unique index index_name on table(column(length)) ;
​“`

02 以修改表结构的方式添加索引,语句格式如下:

​“`mysql
mysql> ALTER TABLE `table_name` ADD UNIQUE index_name on (column(length))
​“`

03 创建表的同时创建索引,语句格式如下:

​“`mysql
mysql> create table table_name (….,unique index index_name(column(length))
mysql> create table press(
id char(6) not null,
name char(6) not null,
brief varchar(128),
primary key(id),UNIQUE index author_name(name(length))
);
​“`

– **主键索引:**

主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值;

创建主键索引的操作方法:

01 以修改表结构的方式添加索引,语句格式如下:

​“`mysql
mysql> ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` );
​“`

02 创建表的同时创建索引,语句格式如下:

​“`mysql
mysql> create table table_name (….,primary key (column));
​“`

> 说明:一般主键索引是在建表时同时创建主键索引的

单列索引创建特殊情况:前缀索引

创建前缀索引方法:

​“`sql
mysql> alter table city add index ix_n(name(10));
​“`

创建索引类型二:单列索引和组合索引

单列索引即一个索引只包含单个列,一个表可以多个单列索引;

组合索引(联合索引)是指组合表的多个字段创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用;

使用组合索引时需要遵循最左前缀匹配原则;

单列索引一般特指的就是之前说明的普通索引、唯一索引或主键索引,所以创建过程不再进行赘述;

创建联合索引的操作方法:

01 直接创建索引,语句格式如下:

​“`mysql
mysql> create index index_name on table(column01,column02);
​“`

02 以修改表结构的方式添加索引,语句格式如下:

​“`sql
mysql> alter table city add index ix_na_po(name,population);
​“`

03 创建表的同时创建索引,语句格式如下:

​“`mysql
mysql> create table table_name (….,index index_name(column01,column02));
​“`

##### **02 数据库索引信息查询**

索引信息简单查看:

​“`sql
mysql> use world;
mysql> desc city;
— 查询表结构信息,获取索引配置
​“`

索引信息的展示形式:

| 序号 | 索引标识 | 解释说明 |
| —- | ——— | ———————————— |
| 01 | PK(PRI) | 表示为聚簇索引,也可以理解为主键索引 |
| 02 | K(MUL) | 表示为辅助索引,也可以理解为一般索引 |
| 03 | UK(UNI) | 表示唯一键索引 |

参考链接博文:https://blog.csdn.net/weixin_71438279/article/details/126945736

索引信息详细查看:

​“`mysql
# 查看索引详细信息
SHOW INDEX FROM table_name [FROM db_name] [WHERE condition];
— table_name:需要查询索引的表名
— db_name:(可选)数据库名。如果你已经在某个数据库上下文中,可以省略此参数。
— condition:(可选)可以添加WHERE子句来筛选索引信息,比如根据索引名称、索引类型等进行筛选。

mysql> use world;
mysql> show index from city;
— 查询表索引信息,获取索引详细信息
​“`

命令输出列信息说明:

| 序号 | 列信息 | 解释说明 |
| —- | ———— | ———————————————————— |
| 01 | table | 表示查询索引信息对应的表名称 |
| 02 | non_unique | 表示是否允许重复值;如果值为1,表示允许重复值;如果值为0,表示不允许重复值(唯一索引) |
| 03 | key_name | 索引名称。主键索引名通常为PRIMARY。 |
| 04 | seq_in_index | 索引中的列的序号。对于组合索引,这表示列在索引中的位置。 |
| 05 | column_name | 表示索引对应表中的列名,索引涉及的列 |
| 06 | collation | 排序规则。A表示升序,D表示降序,NULL表示不可排序 |
| 07 | cardinality | 索引的基数。这是一个估算值,表示索引中唯一值的数量。这个值对于查询优化器选择索引非常重要。 |
| 08 | sub_part | 索引的前缀长度。对于部分索引,这表示索引的前缀长度。 |
| 09 | packed | 索引是否被压缩。如果索引未被压缩,该列的值为NULL。 |
| 10 | null | 列是否允许包含NULL值 |
| 11 | index_type | 索引类型。常见的类型有BTREE、HASH、FULLTEXT等。 |
| 12 | comment | 表示索引的备注信息 |

索引选择度参考链接:https://blog.csdn.net/weigeshikebi/article/details/80214965

##### **03 数据库索引信息删除**

– **单列索引信息删除方法:**

删除普通索引信息:

​“`mysql
mysql> alter table 表名 drop index 索引名;
mysql> alter table t100w drop index idx_name;
​“`

删除唯一索引信息:

​“`mysql
mysql> alter table 表名 drop index 索引名;
mysql> alter table t100w drop index id;
​“`

删除主键索引信息:

​“`mysql
mysql> alter table 表名 drop primary key;
mysql> alter table t100w drop primary key;
​“`

– **组合索引信息删除方法:**

​“`mysql
mysql> alter table 表名 drop index 索引名;
mysql> alter table t100w drop index oldboy;
​“`

#### 1.6.5 数据库索引创建原则

传统的查询方法是按照表的顺序遍历查询的,无论查询几条数据,MySQL需要从头开始遍历表,直到找到该数据;

创建索引后,MySQL一般通过BTREE算法生成一个索引文件,在查询数据库时,首先找到索引文件并遍历索引记录;

在其中找到对应的键后就可以获取对应值的数据,查询效率会提高很多;

然后,使用索引是有代价的,索引设计得不合理,或者缺少索引都会对数据库和应用程序的性能造成影响;

高效的索引对于良好性能的获取非常重要,因此,只要遵循创建索引的有效原则建立索引,才能真正达到事半功倍的效果;

**01 创建索引要有专人完成**

– 索引由DBA或表的拥有者负责创建和撤销,其他用户不能随意操作;
– 索引由系统自动选择,或由用户打开,用户可执行重建索引操作;

**02 是否创建索引取决于表的数据量**

– 基本表中的记录的数据量越多,记录越长,越有必要创建索引。创建索引后,查询速度的提升效果会很明显;

要避免对经常更新的表创建过多的索引,索引中的列也要尽可能少;

– 数据量小的表最好不要使用索引,由于数据较少,查询花费的时间可能比遍历索引的时间还要短,创建索引可能不会产生优化效果

对经常用于查询的字段应该创建索引,但要避免添加不必要的字段;

– 索引要根据数据查询或数据处理的要求确定是否创建,对于查询频率高,实时性要求高的数据一定要建立索引

**03 索引数据量要适度**

– 索引文件占用文件目录和存储空间,因此索引过多会加重系统负担;

– 索引需要自身维护,当基本表的数据增加、删除或修改时,索引也会进行调整和更新,索引文件也要随之变化,以保持与基本表一致;

– 索引过多会影响数据增、删、改的速度;

索引并非越多越好,一张表中如果有大量的索引,不仅占用磁盘空间,而且还会影响insert、delete、update等操作的性能;

**04 避免使用索引的情况**

– 包含太多重复值的字段;
– 查询中很少被引用的字段;
– 值特别长的字段;
– 查询返回率很高的字段;
– 具有很多NULL值的字段;
– 需要经常增、删、改的字段;
– 记录较少的表;
– 需要频繁、大批量进行数据更新的基本表;

**辅助索引检索数据产生回表问题分析:**(回表次数越少越高)

产生问题:

① 在回表过程中,有可能会出现多次的回表,从而造成磁盘IOPS的升高;(因为是随机IO操作过程)

② 在回表过程中,有可能会出现多次的回表,从而造成磁盘IO量的增加;

解决方法:

① 可以建立联合索引,调整查询条件,使辅助索引过滤出更精细主键ID信息,从而减少回表查询的次数;

② 可以控制查询信息,实现覆盖索引,辅助索引完全覆盖查询结果;

③ 优化器算法做调整???(MRR-多路读功能 ICP-索引下推功能 )

**构建索引树高度问题分析:**(索引树高度越低越好)

影响索引树高度因素:

① 数据行数量会对高度产生影响;(3层BTREE — 可以实现一般2000万行数据索引的存储-20~30列表)

​ 解决方法:可以拆分表 拆分库 或者实现分布式存储;

② 索引字段长度过大会对高度产生影响;

​ 解决方法:利用前缀索引解决问题

③ 数据类型设定会对高度产生影响;

​ 解决方法:列定义时,选择简短合适的数据类型;

#### 1.6.6 数据库索引应用压测

在进行索引操作之前,可以进行一个压力测试,将一个100W数据量的数据库备份数据进行备份恢复:

​“`tiki wiki
# 进行测试数据恢复操作:
mysql> source ~/t100w_oldboy.sql

# 进行数据库程序服务压测:
mysqlslap –defaults-file=/etc/my.cnf –concurrency=100 –iterations=1 –create-schema=’oldboy’ –query=”select * from oldboy.t100w where k2=’VWlm'” engine=innodb –number-of-queries=2000 -uroot -p123456 -h192.168.30.101 -verbose
— concurrency=100 模拟同时100会话连接;
— iterations=1 测试执行的迭代次数,代表要在不同并发环境下,各自运行测试多少次
— create-schema=’test’ 指定操作的数据库信息;
— query=”select * from test.100w where k2=’780P'” 指定压测过程具体执行了什么语句操作
— number-of-queries=2000 指定一共做了多少次查询,总的测试查询次数(并发客户数×每客户查询次数)
​“`

数据库压力测试结果情况:

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-07章-数据库索引知识介绍/课件配图资料/1668098473569.png)

进行索引建立优化:

​“`sql
mysql> alter table oldboy.t100w add index idx_k2(k2);
​“`

在进行压测检查确认:

“`

## 2 索引总结

“`sh
01 数据库服务索引知识

– 数据索引功能作用
– 数据索引算法结构
– 数据索引构建方式(聚簇索引-主键索引 辅助索引-普通索引 唯一索引 前缀索引 联合索引)
– 数据索引管理方式(创建索引 查看索引 删除索引)
– 数据索引应用测试(压力测试)
02 数据库服务执行计划
– 数据库执行计划概述
– 数据库执行计划查看
– 数据库索引应用类型(慢查询语句)

数据库服务处理SQL语句流程:
步骤一:需要确认客户端可以访问服务端
步骤二:在数据库服务层进行SQL语句处理

– 连接器:管理连接 权限验证

– 分析器:词法分析 语法分析

– 优化器:执行计划生成 索引选择

– 执行器:控制引擎 获取执行结果
步骤三:在数据库服务引擎层调取或存储数据

– 存储结构层次 (段 区-1M 页-16KB)

– 磁盘建立关联 (1页-4block-32扇区 – 顺序IO存储)

– 内存建立关联 (数据页加载数据 1个数据页-16KB-IO)

01 数据库服务索引知识

– 数据索引功能作用
1)利用索引可以加快数据查询效率(select update delete insert)
2)利用索引可以锁定调取数据范围

– 数据索引算法结构
早期:遍历算法 每个表的每个数据页都去查看 和指定条件信息最比较
select * from oldboy.t1 where id=10000
第一行数据调取 id-01 name age
第二行数据调取 id-02 name age
第三行数据调取
第十行数据调取 id-10 name age — 数据信息返回给server层 — 客户端
改进:二叉树算法 (红黑 均衡树)
可以减少一部分数据调取过程,提高查询效率
二叉树结构如果出现链式结构,查询效率也会降低
二叉树查询数据信息时,无法做到均衡查询的效率
目前:B+Tree结构 (B-Tree B+Tree) ***** 结构特点(根 支 页 — 锁定查询数据区域 查询数据消耗资源更均衡 因为有底层数据页横向适合范围查询)
具体查询数据的树形结构
优化二叉树层次结构,可以控制数的结构在3-4层即可
使查询数据时间成本和资源消耗成本更加均衡 (数据信息都存储在底层页节点)
由于B+Tree结构具有横向指针,也更适合于范围查询数据
https://blog.51cto.com/u_16213559/11217209

– 数据索引构建方式
聚簇索引结构 (利用主键列信息 构建根节点 支节点 叶节点-索引列+数据列)
聚簇索引的构建方式:
– 数据表创建时,显示的构建了主键信息(pk),主键(pk)就是聚簇索引;
– 数据表创建时,没有显示的构建主键信息时,会将第一个不为空的UK的列做为聚簇索引;
– 数据表创建时,以上条件都不符合时,生成一个6字节的隐藏列作为聚簇索引;

① 按照ID逻辑顺序,在同一个区中连续的数据页上,有序存储数据行;
② 数据行所在的数据页,作为聚簇索引的叶子节点(叶子节点就是所有数据行);
③ 叶子节点构建完后,可以构建no-left(支节点),用于保存的是leaf节点中的ID范围和指针信息;
④ 支节点构建完后,可以构建root(根节点),用于保存的是no-leaf节点中的ID范围和指针信息;
⑤ 并且leaf节点和no-leaf相邻数据页之间都具有双向指针,从而加速数据的范围查找;

辅助索引结构 (利用指定索引列信息 构建根节点 支节点 叶节点-主键列+辅助索引列)
辅助索引的构建方式:

– 数据表创建时,显示的构建了一般索引信息(mul),一般索引信息(mul)就是辅助索引;
– 数据表创建时,没有显示的构建一般索引信息时,在查询检索指定数据信息,会进行全表扫描查找数据;

① 调取需要建立的辅助索引列信息,并加上相应主键列的所有信息,存储在特定的内存区域中;
② 根据调取的辅助索引列信息,进行字符的顺序排序,便于形成范围查询的区间,并将排序后的数据信息存储在特定数据页中;
③ 叶子节点构建完后,可以构建no-left(支节点),用于保存的是leaf节点中的字符范围和指针信息;
④ 支节点构建完后,可以构建root(根节点),用于保存的是no-leaf节点中的字符范围和指针信息;
⑤ 找到相应辅助索引的数据信息后,在根据辅助索引与聚簇索引的对应关系,获取到相应的主键信息,从而获取相应其他数据信息
在利用聚簇索引获取其他数据信息的过程,也可以称之为【回表查询过程】;

– 数据索引管理方式
创建索引信息:
1)主键索引 (聚簇索引–调取数据)
— 创建表时创建
create table table_name (….,primary key (column));
create table xiaoA01 (id int,name char(10),age tinyint,gender char(1),primary key(id));
— 创建表后创建
ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` );
alter table xiaoA02 add primary key (id);

2)普通索引 (辅助索引–根据指定列查询数据)
— 创建表时创建
create table table_name (….,index index_name(column));
create table xiaoB01 (id int,name char(10),age tinyint,gender char(1),index idx_name(name));
— 创建表后创建
alter table table_name add index idx_name(column);
alter table xiaoB02 add index idx_name(name);

3)唯一索引 (辅助索引–索引列数据必须唯一,可以为空 保证/限制回表次数)
— 创建表时创建
create table table_name (….,unique index index_name(column))
create table xiaoC01 (id int,name char(10),age tinyint,gender char(1),unique index uidx_name(name));
— 创建表后创建
ALTER TABLE `table_name` ADD UNIQUE index index_name on (column)
alter table xiaoC02 add unique index uidx_name(name);

4)联合索引 (辅助索引–可以将多个列进行索引创建 减少回表次数)
— 创建表时创建
create table table_name (….,index index_name(column01,column02,..));
create table xiaoD01 (id int,name char(10),age tinyint,gender char(1),index idx_na_ag(name,age));
— 创建表后创建
alter table table_name add index idx_name(column01,column02,..);
alter table xiaoD02 add index idx_na_ag(name,age);

5)前缀索引 (辅助索引–可以截取数据列部分信息存储在索引数据页中 可以有效控制索引树高度)
— 创建表时创建
create table table_name (….,index index_name(column(length))
create table xiaoE01 (id int,name char(10),age tinyint,gender char(1),index idx_na(name(5)));
— 创建表后创建
ALTER TABLE `table_name` ADD index index_name (column(length))
ALTER TABLE xiaoE02 ADD index idx_na(name(5)))
“`

# 第十一章 服务执行计划

“`sh
#### 1.8.1 数据库执行计划概念

在介绍数据库服务程序运行逻辑时,在SQL层处理SQL语句时,会根据解析器生成解析树(多种处理方案);

然后在利用优化器生成最终的执行计划,然后在根据最优的执行计划进行执行SQL语句;

作为管理员,可以在某个语句执行前,将语句对应的执行计划提取出来进行分析,便可大体判断语句的执行行为,从而了解执行效果;

SQL语句只是告诉了数据库要做什么,并没有告诉数据库如何做,查看SQL语句的执行计划可以使SQL的执行过程从黑盒变白盒;

`可以简单理解:执行计划就是最优的一种执行SQL语句的方案,表示相应SQL语句是如何完成的数据查询与过滤,以及获取;`

#### 1.8.2 数据库执行计划获取

可以利用命令进行获取执行计划信息:explain/desc

​“`SQL
explain select * from oldboy.t100w where k2=’VWlm’;
或者
desc select * from oldboy.t100w where k2=’VWlm’;
​“`

命令执行输出信息:

“`

![](D:/学习//4_数据库/视频和笔记/系统运维95期-Day13-数据库服务存储引擎/课程笔记目录/MySQL中级数据库课程-08章-数据库服务执行计划/课件配图资料/1668100222339.png)

输出信息解释说明:

| 序号 | 字段 | 解释说明 |
| —- | ————— | ———————————————————— |
| 01列 | ID | 表示语句执行顺序,单表查询就是一行执行计划,多表查询就会多行执行计划;
显示表或子查询属于查询的哪一个部分 |
| 02列 | select_type | 表示语句查询类型,sipmle表示简单(普通)查询
primary表示嵌套查询最外层的查询块,subquery代表select语句的子查询块 |
| 03列 | `table` | 表示语句针对的表,单表查询就是一张表,多表查询显示多张表; |
| 04列 | partitions | 表示匹配的分区信息 |
| 05列 | `type***` | 表示索引应用类型,通过类型可以判断有没有用索引,其次判断有没有更好的使用索引 |
| 06列 | `possible_keys` | 表示可能使用到的索引信息,因为列信息是可以属于多个索引的,如果为null表示不考虑使用索引 |
| 07列 | `key` | 表示确认使用到的索引信息,如果为null表示不使用索引 |
| 08列 | `key_len***` | 表示索引覆盖长度,对联合索引是否都应用做判断 |
| 09列 | ref | 表示当使用索引列等值查询时,与索引列进行等值匹配的对象信息 |
| 10列 | `rows` | 表示查询扫描的数据行数(尽量越少越好),尽量和结果集行数匹配,从而使查询代价降低
估算的找到所需记录所需要读取的行数 |
| 11列 | fltered | 表示查询的匹配度,返回结果的行占需要读到行(rows字段)的百分比 |
| 12列 | Extra | 表示额外的情况或额外的信息,其他字段中不包含的额外说明都放在该字段 |

特殊说明:

实际工作中,如果发现一个正在执行的SQL语句耗时长,若想查询它的执行计划,通常的做法是使用explain生成该SQL语句执行计划;

但因为统计信息等原因,生成的执行计划和正在执行的执行计划可能不完全相同,更好的做法是使用explain for connection

查询当前正在使用的执行计划

例如:如下的SQL语句查询出了当前会话号:

“`mysql
mysql> select connection_id();
“`

在当前会话中执行一个慢SQL语句,如下所示;

“`mysql
mysql> select sleep(60),* from oldboy.t100w where k2=’VWlm’;
“`

根据会话号在其他会话里查询正在执行的SQL语句的执行计划;

“`mysql
mysql> explain for connection xx\G
“`

#### 1.8.3 数据库索引应用类型

利用类型信息,来判断确认索引的扫描方式,常见的索引扫描方式类型:

| 序号 | 类型 | 解释说明 |
| —- | —————— | ———————————————————— |
| 01 | ALL – ok | 表示全表扫描方式,没用利用索引扫描类型; |
| 02 | index | 表示全索引扫描方式,需要将索引树全部遍历,才能获取查询的信息(主键index=全表扫描) |
| 03 | range | 表示范围索引方式,按照索引的区域范围扫描数据,获取查询的数据信息; |
| 04 | ref | 表示辅助索引等值(常量)查询,精准定义辅助索引的查询条件 |
| 05 | eq_ref | 表示多表连接查询时,被驱动表的连接条件是主键或者唯一键时,获取的数据信息过程; |
| 06 | const(constants) | 表示主键或者唯一键等值(常量)查询,精准定义索引的查询条件 |
| 07 | system | 这是最高级别的访问类型,表示 MySQL只有一行数据,这行数据是从系统表中读取的。 |

# 第十二章 数据库服务引擎

## 1 概念

“`sh
存储引擎就是数据库服务中的文件系统,用户可以根据应用的需要选择如何存储和索引数据,是否使用事务等;

存储引擎作用:(磁盘管理器 — 引擎)

1)可以利用数据库存储引擎,去管理磁盘调取或存储数据;

2)可以将磁盘调取数据和内存进行交互,可以将内存中修改或添加的数据存储到磁盘中
“`

## 2 引擎种类

“`sh
#### 数据库存储引擎种类

在各种版本的数据库服务中,是有多种存储引擎可以应用的,以MySQL数据库服务为例,可以使用命令查看可以应用存储引擎:

​“`sql
mysql> show engines;
​“`

引擎类型信息输出:
db02 [(none)]>show engines;
+——————–+———+—————————————————————-+————–+——+————+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+——————–+———+—————————————————————-+————–+——+————+
| ndbcluster | NO | Clustered, fault-tolerant tables | NULL | NULL | NULL |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| ndbinfo | NO | MySQL Cluster system information storage engine | NULL | NULL | NULL |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
+——————–+———+—————————————————————-+————–+——+————+

在实际场景中,99.9%都是使用innodb存储引擎,并且在最新版8.0数据库中,所有mysql数据库中的表对应的引擎也都改为了innodb;

**如果在面试环节中,面试官询问你:**

– 列举出mysql中支持的存储引擎种类:InnoDB、MyISAM、CSV、MEMORY;

– 列举出mysql分支产品的存储引擎种类:在percone、mariadb数据库中,可能还会应用TokuDB MyRocks Rocksdb存储引擎

从特点上可以支持innodb引擎的特性(支持事务),并且数据压缩比比较高(15倍),数据插入性能比较强(5~6倍);

以上存储引擎就比较适合于zabbix监控类的平台,归档数据、历史数据存储业务等,数据量级比较大的情况;

监控服务部署tokuDB存储引擎参考链接:https://www.cnblogs.com/oldboy-heqing/articles/16891210.html

#### 1.11.3 数据库存储引擎特性

在数据库服务领域,大部分场景下都会使用innodb存储引擎,是因为innodb存储引擎具有一定优秀特性:

| 序号 | 特性 | 解释说明 |
| —- | ———— | ———————————————————- |
| 01 | 数据访问特性 | 支持多版本并发控制特性(MVCC),支持行级锁控制并发 |
| 02 | 数据索引特性 | 支持聚簇索引/辅助索引特性,可以组织存储数据和优化查询(IOT) |
| 03 | 数据事务特性 | 支持事务概念特性,可以实现数据的安全保证 |
| 04 | 数据缓冲特性 | 支持多缓冲区功能,自适应hash索引(AHI) |
| 05 | 数据迁移特性 | 支持复制数据中的高级功能特性,支持数据备份恢复的热备 |
| 06 | 服务自愈特性 | 支持自动故障恢复(CR-Crash Recovery) |
| 07 | 数据存储特性 | 支持数据双写机制(Double write) 数据存储有关的安全机制 |

**如果在面试环节中,面试官询问你:**

– InnoDB核心特性有哪些,以及与MyISAM存储引擎之间的区别:

InnoBD支持:事务、mvcc、聚簇索引、外键、缓冲区、AHI、DW;MyISAM均不支持

InnoDB支持:行级锁,MyISAM只支持表级锁;

InnoDB支持:数据热备,可以保证业务正常运行,对业务影响低,MyISAM只支持温备份,需要锁表备份;

InnoDB支持:支持CR自动故障恢复,宕机自动恢复,数据安全和一致性可以得到保证;MyISAM不支持,宕机可能丢失当前数据;

**企业实际场景案例分析说明:**

案例说明01:某期学员负责运维+MySQL相关工作;

平台环境:zabbix 3.2 + centos 7.3 + mariadb 5.5(InnoDB引擎),利用监控平台,监控了2000多个节点服务;

问题现象:每隔一段时间zabbix服务就会运行操作很卡,每隔3-4个月,都要重新部署zabbix,存储空间经常爆满(ibdata1 400~500G);ibdate1 ibdata1-01

异常分析:

– zabbix版本过低,建议将zabbix程序进行升级更新;
– zabbix使用的数据版本过低,建议将数据库版本进行升级,因为新版本数据库的原生态环境就比旧版本好些;
– 在数据库5.5版本中,在没有做数据存储调配时,数据库所有数据都会保存到ibdata1文件中;
– 在ibdata1文件中的数据空间,不会因为数据库中的数据删除,产生数据回缩的效果,即空间不释放;

优化建议:

– 数据库版本升级到percona 5.7+(mariadb 10.x+),zabbix软件升级更高版本;
– 数据库服务存储引擎改为tokudb;
– 监控数据最好按月份进行数据切割(二次开发zabbix程序,数据保留机制功能重写,并且数据库分表存储)
– 将数据库服务的binlog功能关闭(双1);
– 数据库服务相关内存优化参数调整;

优化思路:

– zabbix程序原生态支持TokuDB,经过压力测试,5.7要比5.5数据库版本性能高出 2~3倍;
– 使用TokuDB作为数据库存储引擎,insert数据比innodb要快的多,数据压缩比也要比Innodb高;
– 监控数据按月份进行切割(分区),为了能够truncate每个分区表,以便立即释放存储空间;
– 将数据库服务binlog关闭,是为了减少无关日志的记录,避免磁盘IO的消耗,以及节省磁盘空间的使用;
– 参数优化调整,主要是对安全性参数或内存相关参数调整,提高数据库服务运行性能;

企业案例资料参考:

https://mariadb.com/kb/en/installing-tokudb

https://docs.percona.com/percona-server/5.7/tokudb/tokudb_intro.html

https://www.percona.com/doc/percona-server/5.7/tokudb/tokudb_installation.html

案例说明02:企业客户实际数据库需求

平台环境:centos 5.8+mysql 5.0版本,MyISAM存储引擎+网站架构LNMP,数据量50G左右

问题现象:业务并发压力大的时候,整体网站访问非常卡,还会出现数据库服务宕机情况,造成部分数据丢失

问题分析:

– MyISAM存储引擎具有表级锁,在高并发访问时,会频繁出现锁等待情况;
– MyISAM存储引擎不支持事务机制,在断电或宕机时,会有可能丢失数据信息;

优化建议:

– 数据库服务版本进行升级,从5.0升级到更高的版本;ok
– 数据库服务升级后,迁移所有表数据到新环境(表空间迁移),调整存储引擎为InnoDB;
– 数据库服务开启双1安全参数;
– 数据库服务进行重构主从架构
“`

## 3 存储引擎应用

“`sh
##### 01 引擎基本操作说明:

**数据库存储引擎信息查看:**

​“`tiki wiki
# 查看数据库可用存储引擎
mysql> show engines;

# 查看数据库默认存储引擎
mysql> select @@default_storage_engine;
+———————————-+
| @@default_storage_engine |
+———————————-+
| InnoDB |
+———————————-+
1 row in set (0.00 sec)
​“`

**数据库存储引擎配置修改:**

​“`tiki wiki
# 永久修改存储引擎配置
[root@xiaoQ-01 ~]# vim /etc/my.cnf
default_storage_engine=InnoDB
— 重启数据库服务生效
​“`

**数据表存储引擎信息查看:(具体表的存储引擎)**

​“`tiki wiki
# 查看建表语句获取存储引擎信息
mysql > show create table city;

# 查看information_schema数据库获取存储引擎信息
mysql > select table_schema,table_name,engine from information_schema.tables where table_schema not in(‘sys’,’mysql’,’information_schema’,’performance_schema’)
​“`

**数据表存储引擎配置修改:(具体表的存储引擎)**

​“`tiki wiki
# 创建表时设置存储引擎
mysql > create table xxx (id int) engine=innodb charset=utf8mb4;

# 修改表示设置存储引擎
mysql > alter table world.xxx engine=myisam;
mysql > alter table world.xxx engine=innodb;
​“`

#### 1.11.5 数据库存储引擎结构

对于InnoDB存储引擎来说,数据时存储在磁盘上,而执行引擎想要操作数据,必须先将磁盘的数据加载到内存中才能操作;

当数据从磁盘中取出后,缓存内存中,下次查询同样的数据的时候,直接从内存中读取,这样大大提高了查询性能;

数据库服务存储引擎结构的介绍,可以依据官方图示参考说明:

https://dev.mysql.com/doc/refman/8.0/en/innodb-architecture.html

结合官方存储引擎结构图,可以看出存储引擎结构分为两个部分:

内存部分 / 磁盘部分(表空间数据 日志文件数据)

##### **01 On-Disk Structures(磁盘结构部分)**

在磁盘存储结构中,会使用表空间模式进行数据信息的管理,经常提到的段 区 页概念也是属于表空间的逻辑结构;

表空间用来存储表结构和数据,表空间可以分为系统表空间、独立表空间、通用表空间、临时表空间等多种类型;

表空间的概念源于oracle数据库,最初的目的是为了能够更好的做存储的扩容;因此数据库的表空间技术类似磁盘管理的LVM技术;

InnoDB Data Dictionary:数据字典

InnoDB数据字典由内部系统表组成,这些表包含用于查找表、索引和表字段等对象的元数据。

在数据库服务中所使用的表空间也被划分出几种种类:

**类型一:共享(系统)表空间**

属于数据库服务5.5版本时默认的表空间应用,具体数据存储数据方式为:ibdata1~ibdataN

ibdata共享表空间在各个版本之间的作用区别:

| 数据库版本 | 存储数据 | 解释说明 |
| ————- | ———— | ———————————————————— |
| MySQL 5.5版本 | 系统相关数据 | 全局数据字典信息(表基本结构信息、状态系统参数、属性)、undo回滚日志(记录撤销操作);
Double write buffer信息、临时表信息、changer buffer |
| | 用户相关数据 | 业务表数据行、表的索引数据均统一存储在ibdata1中,实现集中管理
数据表中数据清理后,ibdata1也不会释放磁盘空间 |
| MySQL 5.6版本 | 系统相关数据 | 全局数据字典信息(表基本结构信息、状态系统参数、属性)、undo回滚日志(记录撤销操作);
Double write buffer信息、临时表信息、changer buffer |
| | 用户相关数据 | `共享表空间只存储系统数据,用户相关数据被独立管理了(独立表空间管理)` |
| MySQL 5.7版本 | 系统相关数据 | 全局数据字典信息 undo回滚日志 Double write buffer信息、changer buffer
`临时表信息被独立出来了,undo也可以设定为独立` |
| | 用户相关数据 | 共享表空间只存储系统数据,用户相关数据被独立管理了(独立表空间管理) |
| MySQL 8.0.11 | 系统相关数据 | Double write buffer信息、changer buffer
`undo回滚日志信息被独立出来了,数据字典信息也不再集中存储管理了` |
| | 用户相关数据 | 共享表空间只存储系统数据,用户相关数据被独立管理了(独立表空间管理) |
| MySQL 8.0.20 | 系统相关数据 | changer buffer
`Double write buffer信息被独立出来了` |

**共享表空间管理:**

– 扩容共享表空间操作:

扩容前共享表空间信息查看:

​“`SQL
mysql> select @@innodb_data_file_path;
+————————————-+
| @@innodb_data_file_path |
+————————————-+
| ibdata1:12M:autoextend |
+————————————-+
1 row in set (0.00 sec)
— 可以在初始安装好数据库服务后,进行修改配置为两个ibdate文件,每个共享表空间文件占用2G,总共占用4个G空间

mysql> select @@innodb_autoextend_increment;
+———————————————+
| @@innodb_autoextend_increment |
+———————————————+
| 64 |
+———————————————+
1 row in set (0.00 sec)
— 查看参数信息说明:ibdata1文件,默认初始大小12M,不够用会自动扩展,默认每次扩展64M
​“`

共享表空间的扩容操作方法:

​“`tiki wiki
# 编写数据库配置文件信息
vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:12M;ibdata2:100M;ibdata3:100M:autoextend
— 需要注意的是ibdata1文件大小必须和实际数据库要存储的数据相匹配,否则会出现如下报错信息
[ERROR] [MY-012264] [InnoDB] The innodb_system data file ‘./ibdata1’ is of a different size 768 pages (rounded down to MB) than the 4864 pages specified in the .cnf file!
— 表示ibdate1指定大小超过了原有ibdata1实际的大小尺寸

# 查看配置信息是否生效
mysql> select @@innodb_data_file_path;
+———————————————————————+
| @@innodb_data_file_path |
+———————————————————————+
| ibdata1:12M;ibdata2:100M;ibdata3:100M:autoextend |
+———————————————————————+
1 row in set (0.00 sec)
​“`

数据库初始化时设置共享表空间容量建议:

| 序号 | 版本信息 | 建议说明 |
| —- | ——— | ———————————————————— |
| 01 | MySQL 5.7 | 设置共享表空间2~3个,大小建议512M或1G,最后一个定制为自动扩展 |
| 02 | MySQL 8.0 | 设置共享表空间1个即可,大小建议512M或1G |

共享表空间的初始设置方法:

​“`tiki wiki
# 模拟初始化清理数据
[root@xiaoQ-01 ~]# /etc/init.d/mysqld stop
[root@xiaoQ-01 ~]# rm -rf /data/3306/data/*

# 模拟初始化配置文件
[root@xiaoQ-01 ~]# vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:100M;ibdata2:100M;ibdata3:100M:autoextend

# 模拟初始化操作命令
[root@xiaoQ-01 ~]# mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data

# 模拟初始化重启服务
[root@xiaoQ-01 ~]# /etc/init.d/mysqld start
​“`

**类型二:独立表空间**

在数据库服务5.6版本中,针对用户数据,可以进行单独的存储管理,存储表的数据行和索引等相关信息;

**独立表空间在各个版本之间的作用区别:**

– 在数据库服务8.0版本前

用户表包含三个部分组成(表.ibd 表.frm ibdata1-全局数据字典信息存储);

所以在8.0之前,如果想修改表数据结构信息(元数据修改),都会修改frm和ibdata文件信息,每次更新都会锁表(元数据锁);

因为要保证数据一致性,并且两个表均更新完,才能释放解锁,因此在8.0前修改元数据信息,要避开业务繁忙时间段;

– 在数据库服务8.0版本后

用户表数据进行统一存储(表.ibd); 如果想修改表数据结构信息(元数据修改),只会修改ibd文件信息;

此时不需要对两个表文件均更新,只要更新一个文件即可,因此对文件锁的代价降低了,降低了对业务的影响;

**独立表空间管理:**

– 表空间配置参数信息查看

​“`tiki wiki
mysql > select @@innodb_file_per_table;
+———————————+
| @@innodb_file_per_table |
+———————————+
| 1 |
+———————————+
1 row in set (0.00 sec)
— 表示每个表就是一个独立文件,进行数据信息的独立存储,不建议进行修改,如果改为0就是所有数据统一存储在共享表空间

[root@xiaoQ-01 ~]# ibd2sdi city.ibd
— 可以看到文件中存储的元数据信息(数据字典信息),并且数据库8.0之后不再有表对应的frm文件信息了
— 在数据库5.7环境中,每个表数据信息会存储生成两个表 frm ibd
— frm文件中存储数据表的数据字典信息(元数据信息)
— ibd文件中存储数据行信息和索引信息
​“`

– 表空间配置参数信息修改

​“`tiki wiki
mysql > set global innodb_file_per_table=0
— 设置为0表示利用共享表空间存储用户数据 1表示利用独立表空间存储用户数据
​“`

**表空间企业应用案例:** 数据库服务宕机 — 重新部署数据库 —

案例01:利用独立表空间进行快速数据迁移(源端 3306/test/t100w –> 目标端 3307/test/t100w)

说明:可以在需要某个表中的数据信息时,可以将数据表的独立表空间数据信息做迁移,在另一个数据库中进行恢复即可

**操作步骤一:锁定源端t100w表**

​“`tiki wiki
mysql > lock tables oldboy.t100w write;
— 给t100w表加写数据锁
mysql > show create table oldboy.t100w;
CREATE TABLE `t100w` (
`id` int DEFAULT NULL,
`num` int DEFAULT NULL,
`k1` char(2) DEFAULT NULL,
`k2` char(4) DEFAULT NULL,
`dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY `idx` (`k1`,`k2`,`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
— 获取创建表结构数据信息
​“`

**操作步骤二:目标端创建oldboy库和t100w空表**

​“`tiki wiki
mysql> create database oldboy;
— 创建新的数据库
mysql > CREATE TABLE `t100w` (
`id` int DEFAULT NULL,
`num` int DEFAULT NULL,
`k1` char(2) DEFAULT NULL,
`k2` char(4) DEFAULT NULL,
`dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY `idx` (`k1`,`k2`,`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
— 创建新的数据表
​“`

**操作步骤三:单独删除空的表空间文件**

​“`tiki wiki
mysql> alter table oldboy.t100w discard tablespace;
— 删除t100w表的ibd数据文件信息,但是保留t100w的frm,ibdata1中关于t100w的系统数据
​“`

**操作步骤四:拷贝源端ibd文件到目标端目录,并设置权限**

​“`tiki wiki
[root@xiaoQ-01 ~]# cp /data/3306/data/oldboy/t100w.ibd /data/3307/data/oldboy/
[root@xiaoQ-01 ~]# chown -R mysql.mysql /data/*
​“`

**操作步骤五:导入表空间**

​“`tiki wiki
mysql> alter table oldboy.t100w import tablespace;
— 在目标端加载识别迁移过来的数据文件信息
mysql> select count(*) from t100w;
+———-+
| count(*) |
+———-+
| 1000000 |
+———-+
1 row in set (0.04 sec)
— 查看数据表中是否有迁移古来的数据信息
​“`

**操作步骤六:解锁源端数据表**

​“`tiki wiki
mysql> unlock tables;
​“`

案例02:利用表空间迁移功能实现数据损坏恢复

说明:操作系统突然断电了,启动完成后 / 变为只读了,fsck修复文件系统,系统再次重新启动后,mysql启动不了了

结果:造成confulence库在、jira库不见了(备份没有 日志也没开)

服务:jira(bug追踪)、confluence(内部知识库) 、mysql 5.6.33(innodb引擎 使用独立表空间) — LNMT架构

硬件:联想服务器(8核 16G内存 500G存储空间 没有raid),centos 6.8系统

========================================================================================

对话描述:

学生:这种情况怎么恢复?

老师:有备份吗?

学生:连二进制日志都没有,没有备份,没有主从

老师:jira数据库数据没什么办法了,只能进行硬盘数据恢复了

学生:jira数据库数据先不用关注,数据磁盘已经拉到中关村处理了

​ 主要是confulence库还想使用,但将生成中的库目录,导入到其他主机上(var/lib/mysql),无法直接访问数据库中数据?

​ 老师有没有工具能直接读取数据库目录中的ibd文件内容

老师:我查查,最后发现没有

​ 我们可以尝试下独立表空间迁移

​ create table xx

​ alter table coufulence.t1 discard tablespace;

​ alter table coufulence.t1 import tablespace;

​ 虚拟环境测试可行

问题:confulence库中总共有107张表

困惑:如何创建107张和原来一模一样的表

解决:学生环境中有2016年的历史库,让学生利用mysqldump命令备份confulence历史库

​ mysqldump -uroot -ppassw0rd -B confulence –no-date > test.sql 只获取所有表结构信息

​ 如果是自研数据库,没有备份怎么办

​ mysql工具包中,拥有mysqlfrm工具也可以读取frm文件获取表结构

========================================================================================

**操作步骤一:备份历史数据库的所有表结构信息,并进行恢复**

​“`tiki wiki
[root@xiaoQ-01 ~]# mysqldump -uroot -ppassw0rd -B confulence –no-date > test.sql
mysql > create database confulence
mysql > source test.sql

# 如果没有提前没有进行数据表的结构备份,也可以通过读取表结构文件信息,获取数据表结构
mysqlfrm –diagnostic gis.frm >gis.txt
— MySQL 5.7利用frm文件获取表结构信息
— mysqlfrm工具命令没有需要进行下载安装:https://downloads.mysql.com/archives/utilities/

ibd2sdi –dump-file name.txt name.ibd
— MySQL 8.0利用ibd文件获取表结构信息
​“`

> 说明:原ibd文件时的数据库版本要和当前数据库版本一致(如8.0.11和8.0.23版本不同会导致复原失败)

根据ibd文件解析的json信息,可以根据以下代码获取创建表语句:

​“`php
request->param();
// 替换为你的 JSON 数据
$filename = “city.txt”;
$jsonData = file_get_contents($filename);
// 解析 JSON 数据
$data = json_decode($jsonData, true);
// 提取表名和字段信息
$tableName = $data[1][‘object’][‘dd_object’][‘name’];
$columns = $data[1][‘object’][‘dd_object’][‘columns’];
// 构建创建表的 SQL 查询语句
$sql = “CREATE TABLE $tableName (“;

foreach ($columns as $column) {
$columnName = $column[‘name’];
// 如果字段名不是 DB_TRX_ID 和 DB_ROLL_PTR,则构建该字段的 SQL
if ($columnName !== ‘DB_TRX_ID’ && $columnName !== ‘DB_ROLL_PTR’ && $columnName !== ‘DB_ROW_ID’) {
$columnType = $column[‘column_type_utf8’];
$isNullable = $column[‘is_nullable’] ? ‘NULL’ : ‘NOT NULL’;
$default = ($column[‘default_value_null’] || $column[‘default_value_utf8_null’]) ? ” : “DEFAULT ‘{$column[‘default_value’]}'”;

// 构建列的注释,如果注释为空,不包含 COMMENT 部分
$comment = isset($column[‘comment’]) && !empty($column[‘comment’]) ? “COMMENT ‘{$column[‘comment’]}'” : ”;

// 构建列的 SQL
$sql .= “$columnName $columnType $isNullable $default $comment, “;
}
}
// 去除最后的逗号和空格
$sql = rtrim($sql, ‘, ‘) . “);”;
echo $sql;
}
test()
?>
​“`

**操作步骤二:删除空表的独立表空间**

​“`sql
select concat(“alter table “,table_schema,”.”,table_name,” discard tablespace;”) from information_schema.tables where table_schema=’confulence’; into outfile ‘/tmp/discard.sql’;
source /tmp/discard.sql
​“`

实际执行过程发现,有20-30张表无法成功,主外键关系问题,如果一个表一个表分析表结构,处理外键关系很痛苦

​“`sql
set foreign_key_checks=0
— 跳过外键检查,从而把有问题的20-30张表的独立表空间也删除了
​“`

**操作步骤三:拷贝生成中confulence库下的所有表的ibd文件到准备好的环境中并加载识别**

​“`sql
select concat(“alter table “,table_schema,”.”,table_name,” import tablespace;”) from information_schema.tables where table_schema=’confulence’ into outfile ‘/tmp/import.sql’;
source /tmp/import.sql
​“`

**操作步骤四:进行数据信息验证**

表都可以访问了,数据挽回了出现问题时刻的状态

案例03:mysql 5.7中误删除了ibdata1数据文件,导致数据库服务无法启动;(作业)

说明:如何恢复t100w表中数据,并且假设库中有100张表,而且表结构无法通过show create table获得;

提示:有可能是自研数据库,并且没有数据备份

思路:先获取表结构信息,然后重新建表,删除空表的独立表空间,导入表的数据文件,加载识别表数据信息

操作步骤一:mysql工具包中含有mysqlfrm工具,可以读取frm文件获得表结构;

​“`tiki wiki
[root@xiaoQ-01 ~]# ./mysqlfrm /data/3306/data/test/t100w.frm –diagnostic
​“`

操作步骤二:将新库中所有独立表空间进行删除

​“`sql
select concat(‘alter table ‘,table_schema,’.’table_name,’ discard tablespace;’) from informatin_schema.tables where table_schema=’confluence’ into outfile ‘/tmp/discard.sql’;
source /tmp/discard.sql
​“`

**类型三:undo表空间**

利用undo表空间主要用来完成撤销工作(回滚操作);

在数据库5.7版本中,默认存储在共享表空间中(ibdata);在数据库8.0版本后,默认就是独立存储了(undo_001-undo_002);

在实际生产环境中,建议在5.7版本之后,都将undo表空间进行独立文件存储;

**undo表空间管理:**

– 表空间配置参数信息查看

​“`tiki wiki
mysql> select @@innodb_undo_tablespaces;
+——————————————-+
| @@innodb_undo_tablespaces |
+——————————————-+
| 2 |
+——————————————-+
1 row in set (0.00 sec)
— 确认是否打开独立undo模式,并设置undo表空间文件个数(3-5个)

mysql> select @@innodb_max_undo_log_size;
+——————————————-+
| @@innodb_max_undo_log_size |
+——————————————-+
| 1073741824 |
+——————————————-+
1 row in set (0.00 sec)
— 表示undo日志信息的大小,默认1G

mysql> select @@innodb_undo_log_truncate;
+——————————————-+
| @@innodb_undo_log_truncate |
+——————————————-+
| 1 |
+——————————————-+
1 row in set (0.00 sec)
— 表示开启undo自动回收的机制(undo purge)

mysql> select @@innodb_purge_rseg_truncate_frequency;
+———————————————————-+
| @@innodb_purge_rseg_truncate_frequency |
+———————————————————-+
| 128 |
+———————————————————-+
1 row in set (0.00 sec)
— 触发自动回收的条件,单位是检测次数
​“`

> 官方参数使用说明(important):
>
> The number of undo tablespaces can only be configured when initializing a MySQL instence and is fixed for the
>
> life of the instance;
>
> undo表空间的数量只能在初始化MySQL实例时配置,并且在实例生命周期内是固定的

– 表空间配置参数修改调整

修改数据库5.7版本服务的undo表空间,实现undo表空间的独立存储;

查看获取数据库5.7版本的默认undo配置情况:

​“`tiki wiki
mysql> select @@innodb_undo_tablespaces;
+————————————–+
| @@innodb_undo_tablespaces |
+————————————–+
| 0 |
+————————————–+
1 row in set (0.00 sec)
— 在数据库5.7版本中,undo表空间默认并未实现独立存储;
​“`

关闭数据库服务程序,对undo表空间进行独立存储配置:

​“`tiki wiki
# 关闭数据库服务程序,清理数据库服务数据目录
[root@xiaoQ-01 ~]# systemctl stop mysqld3357
[root@xiaoQ-01 ~]# systemctl is-active mysqld3357
unknown
— 关闭数据库服务程序
[root@xiaoQ-01 ~]# rm -rf /data/3357/data/*
— 删除清空数据库数据目录

# 编写修改数据库服务配置文件
[root@xiaoQ-01 ~]# vim /data/3357/my.cnf
[mysqld]
innodb_undo_tablespaces=3
innodb_max_undo_log_size=128M
innodb_undo_log_truncate=ON
innodb_purge_rseg_truncate_frequency=32
— 在数据库服务端添加以上参数信息
​“`

重新初始化数据库服务程序:

​“`tiki wiki
[root@xiaoQ-01 ~]# /usr/local/mysql57/bin/mysqld –defaults-file=/data/3357/my.cnf –initialize-insecure –basedir=/usr/local/mysql57 –datadir=/data/3357/data –user=mysql

[root@xiaoQ-01 ~]# ll /data/3357/data/undo*
-rw-r—– 1 mysql mysql 10485760 11月 15 10:19 /data/3357/data/undo001
-rw-r—– 1 mysql mysql 10485760 11月 15 10:19 /data/3357/data/undo002
-rw-r—– 1 mysql mysql 10485760 11月 15 10:19 /data/3357/data/undo003
​“`

重新启动数据库服务程序:

​“`tiki wiki
[root@xiaoQ-01 ~]# systemctl start mysqld3357
[root@xiaoQ-01 ~]# systemctl is-active mysqld3357
active
​“`

实现undo表空间文件指定目录存储

​“`tiki wiki
# 将数据库服务进行关闭
[root@xiaoQ-01 ~]# systemctl stop mysqld3357

# 编写数据库服务配置文件
[root@xiaoQ-01 ~]# vim /data/3357/my.cnf
[mysqld]
innodb_undo_directory=/data/3357/undologs

# 创建存储undo表空间文件目录
[root@xiaoQ-01 ~]# mkdir -p /data/3357/undologs
[root@xiaoQ-01 ~]# chown -R mysql.mysql /data/*
[root@xiaoQ-01 ~]# cp -a /data/3357/data/undo* /data/3357/undologs/

# 将数据库服务进行启动
[root@xiaoQ-01 ~]# mysql -S /tmp/mysql3357.sock
mysql > select @@innodb_undo_directory;
+————————————-+
| @@innodb_undo_directory |
+————————————-+
| /data/3357/undologs |
+————————————-+
1 row in set (0.00 sec)
​“`

> 说明:对于数据库8.0版本,在进行undo表空间配置信息调整的时候,可以进行在线调整;

数据库8.0 undo表空间与数据库5.7undo表空间区别资料:

https://dev.mysql.com/doc/refman/8.0/en/innodb-undo-tablespaces.html

===============================================================================================

数据库8.0独立表空间设置扩展:Adding Undo Tablespaces

Because undo logs can become large during long-running transactions, creating additional undo tablespaces

can help prevent individual undo tablespaces from becoming too large.

As of MySQL 8.0.14, additional undo tablespaces can be created at runtime using [`CREATE UNDO TABLESPACE`](https://dev.mysql.com/doc/refman/8.0/en/create-tablespace.html) syntax.

​“`sql
# 创建新的独立的undo表空间文件
CREATE UNDO TABLESPACE tablespace_name ADD DATAFILE ‘file_name.ibu’;

# 查看已经创建的独立的undo表空间文件
mysql> select tablespace_name,file_name from information_schema.files where file_type like ‘undo log’;
+—————————+—————-+
| TABLESPACE_NAME | FILE_NAME |
+—————————+—————-+
| innodb_undo_001 | ./undo_001 |
| innodb_undo_002 | ./undo_002 |
| tablespace_name | ./xiaoQ1.ibu |
+—————————+—————-+
3 rows in set (0.00 sec)

# 删除已有的独立的undo表空间文件
ALTER UNDO TABLESPACE tablespace_name SET INACTIVE;
— 将指定的undo表空间信息设置为失效
DROP UNDO TABLESPACE tablespace_name;
— 删除指定的undo表空间信息

# 查看已有的独立的undo表空间状态
SELECT NAME, STATE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES
WHERE NAME LIKE ‘tablespace_name’;
​“`

===============================================================================================

**类型四:temp表空间**

临时表空间主要用于存储临时表信息,主要是在使用group by,order by,having,unique all,子查询等情况都会使用临时表;

临时表可以存储在内存和磁盘上;

**临时表空间管理:**

– 扩容临时表空间操作:

扩容前临时表空间信息查看:

​“`SQL
mysql> select @@innodb_temp_data_file_path;
+——————————————–+
| @@innodb_temp_data_file_path |
+——————————————–+
| ibtmp1:12M:autoextend |
+——————————————–+
1 row in set (0.00 sec)

mysql> select @@innodb_autoextend_increment;
+———————————————+
| @@innodb_autoextend_increment |
+———————————————+
| 64 |
+———————————————+
1 row in set (0.00 sec)
— 查看参数信息说明:ibtmp1文件,默认初始大小12M,不够用会自动扩展,默认每次扩展64M
​“`

临时表空间的扩容操作方法:

​“`tiki wiki
# 编写数据库配置文件信息
vim /etc/my.cnf
[mysqld]
innodb_temp_data_file_path=ibtmp1:12M;ibtmp2:120M:autoextend:max:500M
— 需要注意的是ibdata1文件大小必须和实际数据库要存储的数据相匹配,否则会出现如下报错信息

# 查看配置信息是否生效
mysql> select @@innodb_temp_data_file_path;
+———————————————————————+
| @@innodb_temp_data_file_path |
+———————————————————————+
| ibtmp1:12M;ibtmp2:120M:autoextend:max:500M |
+———————————————————————+
1 row in set (0.00 sec)
​“`

> 说明:建议数据初始化之前设定好临时表空间,建议2~3个,大小512M~1G;

数据库初始化时设置临时表空间容量建议:

| 序号 | 版本信息 | 建议说明 |
| —- | ——— | ———————————————————— |
| 01 | MySQL 5.7 | 设置共享表空间2~3个,大小建议512M或1G,最后一个定制为自动扩展 |
| 02 | MySQL 8.0 | 设置共享表空间1个即可,大小建议512M或1G |

临时表空间的初始设置方法:

​“`tiki wiki
# 模拟初始化清理数据
[root@xiaoQ-01 ~]# /etc/init.d/mysqld stop
[root@xiaoQ-01 ~]# rm -rf /data/3306/data/*

# 模拟初始化配置文件
[root@xiaoQ-01 ~]# vim /etc/my.cnf
[mysqld]
innodb_temp_data_file_path=ibtmp1:12M;ibtmp2:120M:autoextend:max:500M

# 模拟初始化操作命令
[root@xiaoQ-01 ~]# mysqld –initialize-insecure –user=mysql –basedir=/usr/local/mysql –datadir=/data/3306/data

# 模拟初始化重启服务
[root@xiaoQ-01 ~]# /etc/init.d/mysqld start
​“`

**类型五:redo事务日志**

redo log属于事务重做日志文件,主要用于记录内存数据页的变化(记录在内存中对数据页的操作信息),都会以日志文件方式记录;

可以实现”前进”(WAL-write ahead log)的功能,数据库会保证redo操作日志优先于数据写入磁盘,加快了事务提交效率(提高并发);

在进行日志信息记录时,采用的是顺序IO,而数据存储时采用的异步IO(随机IO);

重做日志,记录了所有缓冲池修改的数据,修改数据的时候先写日志,后修改的缓冲区;

假设修改写入操作的时候数据库崩溃了或停电了,等下次启动通过重做日志来保持数据的正确性。

redo事务日志的存储路径为:默认存储在数据库服务的数据目录下,默认大小为48M

​“`tiki wiki
[root@xiaoQ-01 data]# pwd
/data/3306/data
[root@xiaoQ-01 data]# ll ib_log*
-rw-r—– 1 mysql mysql 50331648 11月 15 11:34 ib_logfile0
-rw-r—– 1 mysql mysql 50331648 11月 15 11:27 ib_logfile1
​“`

**redo事务日志管理:**

– 进行redo事务日志操作:

redo事务日志配置信息查看:

​“`SQL
mysql> show variables like ‘%innodb_log_file%’;
+———————————–+—————+
| Variable_name | Value |
+———————————–+—————+
| innodb_log_file_size | 50331648 |
| innodb_log_files_in_group | 2 |
+———————————–+—————+
2 rows in set (0.00 sec)
— 在实际生产环境中,建议大小为512M~4G,应用组数为2~4组(写入数据过程轮询写入)
​“`

redo事务日志配置操作方法:

​“`tiki wiki
# 编写数据库配置文件信息
vim /etc/my.cnf
[mysqld]
innodb_log_file_size=100M
innodb_log_files_in_group=3

# 确认配置信息是否已经生效
[root@xiaoQ-01 data]# /etc/init.d/mysqld restart
[root@xiaoQ-01 data]# ll /data/3306/data/ib_log*
-rw-r—– 1 mysql mysql 104857600 11月 15 15:12 /data/3306/data/ib_logfile0
-rw-r—– 1 mysql mysql 104857600 11月 15 15:12 /data/3306/data/ib_logfile1
-rw-r—– 1 mysql mysql 104857600 11月 15 15:12 /data/3306/data/ib_logfile2
​“`

**类型六:ib_buffer_pool预热文件**

ib_buffer_pool预热文件可以用于缓冲和缓存,可以存储”热”数据页(经常查询或修改的数据页),从而减少物理IO消耗;

从数据库5.7版本开始,数据库正常关闭后,内存中存储的数据页缓冲或缓存信息均会失效,重新启动后还会消耗IO获取相应数据页信息;

为了可以尽量减少磁盘IO的消耗,可以将内存中的热数据页信息存储在ib_buffer_pool文件中;

数据库服务再次启动后,会直接读取ib_buffer_pool文件中信息,并将读取的信息加载到内存中,最终减少随机IO数量;

> 说明:存在ib_buffer_pool预热文件后,有可能在数据库服务关闭时比较耗费一些时间,但实际环境数据库服务关闭情况较少;

**类型七:Doublewrite Buffer(DWB)文件**

双写缓冲区,我们知道数据修改先修改的Page页后又刷到磁盘的,在刷到磁盘前这些数据会先存放在双写缓存区中;

双写缓存区是用来保障数据写入磁盘时候出现问题的备份。

DWB文件主要作用是:mysql process crash in the middle of a page write(在数据库服务存储时,数据页写了一半);

数据库Innodb可以找到一个好的数据页副本从Doublewrite Buffer文件中,主要是避免数据信息出现损坏;

MySQL数据库最小IO存储单元是page(16kB),OS系统中最小的IO存储单元是block(4kB),OS也可以称为存储子系统;

会出现一个问题:数据库系统与操作系统的存储关系问题,在数据库中写入一个数据页时,在文件系统层面可能只是写入了2个block;

在数据库8.0.19之前,默认在ibdataN文件中进行存储,在数据库8.0.20以后,可以进行独立文件存储;

​“`tiki wiki
[root@xiaoQ-01 data]# ll *ib_16384*
-rw-r—– 1 mysql mysql 196608 11月 15 15:14 #ib_16384_0.dblwr
-rw-r—– 1 mysql mysql 8585216 11月 15 11:27 #ib_16384_1.dblwr
​“`

##### **02 In-Memory Structures(内存结构部分)**

在内存结构中也是包含很多的组成部分,主要的组成部分有:

**组成部分一:InnoDB Buffer Pool(IBP)**

Buffer Pool内存存储区域主要用来缓冲或缓存数据库服务的数据页和索引页,是MySQL中最大的、最重要的内存区域;

缓冲池,数据缓冲池里面不是直接存放数据,而是存放page页,将数据存放在了page页中,在缓冲池page页是通过链表形式来存放的;

**Buffer Pool内存空间管理:**

– Buffer Pool配置参数信息查看:

​“`tiki wiki
mysql> select @@innodb_buffer_pool_size;
+—————————————+
| @@innodb_buffer_pool_size |
+—————————————+
| 134217728 |
+—————————————+
1 row in set (0.00 sec)
— buffer pool默认内存空间大小为128M,生产建议大小可以设置为物理内存总量的50%~80%
​“`

– Buffer Pool配置参数修改方法:

​“`tiki wiki
# 配置信息临时调整
mysql > set global innodb_buffer_pool_size=268435456;
— 配置调整后,重新登录mysql数据库生效

# 配置信息永久调整
[root@xiaoQ-01 ~]# vim /etc/my.cnf
[mysqld]
innodb_buffer_pool_size=256M
— 配置调整后,重新启动mysql数据库生效
​“`

**组成部分二:Change Buffer**

写缓冲区,正常情况下修改数据是先修改的缓冲池中Page的数据,但是缓冲池肯定不是所有的数据;

而修改数据没有对应的Page数据的时候并不会直接把数据加载到缓冲池中去,而是放在了写缓冲区中记录;

等到数据被读取的时候再把数据合并到缓冲池中。

**组成部分三:Adaptive Hash Index**

自适应Hash索引,InnoDB存储引擎会根据Page页的访问频率和模式建立对应的Hash索引,这个索引是根据查询情况自动建立的;

称为自适应Hash索引。

**组成部分四:InnoDB Log Buffer(ILB)**

Log Buffer内存存储区域主要用来缓冲 redo/undo log日志信息;

日志缓冲区,主要用来保存写入磁盘的(Redo/Undo)日志文件,日志缓冲区会定期刷新到磁盘log文件中;

这样不用每次日志都进行磁盘IO操作,提高效率。

**Log Buffer内存空间管理:**

– Log Buffer配置参数信息查看:

​“`tiki wiki
mysql> select @@innodb_log_buffer_size;
+————————————–+
| @@innodb_log_buffer_size |
+————————————–+
| 16777216 |
+————————————–+
1 row in set (0.00 sec)
— log_buffer默认内存空间大小为16M,生产建议大小可以设置为innodb_log_file_size文件大小的 1-N倍(后续说明)
​“`

– Log Buffer配置参数修改方法:

​“`tiki wiki
# 配置信息临时调整
mysql > set global innodb_log_buffer_size=33554432;
— 配置调整后,重新登录mysql数据库生效

# 配置信息永久调整
[root@xiaoQ-01 ~]# vim /etc/my.cnf
[mysqld]
innodb_log_buffer_size=32M
— 配置调整后,重新启动mysql数据库生效
​“`

“`

# 第十三章 事务机制

#### 1.12.1 数据库存储事务机制概念

事务(Transaction)可以更通俗的理解为交易,所以事务会伴随着交易类的业务类型出现的概念(工作模式);

现实生活中存在很多的交易行为,比如:物换物的等价交换、货币换物的等价交换、虚拟货币换物(虚拟物品)的等价交换;

因此就需要考虑如何保证现实生活中交易过程的和谐,一般会有法律、道德等方面规则进行约束;

而在数据库服务中为了保证线上交易的”和谐”,便加入了”事务”工作机制

#### 1.12.2 数据库存储事务机制特性

数据事务设计遵循ACID的原则:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)

一个支持事务(Transaction)的数据库,必须要具有这四个特性,否则在事务过程当中无法保证数据的正确性;

在数据库服务中引入事务机制概念,主要是为了应用事务机制的相关特性处理安全一致性问题,其中事务机制主要包含的特性有:

**特性一:原子性(Atomicity)**

原子性表示一个事务生命周期中的DML语句,要么全成功要么全失败,不可以出现中间状态;

事务是数据库的逻辑工作单位,事务中包括的所有操作要么都做,要么都不做。

语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;`实现主要基于undo log`

“`
Begin:DML01 DML02 DML03 Commit;
“`

**特性二:一致性(Consistency)**

数据库事务的一致性是指事务必须确保数据库从一个一致性状态变换到另一个一致性状态。

一致性表示一个事务发生前、中、后,数据都最终保持一致,即读和写都要保证一致性;

事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障;

“`
CR + Double write
“`

举例说明补充说明:

事务开始之前和结束之后,数据库的完整性约束(如字段约束、外键约束、触发器等)没有被破坏;

在转账操作中,无论转账操作是否成功,账户A和账户B的存款总额应保持不变。

一致性还涉及业务逻辑上的完整性;

比如转账操作中,账户A减少的金额应与账户B增加的金额相等。

事务的原子性、隔离性和持久性是实现一致性的手段:

– 原子性确保事务中的所有操作要么全部完成,要么全部不执行;

– 隔离性确保并发事务之间的操作相互隔离,不会相互干扰;

– 持久性则确保事务对数据库的改变一旦提交,就不会丢失,即使在系统故障的情况下也能恢复。

**特性三:隔离性(Isolation)**

隔离性表示一个事务操作数据行的时候,不会受到其他事务的影响,主要利用锁机制来保证隔离性;

即一个事务内部的操作及使用的数据对其他事务是隔离的,并发执行的各个事务之间互相不干扰;

**特性四:持久性(Durability)**

持久性表示一旦事务进行了提交,即可永久生效(落盘)

保证事务提交后不会因为宕机等原因导致数据丢失;`实现主要基于redo log`

事务ACID相关知识官方说明:https://dev.mysql.com/doc/refman/8.0/en/mysql-acid.html

#### 1.10.3 数据库存储事务生命周期

在运用事务机制完成相关工作任务时,对于事务使用是存在生命周期概念的,标准显示的事务生命周期控制语句有:

“`tiki wiki
# 开启事务机制
begin;
start transaction;
#事务周期内存,完成事件操作
DML01
DML02
DML03

# 提交事务任务(事务结束 在binlog中记录事件信息)
commit;
# 回滚事务操作(事务结束)
rollback;
“`

> 说明:事务生命周期中,只能使用DML语句,其中包括:select、update、delete、insert;DDL语句会隐式进行提交

事务的生命周期操作演示:

“`tiki wiki
# 进行测试数据库查询数据
mysql> use world;
mysql> select * from city limit 10;

# 进行测试数据库数据撤销修改
mysql> begin;
mysql> update city set population=10 where id=1;
mysql> update city set population=10 where id=2;
— 由于是采用事务进行的修改,所以只是在内存层面进行的修改,并没有对磁盘上的数据进行修改;
mysql> select * from city limit 10;
— 由于是采用事务进行的修改,此时看到的数据信息只是内存层面的修改信息
mysql> rollback;
— 由于是采用事务进行的撤销,会读取undo文件信息,将事务操作撤回到事务开始前的状态
mysql> select * from city limit 10;
— 由于是采用事务进行的修改,当撤销操作执行完,看到数据信息还是原来的;

# 进行测试数据库数据永久修改
mysql> begin;
mysql> update city set population=10 where id=1;
mysql> update city set population=10 where id=2;
— 由于是采用事务进行的修改,所以只是在内存层面进行的修改,并没有对磁盘上的数据进行修改;
mysql> select * from city limit 10;
— 由于是采用事务进行的修改,此时看到的数据信息只是内存层面的修改信息
mysql> commit;
— 由于是采用事务进行的提交,会加载redo文件信息,将事务内存层面的修改同步到磁盘中(完成了D特性)
mysql> select * from city limit 10;
— 由于是采用事务进行的修改,当执行操作执行完,看到数据信息将永久保存下载;
“`

#### 1.10.4 数据库存储事务提交方式

**方式一:在事务生命周期管理过程中,事务的提交机制可以采用自动提交方式(auto_commit)**

**事务自动提交方式作用说明:**

事务自动提交表示在没有显示的使用`begin`语句的时候,执行DML操作语句时,会在DML操作语句前自动添加`begin`;

并在DML操作语句执行后自动添加`commit`;

在生产环境中,若处于频繁事务业务场景中,建议关闭autocommit自动提交功能,或者每次事务执行的时候;

都进行显示的执行`begin`和`commit`

**事务自动提交方式参数信息:**

“`tiki wiki
mysql> select @@autocommit;
+———————+
| @@autocommit |
+———————+
| 1 |
+———————+
1 row in set (0.00 sec)
— 在事务自动提交功能设置修改时,设置为1表示开启自动提交,设置为0表示关闭自动提交
“`

**事务自动提交方式参数修改:**

“`tiki wiki
# 临时关闭事务自动提交功能
mysql> set global autocommit=0;
— 配置调整后,重新登录mysql数据库生效

# 永久关闭事务自动提交功能
[root@xiaoQ-01 ~]# vim /etc/my.cnf
[mysqld]
autocommit=0
— 配置调整后,重新启动mysql数据库生效
“`

事务自动提交方式设置方式优点缺点说明:

| 序号 | 参数配置 | 优势 |
| —— | ———————————- | ———————————————————— |
| 情况01 | autocommit=0
关闭事务自动提交 | 可以编写多个关联的DML,进行一次性提交操作,若出现异常可以回滚
符合原子特性 |
| | | **劣势** |
| | | 可能出现多个关联的DML,只是完成了部分操作,这时就可能等待状态
基于隔离特性,操作的数据表或数据行就会进入锁定状态 |
| | **参数配置** | **优势** |
| 情况02 | autocommit=1
开启事务自动提交 | 可以出现多个关联的DML,逐行操作自动提交,就可以不用处于锁等待状态 |
| | | **劣势** |
| | | 可能出现多个关联的DML,,每执行一条就进行提交,会造成多个语句执行不符合原子性 |

**方式二:在事务生命周期管理过程中,事务的提交机制可以采用隐式提交方式:**

在进行事务操作时,需要注意操作语句必须都是DML语句,如果中间插入了DDL语句,也会造成之前的事务操作自动提交;

“`tiki wiki
begin; DML1; DML2; DDL1; COMMIT; DML3; COMMIT;
— 这种情况出现会破坏原本事务的原子性
“`

**隐式自动提交方式语句:**

在出现隐式自动提交时,可能导致提交的非事务语句有:

| 序号 | 语句类型 | 涉及命令 |
| —- | ———— | ————————————————— |
| 01 | DDL语句类型 | alter、create、drop |
| 02 | DCL语句类型 | grant、revoke、set password |
| 03 | 锁定语句类型 | lock tables、unlock tables |
| 04 | 其他语句类型 | truncate table、load data infile、select for update |

> 说明:在多个数据库会话窗口中,A窗口的所有事务性DML操作,不会受到B窗口的非事务语句影响,同一会话窗口会有影响;

**隐式自动回滚情况分析:**

– 情况一:在事务操作过程中,会话窗口自动关闭了,会进行隐式自动回滚;
– 情况二:在事务操作过程中,数据库服务被停止了,会进行隐式自动回滚;
– 情况三:在事务操作过程中,出现事务冲突死锁了,会进行隐式自动回滚;

#### 1.10.5 数据库存储事务隔离级别

数据库事务隔离级别主要作用是实现事务工作期间,数据库操作读的隔离特性,所谓读的操作就是将数据页可以调取到内存;

然后可以读取数据页中相应数据行的能力,并且不同事务之间的数据页读操作相互隔离;

可以简单理解为:一个事务在对数据页中数据行做更新操作时,在没有更新提交前,另一个事务此时是不能读取数据页中数据行内容的;

对于数据库存储事务隔离级别包括4种,可以通过操作命令查看获取当前使用的隔离级别:

“`tiki wiki
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| REPEATABLE-READ |
+———————————+
1 row in set (0.00 sec)
“`

**常用的事务隔离级别类型:**

**类型一:RU(READ-UNCOMMITTED 表示读未提交)**

可以读取到事务未提交的数据,隔离性差,会出现脏读(当前内存读),不可重复读,幻读问题;

**类型二:RC(READ-COMMITTED 表示读已提交)**`可用`

可以读取到事务已提交的数据,隔离性一般,不会出现脏读问题,但是会出现不可重复读,幻读问题;

**类型三:RR(REPEATABLE-READ 表示可重复读)**`默认`

可以防止脏读(当前内存读),防止不可重复读问题,防止会出现的幻读问题,但是并发能力较差;

会使用next lock锁进制,来防止幻读问题,但是引入锁进制后,锁的代价会比较高,比较耗费CPU资源,占用系统性能;

**类型四:SR(SERIALIZABLE 可串行化)**

隔离性比较高,可以实现串行化读取数据,但是事务的并发度就没有了;

这是事务的最高级别,在每条读的数据上,加上锁,使之不可能相互冲突

事务隔离级别官方链接:https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html

**常用的事务隔离级别名词:**

在解释分析说明相应的隔离级别名词前,需要对数据库事务隔离级别进行调整,以及关闭自动提交功能:

“`tiki wiki
# 设置事务隔离级别
mysql> set global transaction_isolation=’READ-UNCOMMITTED’; 隔离级别最弱(并行读取数据问题) 并行处理能力最强
mysql> set global transaction_isolation=’READ-COMMITTED’; RC
mysql> set global transaction_isolation=’REPEATABLE-READ’; 抑制写并行操作 RR
mysql> set global transaction_isolation=’SERIALIZABLE’; 抑制读/写并行操作 隔离级别最强 并行处理会话/处理事务能力 弱

# 查看事务隔离级别
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| READ-UNCOMMITTED |
+———————————+
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| READ-COMMITTED |
+———————————+
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| REPEATABLE-READ |
+———————————+

# 临时关闭自动提交功能:
mysql> set global autocommit=0;
mysql> select @@autocommit;
+———————+
| @@autocommit |
+———————+
| 0 |
+———————+
“`

创建隔离级别测试数据表:

“`sql
mysql> use oldboy
mysql> create table t1 (
id int not null primary key auto_increment,
a int not null,
b varchar(20) not null,
c varchar(20) not null
) charset=utf8mb4 engine=innodb;

mysql> begin;
mysql> insert into t1(a,b,c)
values
(5,’a’,’aa’),
(7,’c’,’ab’),
(10,’d’,’ae’),
(13,’g’,’ag’),
(14,’h’,’at’),
(16,’i’,’au’),
(20,’j’,’av’),
(22,’k’,’aw’),
(25,’l’,’ax’),
(27,’o’,’ay’),
(31,’p’,’az’),
(50,’x’,’aze’),
(60,’y’,’azb’);
mysql> commit;
— 确认两个SQL会话窗口,即不同的事务查看的数据是否一致的;
“`

– **名词解读分析一:脏读**

脏读主要表示在一个事务窗口中,没有数据修改提交操作前,另一个事务就可以看到内存中数据页的修改;

简单理解:在一个事务窗口中,可以读取到别人没有提交的数据信息;

**利用隔离级别RU解读:**

“`tiki wiki
# 设置事务隔离级别
mysql> set global transaction_isolation=’READ-UNCOMMITTED’;
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| READ-UNCOMMITTED |
+———————————+
mysql> set global autocommit=0;
mysql> select @@autocommit;
— 重新开启两个SQL会话窗口

# 数据库A会话窗口操作
mysql> begin;
mysql> update t1 set a=10 where id=1;
— 只是在内存层面进行数据页中数据修改
mysql> rollback;
— 进行事务回滚操作

# 数据库B会话窗口操作
mysql> begin;
mysql> select * from t1 where id=1;
+—-+—-+—+—-+
| id | a | b | c |
+—-+—-+—+—-+
| 1 | 10 | a | aa |
+—-+—-+—+—-+
1 row in set (0.01 sec)
— 在A会话窗口没提交的事务修改,被B会话窗口查询到了
mysql> select * from t1 where id=1;
+—-+—-+—+—-+
| id | a | b | c |
+—-+—-+—+—-+
| 1 | 5 | a | aa |
+—-+—-+—+—-+
1 row in set (0.01 sec)
— 在A会话窗口进行回滚后,在B窗口查询的数据又恢复了
“`

– **名词解读分析二:不可重复读**

不可重复读表示在一个事务中,利用相同的语句多次查询,获取的数据信息是不同的;

**利用隔离级别RU解读:**

“`tiki wiki
# 数据库B会话窗口操作
mysql> begin;
mysql> select * from t1 where id=1;
+—-+—-+—+—-+
| id | a | b | c |
+—-+—-+—+—-+
| 1 | 10 | a | aa |
+—-+—-+—+—-+
1 row in set (0.01 sec)
— 在B会话事务窗口进行数据第一次查询看到数据信息:a=10
mysql> select * from t1 where id=1;
+—-+—-+—+—-+
| id | a | b | c |
+—-+—-+—+—-+
| 1 | 5 | a | aa |
+—-+—-+—+—-+
1 row in set (0.01 sec)
— 在B会话事务窗口进行数据第二次查询看到数据信息:a=5
“`

**利用隔离级别RC解读:**

“`tiki wiki
# 设置事务隔离级别
mysql> set global transaction_isolation=’READ-COMMITTED’;
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| READ-COMMITTED |
+———————————+
mysql> set global autocommit=0;
mysql> select @@autocommit;
— 重新开启两个SQL会话窗口

# 数据库A会话窗口操作
mysql> use oldboy;
mysql> begin;
mysql> select * from t1 where id=1;
+—-+—+—+—-+
| id | a | b | c |
+—-+—+—+—-+
| 1 | 5 | a | aa |
+—-+—+—+—-+
1 row in set (0.00 sec)
— A窗口事务查询信息 = B窗口事务查询信息
mysql> update t1 set a=10 where id=1;
— A窗口事务进行修改
mysql> commit;
— A窗口事务进行提交

# 数据库B会话窗口操作
mysql> use oldboy;
mysql> begin;
mysql> select * from t1 where id=1;
+—-+—+—+—-+
| id | a | b | c |
+—-+—+—+—-+
| 1 | 5 | a | aa |
+—-+—+—+—-+
1 row in set (0.00 sec)
— A窗口事务查询信息 = B窗口事务查询信息
mysql> select * from t1 where id=1;
+—-+—+—+—-+
| id | a | b | c |
+—-+—+—+—-+
| 1 | 5 | a | aa |
+—-+—+—+—-+
1 row in set (0.00 sec)
— B窗口事务查询信息,不能看到A窗口事务未提交的数据变化,避免了脏数据问题;
mysql> select * from t1 where id=1;
+—-+—+—+—-+
| id | a | b | c |
+—-+—+—+—-+
| 1 | 10 | a | aa |
+—-+—+—+—-+
1 row in set (0.00 sec)
— A窗口事务提交之后,B窗口事务查询信息和之前不同了
“`

**利用隔离级别RR解读:**

“`tiki wiki
# 设置事务隔离级别
mysql> set global transaction_isolation=’REPEATABLE-READ’;
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| REPEATABLE-READ |
+———————————+
mysql> set global autocommit=0;
mysql> select @@autocommit;
— 重新开启两个SQL会话窗口

# 数据库A会话窗口操作
mysql> use oldboy;
mysql> begin;
mysql> select * from t1;
— 确认初始数据信息
mysql> update t1 set a=10 where id=1;
— A窗口事务进行修改
mysql> commit;
— A窗口事务进行提交

# 数据库B会话窗口操作
mysql> use oldboy;
mysql> begin;
mysql> select * from t1;
— 确认初始数据信息
mysql> select * from t1 where id=1;
+—-+—+—+—-+
| id | a | b | c |
+—-+—+—+—-+
| 1 | 5 | a | aa |
+—-+—+—+—-+
1 row in set (0.00 sec)
— B窗口事务查询信息,不能看到A窗口事务未提交的数据变化,避免了脏数据问题;
mysql> select * from t1 where id=1;
+—-+—+—+—-+
| id | a | b | c |
+—-+—+—+—-+
| 1 | 5 | a | aa |
+—-+—+—+—-+
1 row in set (0.00 sec)
— A窗口事务提交之后,B窗口事务查询信息和之前是相同的;
— 在RR级别状态下,同一窗口的事务生命周期下,每次读取相同数据信息是一样,避免了不可重复读问题
mysql> commit;
mysql> select * from t1 where id=1;
— 在RR级别状态下,同一窗口的事务生命周期结束后,看到的数据信息就是修改的了
“`

– **名词解读分析三:幻读**

**利用隔离级别RC解读:**

“`tiki wiki
# 设置事务隔离级别
mysql> set global transaction_isolation=’READ-COMMITTED’;
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| READ-COMMITTED |
+———————————+
mysql> set global autocommit=0;
mysql> select @@autocommit;
— 重新开启两个SQL会话窗口

# 数据库A会话窗口操作(重新进入)
mysql> use oldboy;
mysql> select * from t1;
+—-+—-+—+—–+
| id | a | b | c |
+—-+—-+—+—–+
| 1 | 10 | a | aa |
| 2 | 7 | c | ab |
| 3 | 10 | d | ae |
| 4 | 13 | g | ag |
| 5 | 14 | h | at |
| 6 | 16 | i | au |
| 7 | 20 | j | av |
| 8 | 22 | k | aw |
| 9 | 25 | l | ax |
| 10 | 27 | o | ay |
| 11 | 31 | p | az |
| 12 | 50 | x | aze |
| 13 | 60 | y | azb |
+—-+—-+—+—–+
13 rows in set (0.00 sec)
— 查看获取A窗口表中数据
mysql> alter table t1 add index idx(a);
— 在A窗口中,添加t1表的a列为索引信息
mysql> begin;
— 在A窗口和B窗口中,同时做开始事务操作;
mysql> update t1 set a=20 where a<20; -- 在A窗口中,将a<20的信息均调整为20 mysql> commit;
— 在A窗口中,进行事务提交操作,是在B窗口事务没有提交前
mysql> select * from t1;
— 在A窗口中,查看数据信息,希望看到的a是没有小于20的,但是结果看到了a存在等于10的(即出现了幻读)

# 数据库B会话窗口操作(重新进入)
mysql> use oldboy;
mysql> select * from t1;
+—-+—-+—+—–+
| id | a | b | c |
+—-+—-+—+—–+
| 1 | 10 | a | aa |
| 2 | 7 | c | ab |
| 3 | 10 | d | ae |
| 4 | 13 | g | ag |
| 5 | 14 | h | at |
| 6 | 16 | i | au |
| 7 | 20 | j | av |
| 8 | 22 | k | aw |
| 9 | 25 | l | ax |
| 10 | 27 | o | ay |
| 11 | 31 | p | az |
| 12 | 50 | x | aze |
| 13 | 60 | y | azb |
+—-+—-+—+—–+
13 rows in set (0.00 sec)
— 查看获取B窗口表中数据
mysql> begin;
mysql> insert into t1(a,b,c) values(10,’A’,’B’)
— 在B窗口中,插入一条新的数据信息 a=10
mysql> commit;
— 在B窗口中,进行事务提交操作
“`

**利用隔离级别RR解读:**

“`tiki wiki
# 设置事务隔离级别
mysql> set global transaction_isolation=’REPEATABLE-READ’;
mysql> select @@transaction_isolation;
+———————————+
| @@transaction_isolation |
+———————————+
| REPEATABLE-READ |
+———————————+
mysql> set global autocommit=0;
mysql> select @@autocommit;
— 重新开启两个SQL会话窗口

# 数据库A会话窗口操作
mysql> use oldboy;
mysql> select * from t1;
— 查看获取A窗口表中数据
mysql> alter table t1 add index idx(a);
— 在A窗口中,添加t1表的a列为索引信息
mysql> begin;
mysql> update t1 set a=20 where a>20;
— 在A窗口中,将a>20的信息均调整为20

# 数据库B会话窗口操作
mysql> use oldboy;
mysql> select * from t1;
— 查看获取B窗口表中数据
mysql> begin;
mysql> insert into t1(a,b,c) values(30,’sss’,’bbb’);
— 在B窗口中,插入一条新的数据信息 a=30,但是语句执行时会被阻塞,没有反应;
mysql> show processlist;
— 在C窗口中,查看数据库连接会话信息,insert语句在执行,等待语句超时(默认超时时间是50s)
— 因为此时在RR机制下,创建了行级锁(阻塞修改)+间隙锁(阻塞区域间信息插入)=next lock
— 区域间隙锁 < 左闭右开(可用临界值) ; 区域间隙锁 > 左开右闭(不可用临界值)
“`

利用MVCC机制隔离(只能保证读的隔离)

**MVCC技术概念简述:**

MVCC(multi-version-concurrent-control)即多版本并发控制,是一种并发控制的方法;

可以类别成Git进行并发处理的机制,其实就是每个事务在发生更新的过程中,维护发生更新事务的各个版本;

`各个事务版本通过undo的日志(前镜像)实现快照的技术(read view),从而可以保存多个事务版本;`

在MySQL InnoDB存储引擎下RC、RR基于MVCC(多版本并发控制)进行并发事务控制;

MVCC是基于”数据版本”对并发事务进行访问。

**MVCC技术引入说明:**

根据之前的事务隔离级别,可以等到以下结论信息:

对于RR级别在innodb引擎下,可以实现解决不可重复读和幻读等相关问题,需要使用Innodb引擎中的MVCC机制;

| 隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁读 |
| ————— | ———- | —————- | ——————– | —— |
| READ UNCOMMITED | 是 | 是 | 是 | 否 |
| READ COMMITTED | 否 | 是 | 是 | 否 |
| REPEATABLE READ | 否 | 否 | 否(引擎innodb除外) | 否 |
| SERIALIZABLE | 否 | 否 | 否 | 是 |

**MVCC技术原理详述:**

假设一个数据库服务中,出现了以下4个并发事务操作信息:

RR隔离级别查看信息:select 01 查看信息为张三;select 02 查看信息为张三;

RC隔离级别查看信息:select 01 查看信息为张三;select 02 查看信息为张小三;

> 说明:RC级别下出现”不可重复读情况”,RR级别下实现了”可重复读情况

为什么在MySQL数据库中,应用Innodb存储引擎时,两种不同的隔离级别(RR/RC)会出现不同的读取结果?

这就需要了解MVCC的工作原理机制,其中首先需要掌握undo log的链接表机制(版本链):

以上信息就是通过undo log回滚日志所产生的版本链,和每个版本对应的数据镜像信息;

但是新的问题又出现了:

undo log回滚日志不是会被删除吗?特别是中间数据万一被删除了版本链不就断了吗?

`undo log版本链并不是立即删除清理的;`

MySQL数据库服务要确保版本链上数据镜像不再被其他并行事务”引用”后才进行删除;

了解完什么是undo log版本链相关知识后,那么版本链和MVCC有什么关系呢,下面需要再了解一个新的知识”Read View”;

ReadView是”`快照读`”SQL执行时MVCC提取数据的依据;

– `快照读`就是最普通的select查询SQL语句;(应用MVCC读取数据)

– `当前读`指代执行下列语句时进行数据读取的方式;(应用next key lock锁进制读取数据)

insert、update、delete、select…for update、select…lock in share mode

ReadView是一个数据结构,包含4个组成字段:

| 字段 | 结构 | 解释说明 |
| —- | ————– | ———————————————— |
| 01 | m_ids | 当前活跃的事务编号集合,即没有提交的事务编号汇总 |
| 02 | min_trx_id | 最小活跃事务编号 |
| 03 | max_trx_id | 预分配事务编号,当前最大事务编号+1 |
| 04 | creator_trx_id | readview创建者的事务编号 |

根据以上readview的数据结构信息,可以得到以上数据业务的readview信息:

**场景01:读已提交(RC)-在每一次执行快照读时生成新的readview**

生成的readview数据结构信息如下:

**第一次数据读取过程分析:(RC级别下的第一次readview信息读取)**

版本链数据访问规则:

– 判断当前版本链中数据镜像事务trx_id = creator_trx_id(4)

若成立说明数据就是自己这个事务更改的,可以访问;

– 判断当前版本链中数据镜像事务trx_id < min_trx_id(2) 若成立说明数据已经提交了,可以访问 - 判断当前版本链中数据镜像事务trx_id > max_trx_id(5)

若成立说明该事务是在readview生成以后才开启的,不允许访问数据

– 判断当前版本链中数据镜像事务min_trx_id<=trx_id<=max_trx_id(5) 若成立需要在m_ids事务集合中进行对比,当前事务trx_id若未出现在集合中,则代表数据已经提交了,可以访问 > 结论:因此根据以上的版本链数据访问规则,readview可以读取到事务trx_id=1提交的数据,即数据”张三”;

**第二次数据读取过程分析:(RC级别下的第二次readview信息读取)**

版本链数据访问规则:

– 判断当前版本链中数据镜像事务trx_id = creator_trx_id(4)

若成立说明数据就是自己这个事务更改的,可以访问;

– 判断当前版本链中数据镜像事务trx_id < min_trx_id(2) 若成立说明数据已经提交了,可以访问 - 判断当前版本链中数据镜像事务trx_id > max_trx_id(5)

若成立说明该事务是在readview生成以后才开启的,不允许访问数据

– 判断当前版本链中数据镜像事务 min_trx_id<=trx_id<=max_trx_id(5) 若成立需要在m_ids事务集合中进行对比,当前事务trx_id若未出现在集合中,则代表数据已经提交了,可以访问 > 结论:因此根据以上的版本链数据访问规则,readview可以读取到事务trx_id=1提交的数据,即数据”张小三”;

**场景02:可重复读(RR)-仅在第一次执行快照读时生成readview,后续快照读复用(但有例外情况)**

生成的readview数据结构信息如下:

**第一次数据读取过程分析:(RR级别下的第一次readview信息读取)**

版本链数据访问规则:

– 判断当前版本链中数据镜像事务trx_id = creator_trx_id(4)

若成立说明数据就是自己这个事务更改的,可以访问;

– 判断当前版本链中数据镜像事务trx_id < min_trx_id(2) 若成立说明数据已经提交了,可以访问 - 判断当前版本链中数据镜像事务trx_id > max_trx_id(5)

若成立说明该事务是在readview生成以后才开启的,不允许访问数据

– 判断当前版本链中数据镜像事务 min_trx_id<=trx_id<=max_trx_id(5) 若成立需要在m_ids事务集合中进行对比,当前事务trx_id若未出现在集合中,则代表数据已经提交了,可以访问 > 结论:因此根据以上的版本链数据访问规则,readview可以读取到事务trx_id=1提交的数据,即数据”张三”;

**第二次数据读取过程分析:(RR级别下的第二次readview信息读取)**

由于RR级别下,会复用第一次读的readview信息,所以读取的的数据是一致的,从而实现了可重复读情况;

> 结论:因此根据以上的版本链数据访问规则,readview可以读取到事务trx_id=1提交的数据,即数据”张三”;

RR级别下使用MVCC可以解决幻读问题吗?

可以解决,但不能完全解决;

因为在MVCC机制中,并不是采用锁的机制,完全的对事务数据操作进行了隔离,而是采用版本控制的方式,变相的解决了幻读问题;

对于RR隔离级别中,由于连续多次快照读,ReadView会产生复用情况,所以在两个快照读之间,就算其他事务产生了数据变化;

对于当前事务来说,变化的数据信息都是不可见的,所以没有幻读问题;

但是会有一种特例情况:当两次快照读之间存在当前读,ReadView会重新生成,导致产生幻读;

![1695354305898](D:/学习//4_数据库/视频和笔记/系统运维95期-Day14-数据库服务事务机制/课程笔记目录/MySQL中级数据库课程-11章-数据库服务事务机制/课件配图资料/1695354305898.png)

对于隔离级别而言,只有RC和RR级别可以使用到MVCC机制的,实现一种快照读机制,而RU和SR级别是不会使用到MVCC机制的;

– RC:应用MVCC的快照读机制,是基于语句级别的;`(不可重复读 ture)`

在事务期间,执行每个查询语句的时候,都会检查MVCC版本(快照列表),获取最新的已提交事务的快照;

– RR:应用MVCC的快照读机制,是基于事务级别的;`(不可重复读 false)`

在事务期间,执行首条查询语句的时候,就会生成MVCC版本(相应快照),将会一直读取此快照数据信息,直到事务生命周期结束;

以上的RR隔离级别利用MVCC的快照读机制,又称为一致性快照读;

PROMETHEUS

# Prometheus

## 1 概述

“`sh
Prometheus是一个开源系统监控和警报工具包,最初由SoundCloud构建。自2012年成立以来,许多公司和组织都采用了Prometheus,该项目拥有非常活跃的开发人员和用户社区。它现在是一个独立的开源项目,独立于任何公司进行维护。为了强调这一点,并澄清该项目的治理结构,Prometheus于2016年加入云原生计算基金会(CNCF),成为继Kubernetes之后的第二个托管项目。

第一个是k8s
官网地址:
https://prometheus.io/

CNCF地址:
https://landscape.cncf.io/

虚拟机规划
root@prometheus-server31:~# tail -6 /etc/hosts
10.0.0.31 prometheus-server31
10.0.0.32 prometheus-server32
10.0.0.33 prometheus-server33
10.0.0.41 node-exporter41
10.0.0.42 node-exporter42
10.0.0.43 node-exporter43

所有虚拟机均是双网卡,另外一个网卡网段为192.168.137,IP地址最后一位都相同
“`

## 2 架构

![image-20250320204322088](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320204322088.png)

“`sh
1 prometheus server
时间数据存储,监控指标管理

2 prometheus web ui
集群状态管理,promql

3 jobs exports
Exporter: 为当前的客户端暴露出符合Prometheus规则的数据指标,Exporter以守护进程的模式运行并开始采集数据,Exporter本身也是一个http_server可以对http请求作出响应返回数据(K/V形式的metrics)。
作用:采集中间件数据

4 pushgateway
服务发现: file,DNS,Kubernete,Consul,custom Integration,…

5 altermanager
告警

Prometheus由九个主要软件包组成,其职责如下:
– Prometheus Server:
彼此独立运行,仅依靠其本地存储来实现其核心功能,抓取时序数据,规则处理和报警等。

– Prometheus targets:
静态收集的目标服务数据。

– service discovery:
动态服务发现。

– Client Library:
客户端库,为需要监控的服务生成相应的metrics并暴露给Prometheus Server。
当Prometheus Server来pull时,直接返回实时状态的metrics。

– Push Gateway:
exporter采集型已经很丰富,但是依然需要很多自定义的监控数据,由pushgateway可以实现自定义的监控数据,任意灵活想做什么都可以做到。
exporter的开发需要使用真正的编程语音,不支持shell这种脚本,而pushgateway开发却容易的多。
pushgateway主要用于短期的jobs,由于这类jobs存在时间较短,可能是Prometheus来pull之前就消失了。为此,这次jobs可以直接向Prometheus server端推送它们的metrics,这种凡是主要用于服务层面的metrics,对于机器层面的metrics,需要使用node exporter。

– Exporters:
部署第三方软件主机上,用于暴露已有的第三方服务的metrics给Prometheus。

– Altermanager:
从Prometheus Server端接收到alters后,会进行去除重复数据,分组,并路由到对应的接收方式,以高效向用户完成告警信息发送。常见的方式有: 电子邮件,pagerduty,OpsGenie,Webhook等一些其他的工具。

– Data Visualization:
Prometheus Web UI(Prometheus Server内置的界面),Grafana(第三方可视化组件,需要单独部署)。

– Server Discovery:
动态发现待监控的Target,从而完成监控配置的重要组件,在容器化环境中尤为有用,该组件目前由Prometheus Server内建支持。

上述组件中,大多数都是用Go编写的,因此易于构建和部署为二进制文件。
参考地址:
https://prometheus.io/docs/introduction/overview/
https://github.com/prometheus/prometheus

“`

## 3 二进制部署prometheus

“`sh
wget https://github.com/prometheus/prometheus/releases/download/v2.53.3/prometheus-2.53.3.linux-amd64.tar.gz

tar xf prometheus-2.53.3.linux-amd64/ -C /software

/software/prometheus/prometheus

“`

## 4 脚本部署prometheus

“`sh
1 上传tar.gz包
tar -tf install-prometheus-server-v2.53.3.tar.gz
./download/
./download/prometheus-2.53.3.linux-amd64.tar.gz
./install-prometheus-server.sh

2 解压安装
./install-prometheus-server.sh i

3 访问webUI
http://192.168.137.31:9090

4 如果要卸载
./install-prometheus-server.sh r

5 脚本内容
cat install-prometheus-server.sh
#!/bin/bash

VERSION=2.53.3
ARCH=amd64
SOFTWARE=prometheus-${VERSION}.linux-${ARCH}.tar.gz
URL=https://github.com/prometheus/prometheus/releases/download/v${VERSION}/${SOFTWARE}
DOWNLOAD=./download
INSTALLDIR=/software
BASEDIR=${INSTALLDIR}/prometheus-${VERSION}.linux-amd64
DATADIR=/prometheus/data/prometheus
LOGDIR=/prometheus/logs/prometheus
HOSTIP=0.0.0.0
PORT=9090
HOSTNAME=`hostname`

function prepare() {
# 判断目录是否存在,若不存在则创建
[ -d $INSTALLDIR ] || install -d ${INSTALLDIR}
[ -d $DOWNLOAD ] || install -d ${DOWNLOAD}
[ -d $DATADIR ] || install -d ${DATADIR}
[ -d $LOGDIR ] || install -d ${LOGDIR}

. /etc/os-release

if [ “$ID” == “centos” ];then
# 判断系统是否安装wget
[ -f /usr/bin/wget ] || yum -y install wget
fi

# 判断文件是否存在,若不存在则下载
[ -s ${DOWNLOAD}/${SOFTWARE} ] || wget $URL -O ${DOWNLOAD}/${SOFTWARE}

}

function deploy() {
# 检查环境
prepare

# 解压文件软件包
tar xf ${DOWNLOAD}/${SOFTWARE} -C ${INSTALLDIR}

# 生成启动脚本
cat > /etc/systemd/system/prometheus-server.service <> ${LOGDIR}/prometheus-server.log”
ExecReload=/bin/kill -HUP \$MAINPID
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

# 将服务设置为开机自启动
systemctl daemon-reload
systemctl enable –now prometheus-server
systemctl status prometheus-server
sleep 5
ss -ntl | grep ${PORT}
}

function delete(){
systemctl disable –now prometheus-server.service
rm -rf /etc/systemd/system/node-exporter.service $BASEDIR $DATADIR $LOGDIR
}

function main() {
case $1 in
deploy|i)
deploy
echo “脚本: ${HOSTNAME} 的prometheus-server 已经部署成功![successfully]”
;;
delete|r)
delete
echo “脚本: ${HOSTNAME} 的prometheus-server 已经卸载成功,期待下次使用~”
;;
*)
echo “Usage: $0 deploy[i]|delete[r]”
;;
esac
}

main $1
“`

![image-20250320212744495](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320212744495.png)

## 5 脚本部署node-exporter

“`sh
1 上传tar.gz包
tar -tf install-node-exporter-v1.8.2.tar.gz
./download/
./download/node_exporter-1.8.2.linux-amd64.tar.gz
./install-node-exporter.sh

2 解压安装
./install-node-exporter.sh i

3 访问webUI
http://192.168.137.41:9100/metric
http://192.168.137.42:9100/metric
http://192.168.137.43:9100/metric

4 如果要卸载
./install-node-exporter.sh r

5 脚本内容
cat install-node-exporter.sh
#!/bin/bash
VERSION=1.8.2
SOFTWARE=node_exporter-${VERSION}.linux-amd64.tar.gz
URL=https://github.com/prometheus/node_exporter/releases/download/v${VERSION}/${SOFTWARE}
DOWNLOAD=./download
INSTALLDIR=/software
BASEDIR=${INSTALLDIR}/node_exporter-${VERSION}.linux-amd64
HOST=”0.0.0.0″
PORT=9100
hostname=`hostname`

function prepare() {
# 判断目录是否存在,若不存在则创建
[ -d $INSTALLDIR ] || mkdir -pv ${INSTALLDIR}
[ -d $DOWNLOAD ] || mkdir -pv ${DOWNLOAD}

if [ “$ID” == “centos” ];then
# 判断系统是否安装curl
[ -f /usr/bin/wget ] || yum -y install wget
fi

# 判断文件是否存在,若不存在则下载
[ -s ${DOWNLOAD}/${SOFTWARE} ] || wget $URL -O ${DOWNLOAD}/${SOFTWARE}
}

function install() {
# 检查环境
prepare

# 解压文件软件包
tar xf ${DOWNLOAD}/${SOFTWARE} -C ${INSTALLDIR}

# 生成启动脚本
cat > /etc/systemd/system/node-exporter.service < 500):
假设tcp_wait_conn是咱们自定义的KEY。
若TCP等待数量大于500的机器数量就判断条件为真。

count(rate(node_cpu_seconds_total{cpu=”0″,mode=”idle”}[1m]))
对统计的结果进行计数。

7 其他函数
推荐阅读:
https://prometheus.io/docs/prometheus/latest/querying/functions/

– 监控CPU的使用情况案例
1 统计各个节点CPU的使用率
1.1 我们需要先找到CPU相关的KEY
node_cpu_seconds_total

1.2 过滤出CPU的空闲时间({mode=’idle’})和全部CPU的时间(‘{}’)
node_cpu_seconds_total{mode=’idle’}
过滤CPU的空闲时间。
node_cpu_seconds_total{}
此处的'{}’可以不写,因为里面没有任何参数,代表获取CPU的所有状态时间。

1.3 统计1分钟内CPU的增量时间
increase(node_cpu_seconds_total{mode=’idle’}[1m])
统计1分钟内CPU空闲状态的增量。
increase(node_cpu_seconds_total[1m])
统计1分钟内CPU所有状态的增量。

1.4 将结果进行加和统计
sum(increase(node_cpu_seconds_total{mode=’idle’}[1m]))
将1分钟内所有CPU空闲时间的增量进行加和计算。
sum(increase(node_cpu_seconds_total[1m]))
将1分钟内所有CPU空闲时间的增量进行加和计算。

1.5 按照不同节点进行分组
sum(increase(node_cpu_seconds_total{mode=’idle’}[1m])) by (instance)
将1分钟内所有CPU空闲时间的增量进行加和计算,并按照机器实例进行分组。
sum(increase(node_cpu_seconds_total[1m])) by (instance)
将1分钟内所有CPU空闲时间的增量进行加和计算,并按照机器实例进行分组。

1.6 计算1分钟内CPU空闲时间的百分比
sum(increase(node_cpu_seconds_total{mode=’idle’}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)

1.7 统计1分钟内CPU的使用率,计算公式: (1 – CPU空闲时间的百分比) * 100%。
(1 – sum(increase(node_cpu_seconds_total{mode=’idle’}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100

1.8 统计1小时内CPU的使用率,计算公式: (1 – CPU空闲时间的百分比) * 100%。
(1 – sum(increase(node_cpu_seconds_total{mode=’idle’}[1h])) by (instance) / sum(increase(node_cpu_seconds_total[1h])) by (instance)) * 100

2 计算CPU用户态的1分钟内百分比
sum(increase(node_cpu_seconds_total{mode=’user’}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance) * 100

3 计算CPU内核态的1分钟内百分比
(sum(increase(node_cpu_seconds_total{mode=’system’}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100

4 计算CPU IO等待时间的1分钟内百分比
(sum(increase(node_cpu_seconds_total{mode=’iowait’}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100

5 通过top指令查看CPU
top
“`

![image-20250320220120547](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320220120547.png)

## 9 grafana基于mysql作为数据存储添加prometheus

“`sh
1 查看官网
https://grafana.com/grafana/download/9.5.21?pg=graf&plcmt=deploy-box-1

2 下载安装依赖和grafana
sudo apt-get install -y adduser libfontconfig1 musl
wget https://dl.grafana.com/enterprise/release/grafana-enterprise_9.5.21_amd64.deb
sudo dpkg -i grafana-enterprise_9.5.21_amd64.deb

3 docker部署mysql
docker load < mysql-v8.0.36-oracle.tar.gz fc037c17567d: Loading layer 118.8MB/118.8MB 152c1ecea280: Loading layer 11.26kB/11.26kB fb5c92e924ab: Loading layer 2.359MB/2.359MB 5b76076a2dd4: Loading layer 13.86MB/13.86MB a6909c467615: Loading layer 6.656kB/6.656kB eaa1e85de732: Loading layer 3.072kB/3.072kB 9513d2aedd12: Loading layer 185.6MB/185.6MB 84d659420bad: Loading layer 3.072kB/3.072kB 876b8cd855eb: Loading layer 298.7MB/298.7MB 1c0ff7ed67c4: Loading layer 16.9kB/16.9kB 318dde184d61: Loading layer 1.536kB/1.536kB Loaded image: mysql:8.0.36-oracle 4 启动mysql docker run -d --name mysql-server --restart always --network host -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -e MYSQL_DATABASE=prometheus -e MYSQL_USER=ysl -e MYSQL_PASSWORD=123456 mysql:8.0.36-oracle --character-set-server=utf8 --collation-server=utf8_bin --default-authentication-plugin=mysql_native_password 5 修改grafana配置文件 vim /etc/grafana/grafana.ini ... type = mysql host = 10.0.0.43:3306 name = prometheus user = ysl password = 123456 6 启动grafana systemctl restart grafana-server.service ss -ntl | grep 3000 LISTEN 0 4096 *:3000 *:* 7.登录Grafana的webUI http://10.0.0.31:3000/ ``` ![image-20250320224003443](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320224003443.png) ## 10 grafana使用 ### 1 添加prometheus ![image-20250320224404386](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320224404386.png) ![image-20250320224430378](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320224430378.png) ![image-20250320224528821](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320224528821.png) ![image-20250320224600031](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320224600031.png) ### 2 添加dashboard ![image-20250320224723160](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320224723160.png) ![image-20250320224742808](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250320224742808.png) ![image-20250321103350589](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321103350589.png) ![image-20250321104835583](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321104835583.png) ![image-20250321104418308](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321104418308.png) ### 3 继续添加dashboard ![image-20250321104513530](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321104513530.png) ### 4 保存dashboard ![image-20250321105619856](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321105619856.png) ![image-20250321105734581](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321105734581.png) ![image-20250321105751437](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321105751437.png) ### 5 重新打开grafana查看刚刚保存的dashboard ![image-20250321111736157](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321111736157.png) ### 6 添加ROW 添加row后可折叠 ![image-20250321111948631](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321111948631.png) ![image-20250321112023191](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321112023191.png) ![image-20250321112154431](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321112154431.png) ### 7 grafana 表格定义 #### 1 添加可视化 ![image-20250321112628589](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321112628589.png) #### 2 查询服务器信息 node_boot_time_seconds avg(node_uname_info) by (instance,nodename,release) ![image-20250321112948035](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321112948035.png) ![image-20250321113020884](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321113020884.png) ![image-20250321114136180](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321114136180.png) ```sh 找到transform,查找filter by name,这里几个参数都是对应图中的小标题,这里小标题不人性化,可以重新设置 ``` ![image-20250321115835568](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321115835568.png) ![image-20250321115933440](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321115933440.png) ![image-20250321120009678](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321120009678.png) ![image-20250321120149993](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321120149993.png) ![image-20250321120328044](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321120328044.png) ![image-20250321120431497](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321120431497.png) ```sh 此时instance小标题就变成了修改的标题,按照此方法一直添加、修改 ``` ![image-20250321120748972](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321120748972.png) #### 3 复制表格 ![image-20250321121205882](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321121205882.png) #### 4 合并 ![image-20250321121617681](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321121617681.png) ![image-20250321121704128](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321121704128.png) ![image-20250321121909641](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321121909641.png) #### 5 panel改名 ![image-20250321122002201](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321122002201.png) ![image-20250321122157294](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321122157294.png) ![image-20250321122325536](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321122325536.png) ```sh 参考链接: https://www.cnblogs.com/yinzhengjie/p/18538430 ``` 同样方法增加cpu使用率(1 - avg(rate(node_cpu_seconds_total{mode="idle"}[1m])) by (instance)) * 100 内存大小 node_memory_MemTotal_bytes-0 增加内存时要注意:以下图解 ![image-20250321124720154](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321124720154.png) ![image-20250321125049833](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321125049833.png) ![image-20250321125233877](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321125233877.png) 再统计内存使用率 (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes))*100 网卡出流量max(rate(node_network_transmit_bytes_total[1m])) by (instance) ![image-20250321130045485](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321130045485.png) #### 6 配置阈值和配色 ![image-20250321130354715](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321130354715.png) ![image-20250321130436197](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321130436197.png) ![image-20250321130525137](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321130525137.png) ```sh 此处做一个测试,再node-exporter41上做压测,看是否会变成红色 stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 1m ``` ![image-20250321130853822](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321130853822.png) ## 8 grafana自定义变量 ![image-20250321145120549](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321145120549.png) ![image-20250321145143760](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321145143760.png) ![image-20250321145838991](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321145838991.png) ![image-20250321145931607](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321145931607.png) metric配置为{job="node-exporter"} node-exporter是从prometheus来的 ![image-20250321150452714](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321150452714.png) ![image-20250321150402838](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321150402838.png) ![image-20250321151009769](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321151009769.png) 修改以前配置的dashboard,将变量写入以前配置文件中 ![image-20250321151500522](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321151500522.png) ```sh 计算CPU IO等待时间的1分钟内百分比 (sum(increase(node_cpu_seconds_total{mode='iowait',instance="$host"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100 ``` ![image-20250321151547891](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321151547891.png) ```sh 统计一分钟内cpu的使用率 (1 - sum(increase(node_cpu_seconds_total{mode='idle',instance='$host'}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100 ``` ![image-20250321151656996](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321151656996.png) ```sh 计算CPU IO等待时间的1分钟内百分比 (sum(increase(node_cpu_seconds_total{mode='iowait',instance='$host'}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100 ``` ![image-20250321151958353](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321151958353.png) ```sh 计算CPU内核态的1分钟内百分比 (sum(increase(node_cpu_seconds_total{mode='system',instance='$host'}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100 ``` ![image-20250321152050210](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321152050210.png) 最后选择查看 ![image-20250321152202491](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321152202491.png) ## 9 grafana dashboard备份和恢复 ### 1 备份 #### 1 下载json备份 ![image-20250321153008234](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153008234.png) ![image-20250321153042987](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153042987.png) #### 2 import 备份 ![image-20250321153150346](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153150346.png) ![image-20250321153225170](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153225170.png) ### 2 恢复 #### 1 删除 ![image-20250321153504812](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153504812.png) ![image-20250321153544852](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153544852.png) #### 2 恢复 ![image-20250321153634481](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153634481.png) ![image-20250321153704739](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153704739.png) ![image-20250321153742565](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153742565.png) ![image-20250321153807331](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321153807331.png) ```sh { "annotations": { "list": [ { "builtIn": 1, "datasource": { "type": "grafana", "uid": "-- Grafana --" }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "type": "dashboard" } ] }, "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, "id": 3, "links": [], "liveNow": false, "panels": [ { "collapsed": true, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 8, "panels": [ { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "custom": { "align": "auto", "cellOptions": { "type": "auto" }, "inspect": false }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green" }, { "color": "red", "value": 80 } ] } }, "overrides": [ { "matcher": { "id": "byName", "options": "instance" }, "properties": [ { "id": "displayName", "value": "服务器IP" } ] }, { "matcher": { "id": "byName", "options": "Time" }, "properties": [ { "id": "displayName", "value": "开机时间" } ] }, { "matcher": { "id": "byName", "options": "nodename" }, "properties": [ { "id": "displayName", "value": "主机名" } ] }, { "matcher": { "id": "byName", "options": "release" }, "properties": [ { "id": "displayName", "value": "内核版本" } ] }, { "matcher": { "id": "byName", "options": "Value #load" }, "properties": [ { "id": "displayName", "value": "负载" } ] }, { "matcher": { "id": "byName", "options": "Value #core" }, "properties": [ { "id": "displayName", "value": "CPU使用率" }, { "id": "custom.cellOptions", "value": { "type": "color-background" } } ] }, { "matcher": { "id": "byName", "options": "Value #Memory" }, "properties": [ { "id": "unit", "value": "bytes" }, { "id": "displayName", "value": "内存总量" } ] }, { "matcher": { "id": "byName", "options": "Value #Memory Used" }, "properties": [ { "id": "displayName", "value": "内存使用率" } ] }, { "matcher": { "id": "byName", "options": "Value #NetWork" }, "properties": [ { "id": "displayName", "value": "网卡流量" }, { "id": "unit", "value": "bytes" } ] } ] }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 1 }, "id": 7, "options": { "cellHeight": "sm", "footer": { "countRows": false, "fields": "", "reducer": [ "sum" ], "show": false }, "showHeader": true }, "pluginVersion": "9.5.21", "targets": [ { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "exemplar": false, "expr": "avg(node_uname_info) by (instance,nodename,release)", "format": "table", "instant": true, "legendFormat": "__auto", "range": false, "refId": "kernel" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "exemplar": false, "expr": "node_load5-0", "format": "table", "hide": false, "instant": true, "legendFormat": "__auto", "range": false, "refId": "load" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "exemplar": false, "expr": "(1 - avg(rate(node_cpu_seconds_total{mode=\"idle\"}[1m])) by (instance)) * 100", "format": "table", "hide": false, "instant": true, "legendFormat": "__auto", "range": false, "refId": "core" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "exemplar": false, "expr": "node_memory_MemTotal_bytes-0", "format": "table", "hide": false, "instant": true, "legendFormat": "__auto", "range": false, "refId": "Memory" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "exemplar": false, "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes))*100", "format": "table", "hide": false, "instant": true, "legendFormat": "__auto", "range": false, "refId": "Memory Used" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "exemplar": false, "expr": "max(rate(node_network_transmit_bytes_total[1m])) by (instance)", "format": "table", "hide": false, "instant": true, "legendFormat": "__auto", "range": false, "refId": "NetWork" } ], "title": "服务器集群概览", "transformations": [ { "id": "filterFieldsByName", "options": { "include": { "names": [ "Time", "instance", "nodename", "release", "Value #load", "Value #core", "Value #Memory", "Value #Memory Used", "Value #NetWork" ] } } }, { "id": "merge", "options": {} } ], "transparent": true, "type": "table" } ], "title": "Overview", "type": "row" }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 1 }, "id": 6, "panels": [], "title": "CPU监控", "type": "row" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [ { "__systemRef": "hideSeriesFrom", "matcher": { "id": "byNames", "options": { "mode": "exclude", "names": [ "10.0.0.41:9100" ], "prefix": "All except:", "readOnly": true } }, "properties": [ { "id": "custom.hideFrom", "value": { "legend": false, "tooltip": false, "viz": true } } ] } ] }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 2 }, "id": 5, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "expr": "(sum(increase(node_cpu_seconds_total{mode='iowait',instance=\"$host\"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100\r\n", "legendFormat": "__auto", "range": true, "refId": "A" } ], "title": "计算CPU IO等待时间的1分钟内百分比", "transparent": true, "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 2 }, "id": 1, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "expr": "(1 - sum(increase(node_cpu_seconds_total{mode='idle',instance='$host'}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100\r\n", "legendFormat": "__auto", "range": true, "refId": "A" } ], "title": "统计一分钟内cpu的使用率", "transparent": true, "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 10 }, "id": 4, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "expr": "(sum(increase(node_cpu_seconds_total{mode='iowait',instance='$host'}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100\r\n", "legendFormat": "__auto", "range": true, "refId": "A" } ], "title": "计算CPU IO等待时间的1分钟内百分比", "transparent": true, "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 10 }, "id": 3, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "editorMode": "code", "expr": "(sum(increase(node_cpu_seconds_total{mode='system',instance='$host'}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)) * 100\r\n", "legendFormat": "__auto", "range": true, "refId": "A" } ], "title": "计算CPU内核态的1分钟内百分比", "transparent": true, "type": "timeseries" } ], "refresh": "", "schemaVersion": 38, "style": "dark", "tags": [], "templating": { "list": [ { "current": { "selected": false, "text": "10.0.0.41:9100", "value": "10.0.0.41:9100" }, "datasource": { "type": "prometheus", "uid": "c2807b1d-1750-4ac6-905d-29467a8acb1f" }, "definition": "label_values({job=\"node-exporter\"},instance)", "description": "需要查看的具体主机的IP地址", "hide": 0, "includeAll": false, "label": "选择查询节点", "multi": false, "name": "host", "options": [], "query": { "query": "label_values({job=\"node-exporter\"},instance)", "refId": "PrometheusVariableQueryEditor-VariableQuery" }, "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 0, "type": "query" } ] }, "time": { "from": "2025-03-21T02:43:07.257Z", "to": "2025-03-21T02:46:44.145Z" }, "timepicker": {}, "timezone": "", "title": "自定义dashboard-cpu", "uid": "f0b29f48-f63b-422f-a9b7-85702ad5a6c0", "version": 4, "weekStart": "" } ``` ## 10 导入第三方Node Exporter ![image-20250321154241515](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321154241515.png) ![image-20250321154425025](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321154425025.png) 去官网查自己想要的模版,记录id号 ![image-20250321154735800](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321154735800.png) ![image-20250321154837132](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321154837132.png) ![image-20250321154901830](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321154901830.png) ![image-20250321154915855](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321154915855.png) 可以每个点进去查看PromQL,然后借鉴 ## 11 node exporter ```sh node exporter整个流程 1 主要作用,采集linux的一些指标,内存,磁盘,网络等,通过http端口9100暴露出去 2 prometheus采集node exporter指标保存到本地,prometheus配置了配置文件,指向了node exporter 3 grafana配置数据源指向prometheus,展示数据 4 grafana 定义变量、dashboard、行信息等 5 从官网导入模版,修改 ``` ## 12 prometheus监控 ### 1 监控windows ```sh 1 官网下载安装包 2 windows运行 ``` ![image-20250321162603689](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321162603689.png) ```sh 3 修改prometheus配置文件 vim /software/prometheus-2.53.3.linux-amd64/prometheus.yml ... - job_name: "windows-exporter" static_configs: - targets: ["192.168.137.254:9182"] 4 热加载prometheus curl -X POST 10.0.0.31:9090/-/reload 5 prometheus 查看 6 官网下载windows模版 20763 ``` ![image-20250321163459795](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321163459795.png) ![image-20250321163754243](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250321163754243.png) ### 2 监控zookeeper集群 1 zookeeper启用metrc指标 ```sh zookeeper每个阶段执行以下命令 cat >>/software/zookeeper/conf/zoo.cfg<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml< create user ‘exporter’@’%’ identified by ‘123456’ with max_user_connections 3;
Query OK, 0 rows affected (0.08 sec)

mysql> GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO ‘exporter’@’%’;
Query OK, 0 rows affected (0.01 sec)

5 启动mysql_expoerter
root@node-exporter43:~# cat >>/etc/.my.cnf<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/sd/file-sd-yaml.yaml <>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml <>/software/prometheus-2.53.3.linux-amd64/sd/file-sd-yaml-node_exporter.yaml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml <>/software/prometheus-2.53.3.linux-amd64/prometheus.yml< /etc/systemd/system/pushgatway.service <>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/alertmanager-0.27.0.linux-amd64/alertmanager.yml<>/software/prometheus-2.53.3.linux-amd64/prometheus.yml<>/software/prometheus-2.53.3.linux-amd64/email-rules.yml< }}
– 指标样本值引用: {{ $value }}

为了显式效果,需要了解一些html相关技术,参考链接:
https://www.w3school.com.cn/html/index.asp

2 altertmanger节点自定义告警模板参考案例
2.1 自定义邮件模板
[root@prometheus-server32]# cat >/software/alertmanager-0.27.0.linux-amd64/email.tmpl<alertmanager_test/

{{ range \$i, \$alert := .Alerts }}

{{ end }}

报警项 实例 报警阀值 开始时间
{{ index \$alert.Labels “alertname” }} {{ index \$alert.Labels “instance” }} {{ index \$alert.Annotations “value” }} {{ \$alert.StartsAt }}

{{ end }}
EOF

2.2 alermanager引用自定义模板文件
[root@prometheus-server32 alertmanager-0.27.0.linux-amd64]# cat >>/software/alertmanager-0.27.0.linux-amd64/alertmanager.yml <>/software/alertmanager-0.27.0.linux-amd64/alertmanager.yml< /etc/systemd/system/victoria-metrics.service <>/software/prometheus-2.53.3.linux-amd64/prometheus.yml< etcd-ca-csr.json < ca-config.json < etcd-csr.json < /software/etcd/etcd.config.yml <<'EOF' name: 'node-exporter41' data-dir: /var/lib/etcd wal-dir: /var/lib/etcd/wal snapshot-count: 5000 heartbeat-interval: 100 election-timeout: 1000 quota-backend-bytes: 0 listen-peer-urls: 'https://10.0.0.41:2380' listen-client-urls: 'https://10.0.0.41:2379,http://127.0.0.1:2379' max-snapshots: 3 max-wals: 5 cors: initial-advertise-peer-urls: 'https://10.0.0.41:2380' advertise-client-urls: 'https://10.0.0.41:2379' discovery: discovery-fallback: 'proxy' discovery-proxy: discovery-srv: initial-cluster: 'node-exporter41=https://10.0.0.41:2380,node-exporter42=https://10.0.0.42:2380,node-exporter43=https://10.0.0.43:2380' initial-cluster-token: 'etcd-k8s-cluster' initial-cluster-state: 'new' strict-reconfig-check: false enable-v2: true enable-pprof: true proxy: 'off' proxy-failure-wait: 5000 proxy-refresh-interval: 30000 proxy-dial-timeout: 1000 proxy-write-timeout: 5000 proxy-read-timeout: 0 client-transport-security: cert-file: '/software/certs/etcd/etcd-server.pem' key-file: '/software/certs/etcd/etcd-server-key.pem' client-cert-auth: true trusted-ca-file: '/software/certs/etcd/etcd-ca.pem' auto-tls: true peer-transport-security: cert-file: '/software/certs/etcd/etcd-server.pem' key-file: '/software/certs/etcd/etcd-server-key.pem' peer-client-cert-auth: true trusted-ca-file: '/software/certs/etcd/etcd-ca.pem' auto-tls: true debug: false log-package-levels: log-outputs: [default] force-new-cluster: false EOF 5.2 node-exporter42节点的配置文件 root@node-exporter42:~# mkdir -pv /software/etcd root@node-exporter42:~# cat > /software/etcd/etcd.config.yml < /software/etcd/etcd.config.yml < /usr/lib/systemd/system/etcd.service <<'EOF' [Unit] Description=Etcd Service Documentation=https://coreos.com/etcd/docs/latest/ After=network.target [Service] Type=notify ExecStart=/usr/local/bin/etcd --config-file=/software/etcd/etcd.config.yml Restart=on-failure RestartSec=10 LimitNOFILE=65536 [Install] WantedBy=multi-user.target Alias=etcd3.service EOF 7.启动etcd集群 systemctl daemon-reload && systemctl enable --now etcd systemctl status etcd 8 查看集群状态 root@node-exporter43:~# etcdctl --endpoints="10.0.0.41:2379,10.0.0.42:2379,10.0.0.43:2379" --cacert=/software/certs/etcd/etcd-ca.pem --cert=/software/certs/etcd/etcd-server.pem --key=/software/certs/etcd/etcd-server-key.pem endpoint status --write-out=table +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | 10.0.0.41:2379 | 9378902f41df91e9 | 3.5.17 | 20 kB | true | false | 2 | 9 | 9 | | | 10.0.0.42:2379 | 18f972748ec1bd96 | 3.5.17 | 25 kB | false | false | 2 | 9 | 9 | | | 10.0.0.43:2379 | a3dfd2d37c461ee9 | 3.5.17 | 20 kB | false | false | 2 | 9 | 9 | | +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ 9.验证etcd高可用集群 9.1 停止leader节点 root@node-exporter41:~# systemctl stop etcd root@node-exporter41:~# etcdctl --endpoints="10.0.0.41:2379,10.0.0.42:2379,10.0.0.43:2379" --cacert=/software/certs/etcd/etcd-ca.pem --cert=/software/certs/etcd/etcd-server.pem --key=/software/certs/etcd/etcd-server-key.pem endpoint status --write-out=table {"level":"warn","ts":"2025-03-26T17:22:59.961827+0800","logger":"etcd-client","caller":"v3@v3.5.17/retry_interceptor.go:63","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc0002845a0/10.0.0.41:2379","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 10.0.0.41:2379: connect: connection refused\""} Failed to get the status of endpoint 10.0.0.41:2379 (context deadline exceeded) +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | 10.0.0.42:2379 | 18f972748ec1bd96 | 3.5.17 | 25 kB | true | false | 3 | 10 | 10 | | | 10.0.0.43:2379 | a3dfd2d37c461ee9 | 3.5.17 | 20 kB | false | false | 3 | 10 | 10 | | +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ 10 etcd的基本使用 1 配置别名 每个节点执行 root@node-exporter43:~# tail -1 .bashrc alias etcdctl='etcdctl --endpoints="10.0.0.41:2379,10.0.0.42:2379,10.0.0.43:2379" --cacert=/software/certs/etcd/etcd-ca.pem --cert=/software/certs/etcd/etcd-server.pem --key=/software/certs/etcd/etcd-server-key.pem' root@node-exporter43:~#etcdctl endpoint status --write-out=table 2 查看集群状态 2.1 写入数据KEY的school,value等于xiaoxue [root@node-exporter42 ~]# etcdctl put school xiaoxue OK [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl put scheduler 调度器 OK [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl put class Linux OK [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl put service 服务 OK [root@node-exporter42 ~]# 2.2 查看数据 [root@node-exporter42 ~]# etcdctl get school school xiaoxue [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl get school --keys-only school [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl get school --print-value-only xiaoxue [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl get sch --prefix --keys-only # 匹配"sch"开头的key scheduler school [root@node-exporter42 ~]# [root@node-exporter42 ~]# 2.3 修改数据 [root@node-exporter42 ~]# etcdctl get school --print-value-only xiaoxue [root@node-exporter42 ~]# [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl put school laonanhai # 如果key的值是存在,则直接覆盖 OK [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl get school --print-value-only laonanhai [root@node-exporter42 ~]# 2.4 删除数据 [root@node-exporter42 ~]# etcdctl get sch --prefix --keys-only scheduler school [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl del school 1 [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl get sch --prefix --keys-only scheduler [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl del sch --prefix 1 [root@node-exporter42 ~]# [root@node-exporter42 ~]# etcdctl get sch --prefix --keys-only ``` ## 24 etcd数据备份恢复 ```sh 1 拷贝程序 root@node-exporter43:~# scp /usr/local/bin/etcd* 10.0.0.32:/usr/local/bin/ 2.准备证书文件 2.1 安装cfssl证书管理工具 root@prometheus-server32:~# unzip cfssl-v1.6.5.zip root@prometheus-server32:~# rename -v "s/_1.6.5_linux_amd64//g" cfssl* root@prometheus-server32:~# mv cfssl* /usr/local/bin/ root@prometheus-server32:~# chmod +x /usr/local/bin/cfssl* 3 创建证书存储目录 root@prometheus-server32:~# mkdir -pv /software/certs/etcd && cd /software/certs/etcd/ 4 生成证书的CSR文件: 证书签发请求文件,配置了一些域名,公司,单位 root@prometheus-server32:/software/certs/etcd# cat > etcd-ca-csr.json < ca-config.json < etcd-csr.json < /software/etcd/etcd.config.yml <<'EOF' name: 'prometheus-server32' data-dir: /var/lib/etcd wal-dir: /var/lib/etcd/wal snapshot-count: 5000 heartbeat-interval: 100 election-timeout: 1000 quota-backend-bytes: 0 listen-peer-urls: 'https://10.0.0.32:2380' listen-client-urls: 'https://10.0.0.32:2379,http://127.0.0.1:2379' max-snapshots: 3 max-wals: 5 cors: initial-advertise-peer-urls: 'https://10.0.0.32:2380' advertise-client-urls: 'https://10.0.0.32:2379' discovery: discovery-fallback: 'proxy' discovery-proxy: discovery-srv: initial-cluster: 'prometheus-server32=https://10.0.0.32:2380' initial-cluster-token: 'etcd-k8s-cluster' initial-cluster-state: 'new' strict-reconfig-check: false enable-v2: true enable-pprof: true proxy: 'off' proxy-failure-wait: 5000 proxy-refresh-interval: 30000 proxy-dial-timeout: 1000 proxy-write-timeout: 5000 proxy-read-timeout: 0 client-transport-security: cert-file: '/software/certs/etcd/etcd-server.pem' key-file: '/software/certs/etcd/etcd-server-key.pem' client-cert-auth: true trusted-ca-file: '/software/certs/etcd/etcd-ca.pem' auto-tls: true peer-transport-security: cert-file: '/software/certs/etcd/etcd-server.pem' key-file: '/software/certs/etcd/etcd-server-key.pem' peer-client-cert-auth: true trusted-ca-file: '/software/certs/etcd/etcd-ca.pem' auto-tls: true debug: false log-package-levels: log-outputs: [default] force-new-cluster: false EOF 10 准备启动脚本 root@prometheus-server32:/software/certs/etcd#cat > /usr/lib/systemd/system/etcd.service <<'EOF' [Unit] Description=Etcd Service Documentation=https://coreos.com/etcd/docs/latest/ After=network.target [Service] Type=notify ExecStart=/usr/local/bin/etcd --config-file=/software/etcd/etcd.config.yml Restart=on-failure RestartSec=10 LimitNOFILE=65536 [Install] WantedBy=multi-user.target Alias=etcd3.service EOF 11 启动etcd集群 systemctl daemon-reload && systemctl enable --now etcd systemctl status etcd 12 添加别名 root@prometheus-server32:/software/certs/etcd# tail -1 /root/.bashrc alias etcdctl='etcdctl --endpoints="10.0.0.32:2379" --cacert=/software/certs/etcd/etcd-ca.pem --cert=/software/certs/etcd/etcd-server.pem --key=/software/certs/etcd/etcd-server-key.pem' root@prometheus-server32:/software/certs/etcd# source /root/.bashrc 13 查看etcd状态 root@prometheus-server32:/software/certs/etcd# etcdctl endpoint status --write-out=table +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | 10.0.0.32:2379 | b58958a430a55e35 | 3.5.17 | 25 kB | true | false | 2 | 4 | 4 | | +----------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ 14 43节点创建快照 root@node-exporter43:~# \etcdctl snapshot save /tmp/etcd.backup 15 将快照文件发送到32节点 root@node-exporter43:~# scp /tmp/etcd.backup root@10.0.0.32:~ 16 32节点停止etcd服务 root@prometheus-server32:~# systemctl stop etcd 17 32节点备份etcd的源数据目录 root@prometheus-server32:~# mv /var/lib/etcd/ /var/lib/etcd-bak 18 32节点恢复数据【恢复的数据目录必须为空】 root@prometheus-server32:~# etcdctl snapshot restore etcd.backup --data-dir=/var/lib/etcd/ root@prometheus-server32:~# ll /var/lib/etcd total 12 drwx------ 3 root root 4096 Mar 26 21:57 ./ drwxr-xr-x 43 root root 4096 Mar 26 21:57 ../ drwx------ 4 root root 4096 Mar 26 21:57 member/ 19 32节点启动etcd服务 root@prometheus-server32:~# systemctl start etcd root@prometheus-server32:~# systemctl status etcd ● etcd.service - Etcd Service Loaded: loaded (/lib/systemd/system/etcd.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2025-03-26 21:59:24 CST; 4s ago .... 20 验证数据是否恢复成功 root@prometheus-server32:~# etcdctl get service service 服务 ```

ELASTICSTACK

# 第一章 ElasticStack

## 1 概述

ElasticStack 表示的是一套技术栈,包括但不限于elasticsearch,Logstash,kibana,beats(filebeat,metricsbeat),filebeat采集数据,elastic存储数据,kibana展示数据

| 名字 | 说明 |
| ————– | ——————– |
| ElasticSrearch | 数据存储,检索 |
| Filebeat | 采集数据 |
| logstash | 数据拉取,转换,处理 |
| kibana | 数据展示 |
| kafka | 消息队列 |

## 2 ElasticSearch单机

“`sh
1 下载
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.26-amd64.deb
2 安装
dpkg -i elasticsearch-7.17.26-amd64.deb
3 配置
egrep ^[a-z] /etc/elasticsearch/elasticsearch.yml
cluster.name: ysl-forest
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 0.0.0.0
discovery.type: single-node

4 相关参数说明:
cluster.name
指定ES集群的名称

path.data
数据存储目录。

path.logs
表示日志存储目录。

network.host
暴露ES的IP地址。

discovery.type
部署ES的类型,此处表示的是单点。
5 启动服务
systemctl start elasticsearch.service
6 查看端口
ss -ntl | egrep “9[2|3]00”

7 端口说明:
9200:
对外提供服务的端口,支持http|https协议。

9300:
ES集群数据传输,master选举的端口,使用tcp协议。
8 访问查看
curl -X GET 10.0.0.91:9200/_cat/nodes
“`

## 3 ElasticSearch集群

“`sh
1 配置
grep ^[a-z] /etc/elasticsearch/elasticsearch.yml
cluster.name: ysl-forest
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 0.0.0.0
discovery.seed_hosts: [“10.0.0.91”, “10.0.0.92”,”10.0.0.93″]
cluster.initial_master_nodes: [“10.0.0.91”, “10.0.0.92”,”10.0.0.93″]

2 相关参数说明:
discovery.seed_hosts
当前集群的主机列表。

cluster.initial_master_nodes:
第一次启动时,可以选举为master的主机列表。
3 3个节点都配置
4 启动
systemctl start elasticsearch
5 访问每个节点
curl 10.0.0.91:9200
curl 10.0.0.92:9200
curl 10.0.0.93:9200
6 查看集群状态 每个节点均可执行
curl 10.0.0.93:9200/_cat/nodes?v
“`

## 4 脑裂快速解决方案

“`sh
1.停止所有节点的服务
systemctl stop elasticsearch.service

2.检查配置文件是否正确,每个节点执行,或者掉了哪个节点就在哪个节点执行
grep ^[a-z] /etc/elasticsearch/elasticsearch.yml
cluster.name: ysl-forest
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 0.0.0.0
discovery.seed_hosts: [“10.0.0.91”, “10.0.0.92”,”10.0.0.93″]
cluster.initial_master_nodes: [“10.0.0.91”, “10.0.0.92”,”10.0.0.93″]

3.清空有问题的数据
rm -rf /var/{lib,log}/elasticsearch/* /tmp/*
4.所有节点重启启动ES服务
systemctl start elasticsearch.service

5.验证测试
curl 10.0.0.93:9200/_cat/nodes?v
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
10.0.0.91 45 96 0 0.08 0.02 0.01 cdfhilmrstw * elk91
10.0.0.93 17 96 0 0.05 0.01 0.00 cdfhilmrstw – elk93
10.0.0.92 23 97 0 0.08 0.02 0.01 cdfhilmrstw – elk92

“`

## 5 ES常见术语

“`sh
– ES集群的常见术语
– 索引: index
索引是ES数据的存储逻辑单元,用于客户端的数据读写。

– 分片: shard
一个所有可以有1个或多个分片,可以实现数据的分布式存储。

– 副本: replica
副本分片,可以对分片数据进行备份,可以实现数据读取的负载均衡。

主分片负责数据的读写,而副本分片只能实现数据读取。

– 文档: document
是用户的实际存储数据。

文档存储在对应的分片中的。

文档中分为元数据和源数据。
元数据:用于描述源数据的数据。

源数据: 用户实际存储的数据。

面试题: ES集群的颜色有哪些?分别代表什么含义?
– GREEN:
表示健康状态,所有的主分片和副本分片均能正常访问。

– YELLOW:
表示亚健康状态,表示有部分副本分片无法访问。

– RED:
表示不健康状态,表示有部分主分片无法访问。
“`

## 6 部署kibana

“`sh
wget https://artifacts.elastic.co/downloads/kibana/kibana-7.17.26-amd64.deb
dpkg -i kibana-7.17.26-amd64.deb
grep ^[a-z] kibana.yml
server.port: 5601
server.host: “0.0.0.0”
elasticsearch.hosts: [“http://elk01:9200″,”http://elk02:9200″,”http://elk03:9200”]
i18n.locale: “zh-CN”
相关参数说明:
server.port
暴露的端口号。

server.host
监听的IP地址。

elasticsearch.hosts
ES集群的地址。

i18n.locale
指定语言。
systemctl start kibana
root@elk01:/etc/kibana# ss -ntl | grep 5601
“`

## 7 filebeat

“`sh
部署
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.17.26-amd64.deb
dpkg -i filebeat-7.17.26-amd64.deb
配置
cat /etc/filebeat/config/01-stdin-to-console.yaml
filebeat.inputs:
– type: stdin
output.console:
pretty: true
cat /etc/filebeat/config/01-stdin-to-console.yaml
filebeat.inputs:
– type: stdin
output.console:
pretty: true

[root@elk92 ~]# filebeat -e -c /etc/filebeat/config/01-stdin-to-console.yaml
“`

### 1 filebeat采集本地文件

“`sh
– filebeat采集本地文件案例
1.编写filebeat的配置文件
cat /etc/filebeat/config/02-log-to-console.yaml
filebeat.inputs:
– type: log
paths:
– /tmp/stu*.txt
output.console:
pretty: true

温馨提示:
– 1.filebeat默认按行读取数据;
– 2.如果filebeat数据目录不存在,则每次启动filebeat时会自动创建;
– 3.如果filebeat数据目录存在,则filebeat重启时并不会重复采集数据,如果想要从头采集数据,可以删除filebeat的数据目录
“`

### 2 filebeat采集数据到ES集群

“`sh
– filebeat采集数据到ES集群
1.编写配置文件
cat /etc/filebeat/config/03-log-to-es.yaml
filebeat.inputs:
– type: log
paths:
– /tmp/stu*.txt

output.elasticsearch:
hosts: [“http://10.0.0.91:9200″,”http://10.0.0.92:9200″,”http://10.0.0.93:9200”]
rm -rf /var/lib/filebeat/
filebeat -e -c /etc/filebeat/config/03-log-to-es.yaml

“`

kibana查看数据

![image-20250221161628563](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250221161628563.png)

![image-20250221161831747](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250221161831747.png)

![image-20250221163423092](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250221163423092.png)

### 3 filebeat自定义索引和分片副本

“`sh
1.编写filebeat的配置文件
cat /etc/filebeat/config/04-log-to-es_custom_index.yaml
filebeat.inputs:
– type: log
paths:
– /tmp/stu*.txt

output.elasticsearch:
hosts:
– “http://10.0.0.91:9200”
– “http://10.0.0.92:9200”
– “http://10.0.0.93:9200”
index: “ysl-forest-filebeat-%{+yyyy.MM.dd}”

# 禁用索引生命周期,若启用则自定义索引失效。
setup.ilm.enabled: false

# 索引模板的名称,可以自定义
setup.template.name: ysl-forest
# 定义索引的匹配模式
setup.template.pattern: “ysl-forest-filebeat*”
# 配置索引模板
setup.template.settings:
# 自定义索引的分片数量
index.number_of_shards: 3
# 自定义副本的数量
index.number_of_replicas: 0
# 如果索引模板已经存在,则覆盖已经存在的模板,默认值为false
# 生产环境中建议设置false,因为改为true会降低性能.
setup.template.overwrite: true

2.启动filebeat实例
filebeat -e -c /etc/filebeat/config/04-log-to-es_custom_index.yaml
“`

kibana查看

![image-20250224100354452](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224100354452.png)

![image-20250224120114438](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224120114438.png)

![image-20250224120224518](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224120224518.png)

![image-20250224120412203](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224120412203.png)

![image-20250224120512034](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224120512034.png)

![image-20250224120632310](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224120632310.png)

![image-20250224120602707](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224120602707.png)

### 4 filebeat采集nginx

“`sh
cat 05-nginx-to-es.yaml
filebeat.inputs:
– type: log
paths:
– /root/access.log*
output.elasticsearch:
hosts: [“http://10.0.0.91:9200″,”http://10.0.0.92:9200″,”http://10.0.0.93:9200”]
index: “ysl-nginx-accesslog-%{+yyyy.MM.dd}”

setup.ilm.enabled: false
setup.template.name: ysl-nginx
setup.template.pattern: ysl-nginx*
setup.template.settings:
index.number_of_shards: 3
index.number_of_replicas: 0
setup.template.overwrite: false
“`

### 5 多个filebeat输入源写入不同的es索引

“`sh
打标签tags
cat 06-multiple-input-to-es.yaml
filebeat.inputs:
– type: log
paths:
– /var/log/syslog*
tags: syslog
– type: log
paths:
– /var/log/kerne*
tags: messagelog
output.elasticsearch:
hosts:
– “http://10.0.0.91:9200”
– “http://10.0.0.92:9200”
– “http://10.0.0.93:9200”
indices:
– index: “ysl-syslog-%{+yyyy.MM.dd}”
when.contains:
tags: “syslog”
– index: “ysl-message-%{+yyyy.MM.dd}”
when.contains:
tags: “messagelog”
setup.ilm.enabled: false
setup.template.name: ysl
setup.template.pattern: “ysl*”
setup.template.settings:
index.number_of_shards: 3
index.number_of_replicas: 0
setup.template.overwrite: false
“`

## 8 elastic下载和查看文档

### 1 elastic search

https://elastic.co

![image-20250224154037329](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154037329.png)

![image-20250224154135566](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154135566.png)

![image-20250224154236852](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154236852.png)

![image-20250224154319095](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154319095.png)

![image-20250224154341792](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154341792.png)

![image-20250224154430020](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154430020.png)

### 2 kibana

![image-20250224154712117](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154712117.png)

![image-20250224154732179](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154732179.png)

![image-20250224154749777](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154749777.png)

![image-20250224154808865](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154808865.png)

### 3 filebeat

![image-20250224154911273](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224154911273.png)

![image-20250224155238729](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224155238729.png)

![image-20250224155324649](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250224155324649.png)

## 9 filebeat模块管理

“`sh
1 查看
filebeat modules list
结果中的
Enabled:

Disabled:
表示启用和禁用的模块

2 启用和禁用
filebeat modules enable + 模块名

filebeat modules enable nginx tomcat
Enabled nginx
Enabled tomcat

filebeat modules disable nginx
Disabled nginx

3 模块管理的地城逻辑
root@elk02:/etc/filebeat/modules.d# ll
total 308
drwxr-xr-x 2 root root 4096 Feb 24 17:05 ./
drwxr-xr-x 4 root root 4096 Feb 21 12:17 ../
-rw-r–r– 1 root root 484 Nov 13 23:20 activemq.yml.disabled
-rw-r–r– 1 root root 476 Nov 13 23:20 apache.yml.disabled
-rw-r–r– 1 root root 281 Nov 13 23:20 auditd.yml.disabled
其实就是修改文件

4 filebeat使用nginx模块案例
filebeat modules enable nginx
Enabled nginx

egrep -v “^.*#|^$” /etc/filebeat/modules.d/nginx.yml
– module: nginx
access:
enabled: true
var.paths: [“/root/access.log*”]
error:
enabled: true
ingress_controller:
enabled: false

5 编写filebeat的配置文件写入es集群
cat 07-modules-to-es.yaml
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false

output.elasticsearch:
hosts:
– “http://10.0.0.91:9200”
index: “ysl-forest-modules-nginx-accesslog-%{+yyyy.MM.dd}”

setup.ilm.enabled: false
setup.template.name: ysl-forest-modules-nginx
setup.template.pattern: “ysl-forest-modules-nginx*”
setup.template.settings:
index.number_of_shards: 1
index.number_of_replicas: 0
setup.template.overwrite: true
“`

## 10 kibana展示

![image-20250226164314721](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226164314721.png)

### 1 PV

页面访问量,一条对一个PV

![image-20250226163821568](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226163821568.png)

![image-20250226163857932](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226163857932.png)

![image-20250226163926229](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226163926229.png)

![image-20250226164358261](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226164358261.png)

![image-20250226164538079](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226164538079.png)

![image-20250226164626526](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226164626526.png)

### 2 IP统计

![image-20250226164807213](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226164807213.png)

![image-20250226164823844](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226164823844.png)

![image-20250226165027543](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165027543.png)

![image-20250226165117581](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165117581.png)

### 3 带宽统计

![image-20250226165534178](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165534178.png)

![image-20250226165749152](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165749152.png)

![image-20250226165815181](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165815181.png)

![image-20250226165836098](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165836098.png)

![image-20250226165856573](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165856573.png)

![image-20250226165935185](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226165935185.png)

![](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226170032893.png)

![image-20250226170132407](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226170132407.png)

![image-20250226170443172](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226170443172.png)

### 4 地图

![image-20250226170640261](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226170640261.png)

![image-20250226170728822](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226170728822.png)

![image-20250226171053918](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226171053918.png)

### 5 仪表盘

![image-20250226172515642](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226172515642.png)

![image-20250226172607634](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226172607634.png)

![image-20250226173157310](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226173157310.png)

![image-20250226173353047](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226173353047.png)

![image-20250226173437977](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226173437977.png)

## 11 filestream模块

![image-20250226174139554](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250226174139554.png)

官网上说在7.16版本的时候log模块已经弃用,推荐使用filestream

“`sh
cat 08-filestream-to-es.yaml
filebeat.inputs:
– type: filestream
paths:
– /tmp/test.log

output.elasticsearch:
hosts:
– “http://10.0.0.91:9200”
index: “ysl-filestream-%{+yyyy.MM.dd}”

setup.ilm.enabled: false
setup.template.name: ysl-filestream
setup.template.pattern: “ysl-filestream*”
setup.template.settings:
index.number_of_shards: 1
index.number_of_replicas: 0
setup.template.overwrite: false
“`

## 12 filebeat多行匹配-固定行数匹配

“`dh
测试数据
cat >>/tmp/test_count.log<>/tmp/students-pattern.json< stdin } } output { stdout { codec => rubydebug } } ”

基于配置文件启动logstash
cat /etc/logstash/conf.d/01-stdin-to-stdout.conf
# 表示数据从哪里来
input {
# 表示从标准输入来
stdin {
type => stdin
}
}

# 表示数据到哪里去
output {
# 表示从标准输出去
stdout {
codec => rubydebug
# codec => json
}
}

logstash -f /etc/logstash/conf.d/01-stdin-to-stdout.conf
如果想要从头采集数据,可以删除Logstash的数据目录。
rm -rf /usr/share/logstash/data/
对接文件
cat 02-file-to-stdout.conf
input {
file {
# 首次采集文件时从哪开始读取数据
start_position => “beginning”
# 指定文件的路径
path => “/tmp/testlogstash.log”
}
}

output {
stdout {}
}
echo testlogstash >> /tmp/testlogstash.log
logstash -f /etc/logstash/conf.d/02-file-to-stdout.conf

“`

## 16 ELFK架构案例-filebeat对接logstash

“`sh
logstash配置
cat 03-beats-to-es.conf
input {
beats {
port => 5044
}
}

output {
stdout {}
}

logstash -r -f /etc/logstash/conf.d/03-beats-to-es.conf

-f 指定配置文件
-r 热加载,修改配置文件后不需要重启logstash

ss -ntl | grep 5044
LISTEN 0 4096 *:5044 *:*

此时5044已被监听

filebeat配置

ss -ntl | grep 9000
LISTEN 0 4096 *:9000 *:*

cat /etc/filebeat/config/12-tcp-to-logstash.yaml
filebeat.inputs:
– type: tcp
# 数据从本地的9000端口来
host: “0.0.0.0:9000”

# 数据到Logstash去
output.logstash:
hosts: [“10.0.0.91:5044”]

filebeat -e -c /etc/filebeat/config/12-tcp-to-logstash.yaml

echo www.yangsenlin.top | nc 127.0.0.1 9000
最终数据会到logstash上去
“`

![image-20250311112203127](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311112203127.png)

“`sh
将数据发送到elasticsearch,然后再kibana上展示
cat 03-beats-to-es.conf
input {
beats {
port => 5044
}
}

# 可以对event事件进行过滤处理。
filter {
mutate {
remove_field => [ “agent”,”ecs”,”@version”,”host”,”log”,”input”,”tags”]
}
}

output {
stdout {}

elasticsearch {
# 指定ES集群的地址,多个地址用[]和逗号
hosts => “10.0.0.91:9200”

# 指定ES的索引
index => “ysl-elfk-logstash”
}
}

echo www.yangsenlin.top | nc 127.0.0.1 9000
“`

![image-20250311112816646](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311112816646.png)

到kibana上查看

![image-20250311113230398](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311113230398.png)

## 17 ELK分析数据

![image-20250311121356229](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311121356229.png)

![image-20250311121522869](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311121522869.png)

![image-20250311121629372](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311121629372.png)

![image-20250311122450215](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311122450215.png)

![image-20250311122553947](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311122553947.png)

![image-20250311123757644](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311123757644.png)

## 18 filebeat采集docker日志

“`sh
安装docker导入nginx镜像启动docker容器
docker run -d –name myweb -p 81:80 nginx:1.24-alpine

在宿主机上访问几次
for i in `seq 3`;do curl 10.0.0.91:81;done
查看日志
docker logs -f myweb

“`

### 1 第一种方法

“`sh
cat /etc/filebeat/config/13-docker-nginx-to-es.yaml
filebeat.inputs:

– type: log
paths:
– /var/lib/docker/containers/*.log
output.elasticsearch:
hosts: [“http://10.0.0.91:9200”]
index: “ysl-docker-nginx-accesslog-%{+yyyy.MM.dd}”

setup.ilm.enabled: false
setup.template.name: ysl-docker-nginx
setup.template.pattern: ysl-docker-nginx*
setup.template.settings:
index.number_of_shards: 3
index.number_of_replicas: 0
setup.template.overwrite: false
“`

### 2 第二种方法

https://www.elastic.co/guide/en/beats/filebeat/7.17/filebeat-input-docker.html

![image-20250311164129541](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311164129541.png)

“`sh
cat 13-docker-nginx-to-es.yaml
filebeat.inputs:
– type: docker
#容器相关参数
containers:
##指定容器id
ids:
– ‘*’
#容器日志存储路径,默认值“/var/lib/docker/containers”
path: “/var/lib/docker/containers”
#指定采集的数据流类型,支持stderr,stdout,all(default)
stream: “stdout”
output.elasticsearch:
hosts: [“http://10.0.0.91:9200”]
index: “ysl-docker-nginx-accesslog-%{+yyyy.MM.dd}”

setup.ilm.enabled: false
setup.template.name: ysl-docker-nginx
setup.template.pattern: ysl-docker-nginx*
setup.template.settings:
index.number_of_shards: 1
index.number_of_replicas: 1
setup.template.overwrite: false
“`

![image-20250311165251964](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311165251964.png)

### 3 第三种方法

“`sh
使用filebeat模块
filebeat modules list
filebeat modules enable docker
Module docker doesn’t exist!
没有docker模块
使用container模块

“`

![image-20250311170247040](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311170247040.png)

“`sh
cat 14-container-nginx-to-es.yaml
filebeat.inputs:
– type: container
paths:
– ‘/var/lib/docker/containers/*/*.log’
output.elasticsearch:
hosts: [“http://10.0.0.91:9200”]
index: “ysl-docker-nginx-accesslog-%{+yyyy.MM.dd}”

setup.ilm.enabled: false
setup.template.name: ysl-docker-nginx
setup.template.pattern: ysl-docker-nginx*
setup.template.settings:
index.number_of_shards: 1
index.number_of_replicas: 1
setup.template.overwrite: false
“`

![image-20250311173137961](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311173137961.png)

## 19 filebeat多实例

“`sh
第一个实例
filebeat -e -c /etc/filebeat/config/13-docker-nginx-to-es.yaml

第二个实例
filebeat -e -c /etc/filebeat/config/14-container-nginx-to-es.yaml –path.data /test/filebeat-container

“`

## 20 filebeat mutate插件

“`sh
准备测试数据
cat >>generate_log.py< 5044
}
}

# 可以对event事件进行过滤处理。
filter {
mutate {
remove_field => [ “agent”,”ecs”,”@version”,”host”,”log”,”input”,”tags”]
}
}

output {
stdout {}

# elasticsearch {
# # 指定ES集群的地址
# hosts => “10.0.0.91:9200”
#
# # 指定ES的索引
# index => “ysl-elfk-logstash”
# }
}

logstash -rf /etc/logstash/conf.d/04-beats-apps-mutate-es.conf

浏览以下网址查找strip
https://www.elastic.co/guide/en/logstash/7.17/plugins-filters-mutate.html

cat 04-beats-apps-mutate-es.conf
input {
beats {
port => 5001
}
}

# 可以对event事件进行过滤处理。
filter {
mutate {
remove_field => [ “agent”,”ecs”,”@version”,”host”,”log”,”input”,”tags”]
}
mutate {
split => { “message” => “|” }
}
}

output {
stdout {}

# elasticsearch {
# # 指定ES集群的地址
# hosts => “10.0.0.91:9200”
#
# # 指定ES的索引
# index => “ysl-elfk-logstash”
# }
}
“`

![image-20250311212126651](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311212126651.png)

以上是将字段分隔

“`sh
以下是增加字段
cat 04-beats-apps-mutate-es.conf
input {
beats {
port => 5001
}
}

# 可以对event事件进行过滤处理。
filter {
mutate {
remove_field => [ “agent”,”ecs”,”@version”,”host”,”log”,”input”,”tags”]
}
mutate {
split => { “message” => “|” }

add_field => {
“other” => “%{[message][0]}”
“userid” => “%{[message][1]}”
“action” => “%{[message][2]}”
“svip” => “%{[message][3]}”
“price” => “%{[message][4]}”
}
}
}

output {
stdout {}

# elasticsearch {
# # 指定ES集群的地址
# hosts => “10.0.0.91:9200”
#
# # 指定ES的索引
# index => “ysl-elfk-logstash”
# }
}
“`

![image-20250311212909000](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311212909000.png)

“`sh
完整处理流程
input {
beats {
port => 5001
}
}

filter {
mutate {
split => { “message” => “|” }

add_field => {
“other” => “%{[message][0]}”
“userid” => “%{[message][1]}”
“action” => “%{[message][2]}”
“svip” => “%{[message][3]}”
“price” => “%{[message][4]}”
}
}

mutate {
split => { “other” => ” “}

add_field => {
“dt” => “%{[other][1]} %{[other][2]}”
}

remove_field => [ “agent”,”ecs”,”@version”,”host”,”log”,”input”,”tags”,”message”,”other”]
}

}

#output {
# stdout {}

elasticsearch {
# 指定ES集群的地址
hosts => [“10.0.0.91:9200”]

# 指定ES的索引
index => “ysl-elfk-apps-mutate”
}
}
“`

![image-20250311214321090](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311214321090.png)

![image-20250311214650273](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311214650273.png)

## 21 filebeat date插件

““sh
cat 05-beats-apps-date-es.conf
input {
beats {
port => 5001
}
}

filter {
mutate {
split => { “message” => “|” }

add_field => {
“other” => “%{[message][0]}”
“userid” => “%{[message][1]}”
“action” => “%{[message][2]}”
“svip” => “%{[message][3]}”
“price” => “%{[message][4]}”
}
}

mutate {
split => { “other” => ” “}

add_field => {
“dt” => “%{[other][1]} %{[other][2]}”
}

remove_field => [ “agent”,”ecs”,”@version”,”host”,”log”,”input”,”tags”,”message”,”other”]
}

date {
match => [ “dt”, “yyyy-MM-dd HH:mm:ss” ]

# 如果不定义,则默认会覆盖”@timestamp”字段
target => “ysl-datetime”
}

}

output {
stdout {}

elasticsearch {
hosts => [“10.0.0.91:9200”]

index => “ysl-elfk-apps-date-%{+yyyy.MM.dd}”
}
}
““

![image-20250311221020538](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311221020538.png)

![image-20250311221116586](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250311221116586.png)

![image-20250314212942489](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250314212942489.png)

## 22 filebeat grok geoip 插件

“`sh
https://www.elastic.co/guide/en/logstash/7.17/introduction.html
使用grok groip处理nginx、tomcat日志
会使用到以下的模块,查看模块内容可以得到是怎么回事

find /usr/share/logstash/ -name httpd
/usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.3.4/patterns/legacy/httpd
/usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.3.4/patterns/ecs-v1/httpd

cat /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.3.4/patterns/legacy/httpd
HTTPDUSER %{EMAILADDRESS}|%{USER}
HTTPDERROR_DATE %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{YEAR}

# Log formats
HTTPD_COMMONLOG %{IPORHOST:clientip} %{HTTPDUSER:ident} %{HTTPDUSER:auth} \[%{HTTPDATE:timestamp}\] “(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})” (?:-|%{NUMBER:response}) (?:-|%{NUMBER:bytes})
HTTPD_COMBINEDLOG %{HTTPD_COMMONLOG} %{QS:referrer} %{QS:agent}

# Error logs
HTTPD20_ERRORLOG \[%{HTTPDERROR_DATE:timestamp}\] \[%{LOGLEVEL:loglevel}\] (?:\[client %{IPORHOST:clientip}\] ){0,1}%{GREEDYDATA:message}
HTTPD24_ERRORLOG \[%{HTTPDERROR_DATE:timestamp}\] \[(?:%{WORD:module})?:%{LOGLEVEL:loglevel}\] \[pid %{POSINT:pid}(:tid %{NUMBER:tid})?\]( \(%{POSINT:proxy_errorcode}\)%{DATA:proxy_message}:)?( \[client %{IPORHOST:clientip}:%{POSINT:clientport}\])?( %{DATA:errorcode}:)? %{GREEDYDATA:message}
HTTPD_ERRORLOG %{HTTPD20_ERRORLOG}|%{HTTPD24_ERRORLOG}

# Deprecated
COMMONAPACHELOG %{HTTPD_COMMONLOG}
COMBINEDAPACHELOG %{HTTPD_COMBINEDLOG}

“`

![image-20250313173747474](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250313173747474.png)

“`sh

“`

“`sh
cat 16-nginx-to-logstash.yaml
filebeat.inputs:
– type: filestream
paths:
– /root/access.log*

output.logstash:
hosts: [“10.0.0.91:5044”]

cat 06-nginx-grok_geoip_useragent_date-es.conf
input {
beats {
port => 5044
}
}

filter {
mutate {
remove_field => [ “agent”,”ecs”,”@version”,”host”,”log”,”input”,”tags”]
}

grok {
match => {
“message” => “%{HTTPD_COMMONLOG}”
}
}

useragent {
source => “message”

target => “ysl-useragent”
}

geoip {
source => “clientip”
}

date {
# “04/Jan/2025:10:53:54 +0800”
match => [ “timestamp”, “dd/MMM/yyyy:HH:mm:ss Z” ]
}

}

output {
stdout {}

elasticsearch {
hosts => [“10.0.0.91:9200”]

index => “ysl-elfk-nginx-%{+yyyy-MM-dd}”
}
}

“`

## 23 ElasticStack故障排查思路

“`sh
Kibana如果查询不到数据,可能是由什么原因呢?

– Filebeat端存在问题的可能性:
– filebeat挂掉无法采集数据;
– 配置文件和实际采集的数据不对应;
– 源数据文件为空,未能写入;
– 数据已经采集过了,本地缓存offset未清空;

– logstash和Filebeat同理,也会存在类似的问题。

– ES集群挂掉,导致kibana无法查询数据;

– kibana的时间选择有问题,也会查询不到数据;

– kibana做了KQL数据过滤,也可能导致数据查询不到;

– kibana的索引被删除,索引模式不生效;

“`

## 24 logstash 多实例

“`sh
第一个logstash正常启动
第二个logstash如下
logstash -rf /etc/logstash/conf.d/06-nginx-grok_geoip_useragent_date-es.conf –path.data /tmp/logstash

修改5044,添加–path.data /tmp/logstahs(根据实际修改)
“`

## 25 logstash if多分支语句

“`sh
cat /etc/logstash/conf.d/07-if-tcp.conf
input {
tcp {
port => 6666
type => “xixi”
}

tcp {
port => 7777
type => “haha”
}

tcp {
port => 8888
type => “heihei”
}

}

filter {
mutate {
remove_field => [ “@version”,”port” ]
}

if [type] == “xixi” {
mutate {
add_field => {
“school” => “ysl”
}
}
} else if [type] == “haha” {
mutate {
add_field => {
“class” => “forest”
}
}
} else {
mutate {
add_field => {
“address” => “哈哈”
}
}
}

}

output {
stdout {}

if [type] == “xixi” {
elasticsearch {
hosts => [“10.0.0.91:9200”]
index => “ysl-elfk-logstash-xixi”
}
} else if [type] == “haha” {
elasticsearch {
hosts => [“10.0.0.91:9200”]
index => “ysl-elfk-logstash-haha”
}
}else {
elasticsearch {
hosts => [“10.0.0.91:9200”]
index => “ysl-elfk-logstash-heihei”
}
}
}
“`

## 26 logstash pipeline

“`sh
所谓的pipeline就是Logstash的input,filter,output为一个整体的描述,我们称之为pipeline,默认Logstash仅有一个main的pipeline。
pipeline核心思想就是”拆“

以上多分支语句可以写成如下
cat > /etc/logstash/conf.d/08-pipeline-xixi.conf < 6666
type => “xixi”
}
}
filter {

mutate {
remove_field => [ “@version”,”port” ]

add_field => {
“school” => “ysl”
}
}
}
output {
# stdout {}

elasticsearch {
hosts => [“10.0.0.91:9200”]
index => “ysl-forest-elfk-logstash-xixi”
}
}
EOF

cat > /etc/logstash/conf.d/09-pipeline-haha.conf < 7777
type => “haha”
}
}
filter {

mutate {
add_field => {
“class” => “forest”
}

remove_field => [ “@version”,”port” ]
}
}
output {
# stdout {}

elasticsearch {
hosts => [“10.0.0.91:9200”]
index => “ysl-forest-elfk-logstash-haha”
}
}
EOF

cat > /etc/logstash/conf.d/10-pipeline-heihei.conf < 8888
type => “heihei”
}
}
filter {
mutate {
add_field => {
“address” => “嘿嘿”
}

remove_field => [ “@version”,”port” ]
}

}
output {
# stdout {}

elasticsearch {
hosts => [“10.0.0.91:9200”]
index => “ysl-forest-elfk-logstash-heihei”
}
}
EOF

单独使用logstash -r也是起logstash,只不过会用/etc/logstash/pipelines.yml配置文件,所以需要将配置文件都写入pipeline.yml里即可

tail -6 /etc/logstash/pipelines.yml
– pipeline.id: xixi
path.config: “/etc/logstash/conf.d/08*.conf”
– pipeline.id: haha
path.config: “/etc/logstash/conf.d/09*.conf”
– pipeline.id: heihei
path.config: “/etc/logstash/conf.d/10*.conf”

logstash -r默认会加载/usr/share/logstash/config/pipelines.yml,直接起会报错,需要建目录和软连接
mkdir -pv /usr/share/logstash/config/
ln -svf /etc/logstash/pipelines.yml /usr/share/logstash/config/pipelines.yml

logstash -r
kibana查看数据
“`

## 27 elasticsearch原理

“`sh
数据写到es集群其实就是往索引写入,索引将数据存储到对应的分片
curl 10.0.0.91:9200/_cat/nodes?v
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
10.0.0.91 54 21 6 0.77 1.47 0.79 cdfhilmrstw * elk01

其中”cdfhilmrstw”代表ES支持的各种角色,其中m表示master,d代表数据节点,c代表的是协调节点。

ES集群半数以上节点宕机,则集群服务不可用!

– ES的原理之文档的写入流程
1.客户端提交向ES索引写入请求;
2.将写请求转发给master节点;
3.master节点会根据文档ID(系统自动生成,也可以自定义但不推荐)计算出对应的写入分片;
4.对应的primary shard开始写入数据,replica shard开始同步写入;
写入成功策略: (primary numbers + replica )/ 2 + 1
5.写入成功后提交master结果;
6.返回给客户端写入成功;

– ES的分片数量:
推荐生产环境设置为10个分片,1个副本。

– ES的原理之单个文档的读取流程:
1.客户端根据文档的ID去协调节点查询数据;
2.根据文档的路由ID计算数据存储的编号信息;
hash(routing) % primary_number_shards —> 存储的分片编号
3.根据查询出来的文档编号找本地的”cluster_state”信息查询分片所在节点;
4.去对应节点拉取数据返回给客户端;

– ES的原理之多个文档的读取流程:
1.客户端发起DSL查询语句给协调节点;
2.协调节点查询本地的”cluster_state”的映射信息,找到该索引的所有分片;
3.进入query(搜索):
– 3.1 各节点的分片查询本地的数据并将查询结果放在一个队列中;
– 3.2 各个分片仅将文档的_id及相关性评分返回;
4.fetch(取回):
1.根据query节点各分片返回的数据进行全局排序,决定要取回的文档ID;
2.根据文档ID取回真实数据;
5.最终将数据返回给客户端;

这张图展示了 Elasticsearch (ES) 的数据写入和存储机制,包括客户端请求、内存区域、操作系统内核区域和磁盘区域的交互过程。下面是对图中各部分的详细解释:

### 客户端请求
– 客户端通过 HTTP 或 TCP 协议向 Elasticsearch 发送请求。图中展示了一个 POST 请求,发送 JSON 格式的数据到 `10.0.0.91:9200/ysl_linux/_doc` 地址。

### ES 主进程
– 请求被发送到 Elasticsearch 主进程,主进程负责处理请求并将其路由到相应的分片(shard)。

### 内存区域
– **分片(Shard)**:Elasticsearch 将数据分割成多个分片,每个分片是一个独立的 Lucene 索引。图中展示了一个名为 `index(BKWwEsPkRKK60ZtzJ0Nc7Q)` 的索引,它被分割成多个主分片(primary shards)。
– **倒排索引(Segments)**:每个分片包含多个倒排索引段(segments),每个段包含文档的倒排索引和删除标记(.del 文件)。
– **Searchable 和 Unsearchable**:图中用不同颜色区分了可查询(searchable)和不可查询(unsearchable)的段。可查询的段可以被外界查询,而不可查询的段则不能。

### WAL(Write Ahead Log)
– **预写日志(WAL)**:在数据写入内存区域之前,Elasticsearch 会先将数据写入预写日志(translog),以确保数据的持久性和一致性。
– **Translog 文件**:图中展示了多个 translog 文件(如 translog-4.tlog、translog.ckp 等),这些文件记录了数据写入的事件。

### 操作系统内核区域
– **flush 阶段**:将 Elasticsearch 的段文件提交到操作系统的缓冲区(OS buffer)。
– **reflush 阶段**:将操作系统缓冲区中的数据同步到磁盘。

### 磁盘区域
– **段文件(Segments)**:最终,数据被持久化存储到磁盘上,形成多个段文件。这些段文件包含倒排索引和删除标记。

### 数据写入流程
1. **WAL(Write Ahead Log)**:记录本次的事件,确保数据的持久性。
2. **flush 阶段**:将 Elasticsearch 的段文件提交到操作系统的缓冲区。
3. **reflush 阶段**:将操作系统缓冲区中的数据同步到磁盘。
4. **merge**:定期合并段文件,整理被删除的文件,进行物理删除。

### 总结
这张图展示了 Elasticsearch 的数据写入和存储机制,包括客户端请求、内存区域、操作系统内核区域和磁盘区域的交互过程。通过预写日志(WAL)、flush 和 reflush 阶段,Elasticsearch 确保了数据的持久性和一致性,并将数据持久化存储到磁盘上。同时,通过定期的 merge 操作,Elasticsearch 优化了存储空间和查询性能。
“`

### 1 正排索引

“`sh
以MySQL为例:

如果我们想要查询Linux,则会将blog表的所有content字段全部进行全量查询。性能极差!

MySQL存储上限理论值是64T,但经过实际考察,比如zabbix监控800台服务器,数据量达到1TB,发现性能就极差了!

如果数据量达到100PB如何解决呢?—-》 而ES很轻松就解决了。
“`

### 2 倒排索引

“`sh
所谓的倒排索引,其实就是会多出一张倒排表,用户查询时并不会直接查询数据,而是先去查倒排表。

I : [1001,…]
love: [1001,…]
linux: [1001,1002,…]

先去倒排表查询数据,如果能查到再去原表查询,如果查不到,则直接结束查询。
“`

## 28 es集群的api

“`sh
curl -s 10.0.0.91:9200/_cluster/health | jq
{
“cluster_name”: “my-application”,
“status”: “yellow”,
“timed_out”: false,
“number_of_nodes”: 1,
“number_of_data_nodes”: 1,
“active_primary_shards”: 11,
“active_shards”: 11,
“relocating_shards”: 0,
“initializing_shards”: 0,
“unassigned_shards”: 1,
“delayed_unassigned_shards”: 0,
“number_of_pending_tasks”: 0,
“number_of_in_flight_fetch”: 0,
“task_max_waiting_in_queue_millis”: 0,
“active_shards_percent_as_number”: 91.66666666666666
}

curl -s 10.0.0.91:9200/_cluster/health | jq “.status”
“yellow”
相关性参数说明:
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cluster-health.html#cluster-health-api-response-body

推荐阅读:
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cluster.html

“`

## 29 es和logstash的jvm优化

“`sh
es的jvm优化
egrep -v “^.*#|^$” /etc/elasticsearch/jvm.options | grep -i xm
-Xms256m
-Xmx256m
es集群每台都修改,修改完成后重启es集群
生产环境JVM优化
– 1.推荐是物理内存的一半;
– 2.建议JVM的heap堆内存大小不应该超过32GB,官方建议是26GB是比较安全的阈值;
– 3.关于ES集群扩容建议是1GB对应20个分片,如果物理机有32GB,最多该节点以后640个分片就应该考虑扩容了;

推荐阅读:
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/advanced-configuration.html

logstash的jvm优化
egrep -v “^.*#|^$” /etc/logstash/jvm.options | grep -i xm
-Xms256m
-Xmx256m
重启logstash
对于Logstash而言,如果数据量较大,建议调大内存,生产环境建议是物理机的一半。

“`

## 30 meticbeat

“`sh
mericbeat监控各个插件的服务,通过kibana展示,数据存储在es集群
下载
wget https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-7.17.26-amd64.deb
安装
dpkt -i metricbeat-7.17.26-amd64.deb
配置
egrep -v “^.*#|^$” /etc/metricbeat/metricbeat.yml
metricbeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
setup.template.settings:
index.number_of_shards: 1
index.codec: best_compression
setup.kibana:
host: “10.0.0.91:5601”
output.elasticsearch:
hosts: [“10.0.0.91:9200”]
processors:
– add_host_metadata: ~
– add_cloud_metadata: ~
– add_docker_metadata: ~
– add_kubernetes_metadata: ~

启动
systemctl restart metricbeat
kibana查看数据

“`

![image-20250317105412859](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317105412859.png)

“`sh
metribeat模块
metricbeat modules list
metricbeat modules enable nginx elasticsearch
ls -l /etc/metricbeat/modules.d/*.yml
-rw-r–r– 1 root root 284 Nov 13 23:20 /etc/metricbeat/modules.d/elasticsearch.yml
-rw-r–r– 1 root root 348 Nov 13 23:20 /etc/metricbeat/modules.d/nginx.yml
-rw-r–r– 1 root root 956 Nov 13 23:20 /etc/metricbeat/modules.d/system.yml

metricbeat采集nginx配置
egrep -v “^.*#|^$” /etc/metricbeat/modules.d/nginx.yml
– module: nginx
enabled: true
period: 10s
hosts: [“http://10.0.0.91:81”]
server_status_path: “status”

metricbeat采集elasticsearch配置

egrep -v “^.*#|^$” /etc/metricbeat/modules.d/elasticsearch.yml
– module: elasticsearch
metricsets:
– node
– node_stats
period: 10s
hosts: [“http://10.0.0.91:9200”]

修改metricbeat配置
egrep -v “^.*#|^$” /etc/metricbeat/metricbeat.yml
metricbeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
setup.template.settings:
index.number_of_shards: 1
index.codec: best_compression
setup.dashboards.enabled: true
setup.kibana:
host: “10.0.0.91:5601”
output.elasticsearch:
hosts: [“10.0.0.91:9200”]
processors:
– add_host_metadata: ~
– add_cloud_metadata: ~
– add_docker_metadata: ~
– add_kubernetes_metadata: ~

重启metricbeat

kibana查看数据

“`

![image-20250317115138972](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317115138972.png)

系统

![image-20250317115200270](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317115200270.png)

![image-20250317115251047](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317115251047.png)

![image-20250317115758772](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317115758772.png)

## 31 heartbeat

“`sh
下载
wget https://artifacts.elastic.co/downloads/beats/heartbeat/heartbeat-7.17.26-amd64.deb

安装
dpkg -i heartbeat-7.17.26-amd64.deb

配置
cat heartbeat.yml
heartbeat.config.monitors:
path: ${path.config}/monitors.d/*.yml
reload.enabled: false
reload.period: 5s
heartbeat.monitors:
– type: http
enabled: true
id: my-heartbeat-http
name: my-heartbeat-http
urls: [“http://10.0.0.91:9200”]
schedule: ‘@every 10s’
– type: tcp
enabled: true
id: my-heartbeat-tcp
name: my-heartbeat-tcp
urls: [“10.0.0.91:80”]
schedule: ‘@every 10s’
– type: icmp
enabled: true
id: my-heartbeat-icmp
name: my-heartbeat-icmp
urls: [“10.0.0.91”]
schedule: ‘@every 10s’
setup.template.settings:
index.number_of_shards: 1
index.codec: best_compression
setup.kibana:
output.elasticsearch:
hosts: [“10.0.0.91:9200”]
processors:
– add_observer_metadata:

启动
systemctl restart heartbeat-elastic.service

kibana查看数据

“`

![image-20250317111424727](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317111424727.png)

## 32 es集群加密

“`sh
1 生产证书文件
/usr/share/elasticsearch/bin/elasticsearch-certutil cert -out /etc/elasticsearch/elastic-certificates.p12 -pass “”

2 如果是集群,将证书文件拷贝到其他es节点
chmod 640 /etc/elasticsearch/elastic-certificates.p12
scp -p /etc/elasticsearch/elastic-certificates.p12 root@10.0.0.92:/etc/elasticsearch/

3 修改es集群的配置文件
cat >>/etc/elasticsearch/elasticsearch.yml< 8888
}
}

output {

elasticsearch {
hosts => [“10.0.0.91:9200”]
index => “ysl-logstash-tls-es”
user => elastic
password => “123456”
}
}

2 启动
logstash -rf /etc/logstash/conf.d/11-tcp-to-es_tls.conf

3发送测试数据
echo test_logstash_es_tls | nc 10.0.0.91 8888

4 kibana查看

“`

![image-20250317131429381](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317131429381.png)

35 基于kibana实现RBAC

“`sh
r role
b basic
a access
c ctrol
基于访问角色控制

“`

![image-20250317150548271](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317150548271.png)

![image-20250317150853181](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250317150853181.png)

“`sh
rbac是根据要求创建角色,再创建用户,权限管理
“`

## 35 filebeat对接redis

“`sh
1 部署redis
root@elk01:~# docker load -i redis-7.2.5.tar.gz
9853575bc4f9: Loading layer 77.83MB/77.83MB
15ba19fd0afe: Loading layer 10.75kB/10.75kB
98723f5366da: Loading layer 10.75kB/10.75kB
811293dc7f13: Loading layer 4.143MB/4.143MB
7879a25fefe5: Loading layer 37.57MB/37.57MB
643b046a00e2: Loading layer 1.536kB/1.536kB
5f70bf18a086: Loading layer 1.024kB/1.024kB
b3a84b16d771: Loading layer 4.096kB/4.096kB
Loaded image: redis:7.2.5
root@elk01:~#

2 启动redis
docker run -d –network host –name redis-server –restart always redis:7.2.5

docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9a741a1c37bf redis:7.2.5 “docker-entrypoint.s…” 15 seconds ago Up 15 seconds redis-server

ss -ntl | grep 6379
LISTEN 0 511 0.0.0.0:6379 0.0.0.0:*
LISTEN 0 511 [::]:6379 [::]:*
root@elk01:~#

3 编写filebeat配置文件
cat >>/etc/filebeat/19-tcp-to-redis.yaml< keys *
filebeat-redis
127.0.0.1:6379[10]> type filebeat-redis
list
127.0.0.1:6379[10]> LRANGE filebeat-redis 0 -1
{“@timestamp”:”2025-03-19T10:03:36.732Z”,”@metadata”:{“beat”:”filebeat”,”type”:”_doc”,”version”:”7.17.26″},”host”:{“name”:”elk01″},”agent”:{“type”:”filebeat”,”version”:”7.17.26″,”hostname”:”elk01″,”ephemeral_id”:”df54f4e0-0123-446e-a7bb-e235576119a8″,”id”:”ab0eb895-d64b-425b-b2f3-14d6a4509397″,”name”:”elk01″},”message”:”filebeat-to-redis”,”log”:{“source”:{“address”:”10.0.0.91:59310″}},”input”:{“type”:”tcp”},”ecs”:{“version”:”1.12.0″}}

“`

## 36 logstash对接redis

“`sh
1 编写配置文件
cat >>/etc/logstash/conf.d/13-redis-to-es.conf< “10.0.0.91”

port => 6379

db => 10

data_type => “list”

key => “filebeat-redis”
}
}

filter {
mutate {
remove_field => [ “agent”,”input”,”log”,”@version”,”ecs” ]
}
}

output {
# stdout {}

elasticsearch {
hosts => [“10.0.0.91:9200″,”10.0.0.92:9200″,”10.0.0.93:9200”]
index => “ysl-logstash-elfk-redis”
user => elastic
password => “123456”
}
}
EOF

2 启动logstash
logstash -rf /etc/logstash/conf.d/13-redis-to-es.conf

3 kibana查看数据

4 logstash消费数据redis数据后,redis数据删除
原因:节约资源
root@elk01:~# docker exec -it redis-server redis-cli -n 10 –raw
127.0.0.1:6379[10]> keys *

127.0.0.1:6379[10]>
“`

![image-20250319181201561](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250319181201561.png)

## 37 elasticstach对于kafka和redis如何选择

“`sh
功能上:
两者都可以用来临时缓存数据。

区别:
– 1.性能上甚至Redis速度回更快,毕竟使用的是内存,kafka稍微逊色,因为数据写入磁盘。
– 2.数据量较大时,Redis不太合适,因为数据都得积压到内存中,效率就会降低,存储成本也比较高,因为建议选择kafka;
– 3.Logstash一旦消费了redis数据就会将数据删除,是一对一消费模式(消费者消费数据后数据删除),而kafka是一对多消费模式(消费者消费数据后数据不删除);

“`

## 38 filebeat基于api-key写入数据到es集群

“`sh
1.为什么要启用api-key
为了安全性,使用用户名和密码的方式进行认证会暴露用户信息。

ElasticSearch也支持api-key的方式进行认证。这样就可以保证安全性。api-key是不能用于登录kibana,安全性得到保障。

而且可以基于api-key实现权限控制。

2.ES启用api-key
vim /etc/elasticsearch/elasticsearch.yml

# 添加如下配置
# 启用api_key功能
xpack.security.authc.api_key.enabled: true
# 指定API密钥加密算法
xpack.security.authc.api_key.hashing.algorithm: pbkdf2
# 缓存的API密钥时间
xpack.security.authc.api_key.cache.ttl: 1d
# API密钥保存数量的上限
xpack.security.authc.api_key.cache.max_keys: 10000
# 用于内存中缓存的API密钥凭据的哈希算法
xpack.security.authc.api_key.cache.hash_algo: ssha256

3 拷贝配置文件到其他节点
scp /etc/elasticsearch/elasticsearch.yml 10.0.0.92:/etc/elasticsearch
scp /etc/elasticsearch/elasticsearch.yml 10.0.0.93:/etc/elasticsearch

4 重启es集群
systemctl restart elasticsearch

5 创建api

6 基于api-key解析
echo cV9oSVNaUUJwQUVOWVQyYV9wSjI6akt0d0RXQlJUaS1HLXNZdWhJbXVfZw==| base64 -d | more
q_hISZQBpAENYT2a_pJ2:jKtwDWBRTi-G-sYuhImu_g

7 编写配置文件
cat >>/etc/filebeat/config/20-tcp-to-es.yaml<>/etc/elasticsearch/elasticsearch.yml< 7777
}
}

output {
elasticsearch {
hosts => [“10.0.0.91:9200″,”10.0.0.92:9200″,”10.0.0.93:9200”]
index => “ysl-logstash-elfk-apikey-tls”
# user => elastic
# password => “123456”

# 指定api-key的方式认证
api_key => “sZ8uSpQB8kqe7kUTd5OH:VHHFJfqqQ4iE9ZZFnw75CQ”

# 使用api-key则必须启动ssl
ssl => true

# 跳过ssl证书验证
ssl_certificate_verification => false
}
}
[root@elk93 ~]#
[root@elk93 ~]# logstash -rf /etc/logstash/conf.d/14-tcp-to-es_apikey.conf

3.访问测试
[root@elk91 ~]# echo 88888888888888888888888 | nc 10.0.0.93 7777
[root@elk91 ~]# echo 999999999999999999999999 | nc 10.0.0.93 7777

“`

## 41 es7和es8区别

“`sh
– ES7和ES8的区别:
– ES8默认启用了https认证;
– kibana8功能也更加强大;
“`

# 第二章 kafka和zookeeper

## 1 zookeeper

### 1 zookeeper和kafka的关系

“`sh
– Kafka和ZooKeeper的关系
ZooKeeper 是一个分布式协调服务,常用于管理配置、命名和同步服务。

长期以来,Kafka 使用 ZooKeeper 负责管理集群元数据、控制器选举和消费者组协调等任务理,包括主题、分区信息、ACL(访问控制列表)等。

ZooKeeper 为 Kafka 提供了选主(leader election)、集群成员管理等核心功能,为 Kafka提供了一个可靠的分布式协调服务,使得 Kafka能够在多个节点之间进行有效的通信和管理。

然而,随着 Kafka的发展,其对 ZooKeeper的依赖逐渐显露出一些问题,这些问题也是下面 Kafka去除 Zookeeper的原因。

– kafka 2.8+ 为什么要移除zookeeper组件呢?
1.复杂性增加
ZooKeeper 是独立于 Kafka 的外部组件,需要单独部署和维护,因此,使用 ZooKeeper 使得 Kafka的运维复杂度大幅提升。

运维团队必须同时管理两个分布式系统(Kafka和 ZooKeeper),这不仅增加了管理成本,也要求运维人员具备更高的技术能力。

2. 性能瓶颈
作为一个协调服务,ZooKeeper 并非专门为高负载场景设计, 因此,随着集群规模扩大,ZooKeeper在处理元数据时的性能问题日益突出。

例如,当分区数量增加时,ZooKeeper需要存储更多的信息,这导致了监听延迟增加,从而影响Kafka的整体性能。

在高负载情况下,ZooKeeper可能成为系统的瓶颈,限制了Kafka的扩展能力。

3. 一致性问题
Kafka 内部的分布式一致性模型与 ZooKeeper 的一致性模型有所不同。由于 ZooKeeper和 Kafka控制器之间的数据同步机制不够高效,可能导致状态不一致,特别是在处理集群扩展或不可用情景时,这种不一致性会影响消息传递的可靠性和系统稳定性。

4.发展自己的生态
Kafka 抛弃 ZooKeeper,我个人觉得最核心的原因是:Kafka生态强大了,需要自立门户,这样就不会被别人卡脖子。

纵观国内外,有很多这样鲜活的例子,当自己弱小时,会先选择使用别家的产品,当自己羽翼丰满时,再选择自建完善自己的生态圈。

– KAFKA 2.8+引入Kraft模式抛弃ZooKeeper
kafka2.8.0版本引入了基于Raft共识协议的新特性,它允许kafka集群在没有ZooKeeper的情况下运行。

为了剥离和去除ZooKeeper,Kafka引入了自己的亲儿子KRaft(Kafka Raft Metadata Mode)。

KRaft是一个新的元数据管理架构,基于Raft一致性算法实现的一种内置元数据管理方式,旨在替代ZooKeeper的元数据管理功能。

KRaft的优势有以下几点:
简化部署:
Kafka 集群不再依赖外部的 ZooKeeper 集群,简化了部署和运维的复杂性。
KRaft 将所有协调服务嵌入 Kafka 自身,不再依赖外部系统,这样大大简化了部署和管理,因为管理员只需关注 Kafka 集群。

高效的一致性协议:
Raft 是一种简洁且易于理解的一致性算法,易于调试和实现。KRaft 利用 Raft 协议实现了强一致性的元数据管理,优化了复制机制。

提高性能:
由于元数据管理不再依赖 ZooKeeper,Kafka 集群的性能得到了提升,尤其是在元数据读写方面。

增强可扩展性:
KRaft 模式支持更大的集群规模,可以有效地扩展到数百万个分区。
提高元数据操作的扩展性:新的架构允许更多的并发操作,并减少了因为扩展性问题导致的瓶颈,特别是在高负载场景中。

更快的控制器故障转移:
控制器(Controller)的选举和故障转移速度更快,提高了集群的稳定性。
消除 ZooKeeper 作为中间层之后,Kafka 的延迟性能有望得到改善,特别是在涉及选主和元数据更新的场景中。
KRaft模式下,kafka集群中的一些节点被指定为控制器(Controller),它们负责集群的元数据管理和共识服务,所有的元数据都存储在kafka内部的主题中,
而不是ZooKeeper,控制器通过KRaft协议来确保元数据在集群中的准确复制,这种模式使用了基于时间的存储模型,通过定期快照来保证元数据日志不会无限增长。

完全自主:
因为是自家产品,所以产品的架构设计,代码开发都可以自己说了算,未来架构走向完全控制在自己手上。

控制器(Controller)节点的去中心化:
KRaft 模式中,控制器节点由一组 Kafka 服务进程代替,而不是一个独立的 ZooKeeper 集群。
这些节点共同负责管理集群的元数据,通过 Raft 实现数据的一致性。

日志复制和恢复机制:
利用 Raft 的日志复制和状态机应用机制,KRaft 实现了对元数据变更的强一致性支持,这意味着所有控制器节点都能够就集群状态达成共识。

动态集群管理:
KRaft允许动态地向集群中添加或移除节点,而无需手动去ZooKeeper中更新配置,这使得集群管理更为便捷。

“`

### 2 zookeeper集群部署

“`sh
– zookeeper集群部署
1.什么是zookeeper
ZooKeeper是一个集中式服务,用于维护配置信息、命名、提供分布式同步和提供组服务。所有这些类型的服务都以某种形式被分布式应用程序使用。

生成环境中当读取的数据量少于75%,且每秒的QPS少于6w,则zookeeper集群规模建议是3个。

推荐阅读:
https://zookeeper.apache.org/doc/current/zookeeperOver.html

1 下载
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz

2 解压到指定目录
mkdir -pv /software
tar xf apache-zookeeper-3.8.4-bin.tar.gz -C /software
ln -s /software/apache-zookeeper-3.8.4-bin/ /software/zookeeper

3 配置环境变量
cat >/etc/profile.d/zk.sh< /zk/data/zk/myid 每个节点的myid不能一样
echo 92 > /zk/data/zk/myid
echo 93 > /zk/data/zk/myid

7 修改hosts文件
cat >>/etc/hosts<&1 /var/log/zkweb.log & > /dev/null
端口是8099

“`

![image-20250318104138963](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250318104138963.png)

## 2 kafka

### 1 kafka单点部署

“`sh
1 下载
wget https://dlcdn.apache.org/kafka/3.9.0/kafka_2.13-3.9.0.tgz

2 解压
tar xf kafka_2.13-3.9.0.tgz -C /software/
ln -s /software/kafka_2.13-3.9.0 /software/kafka

3 配置
mkdir /kafka/data/kafka -pv
# 表示kafka的唯一标识
broker.id=91
# 数据的存储路径
log.dirs=/ysl/data/kafka
# 连接zookeeper集群的地址
zookeeper.connect=10.0.0.91:2181,10.0.0.92:2181,10.0.0.93:2181/test-kafka390

4 配置环境变量
cat /etc/profile.d/kafka.sh
#!/bin/bash
export KAFKA_HOME=/software/kafka
export PATH=$PATH:$KAFKA_HOME/bin

5 启动
kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties

6 停止
kafka-server-stop.sh

“`

### 2 kafka jvm调优

“`sh
egrep -v “^.*#|^$” /software/kafka/bin/kafka-server-start.sh | grep -i xm
export KAFKA_HEAP_OPTS=”-Xmx256m -Xms256m”

– 1.生产环境中,建议kafka的堆内存大小不宜过大,推荐设置5~6GB即可。因为其数据存储在磁盘;
– 2.生产环境停止kafka可能时间较长,可以多次执行”kafka-server-stop.sh “脚本,耐心等待,不要使用kill -9会造成数据丢失;

“`

### 3 kafka集群部署

“`sh
1 拷贝程序到其他节点(刚装好单节点的机器执行)
scp -r /software/kafka_2.13-3.9.0/ 10.0.0.92:`pwd`
scp -r /software/kafka_2.13-3.9.0/ 10.0.0.93:`pwd`

scp /etc/profile.d/kafka.sh 10.0.0.92:/etc/profile.d/
scp /etc/profile.d/kafka.sh 10.0.0.93:/etc/profile.d/

2 修改节点的broker.id(各节点执行)
92节点执行
sed -i ‘/^broker/s@91@92@’ /software/kafka_2.13-3.9.0/config/server.properties
grep ^broker.id /software/kafka_2.13-3.9.0/config/server.properties
ln -s /software/kafka_2.13-3.9.0/ /software/kafka
source /etc/profile.d/kafka.sh

93节点执行
sed -i ‘/^broker/s@91@93@’ /software/kafka_2.13-3.9.0/config/server.properties
grep ^broker.id /software/kafka_2.13-3.9.0/config/server.properties
ln -s /software/kafka_2.13-3.9.0/ /software/kafka
source /etc/profile.d/kafka.sh

3 启动,每个节点执行
kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties

4 zkWeb查看

“`

![image-20250318112537047](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250318112537047.png)

![image-20250318112613943](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250318112613943.png)

### 4 生产者和消费者

“`sh
1 生产者产生数据
root@elk03:~# kafka-console-producer.sh –bootstrap-server 10.0.0.92:9092 –topic test-topic
>111111111
>2
>22222222222222
>3333333333333

2 消费者消费数据
kafka-console-consumer.sh –bootstrap-server 10.0.0.91:9092 –topic test-topic –from-beginning
111111111
2
22222222222222
3333333333333

3 再次查看topic列表
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –list
__consumer_offsets
test-topic
root@elk01:/software#
“`

### 5 topic基本管理

“`sh
1 查看topic列表
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –list
__consumer_offsets
test-topic

2 创建topic
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –topic test-topic1 –create –partitions 3 –replication-factor 1

3 查看所有topic详细信息
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –describe
Topic: test-topic TopicId: n9jlbGyJQw2_PDj0M2bMVw PartitionCount: 1 ReplicationFactor: 1 Configs:
Topic: test-topic Partition: 0 Leader: 91 Replicas: 91 Isr: 91 Elr: N/A LastKnownElr: N/A
Topic: test-topic1 TopicId: Gw7WcOb6TPqph0yC8AgL4Q PartitionCount: 3 ReplicationFactor: 1 Configs:
Topic: test-topic1 Partition: 0 Leader: 92 Replicas: 92 Isr: 92 Elr: N/A LastKnownElr: N/A
Topic: test-topic1 Partition: 1 Leader: 93 Replicas: 93 Isr: 93 Elr: N/A LastKnownElr: N/A
Topic: test-topic1 Partition: 2 Leader: 91 Replicas: 91 Isr: 91 Elr: N/A LastKnownElr: N/A
Topic: __consumer_offsets TopicId: 38K_-RGrTIiTROrveDf-eQ PartitionCount: 50 ReplicationFactor: 1 Configs: compression.type=producer,cleanup.policy=compact,segment.bytes=104857600
Topic: __consumer_offsets Partition: 0 Leader: 92 Replicas: 92 Isr: 92 Elr: N/A LastKnownElr: N/A
Topic: __consumer_offsets Partition: 1 Leader: 93 Replicas: 93 Isr: 93 Elr: N/A LastKnownElr: N/A
Topic: __consumer_offsets Partition: 2 Leader: 91 Replicas: 91 Isr: 91 Elr: N/A LastKnownElr: N/A
Topic: __consumer_offsets Partition: 3 Leader: 92 Replicas: 92 Isr: 92 Elr: N/A LastKnownElr: N/A
…..

4 查看指定topic详细信息
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –describe –topic test-topic1
Topic: test-topic1 TopicId: Gw7WcOb6TPqph0yC8AgL4Q PartitionCount: 3 ReplicationFactor: 1 Configs:
Topic: test-topic1 Partition: 0 Leader: 92 Replicas: 92 Isr: 92 Elr: N/A LastKnownElr: N/A
Topic: test-topic1 Partition: 1 Leader: 93 Replicas: 93 Isr: 93 Elr: N/A LastKnownElr: N/A
Topic: test-topic1 Partition: 2 Leader: 91 Replicas: 91 Isr: 91 Elr: N/A LastKnownElr: N/A

5 修改topic分区数量(只能增大不能减小,减小可能会丢失数据)
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –describe –topic test-topic
Topic: test-topic TopicId: n9jlbGyJQw2_PDj0M2bMVw PartitionCount: 1 ReplicationFactor: 1 Configs:
Topic: test-topic Partition: 0 Leader: 91 Replicas: 91 Isr: 91 Elr: N/A LastKnownElr: N/A

test-topic主题只有一个分区,将test-topic分区数量增加到3
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –describe –topic test-topic
Topic: test-topic TopicId: n9jlbGyJQw2_PDj0M2bMVw PartitionCount: 3 ReplicationFactor: 1 Configs:
Topic: test-topic Partition: 0 Leader: 91 Replicas: 91 Isr: 91 Elr: N/A LastKnownElr: N/A
Topic: test-topic Partition: 1 Leader: 92 Replicas: 92 Isr: 92 Elr: N/A LastKnownElr: N/A
Topic: test-topic Partition: 2 Leader: 93 Replicas: 93 Isr: 93 Elr: N/A LastKnownElr: N/A

6 修改副本数量(生产不建议)
https://www.cnblogs.com/yinzhengjie/p/9808125.html

7 删除topic
kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –topic test-topic1 –delete
root@elk01:/software# kafka-topics.sh –bootstrap-server 10.0.0.92:9092 –list
__consumer_offsets
test-topic
数据删除后并不会立刻删除,而是需要等待一段时间(log.segment.delete.delay.ms,kafka 3.9.0版本中默认是1min)后再删除,有延迟时间。

“`

### 6 消费者

“`sh
– 1.同一个消费者组的消费者不能同时拉取同一个topic的分区;
– 2.当消费者组的消费者数量发生变化时就会触发重平衡;
– 3.由于没有消费者进行消费,因此可能会出现数据延迟的情况。
– 4.当有该消费者组的消费者上线后,会继续消费对应分区的offset之后的数据。
– 5.如果想要重新消费topic的数据,可以重新换一个消费者组即可,只要消费者组在kafka集群中没有记录即可;

“`

### 7 kafka术语

“`sh
– topic
逻辑概念,主题,针对生产者和消费者进行读写的单元。

– partition:
一个topic可以有1个或多个分区,从而实现数据的分布式存储。

– replica:
每个分区最少有一个或多个副本,从而实现数据高可用性。

– producer:
向kafka集群写入数据的一方。

– consumer:
从kafka读取数据的一方。
– offset
分区中记录event数据的偏移量,每条消息对应一个offset记录。

– consumer group
任何消费者都隶属于某一个消费者组,一个消费者组可以有多个消费者。

– rebalance
当消费者组的消费者数量发生变化时就会触发重平衡,即重新为消费者分片分区的过程。

– 为什么kafka存在丢失数据的风险
– isr :
和leader数据同步的副本集合。
– osr:
和leader数据不同步的副本集合。
– ar:
isr + osr,表示所有副本。
– leo:
最后一个偏移量。
– hw:
高水位线,ISR列表中最小的leo就是hw。

对于消费者组而言,仅能看到HW之前的数据,无法消费到HW之后的数据。
“`

### 8 kafka数据一致性问题

“`sh
方案1:
kafka使用一个partition就能保证数据顺序一致性
缺点:
无法充分利用集群的资源

方案2:
kafka使用多个partition则需要对生产者数据进行编号,消费者取出数据后基于编号排序
缺点:
增加额外工作
“`

### 9 kafka参数优化

“`sh
vi /software/kafka_2.13-3.9.0/config/server.properties

broker.id
唯一标识kafka节点。

log.dirs
可以定义多个路径,使用逗号分割,实现数据I/O并发读写以提高性能。

log.retention.hours
数据的保留周期,默认保留7天(168h)

zookeeper.connect
建议配置集群,且设置chroot

listeners = PLAINTEXT://your.host.name:9092
配置监听地址,若不指定则默认为主机名,需要配置hosts解析。

auto.create.topics.enable
自动创建topic,建议关闭。将其设置为false,默认为true。
如果设置为true,当topic不存在时,会自动创建,集群的可用性增强,但维护性较差!

delete.topic.enable:
删除topic时,数据并不会删除,因此不会释放磁盘空间。

num.io.threads
服务器用于处理请求的线程数,其中可能包括磁盘I/O,建议设置为cpu核心数即可。

num.network.threads:
服务器用于从网络接收请求并向网络发送响应的线程数,建议设置为cpu核心数即可。

参考链接:
https://kafka.apache.org/documentation/#brokerconfigs

– 客户端(Producer | consumer)
acks: 0

参考链接:
https://kafka.apache.org/documentation/#producerconfigs

– 客户端(Producer | consumer)
acks: 0

group.id

auto.offset.reset

参考链接:
https://kafka.apache.org/documentation/#consumerconfigs

– kafka集群压测

推荐阅读:
https://www.cnblogs.com/yinzhengjie/p/9953212.html
“`

### 10 ElasticStack架构升级及MQ对比

“`sh
为了减轻Logstash压力以及Logstash和filebeat的耦合性,我们可以考虑在Logstash前面加一套MQ集群。

所谓的MQ,指的是Message Queue,即消息队列。但是这种架构无疑是给系统增加了负担:
– 1.MQ不能存在单点问题;
– 2.MQ具有很强的处理数据能力;
– 3.增加了集群的整体复杂性,运维和开发的同学都得增加学习成本;

也就是说,这意味消息队列要提供以下特性:
– 1.MQ集群吞吐量大,能够承担数据的读写; 5台32core,32GB读取处理消息数量23w/s,写速度可以达到220m/s。
– 2.MQ集群要提供非常强的高可用性,不能是单点的故障;
– 3.文档丰富,社区资源丰富;

市面上有很多MQ产品,典型代表有:
– RocketMQ【阿里巴巴,有社区版本(功能较差,文档不够丰富,仅支持Java相关的API)和SAAS版本(功能强,需要花钱),性能很好,单机每秒能够处理10w+/s】

– ActiveMQ【老牌系统,文档相对丰富,性能一般,单机每秒处理1w+/s】

– Kafka【日志收集,大数据分析,性能非常好,单机每秒处理10w+/s,存在丢失数据的风险,但可以忽略不计,API文档非常丰富,基于Java和Scala语言研发。二次开发比较方能,社区完善了Golang,Python等API】

– RabbitMQ【金融公司,文档丰富,性能较好,单机每秒处理1w+/s,有丰富的WebUI,可以做到数据不丢失。API开发相对来说不太友好。基于Erlang语言研发,国内并不流行,因此二次开发招人比较困难。】

“`

### 11 filebeat采集数据写入kafka

“`sh
1 kafka创建topic
kafka-topics.sh –bootstrap-server 10.0.0.92:9092,10.0.0.91:9092,10.0.0.93:9092 –partitions 3 –replication-factor 1 –topic ysl-elfk –create
Created topic ysl-elfk.

2 配置filebeat输出到kafka
cat >>/etc/filebeat/config/18-tcp-to-kafka.yaml<>/etc/logstash/conf.d/12-kafka-to-es.conf< “10.0.0.91:9092,10.0.0.92:9092,10.0.0.93:9092”

topics => [“ysl-elfk”]

group_id => “ysl-logstash004”

auto_offset_reset => “earliest”
}
}

filter {
json {
source => “message”

remove_field => [ “agent”,”input”,”log”,”@version”,”ecs” ]
}

}

output {
# stdout {}

elasticsearch {
hosts => [“10.0.0.91:9200″,”10.0.0.92:9200″,”10.0.0.93:9200”]
index => “ysl-logstash-elfk-kafka”
user => elastic
password => “123456”
}
}
EOF

2 启动logstash
logstash -rf /etc/logstash/conf.d/12-kafka-to-es.conf

3 kibana查看数据

“`

![image-20250319174200720](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250319174200720.png)

GIT

# git

## 1 运维发展过程

![image-20250327111155200](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250327111155200.png)

“`sh
https://www.processon.com/diagraming/67e4b7550804c26b55b70c19
“`

## 2 软件生命周期

“`sh
1 立项
目标与方向、调查
2 开发
需求分析、选择技术栈、代码仓库(git、github、gitee(码云)、gitlab、svn)、功能合并
3 运维
测试QA、打包工具maven、部署、性能测试,自动化测试工具
4 消亡

“`

## 3 ci/cd

“`sh
ci continuous integreation 持续集成: 开发的代码集成到代码仓库
cd continuous delivery 持续交付: 从代码仓库拉取代码部署到测试环境
cd continuous deployment 持续部署: 从代码仓库拉取代码部署到生产环境
“`

## 4 DevOps

“`sh
1 DevOps
Development 开发
Operations 运维

2 DevSecOps
Dev开发
Sec Secure 安全
Ops运维
“`

![image-20250327112340244](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250327112340244.png)

## 5 虚拟机准备

| 角色 | 主机名 | ip | 配置 |
| —————– | ————– | ————————– | —- |
| gitlab代码仓库 | devops-gitlab | 192.168.137.71/172.16.1.71 | 2c4g |
| jenkins | devops-jenkins | 192.168.137.72/172.16.1.72 | 2c4g |
| sonarqube代码检查 | devops-sonar | 192.168.137.73/172.16.1.73 | 1c1g |
| nexus | devops-nexus | 192.168.137.74/172.16.1.74 | 1c1g |

## 6 git和svn

| | git | svn |
| ——– | ———————————————- | ————————————– |
| 共同点 | 存放代码,版本控制 | 存放代码,版本控制 |
| 工作模式 | 分布式(git代码仓库挂了,本地的代码仍旧可以使用) | 中心化(权限集中) |
| 使用 | 入门较难,熟练后容易使用,目前使用率高 | 入门比较简单,服务端linux,客户端windows |
| 分支 | 创建和维护分支方便 | 创建和维护分支繁琐 |

## 7 部署git

“`sh
[root@devops-gitlab ~]# yum -y install git
“`

## 8 git极速上手

“`sh
1 创建项目目录(代码目录)
[root@devops-gitlab ~]# mkdir -p /app/src/bugc-live
[root@devops-gitlab ~]# cd /app/src/bugc-live/
[root@devops-gitlab /app/src/bugc-live]# ll
total 0

2 对代码目录进行初始化(书写代码的时候)成为git仓库
2.1 配置用户
[root@devops-gitlab /app/src/bugc-live]# git config –global user.name ‘zhangsan’

[root@devops-gitlab /app/src/bugc-live]# git config –global user.email ‘644574771@qq.com’

[root@devops-gitlab /app/src/bugc-live]# git config –global -l
user.name=zhangsan
user.gender=nan

2.2 初始化代码目录
[root@devops-gitlab /app/src/bugc-live]# git init
Initialized empty Git repository in /app/src/bugc-live/.git/

[root@devops-gitlab /app/src/bugc-live]# ll .git/
total 12
drwxr-xr-x 2 root root 6 Mar 27 12:57 branches
-rw-r–r– 1 root root 92 Mar 27 12:57 config
-rw-r–r– 1 root root 73 Mar 27 12:57 description
-rw-r–r– 1 root root 23 Mar 27 12:57 HEAD
drwxr-xr-x 2 root root 332 Mar 27 12:57 hooks
drwxr-xr-x 2 root root 21 Mar 27 12:57 info
drwxr-xr-x 4 root root 30 Mar 27 12:57 objects
drwxr-xr-x 4 root root 31 Mar 27 12:57 refs

3 书写代码,添加文件
[root@devops-gitlab /app/src/bugc-live]# echo git_test > index.html

3.1 查看仓库状态
root@devops-gitlab /app/src/bugc-live]# git status
On branch master

No commits yet

Untracked files:
(use “git add …” to include in what will be committed)
index.html

nothing added to commit but untracked files present (use “git add” to track)
[root@devops-gitlab /app/src/bugc-live]#

3.2 进行提交
[root@devops-gitlab /app/src/bugc-live]# git add .
[root@devops-gitlab /app/src/bugc-live]# git status
On branch master

No commits yet

Changes to be committed:
(use “git rm –cached …” to unstage)
new file: index.html

3.3 提交到本地仓库
[root@devops-gitlab /app/src/bugc-live]# git commit -m ‘项目开始,完成度60%’
[master (root-commit) f248882] 项目开始,完成度60%
1 file changed, 1 insertion(+)
create mode 100644 index.html
“`

9 git修改与回滚

“`sh
1 修改文件内容
vi或echo修改

再次提交
git add .
git commit -m ‘项目完成90%’

2进行回滚
[root@devops-gitlab /app/src/bugc-live]# echo “test_git_reflog” > test_git_reflog.html
[root@devops-gitlab /app/src/bugc-live]# git add .
[root@devops-gitlab /app/src/bugc-live]# git commit -m ‘项目完成90%’
[master 0e79f06] 项目完成90%
1 file changed, 1 insertion(+)
create mode 100644 test_git_reflog.html
[root@devops-gitlab /app/src/bugc-live]# git reflog
0e79f06 (HEAD -> master) HEAD@{0}: commit: 项目完成90%
f248882 HEAD@{1}: commit (initial): 项目开始,完成度60%

[root@devops-gitlab /app/src/bugc-live]# git reset –hard f248882
HEAD is now at f248882 项目开始,完成度60%
[root@devops-gitlab /app/src/bugc-live]# ll
total 4
-rw-r–r– 1 root root 9 Mar 27 12:58 index.html
[root@devops-gitlab /app/src/bugc-live]#

此时新建的test_git_reflog已经不见了

“`

## 9 git命令与含义

| 命令 | 含义 |
| —————————- | ———————————————————— |
| git init | 初始化本地仓库目录,每个独立的代码目录(新的)就要运行下..git目录 |
| git config –global | 邮箱,用户名,颜色,全局系统中设置1次即可 |
| git add | 提交数据到缓冲区,git add .(所有文件)或git add 文件 |
| git commit | 把暂存区的数据提交到本地仓库-m “标记/说明” |
| git status | 显示工作空间的状态 |
| git log | 查看提交记录 |
| git reflog | 查看提交记录 |
| git reset | 回滚 |
| git reset –soft cid(版本号) | 把指定的版本数据内容下载到暂存区 |
| git reset HEAD | 暂存区–>工作空间(被修改的状态) |
| git checkout | 文件下载到工作空间并可以使用 git checkout . 或git checkout 文件 |
| git reset –mix 版本号 | |
| git reset –hard 版本号 | 把本地仓库指定版本信息数据下载到工作目录中 |

## 10 git区域与状态

![image-20250327152053900](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250327152053900.png)

## 11 git分支branch

“`sh
分支即是平行空间,假设你在为某个手机系统研发拍照功能,代码已经完成了80%,但如果将这不完整的代码直接提交到git仓库中,又有可能影响到其他人的工作,此时我们便可以在该软件的项目之上创建一个名叫”拍照功能”的分支,

这种分支只会属于你自己,而其他人看不到,等代码编写完成后再与原来的项目主分支合并下即可,这样即能保证代码不丢失,又不影响其他人的工作。
默认的分支-master 主分支,这个分支的代码一般都是可用,可以部署到生产环境的。

一般开发人员开发代码的时候创建dev分支,shopping分支。
其他分支中的代码开发与测试完成要与主分支代码进行合并.
应用名称分支每个分支对应独立功能。
“`

![image-20250327152542232](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20250327152542232.png)

“`sh
案例
默认主分支,完成直播功能,并提交

[root@devops-gitlab /app/src/bugc-live]# echo “complete” >> index.html
[root@devops-gitlab /app/src/bugc-live]# git add .
[root@devops-gitlab /app/src/bugc-live]# git commit -m “complete 100%”
[master eb2b1b0] complete 100%
1 file changed, 1 insertion(+)

2 创建shopping分支,书写代码
[root@devops-gitlab /app/src/bugc-live]# git branch
* master
[root@devops-gitlab /app/src/bugc-live]# #创建分支
[root@devops-gitlab /app/src/bugc-live]# git branch shopping
[root@devops-gitlab /app/src/bugc-live]# git branch
* master
shopping

3 切换分支
[root@devops-gitlab /app/src/bugc-live]# git checkout shopping
Switched to branch ‘shopping’
[root@devops-gitlab /app/src/bugc-live]#

4 查看切换结果
[root@devops-gitlab /app/src/bugc-live]# git branch
master
* shopping

5 书写shopping代码,并提交
[root@devops-gitlab /app/src/bugc-live]# echo ‘shopping 90%’ > shopping.html
[root@devops-gitlab /app/src/bugc-live]# git add .
[root@devops-gitlab /app/src/bugc-live]# git commit -m ‘shopping 90%’
[shopping 3744f29] shopping 90%
1 file changed, 1 insertion(+)
create mode 100644 shopping.html

root@devops-gitlab /app/src/bugc-live]# echo ‘shopping 100%’ > shopping.html
[root@devops-gitlab /app/src/bugc-live]# git add .
[root@devops-gitlab /app/src/bugc-live]# git commit -m ‘shopping 100%’
[shopping ac51a20] shopping 100%
1 file changed, 1 insertion(+), 1 deletion(-)
[root@devops-gitlab /app/src/bugc-live]#

6 将shopping合并到master分支中
[root@devops-gitlab /app/src/bugc-live]# #将shopping合并到master分支中
[root@devops-gitlab /app/src/bugc-live]# git checkout master
Switched to branch ‘master’
[root@devops-gitlab /app/src/bugc-live]# git merge shopping
Updating eb2b1b0..ac51a20
Fast-forward
shopping.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 shopping.html
“`

## 12 git 分支命令总结

| git分支相关命令 | 说明 |
| ——————– | ———————— |
| git branch | 查看分支 |
| git branch name | 创建分支 |
| git branch -d name | 删除分支 |
| git checkout name | 切换分支 |
| git merge name | 合并分支 |
| git checkout -b name | 创建分支并切换到这个分支 |

## 13 tag标签

“`sh
1 创建标签
COMMITID的一个别名,COMMITID不好记忆,标签相对的好记忆。
git tag -a “标签名” -m “描述”

基于当
前最新的COMMITID
git tag -a “标签名称” -m “描述” commitID 指定版
本打标签
#如何上传标签
git push origin –tags
git push origin “标签名称”
Master: V1.0 V2.0
Dev: b1.0 b2.0
git clone -b 标签、分支 https/git
“`

## 14 代码仓库

“`sh
公共仓库:gitee.com/github.com
私有仓库:gitlab,gogs

在gitee上新建仓库
“`

## 15 创建仓库

1 gitee上新建仓库

![image-20250328153432739](D:\Program Files (x86)\Typora\综合架构-git\image-20250328153432739.png)

![image-20250329094701933](D:\Program Files (x86)\Typora\综合架构-git\image-20250329094701933.png)

2 连接远程仓库-秘钥方式

“`sh
创建密钥对
Administrator@ysl MINGW64 ~
$ ssh-keygen.exe
Generating public/private ed25519 key pair.
Enter file in which to save the key (/c/Users/Administrator/.ssh/id_ed25519):
Enter passphrase for “/c/Users/Administrator/.ssh/id_ed25519” (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/Administrator/.ssh/id_ed25519
Your public key has been saved in /c/Users/Administrator/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:u2NAfeAyRbguOfff3gThJRRJvGKvpFGiFK2zcz2rDOk Administrator@ysl
The key’s randomart image is:
+–[ED25519 256]–+
| +. o+o |
| o + .o |
| B . o.. |
| O + =..+ |
| = *S* oo |
| + B.o.+ .. |
| +o=.+ + . |
| . o=.o. o |
| E.++..o . |
+—-[SHA256]—–+

Administrator@ysl MINGW64 ~

“`

![image-20250329100302219](D:\Program Files (x86)\Typora\综合架构-git\image-20250329100302219.png)

3 在远程仓库中配置公钥

![image-20250329095101378](D:\Program Files (x86)\Typora\综合架构-git\image-20250329095101378.png)

![image-20250329095309854](D:\Program Files (x86)\Typora\综合架构-git\image-20250329095309854.png)

![image-20250329100436201](D:\Program Files (x86)\Typora\综合架构-git\image-20250329100436201.png)

![image-20250329100957035](D:\Program Files (x86)\Typora\综合架构-git\image-20250329100957035.png)

“`sh
[root@devops-gitlab /app/src/bugc-live]# git config –global user.name “yangsenlin”
[root@devops-gitlab /app/src/bugc-live]# git config –global user.email “15640879+ysllxl@user.noreply.gitee.com”
[root@devops-gitlab /app/src/bugc-live]# mkdir ysl-live
[root@devops-gitlab /app/src/bugc-live]# cd ysl-live
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git init
Initialized empty Git repository in /app/src/bugc-live/ysl-live/.git/
[root@devops-gitlab /app/src/bugc-live/ysl-live]# touch README.md
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git add README.md
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git commit -m “first commit”
[master (root-commit) 58a2ad5] first commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git remote add origin git@gitee.com:ysllxl/ysl-live.git
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git push -u origin –all
The authenticity of host ‘gitee.com (180.76.199.13)’ can’t be established.
ECDSA key fingerprint is SHA256:FQGC9Kn/eye1W8icdBgrQp+KkGYoFgbVr17bmjey0Wc.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added ‘gitee.com,180.76.199.13’ (ECDSA) to the list of known hosts.
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 225 bytes | 225.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [1.1.5]
remote: Set trace flag 5e49a6b3
To gitee.com:ysllxl/ysl-live.git
* [new branch] master -> master
Branch ‘master’ set up to track remote branch ‘master’ from ‘origin’.
[root@devops-gitlab /app/src/bugc-live/ysl-live]#
“`

“`sh
执行命令后刷新页面,查看
“`

![image-20250329101111837](D:\Program Files (x86)\Typora\综合架构-git\image-20250329101111837.png)

4 新建代码并上传

“`sh
[root@devops-gitlab /app/src/bugc-live/ysl-live]# touch gitee-code-test.txt
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git add .
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git commit -m ‘gitee-code-upload-test’
[master 2b81168] gitee-code-upload-test
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 gitee-code-test.txt
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git tag -m “gitee-code-upload-test” -a “v2.0”
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git push -u origin master
Warning: Permanently added the ECDSA host key for IP address ‘180.76.198.77’ to the list of known hosts.
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 278 bytes | 278.00 KiB/s, done.
Total 2 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [1.1.5]
remote: Set trace flag 754aab8f
To gitee.com:ysllxl/ysl-live.git
58a2ad5..2b81168 master -> master
Branch ‘master’ set up to track remote branch ‘master’ from ‘origin’.
[root@devops-gitlab /app/src/bugc-live/ysl-live]# git push -u origin –tags
Warning: Permanently added the ECDSA host key for IP address ‘180.76.198.225’ to the list of known hosts.
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 182 bytes | 182.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [1.1.5]
remote: Set trace flag fb47f59d
To gitee.com:ysllxl/ysl-live.git
* [new tag] v2.0 -> v2.0
“`

![image-20250329101650381](D:\Program Files (x86)\Typora\综合架构-git\image-20250329101650381.png)

![image-20250329101744758](D:\Program Files (x86)\Typora\综合架构-git\image-20250329101744758.png)

5 git远程仓库命令

“`sh
git远程仓库:
1.配置与远程仓库的认证
ssh√√√√√: 需要将服务器的公钥推送到指定用户下;
https:(私有) 需要有用户名称,密码,每次都需要输入;
2.添加远程仓库:
添加add
git remote add origin [https://或者git(ssh)]
删除remove
git remote remove orgin 即可
改名
git remove rename origin bak
3.将本地的仓库内容,推送到远程仓库:
git add .
git commit -m “Messages”
git push -u origin branch (分支名字) [
master | …. ]
git pull origin branch(分支名字)
4.如果有新员工加入
指定仓库的代码都下载。
git clone [https://|git]
git push origin 分支名字
git pull origin –tag
“`

6 git基础命令

“`sh
1. `git clone`
– 含义:克隆一个远程仓库到本地。
– 用途:当你想要获取一个项目的完整副本时使用。它会创建一个新的本地仓库目录,并将远程仓库中的所有分支和历史记录都拉取到本地。
– 示例:`git clone https://github.com/user/repo.git`,将远程仓库克隆到本地当前目录下的 `repo` 文件夹。

2. `git add`
– 含义:将文件添加到暂存区(staging area)。
– 用途:在提交之前,需要先将文件的更改添加到暂存区。只有暂存区的文件会在下一次提交时被记录。
– 示例:
– `git add file.txt`:将 `file.txt` 添加到暂存区。
– `git add .`:将当前目录下所有更改的文件添加到暂存区。
– `git add -A`:将所有更改(包括新文件、修改文件和删除文件)添加到暂存区。

3. `git commit`
– 含义:将暂存区的更改提交到本地仓库。
– 用途:保存当前工作状态,记录更改的历史信息。
– 示例:
– `git commit -m “描述信息”`:提交暂存区的更改,并添加描述信息。
– `git commit -am “描述信息”`:直接提交所有已跟踪文件的更改(跳过暂存区)。

4. `git push`
– 含义:将本地分支的更改推送到远程仓库。
– 用途:将本地提交的更改同步到远程仓库,供其他开发者使用。
– 示例:
– `git push origin branch_name`:将本地分支 `branch_name` 推送到远程仓库的同名分支。
– `git push -u origin branch_name`:推送的同时设置上游分支(后续可以直接用 `git push` 推送该分支)。

5. `git pull`
– 含义:从远程仓库拉取最新的更改,并合并到当前分支。
– 用途:更新本地分支,使其与远程分支保持一致。
– 示例:
– `git pull origin branch_name`:从远程仓库的 `branch_name` 拉取更改并合并到当前分支。

6. `git fetch`
– 含义:从远程仓库拉取最新的更改,但不自动合并到当前分支。
– 用途:查看远程仓库的最新状态,而不影响本地工作区。通常与 `git merge` 或 `git rebase` 结合使用。
– 示例:
– `git fetch origin`:从远程仓库 `origin` 拉取最新更改。

7. `git merge`
– 含义:将一个分支的更改合并到当前分支。
– 用途:用于整合不同分支的代码。
– 示例:
– `git merge branch_name`:将 `branch_name` 分支的更改合并到当前分支。

8. `git log`
– 含义:查看提交历史记录。
– 用途:用于了解项目的开发历程,查看每次提交的详细信息。
– 示例:
– `git log`:显示完整的提交历史。
– `git log -p`:显示每次提交的详细更改。
– `git log –oneline`:以简洁的单行格式显示提交历史。

9. `git reflog`
– 含义:查看本地仓库的引用日志,记录了所有分支和HEAD的移动历史。
– 用途:用于恢复误操作(如丢失的提交或错误的重置)。
– 示例:
– `git reflog`:显示引用日志。

10. `git status`
– 含义:查看当前工作区和暂存区的状态。
– 用途:了解哪些文件被修改、哪些文件已暂存等。
– 示例:
– `git status`:显示当前工作区和暂存区的状态。

11. `git branch`
– 含义:管理分支。
– 用途:创建、删除、查看分支。
– 示例:
– `git branch`:列出所有本地分支。
– `git branch branch_name`:创建新分支。
– `git branch -d branch_name`:删除分支。

12. `git checkout`
– 含义:切换分支或检出文件。
– 用途:用于切换到其他分支,或者恢复文件到某个版本。
– 示例:
– `git checkout branch_name`:切换到指定分支。
– `git checkout file.txt`:恢复工作区的 `file.txt` 到最近一次提交的状态。

13. `git merge`
– 含义:合并分支。
– 用途:将一个分支的更改合并到当前分支。
– 示例:
– `git merge branch_name`:将 `branch_name` 分支的更改合并到当前分支。

14. `git reset –hard`
– 含义:重置当前分支到指定的提交。
– 用途:用于撤销本地更改,将工作区和暂存区恢复到指定的提交状态。
– 示例:
– `git reset –hard HEAD`:撤销所有暂存区和工作区的更改。
– `git reset –hard commit_id`:将当前分支重置到指定的提交。

15. `git remote add origin`
– 含义:添加远程仓库的地址。
– 用途:设置本地仓库与远程仓库的关联。
– 示例:
– `git remote add origin https://github.com/user/repo.git`:将远程仓库地址添加为 `origin`。

16. `git tag`
– 含义:创建标签。
– 用途:用于标记特定的提交,通常用于版本发布。
– 示例:
– `git tag v1.0`:在当前提交创建标签 `v1.0`。
– `git tag -a v1.0 -m “Release version 1.0″`:创建带注释的标签。

这些命令是 Git 的基础操作,掌握它们可以帮助你高效地管理代码版本和协作开发。
“`

# gitlab

## 1 概述

“`sh
gitlab是私有代码仓库
特点:
1 精细化权限配置,让系统更安全
2 控制用户/用户组是否可以提交到主分支(PR Push Request)
3 它使用Ruby语言写成。后来,一些部分用Go语言重写
“`

## 2 gitlab和github/gitee的关系

| | gitlab | github/gitee |
| —— | ————————————————– | —————————————— |
| 共同点 | 存放代码,git访问 | 存放代码,git访问 |
| 不同点 | 精确化控制权限、全面安全措施、定时备份、升级、迁移 | 使用权限,用户管理比较弱,无法做到精细化权限 |

## 3 应用场景

“`sh
1 开源免费,搭建简单,维护成本低符合中小公司口味 gogs.io
2 权限管理,实现代码对部分人可见,安全性高
3 离线同步
1 #gogs
https://gogs.io/docs/installation/install_from_binary
https://blog.mynook.info/post/host-your-own-git-server-using-gogs/
“`

## 4 架构

![image-20250329103812969](D:\Program Files (x86)\Typora\综合架构-git\image-20250329103812969.png)

![image-20250329103937720](D:\Program Files (x86)\Typora\综合架构-git\image-20250329103937720.png)

![image-20250329104214465](D:\Program Files (x86)\Typora\综合架构-git\image-20250329104214465.png)

“`sh
官网说明
https://docs.gitlab.com/development/architecture/#components
“`

## 5 部署gitlab

“`sh
1 下载安装
[root@devops-gitlab ~]# yum install -y policycoreutils-python-utils.noarch

[root@devops-gitlab ~]# wget https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/7/gitlab-ce-15.9.3-ce.0.el7.x86_64.rpm/download.rpm

[root@devops-gitlab ~]# rpm -ivh –nodeps gitlab-ce-15.9.3-ce.0.el7.x86_64.rpm

2 修改配置文件
[root@devops-gitlab ~]# cp /etc/gitlab/gitlab.rb{,.bak}
[root@devops-gitlab ~]# cat > /etc/gitlab/gitlab.rb<> /etc/hosts
[root@devops-gitlab /app/src/bugc-live]# cat /etc/hosts

3 再次检查git
[root@devops-gitlab /app/src/bugc-live]# git remote -v
gitee git@gitee.com:ysllxl/ysl-live.git (fetch)
gitee git@gitee.com:ysllxl/ysl-live.git (push)
origin http://gitlab.ysl.cn/gitlab-instance-3d7cae8e/test_gitlab.git (fetch)
origin http://gitlab.ysl.cn/gitlab-instance-3d7cae8e/test_gitlab.git (push)

4 查看状态
[root@devops-gitlab /app/src/bugc-live]# git status

5 上传代码,标签
[root@devops-gitlab /app/src/bugc-live]# git push -u origin –all
Username for ‘http://gitlab.ysl.cn’: root
Password for ‘http://root@gitlab.ysl.cn’:
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Delta compression using up to 2 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (12/12), 984 bytes | 984.00 KiB/s, done.
Total 12 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for master, visit:
remote: http://gitlab.ysl.cn/gitlab-instance-3d7cae8e/test_gitlab/-/merge_requests/new?merge_request%5Bsource_branch%5D=master
remote:
remote:
remote: To create a merge request for shopping, visit:
remote: http://gitlab.ysl.cn/gitlab-instance-3d7cae8e/test_gitlab/-/merge_requests/new?merge_request%5Bsource_branch%5D=shopping
remote:
To http://gitlab.ysl.cn/gitlab-instance-3d7cae8e/test_gitlab.git
* [new branch] master -> master
* [new branch] shopping -> shopping
Branch ‘master’ set up to track remote branch ‘master’ from ‘origin’.
Branch ‘shopping’ set up to track remote branch ‘shopping’ from ‘origin’.

[root@devops-gitlab /app/src/bugc-live]# git push -u origin –tags
Username for ‘http://gitlab.ysl.cn’: root
Password for ‘http://root@gitlab.ysl.cn’:
Everything up-to-date
“`

![image-20250330220036034](D:\Program Files (x86)\Typora\综合架构-git\image-20250330220036034.png)

“`sh
6 新建一个标签并上传
[root@devops-gitlab /app/src/bugc-live]# echo test_live_shopping > readme.md
[root@devops-gitlab /app/src/bugc-live]# git add .

[root@devops-gitlab /app/src/bugc-live]# git commit -m “add readme”
[master 252825f] add readme
2 files changed, 2 insertions(+)
create mode 100644 readme.md
create mode 160000 ysl-live
[root@devops-gitlab /app/src/bugc-live]# git push -u origin –all
Username for ‘http://gitlab.ysl.cn’: root
Password for ‘http://root@gitlab.ysl.cn’:
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 377 bytes | 377.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for master, visit:
remote: http://gitlab.ysl.cn/gitlab-instance-3d7cae8e/test_gitlab/-/merge_requests/new?merge_request%5Bsource_branch%5D=master
remote:
To http://gitlab.ysl.cn/gitlab-instance-3d7cae8e/test_gitlab.git
ac51a20..252825f master -> master
Branch ‘master’ set up to track remote branch ‘master’ from ‘origin’.
Branch ‘shopping’ set up to track remote branch ‘shopping’ from ‘origin’.
“`

![image-20250330220825580](D:\Program Files (x86)\Typora\综合架构-git\image-20250330220825580.png)

## 8 gitlab备份与恢复

“`sh
1 修改配置文件
在/etc/gitlab/gitlab.rb增加
#开启备份功能
gitlab_rails[‘manage_backup_path’] = true
#备份目录
gitlab_rails[‘backup_path’] = “/var/opt/gitlab/backups”
#备份文件权限
gitlab_rails[‘backup_archive_permissions’] = 0600
#备份保留时间
gitlab_rails[‘backup_keep_time’] = 604800

2 reconfigure一下
[root@devops-gitlab /app/src/bugc-live]# gitlab-ctl reconfigure

3 开始备份
[root@devops-gitlab /app/src/bugc-live]# gitlab-backup create

[root@devops-gitlab /app/src/bugc-live]# ll /var/opt/gitlab/backups/
total 452
-rw-r–r– 1 git git 460800 Mar 30 22:15 1743344106_2025_03_30_15.9.3_gitlab_backup.tar

4 恢复
gitlab-ctl stop sidekiq
gitlab-backup restore BACKUP= 1743344106_2023_03_30_15.9.3_gitlab_backup.tar
“`

ZABBIX

### 1 监控是什么,为什么要监控

#### 1.1 监控概述

监控是指对行为、活动或其他变动中信息的一种持续性关注,通常是为了对人达成影响、管理、指导或保护的目的

监控:

见识主机,架构状态

控制,事后追责

目标

​ 早发现造出来

​ 网站扩容

随着用户的增多,服务随时可能被oom

#### 1.2 监控大纲

“`
1、监控与命令
2、面试题:你们公司监控了什么
3、监控通用架构
4、监控生产最佳实践
5、监控设备
6、自定义监控
7、自定义监控进阶与故障案例
8、监控与告警,邮件、微信、短信、电话、钉钉、飞书、调取api接口
9、监控886-zabbix-agent2
agent:通用
snmp:网络设备,带宽,流量
jmx(java gateway tomcat)
ipmi
10、自动化监控
自动发现
自动注册
主动与被动
分布式监控proxy:多个机房,多个地区监控
11、监控中级挑战
iid低级自动发现:自动获取、调价监控项、触发器、图形、mysql多实例、tomcat多实例
zabbix内置,自动发现网卡,磁盘分区,硬盘,cpu
手动创建iid(端口)
自动获取对应服务的端口,按照指定格式显示
zabbix客户端,创建自动发现key
创建自定义监控项
web页面操作,添加监控项原型
web页面操作,添加触发器原型
web页面操作,添加图形原型
启动自动发现规则
zabbix api
全网监控项目
zabbix与提升
grafana

“`

### 2 监控的一些命令

| 项目 | 对应的检查命令 |
| —- | ———————————————————— |
| 网站 | curl/wget |
| 服务 | systemctl/service/chconfig |
| 进程 | ps/pstree/pgrep/pidstat/top/htop |
| cpu | top/htop/vmstat/mpstat/lscpu/cpuinfo/w/uptime/sar |
| 内存 | top/free/ps/iotop/vmstat/mpstat/sar/hcache |
| 磁盘 | iptop/iostat/sar,磁盘测试命令dd |
| 网络 | iftop/nethogs/nstat/ifstat/mtr/sar/ip/route |
| 硬件 | megacli(raid)/ipmitool(温度,cpu坟山转速)/Im_sensors(温度) |

“`
procs ———–memory———- —swap– —–io—- -system– ——cpu—–
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 6804916 2708 650304 0 0 13 5 107 143 0 0 99 0 0
“`

### 3 监控有哪些

| 阶段 | 说明 |
| —- | ———————————————————— |
| 过去 | nagios+cacti |
| 目前 | zabbix,grafana,openFaicon(小米开源),prometheus,n9e,滴滴开源 |

### 4 zabbix监控架构

#### 4.1 生命周期

LTS long time support长期维护版本

#### 4.2 zabbix监控架构

“`
zabbix是一个cs架构的服务
zabbix监控流程
zabbix-agent获取数据-发送给zabbix-server服务端-数据存放在服务端–数据库–zabbix web页面展示数据
“`

#### 4.3 主机规划

| 角色 | 主机名 | 网络 | 配置 |
| ———— | ————- | —- | —- |
| zabbix服务端 | zabixx-server | 62 | 2c4g |
| zabbix | web01 | 7 | 1c1g |
| zabbix客户端 | db01 | 51 | 1c1g |

“`
安装步骤
1、安装docker20.10和docker-compose 2.26
2、导入镜像
3、docker-compose启动,浏览器访问与配置
4、宿主机安装客户端zbx_agent2

yum install -y docker
cat >/etc/docker/daemon.json</etc/zabbix/zabbix_agent2.conf< /dev/null` 2>
/dev/null || true
endscript
}
“`

#### 5.2 客户端配置

| zabbix客户端目录详解 | 说明 |
| —————————— | —————————— |
| /etc/zabbix/zabbix_agent2.conf | 配置文件 |
| /etc/zabbix/zabbix_agent2.d/ | 自配置文件目录,用于自定义监控 |
| /var/log/zabbix | 日志 |

#### 5.3 zabbix_agent和zabbix_agent2

| | zabbix_agent | zabbix_agent2 |
| ——– | —————- | ———————————————————— |
| 开发语言 | C语言 | Go语言和C语言 |
| 性能 | 独立进程方式运行 | 1个进程多个线程运行,减少资源消耗,占用较少的tcp资源,能够承受更高并发 |

### 6 监控任意主机流程

“`
1、安装客户端及修改配置文件,测试
2、web页面添加主机,关联模版
3、调试
“`

![image-20241216162748546](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216162748546.png?lastModify=1746594238)

![image-20241216162641623](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216162641623.png?lastModify=1746594238)

![image-20241216162656921](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216162656921.png?lastModify=1746594238)

等待变绿

#### 6.1 小结

“`
1、安装客户端及修改配置文件,测试,交给ansible
2、web页面添加主机,关联模版,通过zabbix自动发现与自动注册
3、调试

调试命令
zabbix_get -s 172.16.1.8 -k system.hostname
“`

### 7 弥补监控死角-自定义监控

#### 7.1 概述

我们通过zbx客户端+各种模版实现监控

linux zabbix agent模板可以监控以下等内容

“`
cpu
磁盘
内存,swap
网络,网卡
系统负载
进程数量
用户登录数量
系统运行时长
自定义监控应用场景
模版中没有我们所需要的监控项
末班中监控项过多

web01自动以监控僵尸进程数量?自定义监控
web01监控没有通过堡垒机登录的用户数量
“`

#### 7.2 自定义监控全流程

| 步骤 | 流程 | 说明 |
| —— | ————————————————— | ————————————– |
| 客户端 | 通过命令、脚本取出对应的值 | |
| | 根据zabbix_agent2要求按格式书写配置文件,创建,键值 | 键值key用于获取客户端数据 |
| 服务端 | 服务端测试键值是否可用 | zabbix_get |
| | web页面:键值也监控项关联,创建监控项 | |
| | web页面:测试 | |
| | web页面:图形 | |
| | web页面:触发器(报警) | 是否发出警告:需要根据情况决定是否设置 |

##### 1 客户端

“`
通过命令、脚本取出对应的值

获取僵尸进程数量
top bn1 | awk ‘NR==2{print $(NF-1)}’

在/etc/zabbix/zabbix_agent2.d目录下新建一个.conf结尾的文件,添加以下内容
UserParameter=check.zombie,top bn1 | awk ‘NR==2{print $(NF-1)}’
重启客户端
固定写法
UserParameter=check.xxx,命令或脚本
“`

##### 2 服务端

“`
在服务端使用以下命令测试
zabbix_get -s 172.16.1.7 -k check.zombie
命令结果0
“`

| zabbix_get命令 | 说明 |
| ————– | ————————— |
| -s | 客户端ip地址 |
| -k | 指定键值 |
| -p | 指定客户端端口号,默认10050 |

##### 3 web页面创建监控项

配置→主机→监控项→创建监控项

![image-20241216172223863](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216172223863.png?lastModify=1746594238)

![image-20241216172337757](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216172337757.png?lastModify=1746594238)

![image-20241216173331604](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216173331604.png?lastModify=1746594238)

![image-20241216180617589](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180617589.png?lastModify=1746594238)

![image-20241216180626903](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180626903.png?lastModify=1746594238)

![image-20241216180643365](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180643365.png?lastModify=1746594238)

![image-20241216180636802](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180636802.png?lastModify=1746594238)

![image-20241216180655107](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180655107.png?lastModify=1746594238)

“`
制造僵尸进程,查看
gcc zombie.c -o zombie
./zombie &
top查看
“`

测试时报错

“`
Connection to Zabbix server “localhost” failed. Possible reasons:
1. Incorrect server IP/DNS in the “zabbix.conf.php”;
2. Incorrect DNS server configuration.
Cannot assign requested address
“`

##### 4 触发器

根据监控项获取的数值,决定是否要告警,是否要提示异样

![image-20241216180913504](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180913504.png?lastModify=1746594238)

![image-20241216180921175](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180921175.png?lastModify=1746594238)

![image-20241216180930510](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180930510.png?lastModify=1746594238)

![image-20241216180937459](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180937459.png?lastModify=1746594238)

![image-20241216180944263](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180944263.png?lastModify=1746594238)

![image-20241216180952458](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216180952458.png?lastModify=1746594238)

![image-20241216181003156](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216181003156.png?lastModify=1746594238)

![image-20241216181009803](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216181009803.png?lastModify=1746594238)

##### 5 图形

![image-20241216181515924](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216181515924.png?lastModify=1746594238)

![image-20241216181522155](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216181522155.png?lastModify=1746594238)

![image-20241216181533136](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216181533136.png?lastModify=1746594238)

![image-20241216181539685](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216181539685.png?lastModify=1746594238)

![image-20241216181544799](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241216181544799.png?lastModify=1746594238)

##### 6 自定义监控小结

“`
只要能通过命令、脚本取出来的东西就可以自定义监控
1、客户端:通过命令脚本取出想要的内容,创建键值key,写入配置文件
2、服务端:命令测试键值,web页面,添加监控项,添加触发器,添加图形
3、调试
“`

### 8 常用键值与触发器函数

#### 8.1 键值

| 常用键值 | 说明 |
| —————— | ———————————————————— |
| agent.hostname | 主机名,获取的是客户端配置文件中指定的主机名 |
| systemctl.hostname | 主机名,系统的主机名,类似于hostname |
| agent.ping | 服务端和客户端是否通畅,通为1,不通为非1 |
| net.if.in[if] | interface网卡网络接口上传流量统计,返回证书,if是网卡名字,可以忽略 |
| proc.num | 进程数,返回整数,name进程名字,user用户,state进程状态,cmaline进程对应命令 |
| net.if.out[if] | 流出流量统计,返回整数 |
| net.tcp.port[port] | 检查是否能建立tcp连接到指定的端口,0不能连接,1可以连接 |

“`
获取的是客户端配置文件中指定的主机名
zabbix_get -s 172.16.1.7 -k agent.hostname
系统的主机名
zabbix_get -s 172.16.1.7 -k system.hostname
zabbix_get -s 172.16.1.7 -k agent.ping
zabbix_get -s 172.16.1.7 -k net.if.in[ens33]
184949
zabbix_get -s 172.16.1.7 -k net.if.out[ens33]
115448

zabbix_get -s 172.16.1.7 -k proc.num
161
zabbix@73ff1d966336:/var/lib/zabbix$ zabbix_get -s 172.16.1.7 -k proc.num[state]
0
zabbix@73ff1d966336:/var/lib/zabbix$ zabbix_get -s 172.16.1.7 -k proc.num[root]
0

zabbix_get -s 172.16.1.7 -k net.tcp.port[,22]
1
zabbix_get -s 172.16.1.7 -p 10050 -k proc.num[,,zomb]
0
“`

#### 8.2 常用键值参考

https://www.zabbix.com/documentation/6.0/zh/manual/config/items/itemtypes/zabbix_agent

#### 8.3 触发器函数

写在触发器表达式中,用于设置报警条件

触发器函数要结合键值(监控项)

| 功能(函数) | 说明 |
| ———— | ——————————– |
| 对比与比较 | |
| last() | 最近值,取出最近一些值 |
| nodata() | 是否有数据 |
| diff() | 是否发生变化,一般配合md5check() |
| 进行计算 | |
| avg() | 平均值 |
| min() | 最小值 |
| max() | 最大值 |

分析案例-目的是用来检查/etc/passwd的变化情况,间接检查是否有用户增加或删除

“`
last(/backup/vfs.file.cksum[/etc/passwd,sha256],#1) <>
last(/backup/vfs.file.cksum[/etc/passwd,sha256],#2)
#倒数第1个 /etc/passwd 的md5值
last(/Zabbix server/vfs.file.cksum[/etc/passwd,sha256],#1)
<>
#倒数第2个 /etc/passwd 的md5值
last(/Zabbix server/vfs.file.cksum[/etc/passwd,sha256],#2)
倒数第1个md5的值和倒数第2个md5的是 如果不相等了,则报警.
目的是用来检查/etc/passwd的变化情况,间接检查是否有用户增加或删除.
“`

#### 8.4 自定义监控-参数案例

“`
把zbx自定义监控键值UserParameter=key,命令或脚本
当成一个脚本或命令
脚本命令运行的时候不要参数,参考我们10.2里面的写法
脚本或命令运行的时候需要传参,参考我们接下来的写法即可
“`

目标:检查指定用户是否存在异地登录

最简单的想法:检查指定用户登录的ip地址。进行对比

“`
选择命令
w who只能显示当前此时此刻,登录情况
lastlog实现
调取接口实现
键值:实现取出指定用户登录的ip地址
服务端:web页面触发器对比
“`

| 步骤 | 流程 | 说明 |
| —— | ——————————————- | ———————————— |
| 客户端 | 通过命令、脚本取出对应的值 | |
| | 根据zbx要求按照格式,书写配置文件,创建键值 | 键值key用于获取客户端数据 |
| | 重新客户端客户端测试键值是否可用 | zabbix_agent2 -t |
| 服务端 | 服务端测试键值是否可用 | zabbix_get |
| | web页面:键值与客户端关联 | |
| | web页面:测试 | |
| | web页面:触发器 | 是否发出警告需要根据情况决定是否设置 |

#### 1 客户端

“`
lastlog |grep root |awk ‘{print $3}’
root有可能未来是其他用户

书写键值
UserParameter=user.login.check[*],lastlog | grep “$1” | awk ‘{print $$3}’
如果使用自定义键值传参,awk取列的时候要使用$$列。
如果没有传参,awk正常使用即可
测试键值
abbix_agent2 -t user.login.check[root]
“`

![image-20241218112943771](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218112943771.png?lastModify=1746594238)

#### 2 服务端

“`
zabbix_get -s 172.16.1.7 -k user.login.check[root]
“`

#### 3 web添加监控项

![image-20241218113744054](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218113744054.png?lastModify=1746594238)

![image-20241218113759979](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218113759979.png?lastModify=1746594238)

web触发器添加

“`
last(/web01/user.login.check[root],#1)
<>
last(/web01/user.login.check[root],#2)
意思是最后两个值不相等
“`

#### 4 小结

“`
自定义监控,key带参数
故障:带参数+awk取列时使用$$3才是取第三列
多看看模版中的监控项和触发器规则
“`

### 9 使用模版

“`
我们一般在某一台机器上创建监控项,触发器,图形,一般用于测试
测试完成需要创建或修改模版,把自定义监控项复制过去
使用的时候只需要把模版与主机关联
发送对应的自定义配置文件和脚本

自定义监控后续步骤
1、创建模版
2、添加自定义监控项
3、添加触发器
4、添加图形
5、模版关联主机
6、客户端配置自定义键值分发配置文件和脚本
“`

#### 1 创建模版

![image-20241218114917352](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218114917352.png?lastModify=1746594238)

![image-20241218114934929](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218114934929.png?lastModify=1746594238)

在模板中创建变量(宏)

![image-20241218115002445](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115002445.png?lastModify=1746594238)

检查模板信息

![image-20241218115016311](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115016311.png?lastModify=1746594238)

#### 2 添加自定义监控项

进入主机中复制即可

![image-20241218115125436](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115125436.png?lastModify=1746594238)

选择要复制的监控项,选择复制即可,(可批量)

![image-20241218115155946](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115155946.png?lastModify=1746594238)

选择复制到模板中

![image-20241218115214410](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115214410.png?lastModify=1746594238)

提示复制成功

![image-20241218115233527](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115233527.png?lastModify=1746594238)

检查末班中监控项部分:多乐两个监控项

![image-20241218115341342](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115341342.png?lastModify=1746594238)

#### 3 复制触发器与图形

主机→触发器

![image-20241218115426127](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115426127.png?lastModify=1746594238)

复制

![image-20241218115436774](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115436774.png?lastModify=1746594238)

检查模板

![image-20241218115447623](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115447623.png?lastModify=1746594238)

复制图形与复制触发器、监控项一致

#### 4 模板关联主机

进入主机中,批量选择要添加的模版的主机,批量更新

![image-20241218115624920](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115624920.png?lastModify=1746594238)

选择模板部分

![image-20241218115640163](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115640163.png?lastModify=1746594238)

添加模版关联主机成功

![image-20241218115700460](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218115700460.png?lastModify=1746594238)

#### 5 配置linux客户端键值

分发键值配置文件到db01和nfs01

重启zbx客户端,使用ansible分发

#### 6 调试

给监控项设置标记,方便分类

“`
zabbix5.x之前叫应用及,zabbix6.x叫标记,都是用于分类
“`

#### 7 小结

“`
找到一台主机进行测试标记,监控项,触发器,图形。。。
然后创建模版,把对应的内容复制到模板中
模板关联主机
键值的配置文件发过去
“`

#### 8 自定义监控流程

“`
客户端:命令,脚本,客户端子配置文件
服务端:测试客户端键值
前端:添加监控项、触发器、图形,并测试有数据后,创建模板,复制监控项,复制触发器,复制图形,模板与主机关联
客户端:分发自定义配置和脚本
测试与检查
“`

## 10 换个角度看监控 zabbix-agent

#### 1 zabbix客户端概述

| zabbix客户端 | 应用场景 |
| ————- | ———————————————————— |
| zabbix-agent2 | 适用于几乎所有情况,支持自定义监控,linux,windows server,android/ios |
| SNMP客户端 | 用于监控网络设备,简单网络管理协议,监控网络设备 |
| JMX | jmxremote java-gateway监控java app(tomcat),未来推介自定义健康zabbixz_agent2+jstack/jmap/jstats |
| IPMI | 监控硬件,直接使用自定义监控ipmitool+megacli |

#### 2 zabbix-agent监控windows

“`
安装客户端配置,服务端添加主机,关联模板调试
“`

##### 2.1 安装windows客户端

安装完成后修改windows zabbix-agents注释掉tls加密认证功能

“`
sed -i ‘/^TLS/s@^@#@g’ zabbix_agent2.conf
net stop “Zabbix Agent 2”
net start “Zabbix Agent 2″
“`

![image-20241218125121756](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218125121756.png?lastModify=1746594238)

#### 3 网络监控snmp

snmp简单网络管理协议

“`
流程:
1、开启网络设备的snmp功能,只读权限,设置社团名字(V2C)(V3用户名+密码),命令行手动测试
2、web添加主机配置接口,关联模板

snmp有多个版本
v2c使用团体名作为认证
v3版本用户名和密码认证
命令行连接测试网络设备
yum install -y net-snmp-utile
snmpwalk -v 2c oldboykey 10.0.0.1 SysDesc
“`

##### 3.1 开启网络设备snmp功能

![image-20241218154935874](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218154935874.png?lastModify=1746594238)

![image-20241218154952673](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218154952673.png?lastModify=1746594238)

配置团体名

![image-20241218155011291](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218155011291.png?lastModify=1746594238)

“`
[root@m03 ~]# snmpwalk -c oldboykx -v 2c 192.168.13.1 SysDesc
snmpwalk 命令,使用get方式访问网络设备
-c 团体名字
-v snmp版本
ip地址
指令(获取网络设备的信息) 名称方式/oid sysdesc、sysUptime、IfNumber、IfDescr、IfInOctet、IfInOctet、
“`

##### 3.2 添加主机

![image-20241218155353852](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218155353852.png?lastModify=1746594238)

![image-20241218155400549](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218155400549.png?lastModify=1746594238)

##### 3.3 检查

![image-20241218155422033](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218155422033.png?lastModify=1746594238)

##### 3.4 小结

“`
网络设备开启snmp功能,web进行检查
用于监控网络设备
支持snmp服务设备进行监控
“`

#### 4 监控java应用

方案选型和原理

| 方案 | 监控方案 | 说明 |
| —– | ————————————– | ———————————————————— |
| 方案1 | 开启java jmxremote | zbx中关联对应的模板,安装与开启java工具 zbx-java-gateway |
| 方案2 | 通过java命令,自定义监控获取想要的指标 | 通过在java应用服务器安装zbx agent和java命令(jmap,jstack)然后自定义监控 |

##### 1 方案1 原理图

![image-20241218162819647](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218162819647.png?lastModify=1746594238)

##### 2 方案2 原理图(类似于自定义监控)

![image-20241218162855472](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241218162855472.png?lastModify=1746594238)

##### 3 方案1实战

“`
1、开启远程监控功能
2、zabbix服务端部署java gateway配置
3、添加主机关联模版
“`

###### 1 开启远程监控功能

“`
修改tomcat目录下bin/catalina.sh
添加以下几行内容
CATALINA_OPTS=”$CATALINA_OPTS \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=172.16.1.9″
172.16.1.9是tomcat服务器自己ip
查看是否有12345端口
“`

###### 2 docker运行gateway

“`
docker run -d –name zbx_java_gateway –link zabbix-mysql-6.0:zabbix-server -p 10052:10052 –network=zabbix_net zabbix/zabbix-java-gateway:ubuntu-6.0-latest
“`

删除已有zbx服务器容器并重新创建1个并指定java gateway ip+端口

“`
docker run –name zabbix-server-mysql-6.0 -d \
-e DB_SERVER_HOST=”mysql-server” \
-e MYSQL_DATABASE=”zabbix” \
-e MYSQL_USER=”zabbix” \
-e MYSQL_PASSWORD=”1″ \
-e MYSQL_ROOT_PASSWORD=”Root123″ \
-e ZBX_JAVAGATEWAY_ENABLE=true \
-e ZBX_JAVAGATEWAY=172.16.1.62 \
-e ZBX_JAVAGATEWAYPORT=10052 \
–link mysql-server:mysql-server \
–network=oldboy_zbx_net \
-p 10051:10051 \
–restart always \
zabbix/zabbix-server-mysql:ubuntu-6.0-latest
修改zbx服务端配置文件.
-e ZBX_JAVAGATEWAY_ENABLE=true 启动java_gateway功能,zbx服务端
java_gateway进程
-e ZBX_JAVAGATEWAY=172.16.1.62 #
-e ZBX_JAVAGATEWAYPORT=10052
“`

docker-compose

“`
services:
db:
image: “mysql:8.0-debian”
container_name: “mysql-server”
networks:
– oldboy_zbx_net
restart: always
ports:
– 3306:3306
– 33060:33060
volumes:
– /app/data/mysql/:/var/lib/mysql/
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_USER_PASS}
command:
– –character-set-server=utf8
– –collation-server=utf8_bin
– –default-authentication-plugin=mysql_native_password
zbx_server:
image: zabbix/zabbix-server-mysql:ubuntu-6.0-latest
container_name: zabbix-server-mysql-6.0
networks:
– oldboy_zbx_net
restart: always
ports:
– 10051:10051
links:
– db:mysql-server
depends_on:
– db
environment:
DB_SERVER_HOST: “mysql-server”
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_USER_PASS}
ZBX_JAVAGATEWAY_ENABLE: true
ZBX_JAVAGATEWAY: 172.16.1.62
ZBX_JAVAGATEWAYPORT: 10052
zbx_web:
image: zabbix/zabbix-web-nginx-mysql:ubuntu-6.0-latest
container_name: zabbix-web-nginx-mysql
networks:
– oldboy_zbx_net
restart: always
ports:
– 80:8080
links:
– db:mysql-server
– zbx_server:zabbix_server
depends_on:
– db
– zbx_server
environment:
ZBX_SERVER_HOST: “zabbix_server”
DB_SERVER_HOST: “mysql-server”
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_USER_PASS}
zbx_java_gateway:
image: zabbix/zabbix-java-gateway:ubuntu-6.0-latest
container_name: zabbix-java-gateway
restart: always
networks:
– oldboy_zbx_net
ports:
– 10052:10052
links:
– zbx_server:zabbix_server
networks:
oldboy_zbx_net:
driver: “bridge”
ipam:
config:
– subnet: 172.100.0.0/16
ip_range: 172.100.1.0/24
gateway: 172.100.1.1
错误
yaml: line 2: did not find expected key
未对齐
使用docker-compose config来检查语法,无输出及语法正确
“`

###### 3 zbx服务端部署java gateway配置

“`
1. 安装
yum install -y zabbix-java-gateway
2. 启动
systemctl enable zabbix-java-gateway.service
systemctl start zabbix-java-gateway.service
grep ‘^[a-Z]’ /etc/zabbix/zabbix_java_gateway.conf
LISTEN_PORT=10052
PID_FILE=”/var/run/zabbix/zabbix_java_gateway.pid”
systemctl restart zabbix-java-gateway.service
ss -lntup |grep java
3. 配置zbx 服务端
grep -n ‘Java.*=’ /etc/zabbix/zabbix_server.conf
317:JavaGateway=127.0.0.1
325:JavaGatewayPort=10052
333:StartJavaPollers=5
4. 重启服务端
“`

![image-20241219123507173](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241219123507173.png?lastModify=1746594238)

![image-20241219123511390](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241219123511390.png?lastModify=1746594238)

![image-20241219123521323](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241219123521323.png?lastModify=1746594238)

###### 4 jar包应用

“`
java -jar xxx.jar写成以下的也可以监控
java -Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=172.16.1.9 \
-jar xxx.jar
“`

###### 4 自定义监控java应用

只需要jdk,agent客户端完成

不需要jmxremote,不需要javagateway

“`
UserParameter=java.thread.state[*],sh /etc/zabbix/zabbix_agent2.d/check_java_thread_state.sh “$1”

[root@web03 /etc/zabbix/zabbix_agent2.d]# cat check_java_thread_state.sh
#!/bin/bash
##############################################################
# File Name:check_java_thread_state.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc:
##############################################################
#1.vars
app=/app/tools/tomcat
state=$1

#2.app pid
app_pid=`jps -lvm | grep “${app}” | awk ‘{print $1}’`

#3.blocked number
function blocked() {
jstack ${app_pid} | grep -i blocked | wc -l
return $?
}

#4.running/runnable number
function run() {
jstack ${app_pid} | egrep -i “running|runnable” | wc -l
return $?
}

#5.waiting number
function wait() {
jstack ${app_pid} | grep -i “waiting” | wc -l
return $?
}

#6.case
function main() {
case “$state” in
blocked) blocked ;;
run) run ;;
wait) wait ;;
*) echo error
esac
}

main
“`

###### 5 java监控小结

“`
方案1:推荐使用自定义监控(命令,脚本)
方法2:jmx功能
“`

#### 5 监控硬件设备

“`
物理服务器等服务器设备
远程控制卡连接物理服务器,开启ipmi功能(开机bios里面修改)
“`

| 监控方案 | 步骤 |
| ——– | ———————————————————— |
| 方案1 | 开启设备的ipmi功能监控,添加接口的时候选择ipmi即可(进入biosLAN局域网访问) |
| 方案2 | 通过客户端命令获取指标实现监控硬件:megacli和ipmitool |

## 11 小结

| zabbix客户端 | 说明 |
| ————- | ———————————————————— |
| zabbix-agent2 | 适用于几乎所有情况,支持自定义监控,windows,linux,android,ios |
| snmp客户端 | 用于监控网络设备,简单网络管理协议,监控网络设备 |
| jmx | java-gateway,推荐zabbix_agent2+jmap/stack/jps/jstats |
| ipmi | 硬件,直接使用自定义监控(ipmitool+megacli) |

![image-20241219163354940](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241219163354940.png?lastModify=1746594238)

## 12 监控自动化

自动添加主机并关联模板

自动发现与自动注册,自动识别zbx客户端主机,web页面(创建主机,关联模板关联用户组,启动主机)

| 自动添加主机方案 | 含义 | 应用场景 |
| ———————- | —————————————————- | ————————————– |
| 自动发现(服务端主动) | 服务端主动去找是否有新的主机,如果有就添加 | 配置简单,大量添加主机不适合,临时可用 |
| 自动注册(客户端主动) | 客户端主动去找服务端提交自己的信息,请求想服务端注册 | 配置繁琐,经常性,大量主机 |

### 1 自动发现

“`
1、客户端配置文件
2、web配置自动发现规则-发现新的主机
3、web配置自动发现的动作,发现主机后关联模板,添加主机,加入主机组,启用

“`

#### 1 客户端zbx agent,配置文件

“`
ansible实现
playbook
yum
template
“`

![image-20241219165044949](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241219165044949.png?lastModify=1746594238)

![image-20241219165050007](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241219165050007.png?lastModify=1746594238)

检查自动发现的主机(此时仅仅发现,并不会添加到zbx主机中)

![image-20241220110403136](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220110403136.png?lastModify=1746594238)

#### 2 web配置动作

“`
1、配置自动发现的动作
2、添加组
3、关联模板
4、启动主机
“`

进入自动发现动作配置

![image-20241220112010987](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112010987.png?lastModify=1746594238)

修改自动发现动作

![image-20241220112049904](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112049904.png?lastModify=1746594238)

启动自动发现动作

![image-20241220112103006](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112103006.png?lastModify=1746594238)

配置自动发现动作的操作(关联主机组,关联模板)

![image-20241220112133316](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112133316.png?lastModify=1746594238)

![image-20241220112137347](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112137347.png?lastModify=1746594238)

检查自动发现

![image-20241220112153253](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112153253.png?lastModify=1746594238)

检查添加的主机

![image-20241220112207150](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112207150.png?lastModify=1746594238)

3 自动发现原理小结

“`
1、客户端配置,配置文件,重启服务
2、web配置自动发现规则,发现主机
3、web配置动作,发现主机后关联模板,添加主机,加入主机组,启用
“`

![image-20241220112406354](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220112406354.png?lastModify=1746594238)

[老男孩教育-zabbix监控架构-自动发现与自动注册总结| ProcessOn免费在线作图,在线流程图,在线思维导图](https://www.processon.com/view/link/62a2a9b35653bb72c28d6c37)

### 2 自动注册

“`
应用场景,经常性添加主机
准备
关闭自动发现的主机
关闭自动发现动作
自动发现的主机删除

1.zabbix客户端配置:修改zabbix客户端配置文件:ServerActive=服务端ip和Hostname=xxx
2.web页面,动作→自动注册autoreg
“`

#### 1 zabbix客户端配置文件

服务端主动把自己的信息,提供给服务端

服务端收到数据后通过自动注册动作,判断与添加

| 客户端的配置 | 说明 |
| —————————– | ———————————————————— |
| Server=172.16.1.62 | 服务端地址 |
| ServerActive=172.16.1.62 | 主动模式下服务端ip地址 |
| Hostname=web01 | 当前主机名,可以使用ansible自动获取主机名 |
| HostnameItem=system.hostname | 通过后面指定的键值获取主机名,Hostname和HostnameItem二选一,Item监控项,键值 |
| HostMetadateItem=system.uname | 主机的元数据键值,类似于自动发现中的system.uname判断存活和获取主机信息 |

HostMetadateItem=system.uname

![image-20241220115925738](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220115925738.png?lastModify=1746594238)

zabbix客户端配置(通用)

“`
[root@web01 ~]# grep ‘^[a-Z]’ /etc/zabbix/zabbix_agent2.conf
PidFile=/var/run/zabbix/zabbix_agent2.pid
LogFile=/var/log/zabbix/zabbix_agent2.log
LogFileSize=0
Server=172.16.1.63
ServerActive=172.16.1.63
HostnameItem=system.hostname
HostMetadataItem=system.uname
Include=/etc/zabbix/zabbix_agent2.d/*.conf
ControlSocket=/tmp/agent.sock
Include=./zabbix_agent2.d/plugins.d/*.conf
“`

#### 2 web页面,动作→自动注册

![image-20241220120230515](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220120230515.png?lastModify=1746594238)

进入自动注册动作配置页面

![image-20241220120308632](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220120308632.png?lastModify=1746594238)

创建自动注册动作

![image-20241220120336123](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220120336123.png?lastModify=1746594238)

配置自动注册动作

![image-20241220120348475](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220120348475.png?lastModify=1746594238)

![image-20241220120354266](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220120354266.png?lastModify=1746594238)

配置自动注册操作

![image-20241220120406804](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220120406804.png?lastModify=1746594238)

完成与等待

![image-20241220120419347](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220120419347.png?lastModify=1746594238)

#### 3 小结

“`
整体流程与自动发现类似,但是自动注册无法在web页面直接查看是否发现了主机,只能看是否添加主机
自动注册,web页面没有地方配置规则,自动注册吧规则写入到了客户端文件中
web页面只需要配置自动注册动作即可
“`

## 13 分布式监控

![image-20241220125009728](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241220125009728.png?lastModify=1746594238)

https://www.processon.com/view/link/62a2f2c87d9c08733ec531a1

### 1 分布式监控概述及应用场景

“`
zabbix分布式(xabbix proxy)监控场景
1、监控多个地区、多个机房的服务器,服务器直接内网不通
2、同一个机房中服务器过多,增加设置代理减轻服务端压力

多个节点(区域、机房)zbx监控问题
1、带宽
2、网络稳定性问题
3、可能存在误报
解决方法
1、客户端直接写服务端公网ip
2、使用分布式监控
“`

### 2 分布式监控实战

| 角色 | ip | 说明 |
| ————- | ———– | ————————————————— |
| zabbix_server | 172.16.1.62 | zabbix服务端,zabbix服务端数据库,zabbix前端web页面 |
| zabbix_proxy | 172.16.1.63 | zabbix_proxy,zabbix_proxy数据库 |
| web03 | 172.16.1.9 | 准备使用proxy代理监控 |

#### 1 zabbix代理

准备数据库

“`
准备一台新机器172.16.1.63
上传docker和docker-compose包
mkdir -p /etc/docker
cat >/etc/docker/dameon.json</usr/lib/systemd/system/docker.service</app/tools/zabbix_proxy/docker-compose.yml</etc/yum.repo.d/mariadb.repo<zbx 6.x
简单升级
前端页面
服务端与客户端升级
数据库准备2套(旧的数据库准备,启动个容器访问旧的数据库即可.)
复杂升级:
前端页面
服务端与客户端升级
数据库升级.(mariadb 5.5 mariadb10.5)

升级流程
1.准备好新的数据库,备份好旧的数据库内容。
2.按照数据库升级 要求变更数据库内容
3.准备新的zabbix_server(rpm包)、命令和配置文件。
4.备份,替换旧的zbx_server命令.检查。
5.前端页面,根据要求准备好php对应版本即可。
6.备份,放入新的前端代码即可。
7.调试。
“`

## 16 全网监控任务

“`
项目背景: 入职后发现网站监控都使用命令,脚本+定时任务方式. 无法显示图.无法看到趋势
项目流程:
1. 开会对接下需求,开发,运营人员.详细需求. 申请资源.
2. 进行规划简单列下内容目标.
3. 详细细致规划,服务,指标,告警
4. 及时汇报.
5. 汇总总结,故障,形式文档.
6. 培训.
“`

## 17 网站需要什么监控

“`
面试题: 你们公司监控了什么?自定义监控了什么?监控指标?。。。。。
潜台词: 问你网站架构监控了什么内容?

cpu,内存,磁盘,网络,带宽,负载等等
按照网站层次架构监控的(多个监控维度)
横向维度:
dns
cdn
安全组
负载
web
数据
存储
备份

运维维度
vpn
堡垒机
zabbix
pingcurl定义脚本补充的监控

纵向维度:任何一台机器
硬件监控
系统监控
服务监控:根据用户访问节点不同而不同
业务/app监控:页面类似于info.php,mysql.php,test.html,test.jsp
api接口监控
“`

### 1 任何一台机器的监控

| 监控内容 | 详细内容 | 具体实现落地 |
| ———– | ———————————————————— | ———————————————————— |
| 硬件监控 | 如果是物理服务器需要监控,温度,风扇转速,raid状态 | zabbix自带:ipmi自定义监控ipmitool/megacli |
| 系统监控 | cpu,负载,内存,磁盘,网络,带宽,io,关键文件是否发生变化aide,进程,僵尸进程,是否有飞堡垒机登录 | 模板+自定义(僵尸,用户异地登录,堡垒机登录,aide,日志secure) |
| 服务监控 | 进程,端口,服务的状态,日志是否有error,fiiled,exception | 模版或根据具体的要求自定义监控 |
| 业务应用app | 检查应用是否可用,书写测试代码页面,info.php,mysql.php | curl命令,web场景/检测 |
| api接口监控 | 监控指定的api接口,比如zbx api,开发提供(内部接口,外部第三方接口) | curl命令,web场景/检测 |

### 2 按照访问顺序监控(一层一层)

dns/cdn,安全组,负载,web,数据库,存储,备份

| 监控内容 | 详细内容 | 具体实现 |
| —————- | ————————————— | ———————————————————— |
| dns | 解析是否正常 | 自定义监控:ping/dig/nslookup 域名:whois 多虑过期 证书:curl -Lsv [www.baidu.com](www.baidu.com) -o /dev/null过滤expire date过期,openssl命令检查 |
| cdn | 是否可用,命中率 | 登录对应cdn页面检查:命中率,流量,带宽 分布式ping,商业:监控宝,听云 面粉网站[www.17ce.com](www.17ce.com) ping.chinaz.com 开源软件:smokeping |
| 防火墙和网络设备 | 监控流量,带宽,端口 | snmp协议 |
| 负载 | ngx服务情况,证书过期,网站访问量,并发 | nginx/haproxy/keepalived状态 等 |
| web | 主要监控服务情况 | 具体服务使用对应模板即可 ngx、php、tomcat(war)、jar |
| 存储 | nfs | 自定义监控,存储目前多少空间,是否能使用, |
| 备份 | 备份的数据量 | 自定义监控,系统是否有备份,发送邮件,占用空间多少 |

### 3 补充监控

“`
apm监控网站性能,用户访问流程链监控
docker监控:容器,cpu,内存,镜像大小
硬件监控ipmi,网络设备监控snmp监控
运维角度服务
“`

### 4 实施全网监控

“`
核心:
1 按照用户访问流程,运维角度,开发角度逐个进行监控
2 辅助每个节点,硬件监控,系统监控,服务监控,业务监控,api监控
“`

#### 1 dns(lb上配置)

“`
自定义监控放在负载均衡节点,任何一个
域名dns是否可用,nslookup查看解析
域名过期,输出剩余时间(天)
web调取api接口查看,dns查询数量

查询dns是否可用
列出域名二级和三级域名
oldboylinux.cn www.oldboylinux.cn blog.oldboylinux.cn shop.oldboylinux.cn
脚本传参+nslookup命令+判断返回值即可.
[root@m02-zbx-server ~]# cat /server/scripts/check_dns.sh
#!/bin/bash
#author: lidao996
#url: oldboyedu.com
#desc: 检查指定的域名是否可以解析
#可以显示1
#不可以显示0
#1.vars
url=$1
#2.判断是否为域名
#2.检查nslookup命令是否存在
which nslookup &>/dev/null || {
yum install -y bind-utils
}
#3.检查
if nslookup $url &>/dev/null ;then
#输出1表示可以使用
echo “1”
else
#输出0
echo “0”
fi
[root@m02-zbx-server ~]# cat
/etc/zabbix/zabbix_agent2.d/dns.conf
UserParameter=check.dns[*],sh /server/scripts/check_dns.sh
“$1”

分部署测试 ping ,dns ,cdn
https://ping.chinaz.com/www.baidu.com
全国或全世界用户访问网站的速度.
第3方免费网站: ping.chianz.com , 17ce.com ,….
第3方收费免费使用: 监控宝https://www.jiankongbao.com/
自己搭建:全国各地服务器+smokeping
“`

#### 2 检查域名剩余时间

“`
[root@lb01 ~]# cat /server/scripts/check_https_expire.sh
#!/bin/bash
##############################################################
# File Name:30.check_url_guoqi.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc:
##############################################################
#1.vars
export LANG=en_US.UTF-8
#检查域名过期
check_domain() {
local expire_date=`whois $url |egrep “Expiry|Expiration”
|awk -F “: ” ‘{print $2}’`
local exprire_date_second=`date -d “${expire_date}” +%s`
local date_second_now=`date +%s`
local date_expire_days=`echo “(${exprire_date_second} –
${date_second_now} )/60/60/24” |bc`
echo “$date_expire_days”
}
#检查证书过期
check_https() {
#这里还可以加入curl判断.
local expire_date=`curl -v https://www.$url |& grep expire
|awk -F “: |GMT” ‘{print $2}’`
local exprire_date_second=`date -d “${expire_date}” +%s`
local date_second_now=`date +%s`
local date_expire_days=`echo “(${exprire_date_second} –
${date_second_now} )/60/60/24” |bc`
echo “$date_expire_days”
}
#main
main() {
choice=$1
url=$2
case “$choice” in
domain)
check_domain ;;
https)
check_https ;;
esac
}
main $*
[root@lb01 ~]# cat /etc/zabbix/zabbix_agent2.d/dns.conf
UserParameter=check.dns[*],/bin/bash
/server/scripts/check_dns.sh “$1”
UserParameter=check.domain_https[*],sh
/server/scripts/check_https_expire.sh “$1” “$2”
“`

#### 3 故障案例-zabbix客户端权限问题

“`
[root@lb01 ~]# echo “zabbix ALL=(ALL) NOPASSWD:ALL”
>>/etc/sudoers
[root@lb01 ~]# tail -1 /etc/sudoers
zabbix ALL=(ALL) NOPASSWD:ALL
[root@lb01 ~]# visudo -c
/etc/sudoers:解析正确
[root@lb01 ~]# cat /etc/zabbix/zabbix_agent2.d/domain.conf
UserParameter=domain.dns[*],sh /server/scripts/check_dns.sh
“$1”
UserParameter=domain.expires[*],sudo sh
/server/scripts/check_expires.sh “$1” “$2”
“`

4 cdn监控

“`
每日带宽,web页面或api监控
每日流量,web页面或api监控
CDN命中率,不低于90%,web页面或api监控
“`

![image-20241221180031697](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241221180031697.png?lastModify=1746594238)

#### 4 防火墙

“`
iptables直接看规则即可,开启或关闭
公有云防火墙查看规则即可
硬件防火墙通过snmp监控即可
“`

#### 5 lb负载均衡

##### 1 监控lb通用的

“`
[root@lb01 ~]# cat /etc/yum.repos.d/ngx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/7/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[root@lb01 ~]# yum install -y nginx
大礼包nginx-tengine233替换 已有nginx命令

物理层:
系统层:使用模板+sys.conf模板
服务层:
nginx状态检查模块(stub_status)有模版,nginx负载均衡检查功能(check书写脚本自定义监控)
访问:日志,状态码,错误error/failed数量,自定义监控
tcp/ip连接数
并发数
系统层:使用模板+sys.conf模板
系统层监控:
模板linux by zabbix agent(cpu,内存,磁盘,负载,网络,磁盘读写,登录用户数,运行时间)
补充:僵尸进程,挂起进程数,文件是否发生变化,aide –check,用户是否来自于堡垒机
lastlog -u root登录的IP地址是否为堡垒机
服务层:nginx
自建
服务层:nginx/haproxy/lvs
如果是nginx或类型的
开启ngx状态检查模块
开启nginx负载均衡状态检查模块
[root@lb01 ~]# cat /etc/nginx/conf.d/blog.conf
uptream check_pools {
server 192.168.137.7:80;
server 192.168.137.8:80;
}

check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send “HEAD / HTTP/1.0\r\nHost:
blog.oldboylinux.cn\r\n\r\n”;
check_http_expect_alive http_2xx http_3xx;
}
server {
listen 80;
server_name blog.oldboylinux.cn ;
error_log /var/log/nginx/check-error.log notice;
#最好加入到每个独立的站点中.
location /lb_status {
#负载均衡状态检查模块
check_status;
access_log off;
}
location / {
proxy_pass http://check_pools;
include proxy.conf;
#XFF
}
}
[root@lb01 ~]# cat /etc/nginx/conf.d/check.conf
[root@lb01 ~]# cat /etc/nginx/conf.d/check.conf
server {
listen 8080;
location = /ngx_status {
stub_status;
access_log off;
}
}
[root@lb01 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax
is ok
nginx: configuration file /etc/nginx/nginx.conf test is
successful
[root@lb01 ~]# systemctl reload nginx
[root@lb01 ~]# curl localhost:8080/ngx_status
Active connections: 1
server accepts handled requests request_time
6 6 14 0
Reading: 0 Writing: 1 Waiting: 0
[root@lb01 /etc/nginx/conf.d]# cat /etc/nginx/proxy.conf
#Host头保留
proxy_set_header Host $http_host;
#XFF头
#XFF追加
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_set_header X-Real-Ip $remote_addr;
#proxy_cache oldboy_lidao;
#proxy_cache_valid 200 302 1h;
#proxy_cache_valid 301 1d;
#proxy_cache_valid any 1m;
#ngx buffer
proxy_buffering on;
proxy_buffer_size 128k;
proxy_busy_buffers_size 256k;
proxy_buffers 32 128k;
“`

![image-20241222114807629](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222114807629.png?lastModify=1746594238)

![image-20241222114818354](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222114818354.png?lastModify=1746594238)

监控nginx状态,注意修改模板,

![image-20241222114847530](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222114847530.png?lastModify=1746594238)

http协议监控与相关项监控

![image-20241222114910959](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222114910959.png?lastModify=1746594238)

修改相关监控-找到模板中对应的监控项进行修改

![image-20241222114946816](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222114946816.png?lastModify=1746594238)

![image-20241222114952704](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222114952704.png?lastModify=1746594238)

![image-20241222114959288](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222114959288.png?lastModify=1746594238)

“`
Nginx: Version监控项修改后的正则
Server: (Tengine|nginx)/([\d.]+)
Nginx: Requests total 监控项修改后的正则
server accepts handled requests request_time\s+([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)

ngx/tengine 负载/web通用的监控 stub_status模块 8080+/ngx_status
“`

##### 2 负载均衡监控,监控指定站点的web情况,自定义监控

nginx负载均衡自定义监控,开启负载均衡监控检查模块 upstream check编译安装nginx,默认没有关联的模版

监控项:有多少个节点,有多少个分组,每个分组里面的节点状态

“`
[root@lb01 ~]# cat /etc/nginx/conf.d/blog.oldboylinux.cn.conf
upstream blog_pools {
server 10.0.0.7:80;
server 10.0.0.8:80;
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send “HEAD /index.php
HTTP/1.0\r\nHost:blog.oldboylinux.cn\r\nUser-Agent:
lb_check\r\n\r\n”;
check_http_expect_alive http_2xx http_3xx;
}
server {
listen 80;
server_name blog.oldboylinux.cn lb01.oldboylinux.cn;
error_log /var/log/nginx/blog.oldboylinux.cn-error.log
notice;
access_log /var/log/nginx/blog.oldboylinux.cn-access.log
main;
location / {
proxy_pass http://blog_pools;
proxy_set_header Host $http_host;
#XFF
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_set_header X-Real-Ip $remote_addr;
#ngx access.log log_format $http_x_forwarded_for;
}
location /lb_status {
check_status;
access_log off;
#allow
#deny
}
}

[root@lb01 ~]# cat /server/scripts/check_lb_pools.sh
#!/bin/bash
##############################################################
# File Name:/server/scripts/check_lb_pools.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc:检查负载均衡 每组里面的情况
##############################################################
#1.vars
url=$1
#2.统计负载均衡后端服务器挂掉的数量
total=`curl -s -H Host:${url} localhost/lb_status?
format=csv |wc -l`
up=`curl -s -H Host:${url} localhost/lb_status?format=csv
|grep -wi up |wc -l`
echo “scale=2; $up / $total * 100” |bc -l
[root@lb01 ~]# cat /etc/zabbix/zabbix_agent2.d/lb.conf
UserParameter=check.lb[*],sh /server/scripts/check_lb_pools.sh
“$1”
[root@lb01 ~]# systemctl restart zabbix-agent2.service

监控keepalived是否切换
监控项:过滤下keepalived是否有进程
监控项:是否有vip,过滤vip就可以,确定是否发生主备切换
在备节点书写监控脚本即可
自定义监控脚本
[root@lb01 ~]# cat /server/scripts/chk_vip.sh
#!/bin/bash
##############################################################
# File Name:/server/scripts/chk_vip.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc:
##############################################################
#1.vars
vip=$1
#2.过滤
vip_cnt=`ip a |grep -w “${vip}” |wc -l`
#3.判断
if [ $vip_cnt -gt 0 ];then
echo 1
else
echo 0
fi
[root@lb01 ~]# cat /etc/zabbix/zabbix_agent2.d/keepalived.conf
[root@lb01 ~]# cat /etc/zabbix/zabbix_agent2.d/keepalived.conf
UserParameter=keepalived.vip[*],sh /server/scripts/chk_vip.sh
“$1″
[root@lb01 ~]# systemctl restart zabbix-agent2.service
“`

“`
监控nginx访问日志和错误日志
nginx访问日志
IP地址出现次数
状态码及出现的次数
nginx错误日志:failed/denied/error/最近5000行
监控系统日志secure日志是否有大量的Failed password
访问日志状态码

[root@lb01 ~]# cat /server/scripts/check_ngx_access_log.sh
#!/bin/bash
##############################################################
# File Name:/server/scripts/check_ngx_access_log.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc:
##############################################################
#1.vars
access_files=”/var/log/nginx/access.log”
code=$1
#2.case
case “$code” in
200) awk ‘{print $9}’ $access_files |grep -w “200”|wc -l
;;
301) awk ‘{print $9}’ $access_files |grep -w “301”|wc -l
;;
302) awk ‘{print $9}’ $access_files |grep -w “302”|wc -l
;;
304) awk ‘{print $9}’ $access_files |grep -w “302”|wc -l
;;
403) awk ‘{print $9}’ $access_files |grep -w “403”|wc -l
;;
404) awk ‘{print $9}’ $access_files |grep -w “404”|wc -l
;;
500) awk ‘{print $9}’ $access_files |grep -w “500”|wc -l
;;
502) awk ‘{print $9}’ $access_files |grep -w “502”|wc -l
;;
503) awk ‘{print $9}’ $access_files |grep -w “503”|wc -l
;;
504) awk ‘{print $9}’ $access_files |grep -w “504”|wc -l
;;
esac
[root@lb01 ~]# cat /etc/zabbix/zabbix_agent2.d/ngx.conf

UserParameter=nginx.log.status[*],sh
/server/scripts/check_ngx_access_log.sh “$1″
触发器 403 50x 设置.
配置图形

错误日志和secure日志分析
#精确过滤
[root@lb01 ~]# start=`date +%Y\/%m\/%d” “%H:%M -d “-1min”`
[root@lb01 ~]#
[root@lb01 ~]# echo $start
2024/07/26 11:36
[root@lb01 ~]# start=`date +”%Y\/%m\/%d %H:%M” -d “-1min”`
[root@lb01 ~]# echo $start
2024\/07\/26 11:37
[root@lb01 ~]# sed -n “/${start}/,\$p”
/var/log/nginx/error.log
#
UserParameter=check.ngx.error,sudo tail -n1000
/var/log/nginx/error.log |egrep -i ‘error|failed|denied’|wc –
l
#分析安全日志系统是否有异常登录(暴力破解)
UserParameter=check.error.login,sudo tail -n1000
/var/log/secure |egrep -i ‘failed password’|wc -l

zbx 自定义监控权限的问题。
grep zabbix /etc/sudoers
zabbix ALL=(ALL) NOPASSWD: ALL

[root@lb01 /etc/zabbix/zabbix_agent2.d]# cat diy_all.conf
UserParameter=check.lb.status,curl -s -H
Host:blog.oldboylinux.cn 10.0.0.5:8080/lb_status?
format=csv |grep up |wc -l
UserParameter=check.dns[*],/bin/bash
/server/scripts/check_dns.sh “$1”
UserParameter=check.domain_https[*],sh
/server/scripts/check_https_expire.sh “$1” “$2”
#ngx错误日志
UserParameter=check.ngx.error,sudo tail -n1000
/var/log/nginx/error.log |egrep -i
‘error|failed|denied’|wc -l
#分析安全日志系统是否有异常登录(暴力破解)
UserParameter=check.error.login,sudo tail -n1000
/var/log/secure |egrep -i ‘failed password’|wc -l

网络tcp/ip 监控

#并发数
UserParameter=net.tcp.estab,sudo ss -ant |grep -i estab |wc -l
#将要断开连接的数量
UserParameter=net.tcp.wait,sudo ss -ant |grep -i wait |wc -l
“`

#### 6 web监控

##### 1 nginx php

“`
应用:代码,war,jar包
服务:nginx,php,tomcat,jar
系统:模板+自定义

监控php
[root@web01 /etc/nginx/conf.d]# cat status.conf
server {
listen 8888;
server_name status.oldboylinux.cn;
location /ngx_status {
stub_status;
}
location /php_status {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
location /php_ping {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
}

egrep ‘^pm.status|^ping’ /etc/php-fpm.d/www.conf
pm.status_path = /php_status
ping.path = /php_ping
ping.response = pong
[root@web01 ~]# egrep -v ‘^$|;’ /etc/php-fpm.d/www.conf
[www]
user = nginx
group = nginx
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.status_path = /php_status
ping.path = /php_ping
ping.response = pong
修改后的配置文件
[www]
user = nginx
group = nginx
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/opt/remi/php74/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/opt/remi/php74/log/phpfpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] =
/var/opt/remi/php74/lib/php/session

php_value[soap.wsdl_cache_dir] =
/var/opt/remi/php74/lib/php/wsdlcache
pm.status_path = /php_status
ping.path = /php_ping
ping.response = pong
“`

![image-20241222120238163](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222120238163.png?lastModify=1746594238)

修改模板中的宏

![image-20241222120301217](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222120301217.png?lastModify=1746594238)

关联模板等待数据

![image-20241222120334792](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222120334792.png?lastModify=1746594238)

##### 2 应用或业务监控 web场景监控

zabbix给我们准备的替代curl/wget命令方式

未来可以用来监控,应用页面,apit接口

“`
#ngx与php是否正常
cat /app/code/zbx/test_info.php

#php与数据库是否正常
cat test_php_db.php

“`

![image-20241222120941580](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222120941580.png?lastModify=1746594238)

![image-20241222120947846](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222120947846.png?lastModify=1746594238)

![image-20241222121013094](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121013094.png?lastModify=1746594238)

![image-20241222121052457](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121052457.png?lastModify=1746594238)

![image-20241222121059828](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121059828.png?lastModify=1746594238)

![image-20241222121107212](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121107212.png?lastModify=1746594238)

![image-20241222121117704](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121117704.png?lastModify=1746594238)

添加触发器

“`
last(/web01/web.test.fail[web场景名字]) <>0
web.test.fail 该监控项将显示场景中失败的步骤数。如果所有步骤都成功执行,则
返回 0

tomcat,jetty,jboss和jar包监控 推荐自定义监控。
“`

| java监控方案 | 说明 |
| ———— | ————————————– |
| 自定义监控 | 书写自定义监控脚本,灵活 |
| jmx监控 | 需要部署zabbix-java-gateway,关联模版。 |

“`
jmap -HEAP javapid导出jvm信息
jps
jstack

#1.jmap自定义监控
jmap -heap javapid
Eden Space:
capacity = 162529280 (155.0MB)
used = 35942680 (34.277610778808594MB)
free = 126586600 (120.7223892211914MB)
22.11458759923135% used
From Space:
capacity = 5242880 (5.0MB)
used = 5234736 (4.9922332763671875MB)
free = 8144 (0.0077667236328125MB)
99.84466552734375% used
To Space:
capacity = 5242880 (5.0MB)
used = 0 (0.0MB)
free = 5242880 (5.0MB)
0.0% used
PS Old Generation
capacity = 36700160 (35.0MB)
used = 15448416 (14.732757568359375MB)
free = 21251744 (20.267242431640625MB)
42.093593052455354% used
过滤jvm不同内存区域使用情况。
[root@web03 ~]# jmap -heap 1295 |grep -i -A4 eden
Eden Space:
capacity = 162529280 (155.0MB)
used = 35942680 (34.277610778808594MB)
free = 126586600 (120.7223892211914MB)
22.11458759923135% used
[root@web03 ~]# jmap -heap 1295 |grep -i -A4 from
From Space:
capacity = 5242880 (5.0MB)
used = 5234736 (4.9922332763671875MB)
free = 8144 (0.0077667236328125MB)
99.84466552734375% used
UserParameter=java.jvm.eden.capacity,jmap -heap 1295 |grep –
i -A4 eden |awk ‘NR==2{print $3}’
UserParameter=java.jvm[*],sh check_jvm.sh “$1” “$2″
$1jvm内存空间名字 eden from to …
$2是对应指标capacity used free

jstack 自定义监控
·获取java进程的线程信息
state状态,线程状态。
“`

#### 7 api监控

“`
使用web场景实现
应用或业务api
服务api接口, /check /health

监控zabbix api接口是否可用
添加web场景流程与上面监控test_info.php流程一致.
区别在于添加api接口的时候不能只看状态码,应该看返回结果的内容,这里过
滤”Zabbix Server”

45427b7e17fcd58957065fbf713d79bb8d9ae2ea9ae0dd41a742606897cc125
“`

![image-20241222121620321](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121620321.png?lastModify=1746594238)

![image-20241222121629396](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121629396.png?lastModify=1746594238)

“`
-X 修改请求方法
-H 修改请求头内容
Content-Type: application/json-rpc 上传数据的格式。
-d 发出请求的时候请求主体的内容(上传的内容)
curl -X POST -H “Content-Type: application/json-rpc” -d ‘
{
“jsonrpc”: “2.0”,
“method”: “host.get”,
“params”: {
“output”: [
“hostid”,
“host”
],
“selectInterfaces”: [
“interfaceid”,
“ip”
]
},
“id”: 2,
“auth”: “令牌的内容”
}’ http://zbx.oldboylinux.cn/api_jsonrpc.php
原始数据部分:
{
“jsonrpc”: “2.0”,
“method”: “host.get”,
“params”: {
“output”: [
“hostid”,
“host”
],
“selectInterfaces”: [
“interfaceid”,
“ip”
]
},
“id”: 2,
“auth”:
“49a5d19318c407c34c4708bfbdc5107067d9614337a5c754ad9b4aa19b36c
100”
}
“`

![image-20241222121705250](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121705250.png?lastModify=1746594238)

![image-20241222121717070](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121717070.png?lastModify=1746594238)

![image-20241222121726846](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121726846.png?lastModify=1746594238)

![image-20241222121735694](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121735694.png?lastModify=1746594238)

然后添加web场景对应的触发器.

![image-20241222121748160](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20241222121748160.png?lastModify=1746594238)

“`
api接口监控
curl/web场景/python/golang语言代码
web场景监控api.
“`

#### 8 redis监控

“`
redis监控模板
监控redis运行,端口,进程
命中率
占用内存.
Redis by Zabbix agent 2
“`

#### 9 DB监控

“`
mysql
zbx自带模板
第3方模板 pt percona tools
pmm 数据库监控专用
“`

#### 10 存储监控

“`
nfs是否可用.
本地进行临时挂载
本地写入数据
检查是否可以写入
卸载
其他存储调用对应的模板即可.
检查空间
“`

#### 11 其他待补充

“`
安全相关(每个节点) 放在最后
其他待补充
任何一个服务使用流程:
1.部署
2.配置
3.使用
4.监控
5.高可用
6.备份 8.考虑容灾
7.安全
“`

#### 12 总结

“`
https://www.processon.com/view/link/62a6fb42e401fd5a4d63d3bc
非分布式。
尽量使用模板。监控网站这些服务。
系统信息:默认模板即可 Linux by Zabbix agent
服务模块监控对应的服务

周末任务:
1. 使用docker-compose一键部署zabbix监控环境(仅仅服务端架构搭建出服务即
可)
2. 讲解录屏说
“`

DOCKER

## 1 容器架构

### 1.1 iaas paas saas

IAAS:基础设施即服务,IDC机房服务器出租,云厂商,云服务器

PAAS:平台即服务,服务运行环境是ok

SAAS软件即服务,服务已经准备好,直接使用产品

![image-20250107155347343](D:\Program Files (x86)\Typora\008-docker\image-20250107155347343.png)

### 1.2 什么是容器

容器是隔离环境中运行的一个进程,如果进程结束,容器就会停止

细致:容器的隔离环境,拥有自己的ip地址,系统文件,主机名,进程管理,相当于一个迷你的系统

### 1.3 容器和虚拟化

| | 虚拟机 | 容器 |
| —- | ———————————————————— | ———————————————————— |
| 优点 | 1、使用简单;2、有成熟的管理工具;3、可以随意定制;4、启动虚拟机要经历完整的linux启动流程 | 1、快速部署,扩容,弹性伸缩;2、大部分都有现成镜像;3、让我们不再关注系统基础设施,把关注点放在配置,升级,优化;4、不依赖硬件;5、启动容器秒级;6、相当于一个进程 |
| 缺点 | 1、需要硬件支持虚拟化技术;2、资源利用率不高;3、同一台虚拟机跑多个服务,可能会有冲突;4、占用资源较多;5、不满足升级,快速扩容,快速部署,回滚不方便 | 1、使用较为复杂;2、共享linux系统内核 |

![image-20250107155409562](D:\Program Files (x86)\Typora\008-docker\image-20250107155409562.png)

### 1.4 docker极速上手指南

linux内核:3.10以上,如果旧的内核,需要升级内核才能使用

unamr -r

安装docker环境,docker-ce(开源),docker-ee(企业版)

安装升级

“`sh
yum install -y docker
wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.24.tgz
tar xf docker-20.10.24.tgz
chown -R root:root docker
mv docker/* bin
rm -rf /usr/local/bin/runc
systemctl enable –now docker
docker version

“`

![image-20250107155415764](D:\Program Files (x86)\Typora\008-docker\image-20250107155415764.png)

### 1.5 配置docker源(用于安装docker 非麒麟系统)

“`sh
1、通用的安装脚本
curl -fsSL https://get.docker.com/ -o install-docker.sh

2、配置docker yum源安装docker
yum install -y yum-untils
yum-config-manager –add-repo https://download.docker.com/linux/centos/docker-ce.repo
sed -i
‘s+https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce+’ /etc/yum.repos.d/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable –now docker
docker version

“`

### 1.6 配置docker下载镜像的加速

“`sh
sudo mkdir -p /etc/docker
#/etc/docker/daemon.json docker服务端的配置文件.
#配置docker下载镜像的加速地址.
sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://bjjtv7cs.mirror.aliyuncs.com"] } EOF [root@docker01 ~]# systemctl daemon-reload [root@docker01 ~]# systemctl restart 自动补全 yum install -y bash-completion bash-completion-extras ``` ![image-20250107155510526](D:\Program Files (x86)\Typora\008-docker\image-20250107155510526.png) ![image-20250107155525060](D:\Program Files (x86)\Typora\008-docker\image-20250107155525060.png) ### 1.7 导入镜像到本地 ```sh tar xf yangsenlinedu_useful_docker_images.tar.gz cd yangsenlinedu_useful_docker_images/ for n in `ls ` ;do docker load -i $n ;done docker images ``` ### 1.8 运行第一个容器 ```sh [root@docker02 ~/yangsenlinedu_useful_docker_images]# docker run -d -p 80:80 --name ngx_v1 nginx:1.24 -d后台运行 -p映射 宿主机:容器 --name 给容器指定名字,容器不通 ``` ![image-20250107155555168](D:\Program Files (x86)\Typora\008-docker\image-20250107155555168.png) ![image-20250107155604621](D:\Program Files (x86)\Typora\008-docker\image-20250107155604621.png) ### 1.9 docker C/S架构 cs client/server 客户端/服务器 | docker相关词汇 | 说明 | | ---------------- | -------------------- | | 镜像image | 存放各种环境或服务 | | 容器container | 进程,运行起来的镜像 | | 仓库(存放镜像) | 远程仓库,本地仓库 | ![image-20250107155538077](D:\Program Files (x86)\Typora\008-docker\image-20250107155538077.png) ![image-20250107155744481](D:\Program Files (x86)\Typora\008-docker\image-20250107155744481.png) docker pull nginx下载nginx镜像到本地仓库 如果本地仓库有,则提示镜像已经下载 如果本地仓库没有,则docker服务端远程访问仓库,下载镜像 使用docker -p端口映射,需要开启iptables的nat内核转发功能net.ipv4.ip_forward = 1 镜像的一些命令 | 命令 | 说明 | | ------------- | ---------------------------------------------- | | docker search | 搜索镜像,优选官方,stars数量多的 | | docker pull | 拉取镜像,注意版本 | | docker push | 上传镜像 | | docker load | 导入镜像 | | docker save | docker save centos:7 -o docker_centos7.tar.gz | | docker images | 查看镜像列表 | | docker rmi | 删除镜像 | | docker tag | 给镜像打标签 | 容器中常用的镜像 | docker镜像使用的系统 | 说明 | | -------------------- | --------------------------------------------- | | ubuntu | 都可以做镜像 18.04 20.04 22.04 | | debian | 都可以做镜像bluster10,bullseye11,bookworm12 | | centos | 都可以做镜像 | | alpine | 镜像非常小 | ### 1.10 保存镜像和导入 简称sl ```sh docker image save 简写docker save docker image load 简写docker load docker save nginx:alpine -o nginx_alpine.tar docker save nginx:alpine | gzip ngx:alpine.tar.gz 导入 docker load -i nginx_alpine.tar 批量导入 使用for循环 批量导出 可以书写批量导出docker镜像脚本. #!/bin/bash #author: ysl996 #desc: 批量导出docker镜像 docker images |awk 'NR>1{print $1″:”$2}’ > /root/images.txt
for name in `cat /root/images.txt`
do
name_new=`echo $name |sed ‘s#:#_#g’`
docker save ${name} -o ${name_new}.tar
done

删除镜像
docker image rm ===docker rmi
docker image prune 清理未使用的镜像
docker iamges -a 查看所有镜像,包含隐藏镜像
“`

### 1.11给镜像设置标签

给镜像设置一个新的名字

应用场景

自定义镜像

搭建与使用内部仓库registry

“`sh
[root@docker01 ~]# docker tag nginx:1.24 nginx:1.24_v1
[root@docker01 ~]# docker images | grep nginx
nginx 1.24 b6c621311b44 17 months ago 142MB
nginx 1.24_v1 b6c621311b44 17 months ago 142MB
nginx 1.24-alpine 55ba84d7d539 17 months ago 41.1MB
“`

### 1.12 查看镜像详细信息

“`sh
[root@docker01 ~]# docker image inspect nginx:1.24-alpine
#jq专门过滤,json形式数据
docker inspect mysql:8.0-debian |jq .[].Id
docker inspect mysql:8.0-debian | jq .[].Config.Env | jq .
[0]
结果中最外面是: [] 所以先用 jq .[]进入到 []中.
结果中{} 可以用jq .Id 形式取出,对于缩进的需要先访问上级然后继续访问

jq需要安装yum install -y jq
“`

### 1.13 自定义镜像

Dockerfile详解

### 1.14 docker镜像指令小结

“`sh
docker pull
docker push
docker save
docker load
docker rmi
docker prune
docker tag
docker build
docker image inspect

“`

## 2 docker的容器管理

容器的一些命令

“`sh
docker container xxx
docker ps
docker run
dockercreate –name
docker start/stop/restart/kill
docker rm 批量删除所有容器docker rm -f `docker ps -aq`
docker exec -it 容器名 /bin/bash
docker inspect
docker stats
docker top

“`

### 2.1 run 运行容器与查看容器信息

“`sh
docker container run过程
1、查找本地是否有这个镜像,如果没有,则先下载镜像docker image pull
2、下载完成后创建容器
3、启动容器
一个docker run相当于pull/create/start
“`

### 2.2 docke容器指令的选项

| docker容器指令的选项 | 说明 |
| ——————– | ————————————— |
| -d | 后台运行 |
| -p | 端口映射 |
| -v | 数据卷挂载 |
| -i | interactive进入交互式,一般与-t一起使用 |
| -t | 分配一个终端 |
| –name | 给容器起名,不起的话会随机起名 |
| -e | 创建修改容器的环境变量 |

用到-p选项的时候需要在/etc/sysctl.conf添加一条net.ipv4.ip_forward = 1

![image-20250107155836817](D:\Program Files (x86)\Typora\008-docker\image-20250107155836817.png)

### 2.3 删除容器

| 删除容器命令 | 说明 |
| ———————————————————— | ———————- |
| docker rm -f | 后面选项是容器名字或id |
| docker rm -f `docker ps -qa` 或docker ps -aq \| xargs docker rm -f | 删除所有容器 |

### 2.4 启动debian/ubt容器

“`sh
[root@docker01 ~]# docker run -it –name centos_7 centos:7 /bin/bash
这样起退出后容器也会退出

[root@docker01 ~]# docker run -itd –name centos_back centos:7 /bin/bash
这样就不会退出
选项-itd容器后台运行同时进入容器,可以用于没有服务的系统镜像后台运行
“`

### 2.5 容器可以一直运行的原理

运行中的容器需要在容器中持续运行某个命令或服务

要在容器中有个命令、服务把这个容器阻塞主

容器想要在后台一直运行,那么容器的初始命令必须阻塞,否则容器就会退出

前台运行

“`sh
nginx -g ‘dameon off’
/usr/sbin/php-fpm –nodaemize
/usr/sbin/sshd/ -D
java -jar xxx.jar
“`

### 2.6 进入容器

“`sh
[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e8bc669b3d02 centos:7 “/bin/bash” 2 minutes ago Up 2 minutes centos_back
[root@docker01 ~]# docker exec -it centos_back /bin/bash
[root@e8bc669b3d02 /]#
“`

### 2.7 exec与attach区别

| docker | exec | attach |
| —— | ——————————- | ———————————————————— |
| 共同点 | 连接到已经运行的容器中 | 连接到已经运行的容器中 |
| 区别1 | 容器不需要有终端(不需要加-it) | 必须有终端(运行) |
| 区别2 | 每个连接互不影响 | 每个连接的所有操作与输出都是同步一致,退出容器后容器也退出了 |

![image-20250107155912446](D:\Program Files (x86)\Typora\008-docker\image-20250107155912446.png)

### 2.8 docker重启策略

| docker重启策略 | 说明 |
| —————– | ———————— |
| always | 自动重启 |
| unless-stopped | 只在容器关闭,停止的时候 |
| on-failure | 只在失败的时候重启 |
| 默认不加–restart | 不会自动重启 |

“`sh
[root@docker01 ~]# docker run -d –name ngx_alpine –restart=always nginx:1.24-alpine
“`

重启策略在容器运行的时候也可以重新添加,所以运行的时候忘了也无所谓

“`sh
[root@docker01 ~]# docker update –restart always `docker ps -aq`
“`

### 2.9 容器日志

| docker logs | 说明 |
| ———– | —————————————— |
| -f | 查看实时更新,显示所有日志后再查看实时更新 |
| –tail 或-n | –tail 20,最近20行 |
| –since | 5m 最近5分钟日志 |
| –until | 指定到什么时间结束 |

“`sh
[root@docker01 ~]# docker logs -n20 -f nginx_test
docker logs -f –since “2023-11-16T00:00:00Z” nginx_v3

docker启动mysql的时候需要添加-e MYSQL_ROOT_PASSWORD=1
[root@docker01 ~]# docker run -d –name mysql_5.7 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1 –restart=always mysql:5.7-debian
“`

### 2.10 docker run 背后的指令

“`sh
#1. 拉取镜像
docker pull nginx:1.24-alpine
#2. 创建容器
docker create -p 81:80 –name ngx_1.24_alpine_v2 —
restart=always nginx:1.24-alpine
#3. 启动容器
docker start ngx_1.24_alpine_v2
#4. 检查结果
docker ps

docker create
docker start
docker stop
docker restart
docker pause/unpause
“`

### 2.11 宿主机文件传输到容器中

“`sh
docker cp传输一个代码文件
[root@docker01 ~]# docker cp initial-setup-ks.cfg ngx_v2:/
“`

### 2.12 保存容器—生成镜像

“`sh
1、启动基础镜像
docker run -d –name ngx_bird_v1 -p 8848:80 –restart=always nginx:1.24

2.将代码传到容器
[root@docker01 ~]# docker cp bird/ ngx_bird_v1:/usr/share/nginx/html/

3.测试连接,没有问题后将容器保存为镜像
[root@docker01 ~]# docker commit ngx_bird_v1 web:ngx_bird_v1

4.使用新的镜像创建容器并测试
[root@docker01 ~]# docker run -d -p 8888:80 –restart=always –name ngx_bird_v2 web:ngx_bird_v1

5.测试通过后删除之前的临时容器
docker rm -f ngx_bird_v1
“`

![image-20250107155928908](D:\Program Files (x86)\Typora\008-docker\image-20250107155928908.png)

“`sh
通过docker commit可以实现初步定义镜像
docker commit 容器名 镜像名:版本

1、选择合适的基础镜像;
2、启动容器,链接容器,部署,配置,调试
3、commit生成镜像
4、通过镜像创建容器并调试

“`

### 2.13 其他容器指令

“`sh
当docker stop关闭不了容器的时候使用docker kill
查看容器中进程信息
docker top 容器名
docker top 容器名 -ef/-efL/aux
docker stats

[root@docker01 ~]# docker top ngx_bird_v2
UID PID PPID C STIME TTY TIME CMD
root 5972 5953 0 11:38 ? 00:00:00 nginx: master process nginx -g daemon off;
101 6013 5972 0 11:38 ? 00:00:00 nginx: worker process
101 6014 5972 0 11:38 ? 00:00:00 nginx: worker process

资源限制
[root@docker01 ~]# docker run -d –name ngx_bird_v3 -m 50m –cpus 1 nginx:1.24

在启动容器的时候没有限制资源,也可以使用docker update添加限制

[root@docker01 ~]# docker update -m 80m –memory-swap 100m ngx_bird_v3
“`

![image-20250107155940437](D:\Program Files (x86)\Typora\008-docker\image-20250107155940437.png)

### 2.14 export和import导入导出

类似于save和load

| save/load | export/import |
| ——— | ———————————– |
| 镜像 | export容器–镜像 import默认没有名字 |

“`sh
[root@docker01 ~]# docker export -o web_bird:v2 ngx_bird_v3
[root@docker01 ~]# ls
anaconda-ks.cfg initial-setup-ks.cfg
bird yangsenlinedu_useful_docker_images
docker yangsenlinedu_useful_docker_images.tar.gz
docker-20.10.24.tgz web_bird:v2
[root@docker01 ~]# docker import web_bird\:v2
sha256:5860fdd4c92ee4fa4e67de865ef72c1f7ab59f2b3778dc0396b65e984abb54e9
[root@docker01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
5860fdd4c92e 4 seconds ago 140MB

“`

### 2.15 容器管理指令小结

| docker容器 | 说明 | 参数 |
| ——————————————– | ——————– | ——————————————- |
| docker run | 启动容器 | -d -it -itd –name –resart –cpus –memory |
| docker ps | 查看容器信息 | -q -a |
| docker exec/attach | 链接容器 | -it |
| docker update | 动态修改容器配置 | cpu限制,内存限制,修改重启规则 |
| docker cp | 传输文件或目录到容器 | 目录对目录,文件对文件 |
| docker commit | 把容器保存为镜像 | 简单定义,复杂一般使用dockerfile |
| docker stop/start/restart/pause/unpause/kill | | |
| docker top/stats | 查看容器状态 | |
| docker inspect | 查看容器信息 | |
| docker export和save区别 | 导出镜像 | |

### 2.16 docker inspect查看信息与过滤

“`sh
查看容器,镜像,网络,数据卷等资源的信息
输出形式是json
1.三剑客取行取列
2.jq命令加工json query查看
3.docker自带的工具
[root@docker01 ~]# docker inspect ngx_bird_v3 | jq .[].Config.ExposedPosts

镜像
镜像名字RepoTags
映射的端口号Config.ExposedPorts
镜像大小Size

容器
容器名字Name
容器状态State.Status
重启策略HostConfig.RestartPolicy
容器使用的镜像Config.Image
ip地址NetworkSettings.IPAddress
“`

### 2.17 端口映射

端口映射的本质类似于iptables防火墙的端口映射

用户通过端口访问容器中的某个端口

本质是通过iptables nat规则实现的,nat表中创建了docker自定义的链

“`sh
[root@docker01 ~]# docker run -d -p 8080:80 –name ngx_test nginx:1.24
相当于添加了一条
iptablws -t nat -A DOCKER ! -i docker0 -p tcp -m tcp –dport 8080 -j DNAT –to-destination 170.17.0.2:80

查看所有运行中容器的ip地址
for ip in `docker ps -q`
do
docker inspect $ip | jq .[].NetworkSettings.IPAddress
done
“`

### 2.18 端口映射案例

1对1端口映射

“`sh
[root@docker01 ~]# docker run -d -p 80:80 -p 443:443 –name ngx_ports nginx:1.24-alpine

-p后面也可以端口范围80-8080:80-8080
“`

映射多个端口

“`sh
一个一个写或者连续
“`

把容器的端口随机映射到宿主机

“`sh
[root@docker01 ~]# docker run -d -P –name ngx nginx:1.24-alpine
-P 大写P

docker ps查看映射到哪个端口了

“`

ip绑定端口

“`sh
用户只能通过宿主机的某个网卡连接这个端口
[root@docker01 ~]# docker run -d -p 172.16.1.81:8081:80 nginx:1.24-alpine

“`

用户访问的时候经历了什么![image-20250107155958261](D:\Program Files (x86)\Typora\008-docker\image-20250107155958261.png)

### 2.19 数据卷挂载

#### 1 概述

如果容器崩了,容器被误删除了,容器中的数据将丢失,接下来解决数据不丢,

如何解决数据持久化问题?数据卷(挂载),让数据永久保存在宿主机中

![image-20250107160046593](D:\Program Files (x86)\Typora\008-docker\image-20250107160046593.png)

![image-20250107160112593](D:\Program Files (x86)\Typora\008-docker\image-20250107160112593.png)

#### 2 实战

docker run -v 宿主机路径:容器内部路径

3 创建数据库容器并完成持久化

| 内容 | 宿主机 | 容器 |
| ——– | ————— | ————– |
| 项目目录 | /app/data/db8.0 | /var/lib/mysql |

“`sh
1、创建主机目录
2、创建容器并指定持久化
[root@docker01 ~]# docker run -d –name mysql –restart always -v /app/data/db8.0:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=1 mysql:8.0-debian
3、进入数据库容器,并创建数据库
[root@docker01 ~]# docker exec -it mysql /bin/bash
mysql -uroot -p1
create database
4、删除容器
[root@docker01 ~]# docker rm -f mysql
5、再创建容器并指定持久化
[root@docker01 ~]# docker run -d –name mysql –restart always -v /app/data/db8.0:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=1 mysql:8.0-debian
6、查看库,库还在
[root@docker01 ~]# docker exec -it mysql mysql -uroot -p1
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.33 MySQL Community Server – GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> show databases;
+——————–+
| Database |
+——————–+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+——————–+
5 rows in set (0.00 sec)

“`

#### 3 数据卷挂载小结

把宿主机文件或目录挂载到容器中

数据持久化,容器没了,数据还在

#### 4 案例-挂载到数据卷空间

做数据持久化,不关注数据具体在哪里

/var/lib/docker目录下面

“`sh
1、创建数据卷空间
[root@docker01 ~]# docker volume create mysql_data
2、查看数据卷空间
[root@docker01 ~]# docker volume inspect mysql_data
3、创建容器
[root@docker01 ~]# docker run -d –name mysql –restart always -v mysql_data:/var/lib/mysql -v MYSQL_ROOT_PASSWORD=1 mysql:8.0-debian
4、查看
[root@docker01 ~]# docker inspect mysql
“`

![image-20250107160136706](D:\Program Files (x86)\Typora\008-docker\image-20250107160136706.png)

#### 5 数据卷小结

熟悉掌握挂载指定的目录或文件到容器中即可

-v指定宿主机目录、文件和容器目录,文件

做持久化,不关注数据放在哪,数据卷空间即可,-v 数据卷空间:容器文件或目录

docker volume

### 3 容器架构自动化部分

docker镜像,容器,端口映射,数据卷挂载

目标:创建一个ngx+bird游戏镜像,自动化实现Dockerfile

#### 3.1 Dockerfile概述

应用场景,通过1个文件Dockerfile,生成自定义镜像

#### 3.2 Dockerfile格式

“`sh
1、指定基础镜像
FROM nginx:1.24-alpine
2、基本信息,相当于说明
LABEL nginx+bird
3、对镜像进行操作,执行命令
RUN sed -i ‘s/#gzip/gzip/g’ /etc/nginx/nginx.conf
4、把压缩包内容传输到目录
ADD bird.tar.gz /usr/share/nginx/html/
5、告诉镜像使用者容器映射的是80 443
EXPOSE 80 443
6、收尾、入口指令,运行容器后默认运行的命令
CMD [“nginx”,”-g”,”daemon off;”]

7、根据Dockerfile构建镜像,-t是给自定义镜像命名
docker build . -t ‘ngx:bird_v1’
8、运行
docker run -d –name bird -p 81:80 ngx:bird_v1
9、调试

“`

![image-20250107160213347](D:\Program Files (x86)\Typora\008-docker\image-20250107160213347.png)

#### 3.3 Dockerfile中的指令

都是大写

| Dockerfile指令 | 含义 | 建议 |
| —————— | ———————————————————— | ———————————————————— |
| Dockerfile开头部分 | | |
| FROM | 指定基本镜像,类似于docker pull下载镜像 | 尽量指定具体的版本 |
| LABEL | 用于指定容器的属性信息 | 推荐使用LABEL,不推荐MAINTAINER |
| MAINTAINER | 不再使用,推荐使用LABEL 个人信息 | |
| ENV | 用于创建Dockerfile中使用的变量 | 软件版本可以创建使用变量 |
| Dockerfile中间部分 | | |
| RUN | 制作镜像过程中需要执行的命令,通常系统配置,服务配置,部署。但是不能出现阻塞 | 不建议连续使用多个RUN使用&&来执行多个命令 |
| ADD | 把指定文件或目录拷贝到容器中,会自动解压压缩包,但是解压不了zip | 拷贝压缩包使用 |
| COPY | 可以把指定的文件或目录拷贝到文件中,不支持地总解压 | 拷贝文件或目录 |
| WORKDIR | 指定容器的默认的工作目录 | 一般用于配合ADD,COPY需要书写容器中路径指令,Dockerfile使用相对路径操作容器 |
| VOLUME | 挂载数据卷 | 创建随机的数据卷挂载容器的目录,推介使用docker run的时候指定-v即可 |
| Dockerfile结尾部分 | | |
| EXPOSE | 指定镜像要对外暴露的端口 | 用于指定一个或多个容器的端口,未来这个端口可以被-P识别 |
| CMD | 容器的入口指令,可以在docker run的时候替换,==运行镜像启动容器的时候,容器默认运行的命令是什么 | 大部分都会使用CMD |
| ENTRYPOINT | 用于指定容器的入口命令,无法被docker run替换,docker run指定的时候仅仅作为entrypoint命令的参数而已 | 使用不多 |

#### 3.4 案例-Dockerfile使用WORKDIR,VOLUME,ENV

“`sh
ENV 全局变量
WORKDIR 工作目录,容器初始目录,进入容器后默认的所在目录,
VOLUME 容器中哪些目录或文件,需要做数据卷挂载-v

[root@docker01 /app/docker/dockerfile/bird]# cat Dockerfile
FROM nginx:1.24-alpine
LABEL bird and ngx
ENV NGX_CONF /etc/nginx/nginx.conf
ENV CODE_TAR bird.tar.gz
ENV VO_DIR /app/code/upload/

WORKDIR /usr/share/nginx/html/
RUN sed -i ‘s/#gzip/gzip/g’ ${NGX_CONF}
ADD ${CODE_TAR} .

VOLUME ${VO_DIR}

EXPOSE 80

CMD [“nginx”,”-g”,”daemon off;”]
[root@docker01 /app/docker/dockerfile/bird]#
“`

#### 3.5 小结

ENV创建全局环境变量

WORKDIR指定工作目录

VOLUME指定容器中哪些路径需要映射出去,类似EXPOSE

#### 3.6 Dockerfile相关故障

1.dockerfile书写问题

2.docker run然后看日志

3.docker run -it前台查看启动流程

4.docker run -it xxx /bin/bash进入容器,执行检查类命令,手动检查配置文件

#### 3.7 CMD,ENTRYPOINT区别

| CMD和ENTRYPOINT区别 | 共同点 | 区别 |
| ——————- | ————————————————- | ———————————————————— |
| CMD | 运行容器的时候默认运行CMD或者ENTRYPOINT后面的命令 | run的时候替换,如果镜像名字后面指定了命令,则CMD内容就会被替换 |
| ENTRYPOINT | 运行容器的时候默认运行CMD或者ENTRYPOINT后面的命令 | run的时候如果指定了命令内容,那只是entrypoint的参数而已,追加 |

“`sh
[root@docker02 /app/docker/dockerfile]# docker run -d -p 1111:80 –name nginx_entrypoint ngx_entrypoint:latest -g daemon off;
40832fd5b023943d8fc6ee686eda41a3386d9aae2f024defff9c700621a9a613
[root@docker02 /app/docker/dockerfile]# ls
03-test-cmd-entrypoint bird Dockerfile
[root@docker02 /app/docker/dockerfile]# cat Dockerfile
FROM nginx:1.24
LABEL author:ysl desc:test cmd and entrypoint

ENTRYPOINT [“nginx”]
“`

| CMD和ENTRYPOINT同时使用 | 说明 |
| ———————– | ————————————— |
| 同时使用 | CMD写的内容将作为ENTRYPOINT的内容的选项 |
| 使用 | ENTRYPOINT后面接脚本用于判断 |

“`sh
FROM nginx:1.24
LABEL author=ysl996 desc=”测试 cmd和entrypoint”
ENTRYPOINT [“nginx”]
CMD [“-g”,”daemon off;”]
“`

#### 3.8 多阶段提交

解决问题:

防止镜像过大,因为dockerfile创建镜像过程中每个步骤都会有子镜像产生,还有有些我们只需要结果,并不需要安装的依赖

使用dockerfile多阶段提交方法:类似于接力,选择一个或多个临时镜像进行编译,最终把临时镜像中的结果复制到指定的新的镜像中

“`sh
不使用多阶段提交,安装tengine

“`

#### 3.9 多阶段提交应用场景

目标:压缩镜像大小

应用场景:编译(nginx,java代码,golang代码,前端代码)

镜像分层次架构,适用于编程、构建场合,先通过中间镜像进行编译,变成结果放到新的镜像中

FROM ubuntu:22.04 AS temp 给中间镜像起个别名

最终镜像中通过COPY –from=temp /app/ /app/

/app/docker/dockerfile/04中Dockerfile有问题

#### 3.10 war包容器tomcat

“`sh
FROM tomcat:9.0-jdk8
LABEL author=ysl996
ENV WAR=ROOT.war
ENV WEBAPP=/usr/local/tomcat/webapps/
WORKDIR ${WEBAPP}
ADD ${WAR} .
EXPOSE 8080
CMD [“catalina.sh”,”run”]
#通过指定命令对容器中的服务进行检查
#用于检查容器运行中(服务运行)但是用户无法访问
HEALTHCHECK –interval=5s –timeout=20s –retries=2 CMD curl 127.0.0.1:8080

HEALTHCHECK指令监控服务,业务是否正常,CMD
curl web服务
mysql -ucheck -p1 -e “select user,host from mysql.user;”
redis-cli info

“`

#### 3.11 制作jar包容器-ngx-webtui

“`sh
FROM java:8u111-jdk
LABEL author=yangsenlinysl996
ENV CODE_DIR=/app/code/
ENV JAR_NAME=nginxWebUI-3.4.0.jar
#默认用的命令解释器/bin/sh
SHELL [“/bin/bash”,”-c”]
RUN set -euxo pipefail ;\
umask 0022 ;\
mkdir -p ${CODE_DIR} ;
WORKDIR ${CODE_DIR}
ADD ${JAR_NAME} .
ADD entry.sh /
EXPOSE 8080
CMD [“/entry.sh”]
HEALTHCHECK –interval=5s –timeout=20s –retries=2 \
CMD curl 127.0.0.1:8080
“`

#### 3.12 网站架构容器化(迁移到容器中)

服务,代码,自定义镜像(没有直接可用的镜像或官网的镜像无法满足)

自定义tengine镜像

自定义tomcat镜像

自定义jar包镜像

#### 3.13 前后端分离镜像

mysql8.0库,用户,导入sql

镜像后端jar+java

前端nginx+子配置文件+代码

“`sh
mysql容器变量
MYSQL_ROOT_PASSWORD root密码
MYSQL_DATABASE 创建指定的库
MYSQL_USER创建用户,MYSQL_PASSWORD用户对应的密码
添加exam库,并授予ysl用户管理exam库
docker run -d –name qh_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=’XZnh@95599′ -e MYSQL_DATABASE=exam -e MYSQL_USER=exam -e MYSQL_PASSWORD=’XZnh@95599′ mysql_8.0-debian
“`

3.14 dockerfile小结

“`sh
FROM
LABEL
ENV
SHELL

WORKDIR
RUN
ADD/COPY

VOLUME
EXPOSE

ENTRYPOINT
CMD
HEALTHCHECK

“`

“`sh
目标:自定义镜像
中级目标:根据企业需求创建各种各样的镜像(服务,配置,代码)
项目目标:
1、网站架构容器化
2、一般web服务即可
熟练掌握dockerfile格式及书写

“`

尽量多阅读官方或gitee、github上面的代码中的dockerfile

“`sh
排障流程
第一类问题:运行docker build故障
根据错误提示的步骤大概定位是哪个步骤出了问题
如果是RUN,拆分,是为了定位哪个命令问题
其他指令看错误提示即可
第二类问题:运行docker run故障
查看docker ps -a –no-trunc查看详细入口命令与错误提示
辅助docker logs查看
docker run -it 容器名 /bin/bash前台运行,进入容器,手动启动服务,观察错误提示
“`

| 生产环境应用建议 | 说明 |
| ———————— | —————————————————- |
| 尽量保证每个镜像功能单一 | 尽量避免多个服务运行在同一个镜像中 |
| 选择合适的基础镜像 | 不一定都要从头做 |
| 注释与说明 | 添加一定的注释和镜像属性信息 |
| 指定版本号 | 使用镜像的时候指定版本 |
| 减少镜像层数/步骤 | 尽可能合并RUN,ADD,COPY |
| 记得收尾(减少镜像大小) | 清理垃圾,记得清理缓存,临时文件,压缩包 |
| 合理使用dockerignore | dockerfile同一个目录,隐藏文件,构建的时候忽略的文件 |

““sh
直接指定要排除的内容
cat .dockerignore
etc*.tar.gz
先排除所有,通过!准许指定文件传输到dockerd
*
!target/nginxWebUI-*.jar
!Dockerfile
!entrypoint.sh
““

#### 3.14 搭建个人网盘

可道云代码

kodexp仅需要ngx+php

kodbox需要ngx+php+mysql+存储+redis

“`sh
代码kodbox,云盘和云桌面
lnmp环境
nginx+php1个镜像
db mysql8.0
redis 5.0

“`

![image-20250107160257687](D:\Program Files (x86)\Typora\008-docker\image-20250107160257687.png)

项目步骤:ngx+php镜像

启动debian容器映射80端口

“`sh
docker run -itd –name ngx_php_kodbox_v1 -p 80:80 ubuntu:22.04 /bin/bash
1、进入容器配置apt源
docker exec -it ngx_php_kodbox_v1 /bin/bash
cp /etc/apt/sources.list /etc/apt/sources.list.bak
sed -ri ‘s/archive.ubuntu.com\/|security.ubuntu.com\//mirrors.aliyun.com\//g’ /etc/apt/sources.list
2、配置nginx源、安装nginx
sed -i ‘s/deb.debian.org/mirrors.aliyun.com/g’ /etc/apt/sources.list

apt update

apt install -y curl gnupg2 ca-certificates lsb-release debian-archive-keyring

curl https://nginx.org/keys/nginx_signing.key | gpg –dearmor \
| tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

gpg –dry-run –quiet –no-keyring –import –import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

echo “deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian `lsb_release -cs` nginx” \
| tee /etc/apt/sources.list.d/nginx.list

echo -e “Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n” \
| tee /etc/apt/preferences.d/99nginx

apt update
apt install -y nginx
3、安装php

apt install -y php7.4-bcmath php7.4-bz2 php7.4-cgi php7.4-cli php7.4-common php7.4-curl php7.4-dba php7.4-dev php7.4-enchant php7.4-fpm php7.4-gd php7.4-gmp php7.4-imap php7.4-interbase php7.4-intl php7.4-json php7.4-ldap php7.4-mbstring php7.4-mysql php7.4-odbc php7.4-opcache php7.4-pgsql php7.4-phpdbg php7.4-pspell php7.4-readline php7.4-snmp php7.4-soap php7.4-sybase php7.4-tidy php7.4-xml php7.4-xmlrpc php7.4-xsl php7.4-zip php7.4-redis
4、检查nginx和php安装结果
dpkg -l |grep nginx
dpkg -l |grep php7.4 |wc -l

5、配置php
5.1 备份配置文件
cp /etc/php/7.4/fpm/pool.d/www.conf /etc/php/7.4/fpm/pool.d/www.conf`date +%F`
cp /etc/php/7.4/fpm/php-fpm.conf /etc/php/7.4/fpm/php-rpm.conf`date +%F`

5.2 修改php-fpm端口
sed -i ‘s/\/run\/php\/php7.4-fpm.sock/127.0.0.1:9000/g’ /etc/php/7.4/fpm/pool.d/www.conf

5.3 修改php7.4的pid文件的路径
sed -i ‘s#/run/php/php7.4-fpm.pid#/run/php7.4-fpm.pid#g’ /etc/php/7.4/fpm/php-fpm.conf

php-fpm7.4 -t
php-fpm7.4
ps -ef | grep php

6、配置ngx
sed -ri ‘/^user/s/nginx/www-data/g’ /etc/nginx/nginx.conf
增加子配置文件
server {
listen 80;
server_name kodbox.yangsenlinlinux.cn;
root /app/code/kodbox;
access_log /var/log/nginx/access_log.log main;
location / {
index index.php;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~* \.hph& {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

7、日志连接
root@9e6f1807a1a5:/etc/nginx/conf.d# rm -rf /var/log/nginx/*
root@9e6f1807a1a5:/etc/nginx/conf.d# ln -sf /dev/stdout /var/log/nginx/access_log.log
root@9e6f1807a1a5:/etc/nginx/conf.d# ln -sf /dev/stderr /var/log/nginx/error.log

部署代码
[root@docker01 ~]# docker cp kodbox/ ngx_php_kodbox_v1:/tmp/
[root@docker01 ~]# docker exec -it ngx_php_kodbox_v1 /bin/bash
root@9e6f1807a1a5:/# mkdir -p /app/code
root@9e6f1807a1a5:/# mv /tmp/kodbox/ /app/code/
root@9e6f1807a1a5:/# chown -R www-data:www-data /app/code/kodbox/

部署mysql和redis镜像
[root@docker01 ~]# docker volume create mysql57_kodbox
mysql57_kodbox
[root@docker01 ~]# docker volume ls
[root@docker01 ~]# docker inspect volume mysql57_kodbox
[root@docker01 ~]# docker run -d –name mysql_kodbox -v mysql57_kodbox:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=’XZnh@95599′ -e MYSQL_DATABASE=kodbox -e MYSQL_USER=kodbox -e MYSQL_USER_PASSWORD=’XZnh@95599′ -p 3306:3306 -p 33060:33060 mysql:5.7-debian
[root@docker01 ~]# docker run -d –name ‘redis5.0’ -v redis_data:/data -p 172.16.1.81:6379:6379 redis:5.0-alpine

“`

“`sh
项目步骤:书写web dockerfile
创建ngx+php镜像
流程
配置apt源,apt update
安装各种软件
进行配置ngx,php
站点目录,代码,修改权限
清理镜像缓存
cmd启动ngx和php

“`

#### 3.15容器互联 –link

–link是用于容器连接其他容器的选项,其他容器要运行中才行

本质是在容器中配置了hosts解析,单向解析

#### 3.16 docker -f 过滤指令

#### 3.17 docker compose

“`sh
目前面临的问题
docker run指令越来越长
docker build后需要手动运行docker run
通过docker compose实现

compose带来的新的问题:docker compose单机编排工具,遇到网站集群里的管理比较费劲

容器集群管理解决方案:
1、脚本
2、ansible+docker compose
3、docker swarm docker官方提供集群管理工具
4、k8s(kubernetes)容器集群编排与管理工具
5、mesos
6、rancher web页面
“`

![image-20250107161203250](D:\Program Files (x86)\Typora\008-docker\image-20250107161203250.png)

单机容器编排工具

“`sh
docker compose类似于docker run指令
集群管理
ansible+shell或docker compose
docker compose需要单独安装,go语言写的,解压后放在/usr/sbin/目录下面
语法是yaml格式

“`

#### 1 compose极速上手指南

“`sh
环境准备
mkdir -p /server/compose/01-run-nginx
默认支持的compose名
docker-compose.yaml或docker-compose.yml

启动命令
docker-compose up -d
“`

| docker-compose组成 | 说明 |
| —————— | ———————————– |
| version | 3.3为了兼容旧的docker-compose加的, |
| services | 指定容器与容器相关信息,核心 |
| volumes | 创建数据卷空间 |
| networks | 自定义网络 |

| docker-compose命令格式 | 说明:这个命令包含了docker container和docker images命令 |
| ———————- | ———————————————————— |
| up -d | up==run创建并运行容器,启动的时候后台运行类似于docke rrun -d |
| down | 删除容器,删除所有内容(网络,数据卷) |
| stop/start/restart | 关闭、开启、重启 |
| ps | 查看容器运行情况,只有-q选项 |
| top | 查看容器进程信息 |
| logs | 容器日志 |
| rm | 删除容器(需要容器已经关闭) |
| 镜像 | |
| images | 查看镜像 |

#### 2 案例-包含数据库kodbox案例

“`sh
部署kodbox、nginx、php、db
流程
1、dockerfile自定义php,复用之前
2、docker run数据库容器,数据卷挂载,数据卷空间
3、docker-compose注意依赖

读取dockerfile
指定镜像名字
docker-compose运行指定的dockerfile,后期不用继续docker build,然后docker-compose up -d

看到day-54文档88页

“`

![image-20250107160333118](D:\Program Files (x86)\Typora\008-docker\image-20250107160333118.png)

#### 3 小结

docker build 构建镜像docker run运行容器

书写docker compose的时候通过docker run自行测试

#### 3.18 docker,docker-compose升级案例

“`sh
1、背景
安全,旧的版本有漏洞,如果软件(命令,服务)有漏洞,升级软件到不受影响的版本
服务新版本,新功能,新环境,新业务使用,旧的保持不变

2、流程:
1.测试环境,部署新服务,部署代码测试
2.准备备用方案,回滚,备份
3.采取正式环境,逐步更新策略,修改负载权重,减小新节点访问量
4.测试ok,逐步更新其他机器

“`

3.具体流程

| 更新流程 | 说明 |
| ———————- | —————————————————- |
| 更新docker-compose | 下载二进制docker-compose的命令,备份已有的命令,替换 |
| 测试docker-compose | 最新版 |
| 更新docker | 下载二进制docker |
| 先备份已有的docker命令 | 关闭容器,服务,替换命令,检查,启动docker,启动容器 |

4.更新docker-compose

“`sh
which docker-compose
mkdir -p /backup/docker-compose
mv `which docker-compose` /backup/docker-compose/
mv docker-compose-linux-x86_64 /usr/bin/docker-compose
chmod 755 /usr/bin/docker-compose
docker-compose -v
“`

5.更新docker

“`sh
1.备份关闭
rpm -ql docker-engine |grep bin |xargs mv -t /backup/docker_bak/
docker stop `docker ps | awk ‘NR>1{print $1}’`
systemctl stop docker

2.升级
tar -xf docker-20.10.24.tgz
chown root.root docker/*
mv docker/* /bin/
systemctl start docker
docker start redis5.0
rm -f /usr/local/bin/runc

“`

### 4 docker镜像仓库

#### 4.1 registry仓库

仓库选型与概述

应用场景:

​ 未来docker官方的镜像无法直接满足我们的需求

​ 我们企业内部也要定制很多镜像

​ 而且这些镜像不想公开,都是私有的

| docker镜像仓库方案 | 应用场景与特点 |
| —————— | ———————————————————— |
| 镜像保存为压缩包 | 使用的时候,sl(save/load),仅适用于节点极少的情况,很不方便 |
| registry镜像仓库 | 使用方便,适用于小型网站集群,(镜像不多,环境不复杂), |
| harbor镜像仓库 | 企业级镜像仓库(docker,k8s)都可以用,图形化界面 |
| 共有云镜像服务 | 阿里云ACR在公有云上申请,个人,企业 |

![image-20250107161239116](D:\Program Files (x86)\Typora\008-docker\image-20250107161239116.png)

“`sh
cat >>/etc/hosts< ‘cgroup:[4026531835]’
lrwxrwxrwx 1 root root 0 Jan 17 11:26 ipc -> ‘ipc:[4026531839]’
lrwxrwxrwx 1 root root 0 Jan 13 23:04 mnt -> ‘mnt:[4026531841]’
lrwxrwxrwx 1 root root 0 Jan 13 23:07 net -> ‘net:[4026531840]’
lrwxrwxrwx 1 root root 0 Jan 13 23:07 pid -> ‘pid:[4026531836]’
lrwxrwxrwx 1 root root 0 Jan 17 11:26 pid_for_children -> ‘pid:[4026531836]’
lrwxrwxrwx 1 root root 0 Jan 17 11:26 time -> ‘time:[4026531834]’
lrwxrwxrwx 1 root root 0 Jan 17 11:26 time_for_children -> ‘time:[4026531834]’
lrwxrwxrwx 1 root root 0 Jan 17 11:26 user -> ‘user:[4026531837]’
lrwxrwxrwx 1 root root 0 Jan 17 11:26 uts -> ‘uts:[4026531838]’
“`

| namespace分类 | 说明 |
| ————- | ———————— |
| net | 网络资源隔离 |
| user | 用户id,信息隔离 |
| mnt | 磁盘资源隔离 |
| ipc | 进程通讯,资源格式 |
| pid | 进程id隔离 |
| uts | 系统资源,比如主机名隔离 |

2 cgroups

“`sh
cd /sys/fs/cgroup/cpu
mkdir yangsenlin-cgroup
cd yangsenlin-cgroup
#压力测试
stress -c 4 -v -t 20m
#进行限制
echo 10000 >cpu.cfs_quota_us
#添加pid到tasks中 关联任务
“`

TOMCAT

### 1 web中间件

| java容器 | 说明 |
| ——– | ——————————————– |
| tomcat | 最常用,较重,功能完善 |
| jetty | 轻量,功能较少 |
| jboss | |
| weblogic | 用于oracle数据库环境使用,weblogic属于oracle |
| 东方通 | 国产java容器,tongweb |
| ….. | |

JVM-JRE-JAVA

jvm:java虚拟机中,运行java代码的地方

jre:java运行环境,提供jvm环境,java命令

jdk:java开发环境,jvm+jre+额外功能

jdk安装的两种方法

“`sh
1、rpm -ivh jdk-8u351-linux-x64.rpm

2、二进制部署jdk
mkdir -p /app/tools/
tar xf jdk-8u341-linux-x64.tar.gz -C /app/tools/
ll /app/tools/
ln -s /app/tools/jdk1.8.0_341/ /app/tools/jdk
在/etc/profile最后添加以下内容
export JAVA_HOME=/app/tools/jdk
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar

source /etc/profile

“`

![image-20250107154434265](D:\Program Files (x86)\Typora\007-tomcat\image-20250107154434265.png)

二进制部署tomcat

“`sh
tar -xf apache-tomcat-9.0.97.tar.gz -C /app/tools/
ln -s /app/tools/apache-tomcat-9.0.97/ /app/tools/tomcat
/app/tools/tomcat/bin/version.sh
“`

### 2 tomcat目录结构

| 目录 | 说明 |
| ——- | ———————————- |
| bin | 存放tomcat管理命令 |
| conf | tomat配置文件 |
| lib | 依赖于库文件,插件文件 |
| logs | 日志目录 |
| webapps | 站点目录 |
| work | tomcat运行java代码的存放代码的目录 |

#### 1 bin目录

| bin目录 | 说明 |
| ———– | ——————————— |
| startup.sh | 启动脚本 |
| shutdown.sh | 关闭脚本 |
| catalina.sh | 核心脚本,配置tomcat优化,jvm优化 |

#### 2 conf目录

| conf配置文件 | 说明 |
| ———— | —————————— |
| server.xml | tomcat配置文件,类似nginx.conf |
| web.xml | 配置文件,辅助文件 |

#### 3 logs目录

| logs目录 | 说明 |
| ———————————– | ———————————————————— |
| catalina.out | tomcat应用日志,启动过程,关闭等错误日志,核心找error,failed,exception |
| catalina.2022-09-15.log | catalina.sh的切割日志,按每天进行切割 |
| localhost_access_log.2022-09-15.txt | 访问日志,未来可以重新定义成跟nginx日志一样格式 |

#### 4 webapps

站点目录

war包,自动解压,自动部署

书写systemctl管理配置文件进行管理

目标:

可以给二进制安装或编译安装的软件书写systemctl配置文件

可以通过systemctl管理服务(开机重启,是否开机启动)

### 3 书写systemctl流程

书写配置文件,参考其他服务

重新加载systemctl

开始使用systemctl管理服务即可

systemctl配置文件路径

/usr/lib/systemd/system/xxx.service

以.service结尾

分为3个部分

[Unit]

[Service]

[Install]

| systemctl配置文件结构 | 说明 |
| ————————– | ———————————————————- |
| [Unit] | 指定注释信息,依赖(先后顺序) |
| Description | 说明与注释 |
| After | 在这里指定服务之后运行,network。target |
| [Service] | 核心,用于指定服务开启、关闭、重启命令 |
| Type=notify | 指定类型simple或forking即可 |
| ExecStart | 服务启动命令 |
| ExecStop | 服务关闭命令 |
| ExecReload | 重启 |
| EnvironmentFile | 配置环境变量的文件(一般对于编译安装,二进制安装需要加上) |
| [Install] | 内容固定,指定运行级别 |
| WantedBy=multi-user.target | 运行级别,一般都是多用户模式 |

“`sh
[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking

# 指定Tomcat的启动和关闭脚本路径
ExecStart=/app/tools/tomcat/bin/startup.sh
ExecStop=/app/tools/tomcat/bin/shutdown.sh

# 指定用户和组,Tomcat通常以非root用户运行

# 环境变量,确保JAVA_HOME被正确设置
Environment=”JAVA_HOME=/app/tools/jdk”

# 确保在启动时重新加载服务
Restart=on-failure

[Install]
WantedBy=multi-user.target
“`

### 4 运行java代码

开发人员书写的java代码:java源代码,无法直接不上到tomcat中

需要对源代码进行编译打包,生成war包或jar包

java代码→编译→war包或jar包

使用war包或jar包部署web服务器

| 如何运行java相关软件包 | 说明 | 应用场景 |
| ———————- | ———————————————————— | ——– |
| war包 | 需要放在java容器中运行,比如放到tomcat的webapps目录下(tomcat会自动加载与运行war包内容) | 功能复杂 |
| jar包 | 不需要依赖,直接运行只需要jdk,通过java -jar xxx.jar运行 | 功能简单 |

#### 1 jar包运行

“`sh
[root@web03 ~]# java -jar -Dfile.encoding=UTF-8 nginxWebUI-3.4.0.jar –server.port=8848 –project.home=/app/code/ngx
“`

–project.home 项目配置文件目录,存放数据文件,证书文件,日志等,默认为/home/nginxWebUI/

#### 2 tomcat管理端

tomcat管理端,web页面管理与查看tomcat信息功能

对tomcat进行调优的时候临时开启

未来生产环境中需要关闭

webapps/ROOT下面

#### 3 开启管理端功能

修改配置文件conf/tomcat-users.xml

修改代码,安全措施,只能127访问

“`sh
在倒数第二行之前添加


“`

#### 4 修改只能127访问

“`sh
cd /app/tools/tomcat/webapps/
sed -i ‘s#127#\\d+#g’ ./host-manager/META-INF/context.xml ./host-manager/WEB-INF/manager.xml ./manager/META-INF/context.xml
“`

### 5 案例01-tomcat部署zrlog应用

LNMT环境部署应用,war包应用

代码war

创建数据库与用户

war包部署到tomcat webapps目录

部署zrlog流程

1.数据库,库,用户

2.tomcat环境,部署war包

3.安装代码与调试

4.接入ngx

“`sh
数据库操作
MariaDB [(none)]> create database zrlog;
Query OK, 1 row affected (0.000 sec)

MariaDB [(none)]> grant all on zrlog.* to ‘zrlog’@’172.16.1.%’ identified by ‘XZnh@95599’;

MariaDB [(none)]> select user,host from mysql.user;

tomcat操作
[root@web03 ~]# mv zrlog-2.2.1-efbe9f9-release.war /app/tools/tomcat/webapps/ROOT.war

这里是启动tomcat后在页面上配置数据库文件后自动生成的,了解一下这个文件即可
[root@web03 /app/tools/tomcat/webapps/ROOT/WEB-INF]# cat db.properties
#This is a database configuration file
#Tue Nov 26 17:06:08 CST 2024
driverClass=com.mysql.cj.jdbc.Driver
user=zrlog
password=XZnh@95599
jdbcUrl=jdbc\:mysql\://172.16.1.51\:3306/zrlog?characterEncoding\=UTF-8&allowPublicKeyRetrieval\=true&useSSL\=false&serverTimezone\=GMT

chown -R root.root /app/tools/tomcat/
find /app/tools/tomcat/webapps/ -type f |xargs chmod 644
find /app/tools/tomcat/webapps/ -type d |xargs chmod 755

nginx配置
[root@web03 /etc/nginx/conf.d]# cat zrlog.ysllinux.cn.conf
server {
listen 80;
server_name zrlog.ysllinux.cn;
error_log /var/log/nginx/zrlog.ysllinux.cn.error.log notice;
access_log /var/log/nginx/zrlog.ysllinux.cn.access.log main;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

以上是没有实现动静分离
下面实现动静分离

[root@web03 /etc/nginx/conf.d]# cat zrlog.ysllinux.cn.conf
server {
listen 80;
server_name zrlog.ysllinux.cn;
error_log /var/log/nginx/zrlog.ysllinux.cn.error.log notice;
access_log /var/log/nginx/zrlog.ysllinux.cn.access.log main;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* \.(html|js|css|png|jpeg|bmp|webp)$ {
root /app/tools/tomcat/webapps/ROOT;
expires 7d;
}
}
“`

### 5 tomcat配置文件

“`sh

#8005端口,可以telnet到8005然后输入SHUTDOWN关闭tomat,有需要的话可以将SHUTDOWN改成其他指令





#配置管理认证等功能



#8080,处理用户的http请求,8443是用于处理https请求的

#engine部分,指定默认的虚拟主机,defaultHost指定的是默认的虚拟主机



#host部分,指定虚拟主机的配置





“`

| 虚拟主机 | tomcat | nginx |
| ——– | —————————————————— | —————————————— |
| 虚拟主机 | host部分 | server{} |
| 域名 | name=“域名“ | server_name java.ysllinux.cn; |
| 端口 | port=”8080″ | listen 80; |
| 站点目录 | appBase=”webapps“ | root /app/code/blog; |
| 自动解压 | unpackWARs=”true” | 无 |
| 自动部署 | autoDeploy=”true” | 无 |
| 日志目录 | valve部分的directory=”logs” | access_log /var/log/nginx/access.log main; |
| 日志名字 | valve部分的prefix=”localhost_access_log” suffix=”.txt” | access_log /var/log/nginx/access.log main; |
| 日志格式 | valve部分的pattern=”%h %l %u %t "%r" %s %b” | log_format main ….. |

要让tomcat访问日志格式与nginx一致,需要替换

“`sh
pattern=”%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" "%{X-Forwarded-For}i"” />
“`

### 6 tomcat多实例

将tomcat的目录多复制几个,然后修改server.xml里面的端口,再启

### 7 java远程监控功能

1、通过各种监控工具

2、使用tomcat自带的监控功能

修改catalina.sh

找CATALINA_OPTS

找到后修改

“`sh
CATALINA_OPTS=”$CATALINA_OPTS \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=10.0.0.9″

-Dcom.sun.management.jmxremote #开启远程监控功能
-Dcom.sun.management.jmxremote.port=12345 #指定端口
-Dcom.sun.management.jmxremote.authenticate=false #关闭认证功能
-Dcom.sun.management.jmxremote.ssl=false #关闭ssl加密功能
-Djava.rmi.server.hostname=10.0.0.9″#写上本地网卡的ip,监听的地址,未来写上内网ip
“`

### 8 java监控命令

“`sh
都是以j开头的
jps
jstack
jmap
jdump

1、jps,jps -lvm相当于ps -ef
[root@web03 ~]# jps
1016 Bootstrap
1694 Jps
[root@web03 ~]# ps -ef | grep 1016
root 1016 1 0 10:11 ? 00:00:08 /app/tools/jdk/bin/java -Djava.util.logging.config.file=/app/tools/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /app/tools/tomcat/bin/bootstrap.jar:/app/tools/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/app/tools/tomcat -Dcatalina.home=/app/tools/tomcat -Djava.io.tmpdir=/app/tools/tomcat/temp org.apache.catalina.startup.Bootstrap start

[root@web03 ~]# jps -lvm | grep tomcat
1016 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/app/tools/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -Dcatalina.base=/app/tools/tomcat -Dcatalina.home=/app/tools/tomcat -Djava.io.tmpdir=/app/tools/tomcat/temp

2、jstack查看线程信息
用法
[root@web03 ~]# jstack 1016 | grep -i state
java.lang.Thread.State: RUNNABLE
java.lang.Thread.State: RUNNABLE
java.lang.Thread.State: RUNNABLE
java.lang.Thread.State: WAITING (parking)
状态
新建状态new
就绪状态runnable
运行状态running
阻塞状态blocked
死亡状态dead
挂起状态parking

统计状态
[root@web03 ~]# jstack 1016 | grep -i state|awk ‘{print $2}’|sort|uniq -c

3、jmap
jmap到处jvm内存数据保留到本地,通过其他软件分析这个文件
[root@web03 ~]# jmap -dump:format=b,file=8080.hprof 1016
Dumping heap to /root/8080.hprof …
Heap dump file created
[root@web03 ~]# ll
total 277620
-rw——- 1 root root 94931250 Nov 27 11:10 8080.hprof

java系统负载高排查流程
1、通过监控得知系统负载高
2、使用w/top/uptime/vmstat查看是cpu还是存还是io
3.1、io高,使用iotop查看到pid再查看pid对应的进程
3.2、内存高,top按M查看内存排行再查看进程
3.3、cpu高,top按P查看cpu排行再查看进程
4、最后查出来是java进程
查看服务日志
使用jstack查看线程信息
使用jmap -dump:format=b,file=8080.hprof 1016
1016是java进程号
5、使用MemoryAnalyzer.exe分析让开发人员看
“`

NGINX

## 1 配置yum源

“`sh
[root@web01 ~]# cat /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[root@web01 ~]# yum install -y nginx

[root@web01 ~]# systemctl enable –now nginx

“`

### 2 部署第二个网站

| 网站要求 | 说明 |
| ———- | ————————————— |
| 域名 | bird.ysllinx.cn |
| 站点目录 | /app/code/bird |
| 子配置文件 | /etc/nginx/conf.d/bird.ysllinux.cn.conf |
| 代码来源 | bird.tar.gz |

nginx只处理静态资源:

html 人

css 衣服

js 特效

动态资源这里是指:用户上传,用户注册,用户评论等等

“`sh
[root@web01 /etc/nginx/conf.d]# cat bird.ysllinux.cn.conf
server {
listen 8080;
server_name bird.ysllinux.cn;
root /root/code/bird;
location / {
index index.html;
}
}

“`

### 3 流程

1、nginx完成部署与测试;

2、根据要求创建自配置文件,准备环境;

3、检查语法后重启

4、hosts文件解析

### 4 ngx核心功能讲解

#### 1 配置文件

/etc/nginx/nginx.conf

##### 1 主配置文件

“`sh
user nginx; #指定nginx所属用户,工具人进程用户
worker_processes auto; #工具人进程
error_log /var/log/nginx/error.log notice; #ngx错误日志路径及级别
pid /var/run/nginx.pid #pid文件

events {
worker_connections 1024; #每个工具人进程最大连接数
}
http {
include /etc/nginx/mime.types; #引用的媒体类型
default_type application/octet-stream; #设置默认的媒体类型
logformat main ‘remote_addr-$remote_user [$time_local] $request’
‘$status $body_types_sent “$http_referer”‘
‘”$http_user_agent” $http_x_forwarded_for’; #指定nginx访问日志格式,格式叫做main,访问里面记录什么内容
access_log /var/log/nginx/access.log main; #使用日志路径,main格式
sendfile on; #提高nginx性能
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf; #引用子配置文件
}
“`

[老男孩教育-最新架构-WEB服务-NGX-nginx.conf| ProcessOn免费在线作图,在线流程图,在线思维导图](https://www.processon.com/view/link/6679326da1d80a3c06ff5575)

![image-20250107124752793](D:\Program Files (x86)\Typora\006-nginx\image-20250107124752793.png)

##### 2 子配置文件

| 网站中常用必会指令 | 说明 |
| —————— | ———————————————————— |
| listen | 指定监听端口 |
| server_name | 指定域名,多个通过空格分隔 |
| location | 匹配请求中的uri,资源地址 |
| root | 指定站点目录,网站的根目录 |
| index | 指定站点的首页文件,用户访问的时候不加任何文件,展示首页文件 |
| error_log | 指定错误状态码与对应的错误页面 |

“`sh
如果站点目录不存在,进行访问会发生什么? 404 Not Found
如果首页文件不存在,进行访问会发生什么? 403 Forbidden
查看错误日志: error.log
“`

![image-20250107124804175](D:\Program Files (x86)\Typora\006-nginx\image-20250107124804175.png)

“`sh
用户请求nginx详细描述
1、dns解析,将域名解析成ip
2、通过ip+端口,三次捂手建立连接
3、http请求
GET / HTTP1.1
Host:域名
User-Agent:UA头,用户浏览器
4、请求通过建立的连接80端口,到达ngx,ngx开始处理,http区域处理
5、用户请求的域名与http配置文件里面的server_name部分匹配
如果匹配成功,则对应的server处理用户请求
如果匹配失败,默认的default_server标记或按照顺序匹配第一个,按名字abc顺序
6、站点处理用户请求时候根据用户请求的uri+站点目录进行处理
7、处理完成后把结果发回给用户
“`

![image-20250107124841904](D:\Program Files (x86)\Typora\006-nginx\image-20250107124841904.png)

##### 3 设置网站的默认站点

“`sh
server {
listen 80 default_server; #标记当前的站点是默认的.
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
“`

uri

例:http://bird.ysllinux.cn uri就是斜线

nginx处理的时候是uri+站点目录,/index.html+/app/code/bird/

index index.html;首页文件

### 5 ngx核心功能详解

#### 1 虚拟主机

虚拟主机:相当于是一个网站,在ngx中通过server{}区域实现

ngx中虚拟主机有不同的类型

#### 2 概述与分类

| 虚拟主机的分类 | 说明 | 应用场景 |
| —————— | ———————— | ———————————————— |
| 基于域名的虚拟主机 | 不同域名,访问不同的站点 | 生产环境最常用 |
| 基于端口的虚拟主机 | 不同端口访问不同站点 | 保护,设置1024以上端口 |
| 基于ip的虚拟主机 | 不同ip访问不同的站点 | 保护,用户只能通过某个ip连接进来,一般适用于内网 |

#### 3 搭建网站流程

“`sh
1、准备子配置文件与检查语法
2、准备目录
3、准备代码,解压过去
4、hosts解析与调试
5、不通域名访问不同主机
“`

#### 4 基于域名的虚拟主机

案例02-创建conf.ysllinux.cn

站点目录/app/code/conf/

“`sh
1、完成后不出案件站点目录进行访问看看报什么错误

没有网站目录,报错404

2、创建站点目录后再访问看看报什么错误

没有首页文件,报错403

3、查看首页文件和内容,访问看看显示什么

[root@web01 /etc/nginx/conf.d]# cat game.ysllinux.cn.conf
server {
listen 80;
server_name game.ysllinux.cn;
root /app/code/game/;
location / {
index index.html;
}
}

本地测试小技巧
curl -H Host:game.ysllinux.cn http://192.168.137.7
-H修改请求头里的内容

“`

#### 5 基于ip的虚拟主机

“`sh
[root@web01 /etc/nginx/conf.d]# cat game.ysllinux.cn.conf
server {
listen 172.16.1.7:8848;
server_name game.ysllinux.cn;
root /app/code/game/;
location / {
index index.html;
}
}

“`

#### 5 案例03-给每个虚拟主机指定自己的错误日志

“`sh
[root@web01 /etc/nginx/conf.d]# cat game.ysllinux.cn.conf
server {
listen 80;
server_name game.ysllinux.cn;
root /app/code/game/;
access_log /etc/nginx/logs/access/game.ysllinux.cn.access.log main;
error_log /etc/nginx/logs/error/game.ysllinux.cn.error.log notice;
location / {
index index.html;
}
}

“`

### 6 ngx日志

| 日志 | 使用建议 | 定义 | 使用 |
| ——– | ———————————- | ——————————– | ———- |
| 错误日志 | 发生错误的时候可以查看 | 通过错误级别指定 | error_log |
| 访问日志 | 记录着用户什么时候访问,用户信息等 | 公共log_format定义访问日志的格式 | access_log |

#### 1 错误日志

指定错误日志的位置和错误级别

格式:error_log 文件名 错误日志级别;

指令放在哪:main,http,mail,stream,server,location

#### 2 错误日志级别

debug,info,notice,warn,error,crit,alert,or emerg

error是默认的

notice是推介的

debug是开发调试使用,临时开启

#### 3 访问日志

访问日志主要用来分析

访问日志是记录用户信息的宝藏

格式:

log_format 格式名字 格式

放在http

#### 4 内置变量

| ngx内置变量 | 说明 |
| ——————— | —————————————————- |
| $remote_addr | 客户端ip地址 |
| $remote_user | 用户名,nginx进行认证用户 |
| $time_local | 时间 |
| $request | 请求报文,请求起始行,(GET URI HTTP/1.1) |
| $status | http状态码 |
| $body_bytes_sent | 响应给客户的文件大小,响应报文主体大小,单位字节byte |
| $http_referer | 从哪里跳转来访问到这个网站的 |
| $http_user_agent | UA客户端代理(浏览器) |
| $http_x_forwarded_for | xff头,使用负载时记录真是ip地址 |
| 其他常用ngx变量 | |
| $requst_method | 请求方法 |
| $uri | 请求中的uri部分 |

access_log指定日志,使用对应格式

使用方法

access_log 日志位置 格式;

放在哪

http,server,localtion if in location,limit_execpt

#### 5 access_log其他选项

| access_log | 说明 |
| —————- | ———————————————————— |
| access_log off | 关闭访问日志一般要配合if或location精确匹配与处理,access_log off或access_log /dev/null |
| 访问日志进行压缩 | gzip文件需要通过zcat/zless/zgrep查看 |
| 进行缓存 | buffer = 32k ,先把日志写入到内存中,定期写入磁盘 |
| 定时刷新 | flush = 10s |
| | 进行缓存和定时刷新哪个先满足就执行哪个 |

access_log /var/log/nginx/bird.ysllinux.cn-access.log main gzip buffer=32k flush=10s

### 7 案例-05搭建大型直播购物网站

“`sh
域名:buy.ysllinux.cn
站点目录:/app/code/buy/
用户首页文件:/app/code/buy/index.html
后台管理页面:/app/code/buy/admin/index.html
要求后台只能内网访问:172.16.1.0/24网段.

[root@web01 /etc/nginx/conf.d]# cat buy.ysllinux.cn.conf
server {
listen 80;
server_name buy.ysllinux.cn;
access_log /etc/nginx/logs/access/buy.ysllinux.cn.access.log main;
error_log /etc/nginx/logs/error/buy.ysllinux.cn.error.log notice;
root /app/code/buy/;
location / {
index index.html;
}
location /admin/ {
allow 172.16.1.0/24;
deny all;
}
}

“`

### 8 案例06:搭建bird小鸟飞飞网站,给网站加速,设置缓存,网站中html,js,css结尾的文

件缓存1天,图片缓存1小时. 浏览器缓存.

“`sh
[root@web01 /etc/nginx/conf.d]# cat bird.buffer.ysllinux.cn.conf
server {
listen 8080;
server_name bird.buffer.ysllinux.cn;
root /app/code/bird/;
location / {
index index.html;
}
location ~* \.(jpg|jpeg|png|gif|bmp)$ {
expires 1h;
}
location ~* \.(html|js|css)$ {
expires max;
}
}
“`

### 9 查看缓存多久

F12-网路-查看右边cache

如果没有F12-选中右键-响应头-cache-control

案例07-部署china站点

“`sh
[root@web01 /etc/nginx/conf.d]# cat china.ysllinux.cn.conf
server {
listen 80;
server_name china.ysllinux.cn;
access_log /etc/nginx/logs/access/china.ysllinux.cn.access.log main;
error_log /etc/nginx/logs/access/china.ysllinux.cn.error.log notice;
root /app/code/china/;
location / {
index index.html;
}
}

“`

![image-20250107125229416](D:\Program Files (x86)\Typora\006-nginx\image-20250107125229416.png)

![image-20250107125235576](D:\Program Files (x86)\Typora\006-nginx\image-20250107125235576.png)

补充打开浏览器F12显示是否缓存的方法:

![image-20250107125256161](D:\Program Files (x86)\Typora\006-nginx\image-20250107125256161.png)

### 10 location概述

#### 1 ngx的location规则

在ngx用于匹配用户请求中的uri,ngx对用户请求中的uri进行判断;

如果请求的uri是xxx则做xxx;

接下来详细说说location规则

url网址https://nginx.org/en/docs/

uri:/en/docs/

http://www.baidu.com/ysl/ysl.avi

uri:/ysl/ysl.avi

url:http://www.baidu.com/ysl/ysl.avi

uri是/后面的内容

location匹配uri,location匹配目录,uri开头的部分;

location /admin/ {}匹配uri中admin开头的。

allow和deny先allow再deny

课后思考与测试,location /admin/匹配uri中包含/admin/还是以/admin/开头

buy.ysllinux.cn/admin #正常

buy.ysllinux.cn/ysladmin/ #404,原因,没有目录

buy.ysllinux.cn/img/admin/ #404,原因,没有目录

#### 2 小结

location规则与正则合用,perl正则

location ~* 正则

~ 区分大小写

~* 不区分大小写

expires 设置浏览器缓存

perl正则新写法

\d相当于[0-9]匹配数字

\w相当于[a-zA-Z0-9_]匹配所有和下划线

#### 3 location小结

| 序号 | location规则 | 说明 |
| —- | —————————- | ———————————————————— |
| 1 | location / {xxx} | 默认规则,保底,location规则在匹配的时候,其他规则都匹配失败了,这个时候匹配默认规则 |
| 2 | location /image/ {} | 用于匹配请求中的uri路径,bird.ysllinux.cn/image/ysl.txt |
| 3 | location ~ \.(jpg\|jpeg)$ {} | 支持正则,区分大小写 |
| 4 | location ~ .*(jpgjpeg)$ {} | 支持正则,不区分大小写 |
| 5 | location ^~ /ysl/ | 不区分正则,仅匹配普通字符,很少使用,优先 |
| 6 | location = /50x.html | 请求的uri与书写的内容一模一样,精确匹配,使用很少 |
| 7 | location @名字 | 命名的location,一般用于return/error_log内部跳转 |

#### 4 以后如果碰到错误页面,让开发写个好看点的

“`sh
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
这句话的意思是只要碰到500就显示/usr/share/nginx/html/50x.html页面
“`

#### 5 案例07-部署china代码

项目需求:

代码:china.tar.gz

站点目录:/app/code/china/

域名:china.buffer.ysllinux.cn

如果访问.js文件,设置1天缓存,站点目录设置为/app/code/china/js

如果访问.css文件,设置1天缓存,站点目录设置为/app/code/china/css

“`sh
server {
listen 80;
server_name china.buffer.ysllinux.cn;
access_log /etc/nginx/logs/access/china.buffer.ysllinux.cn.access.log main;
error_log /etc/nginx/logs/access/china.buffer.ysllinux.cn.error.log notice;
root /app/code/china/;
location / {
index index.html;
}
location ~* \.js$ {
root /app/code/china/js;
expires 1d;
}
location ~* \.css$ {
root /app/code/china/css;
expires 1d;
}
}
“`

#### 6 location匹配时的优先级

| 优先级 | location |
| —— | ——– |
| 1 | = |
| 2 | ^~ |
| 3 | ~ ~* |
| 4 | /image/ |
| 5 | / |

### 11 自建下载站

域名:v.ysllinux.cn

站点目录: /app/code/v/

touch 几个文件即可

温馨提示:不要创建首页文件

自动索引功能(列表站点目录的内容),首页文件不存在

#### 1 aotoindex模块

| autoindex | 应用场景 |
| ———————————————————— | ——————————- |
| autoindex on;开启目录索引功能(显示站点目录下的文件的列表,首页文件不存在) | 用户共享下载网站,配置内部yum源 |
| autoindex_localtime on;显示本地时间 | |
| autoindex_esact_size off;关闭精确大小,off表示以人类可读形式显示大小 | |

#### 2 nginx增加简单认证功能

增加一个svip目录,里面创建文件

增加认证功能(用户名密码)

auth_basic模块

“`sh
server {
listen 80;
server_name v.ysllinux.cn;
root /app/code/v/;
error_log /etc/nginx/logs/error/v.ysllinux.cn.error.log notice;
access_log /etc/nginx/logs/access/v.ysllinux.cn.access.log main;
charset utf8;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
location / {
index index.html;
}
}
location /svip/ {
auth_basic “input password:”;
auth_basic_user_file /etc/nginx/user;
location /status/ {
stub_status;
}
}

yum install -y httpd-tools
#创建文件
htpasswd -bc /etc/nginx/user ysl996 1
#增加用户
htpasswd -b /etc/nginx/user ysl 1
#修改权限
chmod 600 /etc/nginx/user
chown nginx.nginx /etc/nginx/user

“`

访问v.ysllinux.cn时出现以下信息

“`sh
Active connections: 2
server accepts handled requests
14 14 12
Reading: 0 Writing: 1 Waiting: 1
活跃连接数:2
服务器接受已处理的请求
14 14 12
正在阅读: 0 写入: 1 等待中: 1
“`

| ngx状态模块中的指标说明 | 说明 | 说明 |
| ———————– | —————————- | ———– |
| active connections | 当前已建立的连接数和等待数量 | 体现ngx并发 |
| server accepts | 已经接收到客户端的连接总是 | |
| handled | 服务端已经处理的连接数 | |
| requests | 客户端发出请求的总数 | |
| reading | 正在读取的请求头连接数量 | |
| writing | 正在进行的响应的连接数量 | |
| waiting | 排队情况 | |

### 12 ab压力测试功能 apache bench

ab -n 99999 -c 300 http://bird.ysllinux.cn

ab -n 9999 -c 3 -H -Host:v.ysllinux.cn http://192.168.137

-n 次数

-c 并发

### 13 总结

| 模块 | 模块中的核心命令 |
| ————— | —————————————— |
| 目录索引 | autoindex on; |
| 认证功能模块 | auto_basic_user_file; |
| 访问控制模块 | allow,deny |
| ngx状态检查模块 | stub_status |
| ngx核心模块 | root,location,error_log,server_name,listen |
| ngx日志模块 | access_log,log_format |
| …… | |

### 14 动态网站架构(部署一份开发的php代码)

| 网站架构 | 说明与特点 | 性能 | 一句话说明 |
| ——– | ——————————————————— | ———————————————————— | ————————————————– |
| 静态资源 | 网站仅仅包含html,css,js脚本,图片,视频 | 只需要web服务器即可,可以承受高访问量,不支持动态的功能:注册,评论,静态网站功能单一 | 浏览器解析,服务端仅仅负载发送 |
| 动态资源 | 动态网站一般是通过开发语言实现:java,php,python,golang | 动态资源页面需要服务器进行处理ngx+php/tomcat…+数据库,处理后把结果返回给用户 | 动态请求需要服务端进行处理与解析,把结果返回给用户 |

如何区分动态资源和静态资源

动态资源uri一般包含&?

静态资源uri一般包含php,jsp

#### 1 项目01-lnmp环境部署在1台机器

条件

nginx1.26.1

php2

mairadb 10.3

“`sh
1、数据库
web01
mairadb
yum install -y mariadb-server
systemctl enable –now mariadb
mysql_secure_installation
输入
Enter current password for root (enter for none):回车
Set root password? [Y/n] Y设置密码
New password: 输入密码
Re-enter new password: 再次输入
Password updated successfully!
Reloading privilege tables..
… Success!
Remove anonymous users? [Y/n] Y 删除数据库中的匿名用户(没有用户名
的用户,容易导致安全问题)
Disallow root login remotely? [Y/n] Y 是否禁止root远程登录
Remove test database and access to it? [Y/n] Y 是否删除test测试
用的数据库
Reload privilege tables now? [Y/n] Y 是否更新权限信息表

查看库里所有的表
show tables from mysql;
user用户名
host用户白名单,用户可以从哪里登录. 用户是否可以从指定的ip或网段登录. 一般只
能本地登录.
select user,host from mysql.user;
MariaDB [(none)]> select user,host from mysql.user;
+——+———–+
| user | host |
+——+———–+
| root | 127.0.0.1 |
| root | ::1 |
| root | localhost |
+——+———–+
3 rows in set (0.000 sec)

MariaDB [(none)]> create database wordpress;
Query OK, 1 row affected (0.000 sec)

MariaDB [(none)]> grant all on wordpress.* to ‘wordpress’@’172.16.1.%’ idetified by ‘XZnh@95599’;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘idetified by ‘XZnh@95599” at line 1
MariaDB [(none)]> grant all on wordpress.* to ‘wordpress’@’172.16.1.%’ identified by ‘XZnh@95599’;
Query OK, 0 rows affected (0.000 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.000 sec)

2、php安装
清理已经安装php
systemctl stop php-fpm
yum -y remove php*
yum -y install php php-bcmath php-cli php-common php-devel php-embedded php-fpm php-gd php-intl php-mbstring php-mysqlnd php-opcache php-pdo php-process php-xml php-json
[root@web01 /etc]# systemctl enable –now php-fpm
/etc/php-fpm.conf #主配置文件
/etc/php-fpm.d
/etc/php-fpm.d/www.conf #子配置文件,修改目标
使用rpm -ql php-fpm查看

[root@web01 /etc]# egrep -n ‘^(user|group|listen =)’ /etc/php-fpm.d/www.conf
24:user = nginx
26:group = nginx
38:listen = 127.0.0.1:9000

检查语法:
php-fpm -t 看是否有successful
#8.重启服务或reload都行
systemctl restart php-fpm.service

3、下载wordpress
wget https://wordpress.org/latest.zip
unzip latest.zip -d /app/code/blog/

4、配置nginx
server {
listen 80;
server_name blog.ysllinux.cn;
error_log /etc/nginx/logs/error/blog.ysllinux.cn.error.log notice;
access_log /etc/nginx/logs/access/blog.ysllinux.cn.access.log main;
root /app/code/blog/;
location / {
index index.php;
}
location ~* \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

浏览器访问blog.lodboylinux.cn

总结:注意相关目录文件权限,/app/code/blog/目录,将下载的文件放入此目录,注意nginx配置文件时conf结尾
如果要配置客户端上传文件大小需要修改nginx和/etc/php.ini的配置文件
nginx http区需要添加以下配置
client_max_body_size 50m;

修改/etc/php.ini
post_max_size = 80M
upload_max_filesize = 80M

nginx http配置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;

sendfile on;

这个指令启用了sendfile特性,它允许操作系统直接将文件内容从磁盘传输到网络,而不需要复制到用户空间。这样可以提高文件传输效率。
tcp_nopush on;

这个指令启用了TCP_NOPUSH选项,它告诉操作系统不要在TCP包中立即发送数据,而是等待更多的数据一起发送。这样可以减少TCP包的数量,提高网络效率。
tcp_nodelay on;

这个指令启用了TCP_NODELAY选项,它禁用了Nagle算法。Nagle算法会合并小的数据包以减少网络拥塞,但有时会导致延迟增加。禁用Nagle算法可以减少延迟,尤其是在需要实时性的应用中。
keepalive_timeout 65;

这个指令设置了TCP连接的保持活动超时时间。当一个连接在65秒内没有任何数据传输时,Nginx会关闭这个连接。这有助于释放不再使用的连接,避免资源浪费。
types_hash_max_size 4096;

这个指令设置了types_hash的最大大小。types_hash是一个哈希表,用于存储MIME类型。增加这个值可以提高查找MIME类型的效率,但同时也会消耗更多的内存。
“`

![image-20250107125353132](D:\Program Files (x86)\Typora\006-nginx\image-20250107125353132.png)

![image-20250107125400015](D:\Program Files (x86)\Typora\006-nginx\image-20250107125400015.png)

上图是处理静态和动态请求

#### 2 mysql备份与恢复

“`sh
[root@web01 /app/code/blog]# mysqldump -uroot -p –databases wordpress | gzip > /backup/blog.sql.gz

恢复
zcat /backup/blog.sql.gz | mysql -uroot -p wordpress
mysql -uroot -p wordpress < /backup/blog.sql ``` ### 15 部署负载均衡进行配置 ```sh 配置ngx作为负载均衡 [root@lb01 ~]# cat /etc/nginx/conf.d/blog.ysllinux.cn.conf upstream blog_pools { server 10.0.0.7:80; server 10.0.0.8:80; } server { listen 80; server_name blog.ysllinux.cn; error_log /var/log/nginx/blog.ysllinux.cn-error.log notice; access_log /var/log/nginx/blog.ysllinux.cn-access.log main; location / { proxy_pass http://blog_pools; proxy_set_header Host $http_host; } } proxy_set_header:告诉 Nginx 要设置一个代理请求头 location / { proxy_pass http://backend; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } 在这个例子中,proxy_pass 指令告诉 Nginx 将请求转发到 http://backend。proxy_set_header 指令设置了四个不同的请求头: Host:将客户端请求中的 Host 头部值传递给后端。 X-Real-IP:设置请求头 X-Real-IP 为客户端的 IP 地址。 X-Forwarded-For:添加或更新 X-Forwarded-For 请求头,包含客户端的 IP 地址。 X-Forwarded-Proto:设置请求头 X-Forwarded-Proto 为原始请求使用的协议(http 或 https)。 这些设置确保后端服务器能够接收到所有必要的信息,以便正确处理请求。 ``` ![image-20250107125456098](D:\Program Files (x86)\Typora\006-nginx\image-20250107125456098.png) ![image-20250107125556856](D:\Program Files (x86)\Typora\006-nginx\image-20250107125556856.png) ![image-20250107125620894](D:\Program Files (x86)\Typora\006-nginx\image-20250107125620894.png) #### 1 负载均衡指令与模块 2个模块:upstream与proxy upstream指令 proxy_pass指令 proxy_set_header指令 proxy_pass把指令请求往后抛 proxy_pass http://10.0.0.7:80 proxy_pass http://分组名字(upstream) #### 2 upstream写在http模块中,不能写在server,他们是并列的 ```sh [root@lb01 /etc/nginx/conf.d]# cat lb.lodboylinux.cn.conf upstream lb_pools { server 192.168.137.7:80; server 192.168.137.8:80; } server { listen 80; server_name lb.lodboylinux.cn; error_log /var/log/nginx/lb_error.log notice; access_log /var/log/nginx/lb_access.log main; location / { proxy_pass http://lb_pools; proxy_set_header Host $http_host; } } ``` #### 3 proxy_set_header:负载均衡多虚拟主机的故障案例 现象;web节点上有多个虚拟主机,负载均衡在转发数据的时候回出现访问异常,访问多个虚拟主机的默认的或第一个 原因:负载均衡向后端节点发出请求的时候,请求头中的host变成了upstream名字,相当于使用ip访问 解决:通过proxy_set_header指令修改负载到web节点的请求头 proxy_set_header Host $http_host #### 4 proxy_set_header:经过负载均衡后web节点如何记录客户端真实ip地址 解决:增加xff请求头,X-Forwarded-For记录用户真实ip地址 在负载均衡上设置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-Ip $remote_addr; `X-Forwarded-For`用于在代理链中传递客户端的IP地址,而`X-Real-Ip`用于在Nginx和后端服务器之间传递客户端的真实IP地址。在配置这些请求头时,需要确保它们的使用是安全的,并且只对信任的代理开放。 ### 16 网站架构优化方案:动静分离 #### 1 背景 随着网站访问量增加,我们发现网站的动态资源和静态资源,随着访问的 读多写少 我们采取动静分离方案 web服务器为动态服务器(ngx+php),静态服务器)(ngx) #### 2 环境准备 | 环境准备 | 负载均衡 | ip | | -------- | -------------- | ----------- | | lb01 | 负载均衡 | 192.168.135 | | web01 | 动态、默认请求 | 192.168.137 | | web02 | 上传 | 192.168.138 | | web03 | 静态请求 | 192.168.139 | ![image-20250107125639831](D:\Program Files (x86)\Typora\006-nginx\image-20250107125639831.png) #### 3 静态组(web03) 部署ngx nfs服务端 部署代码 ```sh 1.安装ngx cat >>/etc/yum.repo.d/nginx.repo<备,相差50即可
advert_int 1 #心跳间隔,多久发送一次vrrp数据包
authentication { #授权与认证,保持默认即可,对数据包加密
auth_type PASS #简单认证
auth_pass 1111 #111
}
virtual_ipaddress { #设置vip地址
192.168.137.3 dev ens33 label ens33:0 #label设置了别名
}
}

tcpdump抓包
tcpdump -vvv -nnn vrrp -w ~/vrrp.pcap
“`

#### 3 问题

1.脑裂

现象:主备都有vip

原因:

备认为主挂了,接管资源生成vip,实际上主并没有挂,仍有vip

有很多原因可以导致脑裂,开启防火墙,selinux,keepalived配置,物理线路

解决:

监控,备节点,只要备节点有vip就告警

找个第3放机器,在这个机器上执行ssh到备节点,查看是否存在vip

监控到备节点有vip就真的将主节点挂掉

在备节点上执行监控脚本,统计vip数量,判断如果等于1则发出邮件告警

案例01-keepalived基于主机高可用软件

问题:

keepalived只会在主机挂了,网络断开后才会进行主备切换

默认情况下keepalived不会监控某个服务

项目目标:某个服务关闭了,keepalived就进行主备切换

项目步骤

书写脚本,过滤服务进程数,端口数量,检查是否运行,curl或wget

然后在脚本中进行判断,如果服务没有运行,则关闭keepalived

修改keepalived配置文件,通过keepalived调用这个脚本,监控nginx

在keepalived中调用脚本

track_script {

keep_lb.sh

}

#### 4 keepalived双主模式

在主备的/etc/keepalived/keepalived.conf下都添加

“`sh
[root@lb02 ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
router_id lb02
}

vrrp_instance vip_3 {
state BACKUP
interface ens33
virtual_router_id 51
priority 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.137.3 dev ens33 label ens33:0
}
}
vrrp_instance vip_4 {
state MASTER
interface ens33
virtual_router_id 52
priority 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.137.4 dev ens33 label ens33:1
}
}
“`

![image-20250107130045512](D:\Program Files (x86)\Typora\006-nginx\image-20250107130045512.png)

![image-20250107130050383](D:\Program Files (x86)\Typora\006-nginx\image-20250107130050383.png)

##### 1 非抢占模式

keepalived主备默认是抢占模式,主挂了,备接管,主恢复,不希望主重新抢回资源

流程

配置两个节点都是BACKUP

在state BACKUP下面添加一行

nopreempt

![image-20250107130056572](D:\Program Files (x86)\Typora\006-nginx\image-20250107130056572.png)

### 3 https证书

#### 1 概述

“`sh
https == https over tls
基于http协议,传输的时候进行加密
如果不使用https,数据传输都是明文的
应用场景:
目前大部分企业的业务都是使用https加密
企业想使用http 2.0基于https
https加密的流程
1、域名*.jd.com www.jd.com
2、根据域名申请https证书(私钥和公钥(ca证书)),自己创建。(免费的https证书有效期为3个月)
3、进行配置web/lb
4、跳转http–https
“`

![image-20250113115845257](D:\Program Files (x86)\Typora\006-nginx\image-2025011311584525png)

![image-20250113115915828](D:\Program Files (x86)\Typora\006-nginx\image-20250113115915828.png)

#### 2 https申请

![image-20250113123724603](D:\Program Files (x86)\Typora\006-nginx\image-20250113123724603.png)

![image-20250113123825770](D:\Program Files (x86)\Typora\006-nginx\image-20250113123825770.png)

创建–填写信息,审核即可

#### 3 https加密流程和80跳转443

“`sh
申请的https证书的域名与网站域名一致才能正常使用
否则用户访问会有警告与提示
server {
listen 80;
server_name linux.yangsenlin.top;
return 301 https://linux.yangsenlin.top$request_uri;
}
server {
listen 8001 ssl;
server_name linux.yangsenlin.top;
root /app/code/blog/;
ssl_certificate /app/code/https/linux.yangsenlin.top.pem;
ssl_certificate_key /app/code/https/linux.yangsenlin.top.key;
location / {
index index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:8888;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
“`

#### 4 https认证原理

![image-20250113180044799](D:\Program Files (x86)\Typora\006-nginx\image-20250113180044799.png)

![image-20250113180103529](D:\Program Files (x86)\Typora\006-nginx\image-20250113180103529.png)

#### 5 命令行创建https证书

“`sh
#创建私钥 私钥server.key
openssl genrsa -idea -out server.key 2048
#根据私钥创建 证书 server.crt .pem证书
openssl req -days 36500 -x509 -sha256 -nodes -newkey rsa:2048 -keyout server.key -out server.crt
“`

#### 6 网站集群https配置

![image-20250113180326780](D:\Program Files (x86)\Typora\006-nginx\image-20250113180326780.png)

“`sh
温馨提示: 用户–>负载加密(https) 负载到web未加密(http) 配置php网站的时候
有问题.
对php动态部分进行配置.
fastcgi_param HTTPS on; #前面部分的请求是https
“`

#### 7 网站集群全部配置https并配置http2.0

![image-20250114120216830](D:\Program Files (x86)\Typora\006-nginx\image-20250114120216830.png)

“`sh
web01配置
server {
listen 443 ssl http2;
server_name ssl.ysllinux.cn;
root /app/code/ssl;
#ssl key
ssl_certificate
/etc/nginx/ssl_keys/ssl.ysllinux.cn.pem;
ssl_certificate_key
/etc/nginx/ssl_keys/ssl.ysllinux.cn.key;
location / {
index index.html;
}
}

lb01
upstream ssl_pools {
server 10.0.0.7:443 ;
}
server {
listen 80;
server_name ssl.ysllinux.cn;
return 301 https://ssl.ysllinux.cn$request_uri;
}
server {
listen 443 ssl http2;
server_name ssl.ysllinux.cn;
ssl_certificate
/etc/nginx/ssl_keys/ssl.ysllinux.cn.pem;
ssl_certificate_key
/etc/nginx/ssl_keys/ssl.ysllinux.cn.key;
location / {
proxy_pass https://ssl_pools;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_set_header X-Real-Ip $remote_addr;
}
}
“`

#### 8 网站集群部分配置https并配置http2.0

![image-20250114120252867](D:\Program Files (x86)\Typora\006-nginx\image-2025011412025286png)

“`sh
web配置
server {
listen 80;
server_name ssl.ysllinux.cn;
root /app/code/ssl;
location / {
index index.html;
}
}
#lb配置
upstream ssl_pools {
server 10.0.0.7:80 ;
}
server {
listen 80;
server_name ssl.ysllinux.cn;
return 301 https://ssl.ysllinux.cn$request_uri;
}
server {
listen 443 ssl http2;
server_name ssl.ysllinux.cn;
#ssl keys
ssl_certificate
/etc/nginx/ssl_keys/ssl.ysllinux.cn.pem;
ssl_certificate_key
/etc/nginx/ssl_keys/ssl.ysllinux.cn.key;
location / {
proxy_pass http://ssl_pools; #注意
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_set_header X-Real-Ip $remote_addr;
}
}
温馨提示: 用户–>负载加密(https) 负载到web未加密(http) 配置php网站的时候
有问题.
对php动态部分进行配置.
fastcgi_param HTTPS on; #前面部分的请求是http
server {
listen 80;
server_name blog.ysllinux.cn;
root /app/code/blog;
error_log /var/log/nginx/blog-error.log notice;
access_log /var/log/nginx/blog-access.log main;
location / {
index index.php;
}
location ~* \.(html|js|css|jpg|png|jpeg)$ {
expires max;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param HTTPS on; #适用于 负载是https web是
http场景下添加.
#HTTPS on告诉php 请求是来自于
负载的https请求.
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
}
“`

#### 9 优化与监控

##### 1 优化

“`sh
server {
listen 443 ssl;
keepalive_timeout 70;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; #指定ssl
加密协议的版本
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DESCBC3-SHA:RC4-MD5:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5; #加密算
法. 需要排除不安全的算法
#排除null空算法, md5算法
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/cert.key;
#设置https 会话缓存 10MB大小的空间用于存储缓存.
ssl_session_cache shared:SSL:10m;
#超时时间 10分钟
ssl_session_timeout 10m;

}
“`

##### 2 监控

“`sh
监控方案(https证书是否过期)
1 命令行curl的方式监控,https证书已经部署到网站上并且可以访问
2 命令行openssl命令的方法监控,证书无法通过curl访问

脚本流程:
1 域名列表
2 通过命令获取证书的过期日期
3 与当前日期对比,30天之前,转换为秒
4 获得剩余的时间,如果小于30天就发送邮件告警

curl -Lv https://linux.yangsenlin.top:8001 -o /dev/null | & grep ‘expire date’

-o表示把curl命令的响应报文信息定向到指定位置,这里是/dev/null空
|& 表示把管道前面标准输出(正确)和标准错误输出 都传递给后面的命令.如果不加,默认传递标准输出(正确)

1 获取过期日期
export LANG=en_US.UTF-8
curl -Lv https://linux.yangsenlin.top:8001 -o /dev/null |& grep ‘expire date:’|awk -F ‘date:|GMT’ ‘{print $2}’
2 将过期日期转换为秒
date +%s -d ” `curl -Lv https://linux.yangsenlin.top:8001 -o /dev/null |& grep ‘expire date:’|awk -F ‘date:|GMT’ ‘{print $2}’`”
3 获取当前时间
date +%s
4 相减获取还有多少天过期
echo “(1691270161 – 1687142200)/60/60/24” |bc

脚本
#1.vars
export LANG=en_US.UTF-8
url=https://$1
warn=3000
#2.curl 获取日期
expire_date_ori=`curl -v $url |& grep ‘expire date’ |
awk ‘{print $4,$5,$(NF-1)}’`
expire_date_second=`date -d “${expire_date_ori}” +%s`
now_date_second=`date +%s `
#3.计算
days_left=`echo “($expire_date_second –
$now_date_second)/60/60/24” |bc`
#4.判断
if [ $days_left -le $warn ];then
echo “https证书$url,还有$days_left过期,请及时续费”
fi

此脚本可添加for循环
url_info=`cat /url_info.txt`
for url in $url_info
do
脚本命令
done

“`

### 4 nginx优化

合并PDF-2081页

#### 1 安全优化

| 优化说明 | 优化方法 |
| ———————————- | ———————————————————— |
| 1 隐藏nginx版本 | 修改nginx配置文件 server_tokens off;http模块中配置 |
| 2 修改web服务名字 | 修改 nginx 源码配置文件:nginx-xxx/src/core/nginx.h nginx-xxx/src/http/ngx_http_header_filter_module.c nginx-xxx/src/http/ngx_http_special_response.c |
| 3 修改进程用户 | user www www; |
| 4 优化你先服务上传文件大小限制 | client_max_body_size,响应的php也要修改 |
| 5 配置nginx服务相关日志操作 | 防止日志过大进行轮询切割yum安装nginx自动切割logrotate,编译安装手动切割,不分日志内容不进行记录,logrotate日志切割工具+定时任务 |
| 6 配置默认站点禁止恶意解析 | server模块添加return 403; |
| 7 nginx图片及目录防盗链解决方案 | 根据http referer实现防盗链,用户从哪里跳转过来的,referer控制,加入登录与认证,根据cookie防盗链,在产品设计上解决防盗链方案 |
| 8 nginx错误页面的优雅显示 | 对错误代码实行本地页面跳转 |
| 9 nginx站点目录文件及目录权限优化 | 只将用户上传数据的目录权限设置为755,用户和组使用nginx,其余目录和文件未755/644,用户和组使用root |
| 10 nginx防爬虫优化 | 利用robots.txt机器人协议防止爬虫(君子协议),在网站站点下面放robots.txt,利用$http_user_agent变量阻止爬虫代理访问 |
| 11 利用nginx限制请求方法 | $request_method限制请求方法GET,POST,HEAD |
| 12 使用普通用户启动nginx,监牢模式 | 普通用户无法使用1-1024端口,可以使用80跳转8080 |
| 13 控制nginx并发连接数 | limit_req和limit_conn 防止ddos |
| 14 控制客户端请求nginx的速率 | limit_rate |

#### 2 安全优化实践

“`sh
1、隐藏版本server_tokens off;
http {
server_tokens off;
}
http模块中配置

ubuntu安装openssl-devel pcre-devel
apt install -y libssl-dev libpcre2-dev

4、设置用户上传文件大小

client_max_body_size 50m;
可以放在http、server、location模块中,影响程度不一样
nginx修改了还需要修改php.ini文件
/etc/opt/remi/php74/php.ini
694 post_max_size = 5M
846 upload_max_filesize = 50M
配置完成后还需要安装wordpress插件才能生效

“`

![image-20250116124424496](D:\Program Files (x86)\Typora\006-nginx\image-20250116124424496.png)

“`sh
5、日志轮询或日志切割
yum或者apt安装的nginx日志切割文件在/etc/logrotate.d/nginx文件里
cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 640 nginx adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}

日志文件解析
cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily#每日切割一次
missingok#文件不存在报错
rotate 52#循环52次,从第53次开始删除就的切割
compress#压缩
delaycompress#延后一天进行压缩
notifempty#如果文件为空则不切割
create 640 nginx adm#切割后文件的属性
sharedscripts#切割后运行指定的命令,一般是重启的命令
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}

6 对用户请求的URI进行访问控制
location /admin/ {
return 403;#或者deny all
}

7 什么是盗链:网站中盗取其他人网站的资源链接
1 加水印
2 通过referer头判断,用户间接访问就会有这个头部信息
3 配置认证,登录后才能用
在server模块中添加以下信息,可以拒绝
if ( $http_referer ~”img.ysllinux.cn”) {
return 403;
}
“`

![image-20250116154847610](D:\Program Files (x86)\Typora\006-nginx\image-20250116154847610.png)

“`sh
8 错误页面优雅显示
error_page 501 502 503 504 /50x.html;
location = /50x.html {
root /app/code/error/;
}
error_page 400 401 402 403 404 405 406 407 408 409 410 412 413 414 415 /40x.html;
location = /40x.html {
root /app/code/error/;
}
#在 return 如何指定错误提示的页面
set $flag 1;
if ( $flag = 1) {
return 503 http://lb.ysllinux.cn/50x.html ;
}
#404 页面:
https://volunteer.cdn-go.cn/404/latest/404.html

10 nginx防爬虫
什么是爬虫?
通过命令或者软件下载网站指定的信息
curl或wget
登录功能,验证码功能,python,golang
如何访爬虫?
1 君子协议,robots.txt,spider或bot
2 在ngx中通过ua变量进行判断,手动屏蔽爬虫,运营搜索引擎的爬虫爬取你的网站
3 增加登录认证功能,验证码
4 访问频率限制

server {
#下面的屏蔽容易导致误杀,一些搜索引擎的爬虫,未来想精确,写出具体不想要的爬虫即可. if ($http_user_agent ~* “spider|bot” ){
return 403 ;
}
if ($http_user_agent !~* “baidu|google|android|ios|windows” ){
return 403;
}

11 利用nginx限制请求访问
用户请求方法限制 GET,HEAD,POST,PUT,DELETE,OPTIONS.
if ( $http_method !~ “GET|HEAD|POST” ) {
return 403 http://lb.ysllinux.cn/40x.html; #或 deny all;
}

12 nginx监牢模式
监牢模式:通过普通用户运行与管理指定的服务. 这里的用户是普通用户,非虚拟用户.这个用户可以登录系统. 一般编译安装的软件(可以安装到指定目录–prefix=/app/tools/nginx/). 还可以是二进制软件. 如果是 ngx 还有个坑,1-1024 范围的端口特权端口,只能 root 管理.

13 限制下载速度
限制下载速度. limit_rate 100k;
#map 类似 if map $slow $rate {
1 4k; #如果$slow 的值是 1 则$rate 的值是 4k
2 8k; #如果$slow 的值是 2 则$rate 的值是 8k
}
limit_rate $rate;

14 限速(访问频率,ngx处理的频率)
limit_conn_module(connection) 连接频率限制(服务端)
limit_req_module(requst) 请求频率限制(客户端)
木桶原则:
“`

![image-20250116162218526](D:\Program Files (x86)\Typora\006-nginx\image-20250116162218526.png)

“`sh
#测试 limit_conn
limit_conn_zone
limit_conn zone number;
限制这个区域(ip 命名区域) 每一次只能有 number 个链接. Sets the shared memory zone and the maximum allowed number of connections for a given key value. [root@web02 nginx]# cat conf/nginx.conf
worker_processes 1;
user www www;
events {
worker_connections 1024;
}
http{
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
#limit_conn_zone 创建木桶
#$binary_remote_addr 根据客户端 ip 进行限制. #zone=木桶名字:大小;
server {
limit_conn conn_zone 10;
#1 个 ip 地址连接并发数是 1;
location / {
root /app/nginx/html/;
index index.html;
}
}
}. #完成的主配置文件和子配置文件
[root@web01 ~]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;
access_log /var/log/nginx/access.log main;
server_tokens off;
client_max_body_size 50m;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#limit_conn 部分
#创建 limit_conn 木桶 $客户端 ip 地址 zone=桶名字:大小
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
include /etc/nginx/conf.d/*.conf;
}
[root@web01 ~]# vim
[root@web01 ~]# vim /etc/nginx/conf.d/default.conf
[root@web01 ~]# cat /etc/nginx/conf.d/default.conf
[root@web01 ~]# cat /etc/nginx/conf.d/default.conf
server {
listen 80 default_server;
server_name localhost;
charset utf8;
autoindex on;
#调用 limit_conn 木桶 每个 ip 并发连接是 1
limit_conn conn_zone 1;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
#测试命令
ab -n 20 -c 2 10.0.0.8/
#检查错误日志中查看和访问日志
[root@web02 ~]# tail -f /app/nginx/logs/error.log
2019/10/23 17:35:51 [error] 9039#0: *307824 limiting connections by zone “conn_zone”, client:
10.0.0.8, server: , request: “GET / HTTP/1.0”, host: “10.0.0.8” 2019/10/23 17:35:51 [error] 9038#0: *307827 limiting connections by zone “conn_zone”, client:
10.0.0.8, server: , request: “GET / HTTP/1.0”, host: “10.0.0.8” 2019/10/23 17:35:51 [error] 9038#0: *307832 limiting connections by zone “conn_zone”, client:
10.0.0.8, server: , request: “GET / HTTP/1.0”, host: “10.0.0.8” 2019/10/23 17:35:51 [error] 9038#0: *307881 limiting connections by zone “conn_zone”, client:
10.0.0.8, server: , request: “GET / HTTP/1.0”, host: “10.0.0.8” 2019/10/23 17:35:51 [error] 9042#0: *307890 limiting connections by zone “conn_zone”, client:
10.0.0.8, server: , request: “GET / HTTP/1.0”, host: “10.0.0.8”
“`

![image-20250116162354082](D:\Program Files (x86)\Typora\006-nginx\image-20250116162354082.png)

“`sh
#限制请求频率
[root@web01 ~]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;
access_log /var/log/nginx/access.log main;
server_tokens off;
client_max_body_size 50m;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#limit_conn 部分
#创建 limit_conn 木桶 $客户端 ip 地址 zone=桶名字:大小
#limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
#limit_req 部分
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
include /etc/nginx/conf.d/*.conf;
}
[root@web01 ~]# cat /etc/nginx/conf.d/default.conf
server {
listen 80 default_server;
server_name localhost;
charset utf8;
autoindex on;
#调用 limit_conn 木桶 每个 ip 并发连接是 1
#limit_conn conn_zone 1;
#调用 limit_req 并发处理 5
limit_req zone=one burst=5;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
#每个 ip 每秒请求超过 1 就会提示 delaying request 延迟处理请求.

“`

![image-20250116162441787](D:\Program Files (x86)\Typora\006-nginx\image-2025011616244178png)

“`sh
#整体并发超过 5 则提示 limiting requests

“`

![image-20250116162525856](D:\Program Files (x86)\Typora\006-nginx\image-20250116162525856.png)

#### 3 性能优化

| 优化说明 | 优化方法 |
| —————————————- | ———————————————————— |
| 1 修改nginx worker_process | 一般与cpu数量一致,高并发可以为cpu两倍 |
| 2 cpu亲和力(工具人进程平均使用cpu核心) | 利用 worker_cpu_affinity 进行优化(**cpu 亲和力**) 让 CPU 的每隔核心 平均4 颗 CPU 优化配置参数为 0001 0010 0100 1000worker_cpu_affinity 0101 1010;worker_cpu_affinity auto;Linux 系统设置 cpu 亲和力 taskset (15k)Taskset -p oxf pid\#把进程绑定到对应的 cpu 核心上. |
| 3 优化nginx事件处理模型 | use epoll |
| 4 优化nginx工具人进程连接数 | worker_connections |
| 5 优化nginx服务进程打开文件数 | worker_rlimit_nofile 65535; |
| 6 优化nginx服务数量高效传输模式 | 利用sendfile on;开启高效传输模式,tcp_nopush on;表示将数据积攒到一定量再进行传输,tcp_nodelay on;表示将数据信息进行快速传输 |
| 7 优化nginx服务与连接缓存与缓冲信息 | 优化利用fastcgi与php连接的缓存、缓存信息,注意ngx各种的buffer和cache |
| 8 配置nginx gzip压缩 | 利用gzip命令对数据信息压缩优化 |
| 9 brotli压缩第三方 | https环境中 |
| 10 配置nginx expires缓存 | 在location模块中,利用expires将信息缓存到用户浏览器中 |
| 11 超级性能优化 | multi_accept on; events区域,启用后,工作进程将尝试一次接受多个新的链接,这样可以介绍系统调用的此处,可以提高处理连接的效率,尤其是在高并发场景下 |
| | |

“`sh
1 工具人用户
worker_processes 8;cpu数
2 ngx cpu亲和力
worker_cpu_affinity auto;
3 nginx io模型
在events区域增加use epoll
4 优化nginx单工具人进程客户端连接数
events区域增加
worker_connections 10000;需要进行压力测试
5 配置nginx gzip实现性能优化
给静态资源进行压缩,节约带宽.对静态文字资源进行压缩,html,css,js,文字内容.其他静态资源图片,视频不推荐使用 gzip 压缩. gzip on;
gzip on;
gzip_min_length 1k; #设置大于 1K 才进行压缩
gzip_buffers 4 16k; #设置压缩缓存 4 个每个 16k
#gzip_http_version 1.0;
gzip_comp_level 2; #压缩级别 数字越大 压缩率(占用空间)越小 占用 CPU 越多
gzip_types text/plain application/x-javascript text/css application/xml text/javascript
application/x-httpd-php ; #哪些类型的文件 需要进行压缩 这些类型需用 mime type 媒体类型. #mime types #媒体类型(http) === 文件类型(linux)

故障案例:
NSES WITH THE “TEXT/HTML” TYPE ARE ALWAYS COMPRESSED.
GZIP 默认压缩 TEXT/HTML 类型,不用指定,指定会报错。
nginx: [warn] duplicate MIME type “text/html” in /app/nginx-1.14.0//conf/nginx.conf:13
检查:
chrome 浏览器 按 F12

“`

![image-20250116171218006](D:\Program Files (x86)\Typora\006-nginx\image-20250116171218006.png)

![image-20250116171223159](D:\Program Files (x86)\Typora\006-nginx\image-20250116171223159.png)

“`sh
6 配置 Nginx brotli 压缩实现性能优化(下面有案例)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css text/xml application/json application/javascript
application/rss+xml application/atom+xml image/svg+xml;

“`

![image-20250116171258384](D:\Program Files (x86)\Typora\006-nginx\image-20250116171258384.png)

“`sh
7 配置nginx expires缓存
设置静态资源在客户端浏览器中缓存. 图片 类
html,css,js 类
缓存时间设置,变化少,改动少的就可以增加缓存时间缓存 1 天或 10 天. 经常变动的缓存较短 1 小时
location ~* \.(gif|jpg|jpeg|png|bmp|ico)$ {
root /var/www/img/;
expires 30d;
#access_log off;
}

8 优化 nginx 服务与连接缓存与缓冲信息
Linux 中有各种的 buffer 和 cache,他们作用类似实现加速用户读或写操作. 利用软件在内存中创建 buffer 和 cache 区域. cache 用于加速读取. buffer 用于加速写入. 写 buffer 读 cache. #cache 类用于加速读取. 有各种类型,php(fastcgi_cache),通用类(proxy_cache),python(uwsgi_cache)
使用方法都类似. proxy_cache 与 proxy_pass http 区域
proxy_cache_path /dev/shm/ngx_cache/ levels=1:2 keys_zone=ysl_ysl:10m;
http 或 server 或 locaiton 配置
proxy_pass http://blog_pools;
proxy_cache ysl_ysl; #cache 区域名字. proxy_cache_valid 200 302 1h;
proxy_cache_valid 301 1d;
proxy_cache_valid any 1m;
[root@lb01 ~]# cat /etc/nginx/nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid; events { worker_connections 1024;
}stream { upstream l4_pools { server 10.0.0.7:8848; server 10.0.0.8:8848;
}
#log_format server {
listen 8848;
#error_log
#access_log
proxy_pass l4_pools;
}
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘; access_log /var/log/nginx/access.log main; sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
proxy_cache_path /dev/shm/ngx_cache/ levels=1:2 keys_zone=ysl_ysl:10m;
include /etc/nginx/conf.d/*.conf;
}
[root@lb01 ~]# cat /etc/nginx/conf.d/lb.ysllinux.cn.conf
[root@lb01 ~]# cat /etc/nginx/conf.d/lb.ysllinux.cn.conf
#创建分组
upstream lb_pools { server 10.0.0.7:80; server 10.0.0.8:80; check interval=3000 rise=2 fall=5 timeout=1000 type=http;
#Host 部分需要改成站点对应的域名
check_http_send “HEAD / HTTP/1.0\r\nHost: lb.ysllinux.cn\r\nUser-Agent: lb_check\r\n\r\n”; check_http_expect_alive http_2xx http_3xx;
}server {
listen 80; server_name lb.ysllinux.cn;
#access_log
#error_log
location / {
#lb_pools 分组的名字
proxy_pass http://lb_pools;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache ysl_ysl;
proxy_cache_valid 200 302 1h;
proxy_cache_valid 301 1d;
proxy_cache_valid any 1m;
}
location /status { check_status; access_log off;
}
}
检查 :
“`

![image-20250116171502025](D:\Program Files (x86)\Typora\006-nginx\image-20250116171502025.png)

“`sh
# 使用 include 功能精简,配置文件
[root@lb01 ~]# cat /etc/nginx/nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid; events { worker_connections 1024;
}stream { upstream l4_pools { server 10.0.0.7:8848; server 10.0.0.8:8848;
}
#log_format server {
listen 8848;
#error_log
#access_log
proxy_pass l4_pools;
}
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘; access_log /var/log/nginx/access.log main; sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
proxy_cache_path /dev/shm/ngx_cache/ levels=1:2 keys_zone=ysl_ysl:10m;
include /etc/nginx/conf.d/*.conf;
}
[root@lb01 ~]# cat /etc/nginx/proxy.conf
[root@lb01 ~]# cat /etc/nginx/proxy.conf
#Host 头保留
proxy_set_header Host $http_host;
#XFF 头
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache ysl_ysl;
proxy_cache_valid 200 302 1h;
proxy_cache_valid 301 1d;
proxy_cache_valid any 1m;
[root@lb01 ~]# cat /etc/nginx/conf.d/blog.ysllinux.cn.conf upstream blog_pools { server 10.0.0.7:80; server 10.0.0.8:80;
}server {
listen 80; server_name blog.ysllinux.cn; access_log /var/log/nginx/blog-access.log main; error_log /var/log/nginx/blog-error.log notice;
location / {
proxy_pass http://blog_pools;
include proxy.conf;
}
}
“`

![image-20250116171539316](D:\Program Files (x86)\Typora\006-nginx\image-20250116171539316.png)

“`sh
ngx 的各种 buffer. 开启 buffer 功能,设置缓冲区. proxy_buffer fastcgi_buffer uwsgi_buffer. #Host 头保留
proxy_set_header Host $http_host;
#XFF 头
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache ysl_ysl;
proxy_cache_valid 200 302 1h;
proxy_cache_valid 301 1d;
proxy_cache_valid any 1m;
#ngx buffer 配置
proxy_buffering on;
proxy_buffer_size 128k;
proxy_busy_buffers_size 256k;
proxy_buffers 32 128k;

9 timeout系列

一般表示超时时间,连接的时候时间,超过这个时间未完成连接,读/写/连接.
proxy_connect_timeout 连接超时时间.
proxy_read_timeout 定义从代理服务器读取响应的超时. 适当可以加长 300s. proxy_send_timeout 设置将请求传输到代理服务器的超时。适当可以加长 300s.

10 优化nginx服务进程打开文件数量
Linux 文件描述符,用于控制每个进程最多可以打开多少文件. 这个值分为 2 个部分:
1. 系统的设置. [root@web01 ~]# egrep -v ‘^$|#’ /etc/security/limits.conf * soft nofile 65535
* hard nofile 65535
[root@web01 ~]# ulimit -n 65535
2. 服务软件的设置. ngx 主配置文件
user www;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 60000;
use epoll;
}
pidstat -l |grep nginx #ab 访问
“`

HTTP概述

### 1 用户访问网站流程

“`sh
输入网址:

用户在浏览器地址栏输入网站的URL(统一资源定位符)。
DNS解析:

浏览器向DNS(域名系统)服务器请求将域名解析为IP地址。
DNS服务器查询其数据库,返回与域名对应的IP地址。
建立连接:

浏览器使用DNS解析得到的IP地址,通过TCP(传输控制协议)向服务器发起连接请求。
服务器响应请求,完成TCP三次握手过程,建立连接。
发送HTTP请求:

浏览器构建HTTP(超文本传输协议)请求,发送到服务器。
请求包含请求方法(如GET或POST)、请求的资源路径、HTTP版本和可能的请求头信息。
服务器处理请求:

服务器接收到HTTP请求后,根据请求的资源路径处理请求。
如果请求的是静态资源(如HTML文件、CSS文件、图片等),服务器直接从文件系统中检索资源。
如果请求的是动态内容,服务器可能会执行服务器端脚本(如PHP、Python、Node.js等),生成响应内容。
返回响应:

服务器将处理结果(可能是HTML页面、图片、视频等)作为HTTP响应返回给浏览器。
响应包含状态码(如200表示成功)、响应头信息和响应体(实际的数据内容)。
渲染页面:

浏览器接收到服务器的响应后,开始解析HTML文档,并根据HTML、CSS和JavaScript文件渲染页面。
浏览器请求页面中引用的其他资源(如CSS、JavaScript文件、图片等),并重复上述过程以获取这些资源。
执行JavaScript:

浏览器执行页面中的JavaScript代码,这可能包括与服务器的进一步交互(如AJAX请求)。
页面交互:

用户与页面进行交互,如点击链接、填写表单等,这些操作可能会触发新的HTTP请求。
关闭连接:

对于非持久连接,每次HTTP请求/响应后,TCP连接会被关闭。
对于持久连接(如HTTP/1.1的keep-alive或HTTP/2),TCP连接可以被重用,减少了建立和关闭连接的开销。
缓存处理:

浏览器可能会缓存一些资源,以便在用户再次访问同一网站时加快加载速度。
“`

### 2 http概述

默认端口是80

HTTP超文本传输协议: 数据请求与响应.

传输:网站的数据如何传递给用户.

超文本:文本,图片,视频….

用户打开网站后:网站如何传递数据给用户.

专业名字:数据请求与响应

请求request:打开网站,访问网站.

响应response:网站显示出,返回给你想要的内容.

“`sh
[root@m01 /server/ans]# curl -v www.baidu.com
* Trying 39.156.66.18:80…
* Connected to www.baidu.com (39.156.66.18) port 80 (#0)
> GET / HTTP/1.1
> Host: www.baidu.com
> User-Agent: curl/7.71.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK < Accept-Ranges: bytes >大于号是请求
<小于号是响应 -L 选项可以确保 curl 能够正确地获取到最终的目标资源 用于有跳转的uri [root@m01 /server/ans]# wget --debug www.baidu.com ``` http1.0:短连接,每次请求都需要重复建立断开连接,占用服务端资源,基于tcp http1.1:加入长连接功能,80和443,基于tcp http2.0:增加并发,访问更快,基于https,tcp http3.0:基于udp,应用于流媒体, 大部分企业还在使用http1.1, 一部分使用http2.0 目前http3.0(*QUIC*) 流媒体直播在使用. ### 3 http请求 #### 1 请求报文起始行 ```sh ---request begin--- #请求开始 GET / HTTP/1.1 #请求方法、http协议版本 User-Agent: Wget/1.14 (linux-gnu) #UA头 Accept: */* # Host: www.baidu.com #请求的uri Connection: Keep-Alive #连接方式,长连接 ---request end--- ``` ![image-20250107124519966](D:\Program Files (x86)\Typora\005-nginx\image-20250107124519966.png) ![image-20250107124532202](D:\Program Files (x86)\Typora\005-nginx\image-20250107124532202.png) #### 2 常见的请求方法 | GET | 下载 | | ------ | ------------------------------------------------------------ | | POST | 上传 | | HEAD | 类似于GET,仅仅输出响应头部信息,(查看服务端信息,一般用于检查,)curl -l | | DELETE | 删除 | 资源的位置(URI): 这个资源在**网站站点目录**的哪个地方,叫什么名字. 这里面写的/lidao.mp4,斜线并非是Linux系统的根目录.这个/叫网站的站点 目录. URI(统一资源标识符) 站点目录是用于存放网站代码的地方.未来在nginx中我们可以指定与查看 ```sh [root@m01 /server/ans]# curl -I www.baidu.com HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform Connection: keep-alive Content-Length: 277 Content-Type: text/html Date: Fri, 08 Nov 2024 02:44:04 GMT Etag: "575e1f60-115" Last-Modified: Mon, 13 Jun 2016 02:50:08 GMT Pragma: no-cache Server: bfe/1.0.8.18 [root@m01 /server/ans]# wget --method=HEAD --debug www.baidu.com 使用wget和curl发出HEAD请求方法,查看服务端信息,服务端是否可以访问 ``` ```sh 温馨提示: GET /lidaoav.mp4 HTTP/1.1 这里的/不是根,是网站站点目录,未来可以在web服 务中进行配置. /app/code/www/ 站点目录 访问/lidaoav.mp4 === /app/code/www/lidaoav.mp4 ``` ![image-20250107124543540](D:\Program Files (x86)\Typora\005-nginx\image-20250107124543540.png) #### 3 请求头 | 字段(关键字) | 含义 | | -------------- | ---------------------------------------------- | | User-Agent | UA头,客户端代理(用什么工具访问网站),浏览器 | | Host | Host头,表示访问的目标网站,域名或ip | | 。。。 | | #### 4 其他 空行: 分割请求头与请求报文主体 请求报文主体(body): 一般上传的时候才有 #### 5 浏览器调试查看 浏览器的调试功能DevTools F12查看网络部分即可 #### 6 小结 核心内容:请求起始行,请求方法,请求uri 核心内容:请求头中,UA头,HOST头 核心请求报文:用户目录,上传下载,资源位置、名字,自报家门(UA) ### 4 http响应 #### 1 响应报文与起始行 ![image-20250107124553870](D:\Program Files (x86)\Typora\005-nginx\image-20250107124553870.png) 协议与版本 HTTP/1.1 状态码:数字3位,用户描述服务端是否能找到或处理用户的请求 ```sh HTTP/1.1 200 OK Cache-Control: no-cache, private Content-Encoding: gzip Content-Type: application/json Date: Fri, 08 Nov 2024 03:09:20 GMT Server: Apache Tracecode: 05608097990288220170110811 Vary: Accept-Encoding Content-Length: 59 ``` #### 2 响应头 | 响应头字段 | | | -------------- | -------------------------------- | | server | 显示服务端使用的web服务器及版本 | | content | 媒体类型(文件类型) | | Content-Length | 大小 | | location | 跳转之后的新位置,跳转的时候才有 | | via/cache | 查看是否cdn | | | | #### 3 其他 空行 响应报文主体,服务端返回给客户端的数据 #### 4 http协议状态码 | 状态码 | 含义 | | ------ | ------------------ | | 2xx | 表示正常 | | 3xx | 表示需要跳转,正常 | | 4xx | 异常,客户端问题 | | 5xx | 异常,服务端问题 | 详细状态码 | 详细的状态码 | 说明 | | ----------------------------------- | ------------------------------------------------------------ | | 200ok | 访问正常 | | 301 moved Permanetly | 永久跳转 | | 302 found或foundtemporarily | 临时跳转 | | 304 not modified | 浏览器缓存 | | 401 | 认证失败 | | 403 forbidden | 权限拒绝(拒绝访问),1、权限问题 2首页文件问题 | | 404 notfound | 文件找不到,一般辅助错误日志排查 | | 405 method not allowed | 不准许的请求方法,一般服务器或安全软件限制 | | 413 request entity too large | web服务文件大小限制 | | 500 internal error | 内部错误,selinux,其他原因辅助错误日志排查 | | 502 bad gateway | 网关错误,一般发生在负载中(类似情况下),请求发送到后面,后面无人处理 | | 503 service temporarily unavailable | 服务临时不可用,一般人为设置,升级 | | 504 gateway time-out | 网关超时 | curl -Lv -L跟随跳转,遇到301/302会读取响应头中的Location头重新访问 http响应代码 [HTTP 响应状态码 - HTTP | MDN (mozilla.org)](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status) http:用户的请求与响应后格式与定义 http请求报文 请求起始行GET uri http/1.1 请求头head: User-Agent:客户端代理(浏览器) Host:域名 空行 请求报文主体(body):POST http响应报文 响应报文的起始行:http/1.1 状态码 响应头:server(web服务器) 空行 状态码与含义 ### 5 web集群-衡量系统访问量指标 概述 | 指标 | 说明 | | ---------- | --------------------------------------------- | | 并发访问量 | 同一时间内访问用户的数量,tcp已建立连接的数量 | | ip | 访问网站的公网ip | | pv | 页面访问量,page view,用户访问一次,pv+1 | | 传统网站 | 门户网站,搜索网站 | | uv | 独立访客数量,接近于用户数量 | | DAU | 每天用户活跃数量,日活 | | MAU | 月活 | | | | ### 6 常见的网站服务(web中间件) | 网站服务 | 说明 | 官网 | | --------------------------- | ----------------------------------------- | -------------------------- | | nginx | 大部分使用,异步模型(epoll) | http://nginx.org/en/docs | | tengine | 基于nginx二次开发,淘宝开源,更多内置模块 | https://tengine.taobao.ora | | openresty | 基于nginx二次开发,加强lua功能与模块 | | | apache(httpd) | 目前较少使用,select模型,同步 | | | ... | | | | 特殊环境 | | | | tomcat/jboss/jetty/weblogic | 运行java环境的,web服务 | | | php | 预习php,需要nginx(LNMP) | | | python/golang | | | | ... | | | | 国产 | | | | | | |