跳转至

software

Rancher fix

Q:删除nginx webhook后更新rancher 的helm 配置,改为traefik 问题解决了,帮我复盘下

A: 可以,整个问题链路其实很典型:Ingress Controller 切换过程中,旧 nginx 没清干净,新 Traefik 又一开始没完全可用,导致 Rancher 入口中断。

复盘如下。


1. 最初的调度失败原因

你最开始看到的是:

0/3 nodes are available:
1 node(s) didn't have free ports for the requested pod ports,
2 node(s) didn't satisfy plugin(s) [NodeAffinity]

后面看 Traefik Pod YAML,发现它是 DaemonSet 创建的,并且每个 Pod 会被固定调度到对应节点,例如:

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - host-203

这说明:

这个 Traefik Pod 只能调度到 host-203

同时 Traefik 配了:

hostPort: 80
hostPort: 443

所以它必须占用宿主机的 80 和 443。


2. 真正的端口冲突来源

你用命令查到:

kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" node="}{.spec.nodeName}{" hostPorts="}{range .spec.containers[*].ports[*]}{.hostPort}{"/"}{.protocol}{" "}{end}{"\n"}{end}' | grep -E '80/TCP|443/TCP'

结果里有:

kube-system rke2-ingress-nginx-controller-7h97n node=host-201 hostPorts=80/TCP 443/TCP
kube-system rke2-ingress-nginx-controller-vwfgs node=host-202 hostPorts=80/TCP 443/TCP
kube-system rke2-ingress-nginx-controller-sqjft node=host-203 hostPorts=80/TCP 443/TCP

同时 Traefik 也要:

default rke2-traefik-* hostPorts=80/TCP 443/TCP

所以根因是:

rke2-ingress-nginx-controller 已经占用了每个节点的 80/443
rke2-traefik 也想占用每个节点的 80/443
同一个 Node 上同一个 hostPort 不能被两个 Pod 同时使用

因此 Traefik 的 Pod 一开始无法调度。


3. 为什么删除 Service 没用?

你删除了 nginx 的 Service,但 nginx controller Pod 还是重新调度。

原因是:

Service 只负责暴露访问入口
不负责管理 Pod 生命周期

真正管理这些 Pod 的是:

DaemonSet/rke2-ingress-nginx-controller

所以:

删除 Service:不会删除 Pod
删除 Pod:DaemonSet 会重建
删除 DaemonSet:Pod 才会停止,但如果 RKE2 Addon/HelmChart 还在,也可能再次重建

所以要彻底不用 nginx ingress,需要处理它背后的:

DaemonSet
HelmChart
RKE2 内置 addon 配置
admission webhook

4. Rancher 为什么打不开?

你的 Rancher Ingress 是:

Namespace: cattle-system
Name: rancher
Ingress Class: <none>
Address: 192.168.31.201,192.168.31.202,192.168.31.203
Events From: nginx-ingress-controller

虽然它没有显式写:

ingressClassName: nginx

但从 Events 可以看出,之前实际是 nginx ingress controller 在处理 Rancher 的 Ingress

nginx-ingress-controller Scheduled for sync

所以 Rancher 访问链路原来大概是:

浏览器访问 rancher.edelman999.com:443
节点 443
rke2-ingress-nginx-controller
Ingress/cattle-system/rancher
Service/cattle-system/rancher
Rancher Pod

当你删除或破坏 nginx ingress 后,如果 Traefik 还没有正常接管,那么链路就断了:

没有可用的 80/443 Ingress Controller
Rancher 域名自然打不开

5. Helm upgrade 为什么失败?

你执行:

helm upgrade rancher rancher-latest/rancher \
  -n cattle-system \
  --reuse-values \
  --set ingress.ingressClassName=traefik

报错:

failed calling webhook "validate.nginx.ingress.kubernetes.io"
service "rke2-ingress-nginx-controller-admission" not found

这个是关键转折点。

它说明:

nginx ingress admission webhook 配置还在
但 webhook 指向的 Service 已经被删了

也就是集群进入了一个“半删除”状态:

ValidatingWebhookConfiguration 还在
rke2-ingress-nginx-controller-admission Service 不在

Kubernetes API Server 在创建/更新 Ingress 前,会调用这个 webhook 做校验:

helm upgrade 修改 Rancher Ingress
API Server
调用 validate.nginx.ingress.kubernetes.io
访问 rke2-ingress-nginx-controller-admission.kube-system.svc
Service 不存在
Ingress 更新失败
Helm upgrade 失败

所以当时问题已经不是 Helm 参数错,而是 nginx admission webhook 残留阻塞了所有 Ingress 更新


6. 最终解决动作为什么有效?

你删除 nginx webhook 后,再更新 Rancher Helm 配置为 Traefik,问题解决。

这说明最终链路变成了:

删除残留 nginx webhook
API Server 不再调用不存在的 nginx admission service
Rancher Ingress 可以正常更新
spec.ingressClassName 改为 traefik
Traefik 接管 Rancher Ingress
Rancher 恢复访问

最终关键配置应该类似:

spec:
  ingressClassName: traefik

也就是 Rancher 不再被 nginx ingress 处理,而是交给 Traefik。


7. 整个问题的根因总结

可以分成 3 层。

第一层:端口冲突

nginx ingress 和 Traefik 同时使用 hostPort 80/443

这是最开始 Traefik Pending 的原因。


第二层:Ingress Controller 切换不完整

你想从 nginx ingress 切到 Traefik,但一开始:

nginx 没完全清理
Traefik 没完全接管
Rancher Ingress 还处于 nginx 处理逻辑中

所以 Rancher 打不开。


第三层:nginx admission webhook 残留

删除 nginx 相关 Service 后,还留下了:

ValidatingWebhookConfiguration/validate.nginx.ingress.kubernetes.io

它继续拦截 Ingress 更新,但指向的 Service 已经不存在。

所以 Helm upgrade 被阻断。


8. 这次问题最关键的判断点

几个关键命令起了作用:

查 hostPort 冲突

kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" node="}{.spec.nodeName}{" hostPorts="}{range .spec.containers[*].ports[*]}{.hostPort}{"/"}{.protocol}{" "}{end}{"\n"}{end}' | grep -E '80/TCP|443/TCP'

确认 nginx 占了 80/443。


查 Rancher Ingress 当前由谁处理

kubectl describe ingress -n cattle-system rancher

看到:

Ingress Class: <none>
Events From: nginx-ingress-controller

说明 Rancher 原来被 nginx 处理。


Helm upgrade 报 webhook 错

failed calling webhook "validate.nginx.ingress.kubernetes.io"
service "rke2-ingress-nginx-controller-admission" not found

直接定位到:

nginx webhook 残留

9. 以后类似切换建议流程

如果以后从一个 Ingress Controller 切到另一个,建议按这个顺序:

1. 先确认新 controller 正常

kubectl get pods -A | grep -i traefik
kubectl get ingressclass

确认 Traefik Running,并且有:

traefik

IngressClass。


2. 避免 hostPort 冲突

如果两个 controller 都要占:

80
443

只能保留一个,或者让它们跑在不同节点,或者改一个不用 hostPort。


3. 修改业务 IngressClass

例如 Rancher:

helm upgrade rancher rancher-latest/rancher \
  -n cattle-system \
  --reuse-values \
  --set ingress.ingressClassName=traefik

或者临时 patch:

kubectl patch ingress rancher -n cattle-system \
  --type='merge' \
  -p '{"spec":{"ingressClassName":"traefik"}}'

但 Helm 管理的资源,最好用 Helm 改。


4. 再清理旧 controller

旧 nginx 不用了再删:

kubectl delete ds -n kube-system rke2-ingress-nginx-controller

如果是 RKE2 内置组件,还要在 RKE2 配置里禁用:

disable:
  - rke2-ingress-nginx

5. 清理旧 admission webhook

不用 nginx 后,确认是否残留:

kubectl get validatingwebhookconfiguration | grep -i nginx
kubectl get mutatingwebhookconfiguration | grep -i nginx

确认不用后再删:

kubectl delete validatingwebhookconfiguration <nginx-webhook-name>

10. 一句话复盘

这次问题本质是:

RKE2 集群里 nginx ingress 和 Traefik 同时争抢 80/443,
Rancher 原来由 nginx ingress 暴露;
删除 nginx 相关资源后,nginx admission webhook 残留,
导致 Rancher Ingress 无法通过 Helm 更新到 Traefik;
删除残留 webhook 后,Rancher Ingress 成功切换到 Traefik,访问恢复。

最终你做对的关键动作是:

1. 找到 80/443 是 rke2-ingress-nginx-controller 占用
2. 明确 Rancher Ingress 原来被 nginx 处理
3. 删除残留 nginx admission webhook
4. 用 Helm 把 Rancher ingressClassName 改为 traefik

这就是问题解决的完整闭环。

MySQL 监控指标

1.opened_table_definitions

1.查询

MySQL admin@192.168.31.180:(none)> SHOW GLOBAL STATUS LIKE '%Table_definition%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| Open_table_definitions   | 226   |
| Opened_table_definitions | 299   |
+--------------------------+-------+

2 rows in set
Time: 0.179s

k8s-相关问题

1.kubernetes 创建ServiceAccount 后没有生成对应的secret

从 1.24 开始就不会自动生成 secret 了,chanagelog 在这里.

内容如下 LegacyServiceAccountTokenNoAutoGeneration 功能门是测试版,默认启用。启用后,不再为每个 ServiceAccount 自动生成包含服务帐户令牌的 Secret API 对象。使用 TokenRequest API 获取服务帐户令牌,或者如果需要未过期的令牌,请按照本指南为令牌控制器创建一个 Secret API 对象以填充服务帐户令牌

pr: https://github.com/kubernetes/kubernetes/pull/108309

参考:

[1].https://www.soulchild.cn/post/2945/

git modules 相关命令

1.删除子模块文件夹

$ git rm --cached GWToolkit
$ rm -rf GWToolkit
echo -e "backend\ndbinit\nfrontend\ndocs\nreleases\ngreatdas" |  xargs -t -I {} git rm --cached {}
echo -e "backend\ndbinit\nfrontend\ndocs\nreleases\ngreatdas" |  xargs -t -I {}  rm -rf {} 

2. 删除 .gitmodules 文件中相关子模块的信息,类似于:

[submodule "GWToolkit"]
        path = GWToolkit
        url = https://github.com/iphysresearch/GWToolkit.git
rm -rf .gitmodules

3.删除 .git/config 中相关子模块信息,类似于:

[submodule "GWToolkit"]
        url = https://github.com/iphysresearch/GWToolkit.git
        active = true

4.删除 .git 文件夹中的相关子模块文件

$ rm -rf .git/modules/GWToolkit

Mac 自带翻译由于代理导致不可用问题

Mac的自带翻译由于会检测是否存在代理行为会导致不可用,需要进行额外配置

1.在Clash for Windows 中的Settings -> System Proxy 中进行额外配置即可

image-20240201153931939

点击Edit 进行配置,增加以下两行内容

  - sequoia.apple.com
  - seed-sequoia.siri.apple.com

增加后内容如下

image-20240201154155499

点击保存,使得变更生效

参考:

[1].https://zhuanlan.zhihu.com/p/581119370

Kubernetes学习笔记

1.云原生概念

2.容器基本概念

3.Kubernetes基本概念

  • 安装MiniKube https://developer.aliyun.com/article/221687
  • 安装kubectl [https://kubernetes.io/zh/docs/tasks/tools/install-kubectl-linux/]

4.Pod

Pod 实现机制:

  • 共享网络

  • 共享存储

容器设计模式 SideCar

  • 1.Init Container
  • 2.Proxy Container
  • 3.Adapter Container

总结:

  • Pod 是Kubernetes 实现 容器设计模式的核心机制
  • 容器设计模式是Google Borg 的大规模容器集群管理最佳实践
  • 也是Kubernetes 进行复杂应用编排的基础依赖之一
  • 所有设计模式的本质都是解耦和重用

路由器AC,AP 分别是指什么?

AP 是无线接入点(Wireless AccessPoint),负责释放无线信号,转发无线数据的作用。

In computer networking, a wireless access point (WAP), or more generally just access point (AP), is a networking hardware device that allows other Wi-Fi devices to connect to a wired network. As a standalone device, the AP may have a wired connection to a router, but, in a wireless router, it can also be an integral component of the router itself. An AP is differentiated from a hotspot which is a physical location where Wi-Fi access is available.

https://en.wikipedia.org/wiki/Wireless_access_point

AC是无线控制器(Wireless AccessPoint Controller),负责控制AP的所有设置.

Linux 相关配置

0.安装有线驱动

我这里使用的是Realtek 8125 的有线网卡,在官方网站上下载驱动进行安装,网址如下

https://www.realtek.com/en/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-pci-express-software

iptables 使用

1.开启端口映射

添加filter 表的forward链

iptables -I FORWARD -m state -d 192.168.122.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT

添加nat 表的prerouting链

iptables -t nat -I PREROUTING -p tcp --dport 1433 -j DNAT --to-destination 192.168.122.100:9200

一致hash 算法

​ 普通hash算法可以对请求和服务器进行映射,达到降低服务器负载的作用.但是普通hash 算法在增加或者删除一个节点后,需要对大部分的节点进行重新映射,避免来自同一请求分布在不同的服务器上.

​ 通过使用一致hash可以在增加或者删除节点时只更新部分映射,避免服务器长时间不可用的状态.

​ 一致性hash算法将整个hash值空间映射为一个虚拟的圆环,整个hash 空间的取值范围为0-2^32 -1.整个空间按照顺时针顺序分布.

​ 一致hash 将每个对象映射到圆环上的一个点,系统再将可用的节点机器映射到圆环的不同位置.查找某个对象对应的机器时,先通过一致hash算法查找对象对应圆环的位置,沿着圆环边上查找直到遇到某个节点机器,这台机器即为保存对象的位置.

当删除一个节点时,这台节点上的所有值都要移动到下一个节点. 添加一台机器到圆环边上某个点时,这个点的下一台机器需要将这个节点之前对应对象移动的新机器上.更改对象在节点机器上的分布可以通过调整节点机器的位置来实现

针对基础一致性 hash 的缺点一种改进算法是引入虚节点(virtual node)的概念。这个本质的改动:值域不再由物理节点划分,而是由固定的虚拟节点划分,这样值域的不均衡就不存在了。

[参考资料]

[1].https://zh.wikipedia.org/wiki/%E4%B8%80%E8%87%B4%E5%93%88%E5%B8%8C

[2].https://liqingqiya.github.io/hash/%E4%B8%80%E8%87%B4%E6%80%A7%E5%93%88%E5%B8%8C/%E7%AE%97%E6%B3%95/%E5%88%86%E5%B8%83%E5%BC%8F/2020/05/11/dht-hash.html

[3].https://www.toptal.com/big-data/consistent-hashing

Gossip 协议

Gossip 有两种类型:

Anti-Entropy (反煽): 以固定概率传播所有数据

Rumor-Mongering (谣言传播):仅传播新到达的数据

[参考资料]

[1].https://zhuanlan.zhihu.com/p/41228196

[2].https://hyperledger-fabric.readthedocs.io/zh_CN/release-2.2/gossip.html

[3].https://en.wikipedia.org/wiki/Gossip_protocol

commit 的sha值是如何计算的

[1].https://jingsam.github.io/2018/06/09/git-hash.html

0.使用git show 查看commit相关信息

commit bfe4078b84eec85c1cafdb0a26f3fd93b581727e (HEAD -> master)
Author: root <root@hideto>
Date:   Thu Oct 22 10:53:28 2020 +0800

    init commit

diff --git a/1.txt b/1.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/1.txt
@@ -0,0 +1 @@
+hello

在上面的输出中 index其实就是file_sha

filebeat 相关问题清单

1.日志文件是如何被发现又是如何被采集的?

根据配置获取匹配的日志文件,采用linux glob的规则进行匹配。然后会经过复杂的过滤,可以配置exclude_files忽略文件,还可以配置ignore_older 文件修改时间超过设定值的也不会被匹配。 对于文件进行处理,获取文件的状态,同时在已经存在的状态进行对比,如果相同就不会开启新的协程,如果是新的状态就开启一个新的协程。每个input 对象创建时会从register中读取文件状态(offset),对于每一个匹配到的文件都会开启一个新的harvester进行读取。每个harvester都有一个相对应的goroutine

Filebeat 使用

1.将filebeat 多行日志合并

.使用filebeat 将多行日志合并为es 的一个doc,默认情况下,filebeat 会将每一个的日志文件作为es 的一个doc 进行输入,要想将多行日志聚合在一起,需要配置以下几个参数,分别是

  multiline.pattern: '^[0-9]{4}/[0-9]{2}/[0-9]{2}'
  multiline.negate: true
  multiline.match: after

MySQL查询性能优化

1.查询慢的原因

1.1查询的生命周期

查询的生命周期大致可以按照顺序来看

从客户端 --> 到服务器 --> 然后再服务器上进行解析 --> 生成执行计划 --> 执行 ---> 返回结果给客户端

其中执行 是整个生命周期中最重要的阶段,因为这执行这个阶段 有着大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序、分组等。

查询会在不同的地方产生时间消耗,包括网络CPU计算生成统计信息和执行计划锁等待(互斥等待) 等操作,特别是向底层存储引擎检索数据的调用操作,这些操作需要在内存操作CPU操作内存不足时导致等待I/O操作上消耗时间。如果存储引擎不同,可能会产生大量的上下文切换以及系统调用。

SQL 中exists 与in 的区别

select * from A where id in (select id from B);

select * from A where exists (select 1 from B where A.id=B.id);

对于以上两种情况,in是在内存里遍历比较,而exists需要查询数据库,所以当B表数据量较大时,exists效率优于in。

Ubuntu 配置远程连接

1.更换官方默认源

# 备份源镜像源
mv /etc/apt/sources.list /etc/apt/sources.list.bak

ubuntu 16.04 配置如下

deb http://mirrors.aliyun.com/ubuntu/ xenial main
deb-src http://mirrors.aliyun.com/ubuntu/ xenial main

deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main

deb http://mirrors.aliyun.com/ubuntu/ xenial universe
deb-src http://mirrors.aliyun.com/ubuntu/ xenial universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates universe

deb http://mirrors.aliyun.com/ubuntu/ xenial-security main
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main
deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security universe

ubuntu 18.04(bionic) 配置如下

deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

ubuntu 20.04(focal) 配置如下

deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

Go代码调试

1.打印输出

​ 使用golangfmt.Println(),fmt.Printf() 等函数,根据输出与预期的差异进行比较来进行调试,另外一个有用的函数可能是反射相关的函数,比如reflect.TypeOf()reflect.ValueOf(),根据反射函数可以获得指定变量中的内部结构,有助于分析问题。

2.日志输出

​ 日志输入可以借助golang自带的日志包,使用log.Println(),log.Printf()等函数,将需要进行判断的内容打印到日志文件中.

​ 使用log.SetFlags()进行设置日志输出