使用 nsenter 从Kubernetes Node 进入容器网络 Namespace
记录一下使用 nsenter 进入容器的 network namespace 中抓包。在 TroubleShooting 的过程中可能是需要这个方法的。
进入容器ns的步骤
选中一个poddefault haydenarch-68865d5b56-cblc6 ● 1/1 Running 0 172.31.48.162 ip-172-31-53-61.cn-north-1.compute.internal
在节点上找到这个pod的容器id : 02182f3e9137[root@ip-172-31-53-61 ~]$ nerdctl ps| grep archlinux
02182f3e9137 1234567.dkr.ecr.cn-north-1.amazonaws.com.cn/archlinux:latest "sleep infinity" 23 hours ago Up k8s://default/arch-68865d5b56-cblc6/arch
查找这个容器id的进程pid。[root@ip-172-31-53-61 ~]$ nerdctl inspect 02182f3e9137 | grep -i pid
"Pid": 10306,
nsenter 命令进入容器的名称空间。 [root@ip-172-31-53-61 ~]$ nsenter -t 10306 -n
[root@ip-172-31-53-61 ~]$ ip ad
3: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default
link/ether 22:fb:14:7b:91:22 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.31.48.162/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20fb:14ff:fe7b:9122/64 scope link
valid_lft forever preferred_lft forever
对比容器里面执行命令的结果: [root@haydenarch-68865d5b56-cblc6 /]$ ip ad
3: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default
link/ether 22:fb:14:7b:91:22 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.31.48.162/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20fb:14ff:fe7b:9122/64 scope link
valid_lft forever preferred_lft forever
这时候就可以使用节点上面的工具来进行抓包了。
测试可以看到在容器内部是没有tcpdump命令的.
[root@haydenarch-68865d5b56-cblc6 /]$ tcpdump
bash: tcpdump: command not found
在容器内发出一个ping包 。
[root@haydenarch-68865d5b56-cblc6 /]$ ping www.bing.com -c 1
PING a-0001.a-msedge.net (13.107.21.200) 56(84) bytes of data.
64 bytes from 13.107.21.200 (13.107.21.200): icmp_seq=1 ttl=102 time=80.6 ms
--- a-0001.a-msedge.net ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 80.608/80.608/80.608/0.000 ms
在节点上面进入容器的名称空间,使用tcpdump抓包。
[root@ip-172-31-53-61 ~]$ tcpdump -i any -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:09:18.172140 IP 172.31.48.162.46458 > 10.100.0.10.domain: 22082+ A? www.bing.com.default.svc.cluster.local. (56)
09:09:18.172181 IP 172.31.48.162.46458 > 10.100.0.10.domain: 59743+ AAAA? www.bing.com.default.svc.cluster.local. (56)
09:09:18.172406 IP 10.100.0.10.domain > 172.31.48.162.46458: 59743 NXDomain*- 0/1/0 (149)
09:09:18.172470 IP 10.100.0.10.domain > 172.31.48.162.46458: 22082 NXDomain*- 0/1/0 (149)
09:09:18.172513 IP 172.31.48.162.51210 > 10.100.0.10.domain: 59281+ A? www.bing.com.svc.cluster.local. (48)
09:09:18.172533 IP 172.31.48.162.51210 > 10.100.0.10.domain: 43411+ AAAA? www.bing.com.svc.cluster.local. (48)
09:09:18.172635 IP 10.100.0.10.domain > 172.31.48.162.51210: 43411 NXDomain*- 0/1/0 (141)
09:09:18.172707 IP 10.100.0.10.domain > 172.31.48.162.51210: 59281 NXDomain*- 0/1/0 (141)
09:09:18.172743 IP 172.31.48.162.36420 > 10.100.0.10.domain: 41442+ A? www.bing.com.cluster.local. (44)
09:09:18.172773 IP 172.31.48.162.36420 > 10.100.0.10.domain: 6893+ AAAA? www.bing.com.cluster.local. (44)
09:09:18.172947 IP 10.100.0.10.domain > 172.31.48.162.36420: 41442 NXDomain*- 0/1/0 (137)
09:09:18.172985 IP 10.100.0.10.domain > 172.31.48.162.36420: 6893 NXDomain*- 0/1/0 (137)
09:09:18.173030 IP 172.31.48.162.54253 > 10.100.0.10.domain: 9603+ A? www.bing.com.cn-north-1.compute.internal. (58)
09:09:18.173053 IP 172.31.48.162.54253 > 10.100.0.10.domain: 61573+ AAAA? www.bing.com.cn-north-1.compute.internal. (58)
09:09:18.173130 IP 10.100.0.10.domain > 172.31.48.162.54253: 9603 NXDomain* 0/1/0 (173)
09:09:18.173863 IP 10.100.0.10.domain > 172.31.48.162.54253: 61573 NXDomain 0/1/0 (173)
09:09:18.173893 IP 172.31.48.162.49537 > 10.100.0.10.domain: 64334+ A? www.bing.com. (30)
09:09:18.173941 IP 172.31.48.162.49537 > 10.100.0.10.domain: 31567+ AAAA? www.bing.com. (30)
09:09:18.174269 IP 10.100.0.10.domain > 172.31.48.162.49537: 64334 5/0/0 CNAME www-www.bing.com.trafficmanager.net., CNAME cn-bing-com.cn.a-0001.a-msedge.net., CNAME a-0001.a-msedge.net., A 13.107.21.200, A 204.79.197.200 (311)
09:09:18.174345 IP 10.100.0.10.domain > 172.31.48.162.49537: 31567 3/1/0 CNAME www-www.bing.com.trafficmanager.net., CNAME cn-bing-com.cn.a-0001.a-msedge.net., CNAME a-0001.a-msedge.net. (325)
09:09:18.174537 IP 172.31.48.162 > 13.107.21.200: ICMP echo request, id 45375, seq 1, length 64
09:09:18.255142 IP 13.107.21.200 > 172.31.48.162: ICMP echo reply, id 45375, seq 1, length 64
退出的方式直接使用exit即可, 就回到了host本身的ns里面。
源地址检查造成丢包的分析
问题网络访问路径:Client –> NLB –> Application Pod
特别的部分:NLB 开启了保留源地址就意味着 NLB 在转发网络流量的时候不会改变数据包五元组内的SourceIP, 这时候对于后端的Pod和节点来说, 收到的数据包的ip地址来源直接是Client 的IP 地址, 这会导致所有的流量其实都是来自于VPC之外的。 NLB在这其中变成了一个透明代理。从 NLB 发到后端application pod 中的流量会有偶尔timeout的情况, 并不是所有的请求都会timeout ,从客户端抓包显示tcp握手的时候就没有成功, 第一个syn包出去就一直没有回复,然后继续重发等待。 由于后端的pod比较多, 并且nlb在四层做了负载均衡,很难定位到某次的请求具体到了哪个后端pod上面。
写下这些的时候我已经知道了问题的答案是由于 VPC CNI 的一个 env , AWS_VPC_K8S_CNI_EXTERNALSNAT 会指定是否做 SNAT, 比较早的版本, cni 插件没有对 SNAT 在iptables上面进行标记和处理, 这样会导致 过不了操作系统的网络报文地址校验, 进而导致丢包。关于 linux 的数据包源地址校验,也就是 rp_filter 的参数, 在EKS中默认都是1 。
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
rp_filter参数用于控制系统是否开启对数据包源地址的校验。rp_filter参数有三个值,0、1、2,具体含义: 0:不开启源地址校验。 1:开启严格的反向路径校验。对每个进来的数据包,校验其反向路径是否是最佳路径。如果反向路径不是最佳路径,则直接丢弃该数据包。 2:开启松散的反向路径校验。对每个进来的数据包,校验其源地址是否可达,即反向路径是否能通(通过任意网口),如果反向路径不同,则直接丢弃该数据包。
默认的情况下, 这个参数是1, 因此 :数据包发到了eth1网卡,如果这时候开启了rp_filter参数,并配置为1,则系统会严格校验数据包的反向路径。从路由表中可以看,返回响应时数据包要从eth0网卡出,即请求数据包进的网卡和响应数据包出的网卡不是同一个网卡,这时候内核会判断该反向路径不是最佳路径,而直接丢弃该请求数据包。
确认是否存在这个原因的丢包From : https://tldp.org/HOWTO/Adv-Routing-HOWTO/lartc.kernel.rpf.html
定位是否存在丢包两个设置都是关闭的状态
~# cat /proc/sys/net/ipv4/conf/enp3s0/rp_filter
0
~# cat /proc/sys/net/ipv4/conf/enp3s0/log_martians
0
rp_filter导致的丢包数量可以通过netstat命令查看
netstat -s | grep IPReversePathFilter
让内核输出日志到 /var/log/messages 或者 dmesg
sysctl -w net.ipv4.conf.all.log_martians=1
输出的结果大概是这样的。
IPv4: martian source 10.185.203.166 from 10.185.203.172, on dev eth1
ll header: 00000000: fa 16 3e dd 7b bb fa 16 3e 28 00 60 08 00
排查路由表 和 Iptables当 AWS_VPC_K8S_CNI_EXTERNALSNAT 为 False 的时候查看节点的路由rule:
[root@ip-172-31-53-61 ~]# ip rule ls
0: from all lookup local
512: from all to 172.31.49.222 lookup main
512: from all to 172.31.52.222 lookup main
512: from all to 172.31.59.203 lookup main
512: from all to 172.31.61.61 lookup main
512: from all to 172.31.49.246 lookup main
512: from all to 172.31.58.47 lookup main
512: from all to 172.31.53.79 lookup main
512: from all to 172.31.63.97 lookup main
512: from all to 172.31.53.74 lookup main
512: from all to 172.31.54.196 lookup main
512: from all to 172.31.51.218 lookup main
512: from all to 172.31.63.248 lookup main
512: from all to 172.31.54.200 lookup main
512: from all to 172.31.51.108 lookup main
512: from all to 172.31.56.137 lookup main
512: from all to 172.31.54.85 lookup main
512: from all to 172.31.51.82 lookup main
512: from all to 172.31.57.72 lookup main
512: from all to 172.31.59.200 lookup main
512: from all to 172.31.58.18 lookup main
512: from all to 172.31.55.235 lookup main
512: from all to 172.31.48.162 lookup main
512: from all to 172.31.60.128 lookup main
512: from all to 172.31.50.246 lookup main
512: from all to 172.31.61.216 lookup main
512: from all to 172.31.55.130 lookup main
512: from all to 172.31.49.208 lookup main
512: from all to 172.31.55.135 lookup main
512: from all to 172.31.50.208 lookup main
512: from all to 172.31.63.121 lookup main
512: from all to 172.31.52.205 lookup main
512: from all to 172.31.52.71 lookup main
512: from all to 172.31.51.7 lookup main
512: from all to 172.31.53.238 lookup main
1024: from all fwmark 0x80/0x80 lookup main
1536: from 172.31.56.137 lookup 2
1536: from 172.31.54.85 lookup 2
1536: from 172.31.51.82 lookup 2
1536: from 172.31.57.72 lookup 2
1536: from 172.31.59.200 lookup 2
1536: from 172.31.58.18 lookup 2
1536: from 172.31.55.235 lookup 2
1536: from 172.31.48.162 lookup 2
1536: from 172.31.60.128 lookup 2
1536: from 172.31.50.246 lookup 2
1536: from 172.31.61.216 lookup 2
1536: from 172.31.55.130 lookup 2
1536: from 172.31.49.208 lookup 2
1536: from 172.31.55.135 lookup 2
1536: from 172.31.50.208 lookup 3
1536: from 172.31.63.121 lookup 3
1536: from 172.31.52.205 lookup 3
1536: from 172.31.52.71 lookup 3
1536: from 172.31.51.7 lookup 3
1536: from 172.31.53.238 lookup 3
32766: from all lookup main
32767: from all lookup default
路由表 main:
[root@ip-172-31-53-61 ~]# ip r s table main
default via 172.31.48.1 dev eth0
169.254.169.254 dev eth0
172.31.48.0/20 dev eth0 proto kernel scope link src 172.31.53.61
172.31.48.162 dev enicfd09b318e8 scope link
172.31.49.208 dev eni3512a649bfb scope link
172.31.49.222 dev eni8cf9e51b58a scope link
172.31.49.246 dev eni9f41e641d45 scope link
172.31.50.208 dev eniffd28bfda2d scope link
172.31.50.246 dev eni1abad8afd57 scope link
172.31.51.7 dev eni76e381844d3 scope link
172.31.51.82 dev eni524077fd828 scope link
172.31.51.108 dev eni08e24263c30 scope link
172.31.51.218 dev enicb4edb90122 scope link
172.31.52.71 dev eni61a9554ce92 scope link
172.31.52.205 dev eniabe0e0a95e5 scope link
172.31.52.222 dev eni60eac028c5b scope link
172.31.53.74 dev enibecb9c399f8 scope link
172.31.53.79 dev eni6c5800d82af scope link
172.31.53.238 dev eni5a413534f4e scope link
172.31.54.85 dev eni2acd4947ff6 scope link
172.31.54.196 dev eni54f6d6a6254 scope link
172.31.54.200 dev eni47a45758006 scope link
172.31.55.130 dev ...
安装 headscale 建立自己的 Tailnet
Tailscale 虽然是 mesh 的网络模式, 可以点对点的连接所有设备, 能直连会尽量直接连接, 然鹅还是需要一个默认的 server 来进行服务发现和临时中转流量.
那么大概的配置框架就已经出现了, 一个服务发现中心, 和多个不同的客户端.开始的时候直接使用的 tailscale + github 账户登录的方式使用, 然后发现 github 账户直接托管的中心服务不能关闭国外的中转服务器, 这就比较难受, 本来可以直通的线路走了国外的中转不稳定, 会断, 最后还是走国内的便宜云服务器自己维护了一个开源的 headscale 作为中心服务.
安装 Headscaleheadscale 官方文档现在的 headscale 容器镜像的是有问题的, 不太好用, 还得花时间修。
Update: 看起来现在是修复了, 并且费点儿劲可以用起来, 但是不确定稳定性如何.
我准备了这些:
域名 和 域名证书
一台 Debian 的云服务器
公网 ip 地址
具体的安装步骤就是按照官方网站走下来就可以了.一些条件:需要注意的地方就是备案, 不备案会导致无法使用 443.那么需要在tailscale的配置文件中指定端口, 让 tailscale 监听在一个不常用的端口上.
因为没有写清楚 server 的地址和端口, 折腾了一天… 一度怀疑是不是换端口也不行, 必须备案 …
配置文件headscale ~$ vim /etc/headscale/config.yaml
# 大约在配置文件的 13行左右.
server_url 这个字段需要写成 https://YOURHOSTNAME.YOURDOMAIN:PORT 就可以了.
大约在配置文件的77行左右, 会有一个 DEPR 集成的服务, 开启这个服务之后, 可以使用当前的服务器直接作为DEPR中转节点.
77 derp:
78 server:
79 # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
80 # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
81 enabled: true
绑定证书的位置在大约 151行之后, 我使用自己签发的证书, 就是直接配置 182 183 两行的参数就行.
181 ## Use already defined certificates:
182 tls_key_path: /path/to/cert.key
183 tls_cert_path: /path/to/cert.pem
关闭了官方的DERP服务列表:
98 # List of externally available DERP maps encoded in JSON
99 #urls:
100 # - https://controlplane.tailscale.com/derpmap/default
101
102 # Locally available DERP map files encoded in YAML
103 #
104 # This option is mostly interesting for people hosting
105 # their own DERP servers:
106 # https://tailscale.com/kb/1118/custom-derp-servers/
107 #
108 # paths:
109 # - /etc/headscale/derp-example.yaml
110 paths: []
关闭了 OverwriteDNS, 总是会尝试将客户的默认DNS服务器重写为 TailNet DNS.
204 dns_config:
205 # Whether to prefer using Headscale provided DNS or use local.
206 override_local_dns: false
安装tailscale客户端按照安装文档直接安装, 不一样的发行版(是的, Windows 也是 Linux 发行版) 安装方式不同, 基本上启动之后都能用, 完成度非常高.
注册节点的命令节点注册命令记录.
sudo tailscale up --accept-dns=false --advertise-exit-node --advertise-routes=192.168.31.0/24 --login-server=https://YOURHOSTNAME.YOURDOMAIN:PORT --accept-routes
# 也可以是:
sudo tailscale up --accept-dns=false --advertise-exit-node --login-server=https://YOURHOSTNAME.YOURDOMAIN:PORT --accept-routes
# 或者是:
sudo tailscale up --accept-dns=false --login-server=https://YOURHOSTNAME.YOURDOMAIN:PORT --accept-routes
# 最后是:
sudo tailscale up --accept-dns=true --login-server=https://YOURHOSTNAME.YOURDOMAIN:PORT --accept-routes
这个命令执行完毕之后, 会返回一个网页, 网页打开里面有一个命令, 复制命令去 headscale 服务器的命令行(bash)里面执行一下,节点就注册进来了.
更新运行中的 Tailscale 客户端的设置最近需要更新我的一个节点, 发布 VPC 内的 CIDR 块, 这个设置之前没有 advertise-route 参数进行更新 。这个实例在我的默认VPC里面, 这样的话这个实例就直接变成了这个VPC内的IGW, 流量会通过这个实例发送到VPC内, 可以直接将这个网络范围内的DNS指向VPC内的 .2 Resolver, 甚至感觉可以直接在家用 EFS 这类的东西了.
当然, 如果节点需要变动之前运行的参数, 是需要给出和之前一致的参数, 然后添加 或者 变更其中的一部分的.
sudo tailscale up --accept-dns=false --advertise-exit-node --login-server=https://YOURHOSTNAME.YOURDOMAIN:PORT --accept-routes --advertise-routes=172.31.0.0/16
问题汇总查看当前客户端的网络状况
╰─>$ tailscale netcheck
Report:
* UDP: true
* IPv4: yes, PUBLIC_IP:35941
* IPv6: no, but OS has support
* MappingVariesByDestIP: false
* PortMapping:
* CaptivePortal: false
* Nearest DERP: Headscale Embedded DERP
* DERP latency:
- headscale: 24.3ms (Headscale Embedded DERP)
测试ping:
╰─>$ tailscale ping --until-direct -c 0 100.64.0.9
pong from home-SOME_NODE (100.64.0.9) via PUBLIC_IP:50177 in 6ms
tailscale 结合 Sunshine 串流
既然 EC2 显卡都已经能用了, 为啥不能直接启动一个 steam 呢? 于是。。。
安装的步骤比较简单:
# Sunshine 用来作为 stream hosting
sudo pacman -S sunshine
# Steam 以及 Steam-navtive 是 steam 的runtime, ttf 是为了可以正常的显示中文字体, 好像字体上面是最常见的问题, 比如显示出来是一堆方块。
sudo pacman -S steam-native-runtime
sudo pacman -S steam ttf-liberation
这些安装完成之后我自己直接 drun 去调用 steam 就可以了。
启动使用的desktop 文件叫作 steam(native) 启动之后登录, 然后可以正常下载游戏了。
默认可以下载的游戏都是原生支持linux的, 不支持的可以在steam的设置里面打开proton兼容, 之后steam的界面上就不会区分任何平台了。
手柄支持手柄默认不能传递到hosting, sunshine 的启动日志里面有报错:
[2023:12:27:21:35:33]: Error: Could not create Sunshine Gamepad: Permission denied
[2023:12:27:21:35:33]: Error: Could not create Sunshine Gamepad: Permission denied
给予这个报错的搜索结果有两个:
添加当前的用户到 input 组里面 usermod -a -G input ec2-user
# checking
groups ec2-user
第二个方案是, 确保自己的内核装载 uinput 模块。 modprobe uinput
同时还在文档里面找到了另一个地方,需要配置一个 udev ruleecho 'KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"' | \
sudo tee /etc/udev/rules.d/85-sunshine.rules
或者这文档 以及这个Issue
我目前不太确定具体哪个是正确的, 因为重启这个实例的时候把tailscale给玩儿没了.. 现在连不上了…闹心
Redis 笔记
ElastiCache主要概念
ElastiCache nodesA node is the smallest building block of an ElastiCache deployment.node is a fixed-size chunk of secure, network-attached RAM.总结来说, 就是ec2实例上面跑了相同版本的Engine for Redis。
ElastiCache for Redis shards
A Redis shard (called a node group in the API and CLI) is a grouping of one to six related nodes. A Redis (cluster mode disabled) cluster always has one shard.Redis (cluster mode enabled) clusters can have up to 500 shards, with your data partitioned across the shards.
Shard 是多个 Nodes 的集合, 或者叫作节点组. 一个Shard包括的节点有不同的角色, 一个Primary 和 最多5个 Replica.
ElastiCache for Redis clustersA Redis cluster is a logical grouping of one or more ElastiCache for Redis shards. Data is partitioned across the shards in a Redis (cluster mode enabled) cluster.集群模式关闭, 1 Cluster – 1 Shard – 1 - 6 Nodes: 1 Primary and 5 Nodes集群模式开启, 1 Cluster – 500 Shard – 1 - 6 Nodes: 1 Primary Per Shard
ElastiCache for Redis replicationRedis (cluster mode disabled) clusters support one shard (in the API and CLI, called a node group).Redis (cluster mode enabled) clusters can have up to 500 shards, with your data partitioned across the shards.
每个Replica都是Primary中全部数据的复制。 Replica使用异步的方式进行与Primary的数据同步。
第一次 psync2 全量复制所有内存当前存储的数据, 后续使用redis的增量复制。
AWS Regions and availability zones目前中国区不能使用 GlobalStore, 并且Region之间也是无法相互同步数据的。 在不同的az 之间可以做高可用来降低停机的时间。
ElastiCache for Redis endpointsAn endpoint is the unique address your application uses to connect to an ElastiCache node or cluster.
Redis 禁用集群模式的单节点端点单节点的集群端点用于读取和写入. In one word, Single Primary, read and write at one point.用这个节点的 Endpoint 即可。
Redis 禁用集群模式的多节点端点多节点有两个不同的端点, Primary 端点总是连接到Primary 节点,故障切换会切换这个dns指向的后端。Reader Endpoint 在所有的 Replica节点之间分流Connection 用来提供读取行为。
用控制台上面的 Primary Endpoint 和 Reader Endpoint
Redis 启用集群模式的端点集群模式下, 只是配置一个endpoint, 但是连接到Endpoint之后, 客户端可以发现所有的主节点和从节点。
** 用Configuration Endpoint 可以找到集群内部的每一个 Primary 和 Replica节点 **
ElastiCache parameter groupsCache parameter groups are an easy way to manage runtime settings for supported engine software. Parameters are used to control memory usage, eviction policies, item sizes, and more.
简单来说, 创建每一个配置文件在aws的控制台上, 可以调整一部分Redis的参数, 然后可能在集群内可以实时生效, 也可能需要触发一次Failover才能生效。elasticache的参数管理
通常来说, 改动了参数组中的几个参数可能会需要重启节点:
activerehashing
databases
ElastiCache for Redis securityPENDING… Maybe follow offical guide.
ElastiCache security groups创建集群的时候需要指定一个安全组, 需要放行 6379 port, DONE。
ElastiCache subnet groups子网组是运行 Redis 的所有子网的集合, 创建一个子网, 让托管的节点的把ENI放在这个子网里面, 私有子网。
ElastiCache for Redis backups备份特定时间的数据, 可以使用这个用来还原成新的集群, 或者是创建一个集群的种子, 备份中包括所有的data, 和一部分集群的metadata。bgsave 或者 forkless save, 这两个取决于是否有足够的内存空间, 当空间充足的时候使用的默认的 bgsave, 但是肯定的是, bhsave 会有性能的开销,所以最好是使用副本节点来创建备份或者快照。对于forkless本身是另一个机制,但是forkless会尝试delay 写入的延迟,从而确保不会积累过多的change 导致内存压力过大失败。
ElastiCache eventsPENDING… Maybe follow offical guide.
Redis 缓存穿透, 击穿 和 雪崩穿透主要是指异常的查询请求, 缓存未命中的场景下直接访问后端, 后端承载了大量请求导致的崩溃。目前看到需要两个条件:
数据在缓存层未命中。
大量的请求转移到了后端。
请求的数据可能在缓存层 以及 后端都不存在。
避免的方法可能有:
在redis 前面添加一个 BloomFilter, 在请求进来的时候进行过滤, 对于异常的请求直接拒绝或者返回一个NULL。
提前缓存一部分数值为 NULL 的数据, 在缓存层直接接下这些请求。这个本身是有点问题的。
击穿这个概念是指的 少部分热点数据被大量的查询时候, 数据突然从缓存中消失, 可能是过期也可能删除等等, 这样有大量的相同请求发送到后端。解决方案:
设置部分数据永远不过期。
后端进行加分布式锁。
雪崩批量的热数据过期, 这时候大部分的请求可能还在继续尝试查询不同的数据,直接将这些请求发送到了后端的数据库, 数据库崩了。解决方案:
创建多个实例, 和副本来提高可用性。
后端加锁限流。
调整过期时间, 让不同的数据过期的时间错开,防止批量的key 相同的时间过期。
总结起来就是, 避免缓存在特定的场景下失效, 想各种方法保护缓存的可用性。
More NoteCOB: Client Output Buffer, Primary 向 Replica 同步数据使用, Max Memory 没有计算这部分的内存, 使用的是Redis引擎之外的内存(os管理的内存)。
Policy : LRU 不严格, 随机选择三个。maxmemory-sample: 3, 可以调大。 sample越大, 信号的时间越长。
Reclaim策略里面, 每秒扫描200个key, 如果数据量比较大的话, Redis会进入loop阶段, 反复尝试Reclaim到25% 以下。
可以尝试使用 scan 命令扫描全部的数据, 遍历所有的key,这样会触发lazyway主动进行回收。扫描的指令:
scan 0 match * count 20000
LRU vs LFU
为了保持主从一致, primary 上过期或者删除的key, 会同步发送一个显式的 delete 指令, 这个会统计在replica的settypecmd。
snapshot里面的数据在恢复的时候,会检查key 的ttl , 如果超过会直接删除。在Redis内存与物理内存mapping由操作系统的虚拟内存管理器 和 指定的内存分配器进行处理。
关于Info指令的所有参数的解释:https://redis.io/commands/info/
localhost:6379> info memory
# Memory
used_memory:938464
used_memory_human:916.47K # Redis 存储数据的使用量
used_memory_rss:10747904
used_memory_rss_human:10.25M # Redis 常住内存集的用量
used_memory_peak:1134048
used_memory_peak_human:1.08M # Redis 的内存峰值
used_memory_peak_perc:82.75%
used_memory_overhead:888488
used_memory_startup:865904
used_memory_dataset:49976
used_memory_dataset_perc:68.88%
allocator_allocated:1479168 # 内存分配器已经分配的量
allocator_active:1601536
allocator_resident:4575232
total_system_memory:8182751232
total_system_memory_human:7.62G # 系统内存的总量
used_memory_lua:31744
used_memory_vm_eval:31744
used_memory_lua_human:31.00K # Lua 引擎的内存使用量
used_memory_scripts_eval:0
number_of_cached_scripts:0
number_of_functions:0
number_of_libraries:0
used_memory_vm_functions:32768
used_memory_vm_total:64512
used_memory_vm_total_human:63.00K
used_memory_functions:184
used_memory_scripts:184
used_memory_scripts_human:184B
maxmemory:0 # Max Memory 当前的配置
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.08
allocator_ ...
CFS 调度器资料
https://docs.kernel.org/scheduler/sched-design-CFS.htmlhttp://arthurchiao.art/blog/linux-cfs-design-and-implementation-zh/#11-cfs%E8%BF%9B%E7%A8%8Btask%E7%9A%84%E5%85%AC%E5%B9%B3%E8%B0%83%E5%BA%A6https://danluu.com/cgroup-throttling/https://heapdump.cn/article/4235306
追踪数据包经过的iptables规则
https://stackoverflow.com/questions/47645859/meaning-of-modules-instances-in-proc-modules
Lsmod命令基于manpage的说明, 这个命令的数据来源是 : /proc/modules
[root@centos ~]# lsmod
Module Size Used by
iptable_nat 12875 0
nf_conntrack_ipv4 19149 1
nf_defrag_ipv4 12729 1 nf_conntrack_ipv4
nf_nat_ipv4 14115 1 iptable_nat
nf_nat 26583 1 nf_nat_ipv4
nf_conntrack 143360 3 nf_nat,nf_nat_ipv4,nf_conntrack_ipv4
iptable_filter 12810 0
nfit 59735 0
libnvdimm 163620 1 nfit
iosf_mbi 15582 0
crc32_pclmul 13133 0
ghash_clmulni_intel 13273 0
aesni_intel 189456 0
ppdev 17671 0
lrw 13286 1 aesni_intel
gf128mul 15139 1 lrw
glue_helper 13990 1 aesni_intel
ablk_helper 13597 1 aesni_intel
cryptd 21190 3 ghash_clmulni_intel,aesni_intel,ablk_helper
parport_pc 28205 0
parport 46395 2 ppdev,parport_pc
i2c_piix4 22401 0
pcspkr 12718 0
ip_tables 27126 2 iptable_filter,iptable_nat
xfs 1014152 1
libcrc32c 12644 3 xfs,nf_nat,nf_conntrack
crct10dif_pclmul 14307 0
crct10dif_common 12595 1 crct10dif_pclmul
crc32c_intel 22094 1
nvme 32382 1
serio_raw 13434 0
ena 96895 0
nvme_core 63547 3 nvme
sunrpc 366617 1
/proc/modules 的输出结果
[root@centos ~]# cat /proc/modules
iptable_nat 12875 0 - Live 0xffffffffc0661000
nf_conntrack_ipv4 19149 1 - Live 0xffffffffc065b000
nf_defrag_ipv4 12729 1 nf_conntrack_ipv4, Live 0xffffffffc05fd000
nf_nat_ipv4 14115 1 iptable_nat, Live 0xffffffffc05f4000
nf_nat 26583 1 nf_nat_ipv4, Live 0xffffffffc0603000
nf_conntrack 143360 3 nf_conntrack_ipv4,nf_nat_ipv4,nf_nat, Live 0xffffffffc0634000
iptable_filter 12810 0 - Live 0xffffffffc05dd000
nfit 59735 0 - Live 0xffffffffc066d000
libnvdimm 163620 1 nfit, Live 0xffffffffc060b000
iosf_mbi 15582 0 - Live 0xffffffffc05ed000
crc32_pclmul 13133 0 - Live 0xffffffffc05e5000
ghash_clmulni_intel 13273 0 - Live 0xffffffffc059e000
aesni_intel 189456 0 - Live 0xffffffffc05ad000
ppdev 17671 0 - Live 0xffffffffc05a4000
lrw 13286 1 aesni_intel, Live 0xffffffffc0575000
gf128mul 15139 1 lrw, Live 0xffffffffc0590000
glue_helper 13990 1 aesni_intel, Live 0xffffffffc0570000
ablk_helper 13597 1 aesni_intel, Live 0xffffffffc0418000
cryptd 21190 3 ghash_clmulni_intel,aesni_intel,ablk_helper, Live 0xffffffffc0569000
parport_pc 28205 0 - Live 0xffffffffc0596000
parport 46395 2 ppdev,parport_pc, Live 0xffffffffc0583000
i2c_piix4 22401 0 - Live 0xffffffffc057c000
pcspkr 12718 0 - Live 0xffffffffc0466000
ip_tables 27126 2 iptable_nat,iptable_filter, Live 0xffffffffc045e000
xfs 1014152 1 - Live 0xffffffffc0470000
libcrc32c 12644 3 nf_nat,nf_conntrack,xfs, Live 0xffffffffc0459000
crct10dif_pclmul 14307 0 - Live 0xffffffffc0438000
crct10dif_common 12595 1 crct10dif_pclmul, Live 0xffffffffc046b000
crc32c_intel 22094 1 - Live 0xffffffffc041d000
nvme 32382 1 - Live 0xffffffffc040f000
serio_raw 13434 0 - Live 0xffffffffc0407000
ena 96895 0 - Live 0xffffffffc0440000
nvme_core 63547 3 nvme, Live 0xffffffffc0427000
sunrpc 366617 1 - Live 0xffffffffc03ac000
调试 Iptables 的方法Kubernetes 里面大量的使用了iptables 规则的各种转换,可以使用iptables的trace功能进行追踪, 查看具体经过了哪些链表。
iptables -t raw -A PREROUTING -p tcp -s 172.31.47.174/32 -j TRACE
or
iptables -t raw -A PREROUTING -p tcp -d 172.31.71.167 --dport 8090 -j TRACE
modprobe ipt_LOG ip6t_LOG nfnetlink_log
modprobe nf_log_ipv4
xtables-monitor --trace
完成之后就可以在 message 里面看到记录了。
kern :warn : [Thu Sep 21 15:01:24 2023] TRACE: raw:PREROUTING:policy:2 IN=eth3 OUT= MAC=02:19:e6:40:fc:c8:02:55:96:c9:21:66:08:00 SRC=172.31.47.174 DST=172.31.55.27 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=26039 DF PROTO=TCP SPT=22896 DPT=8090 SEQ=1763415057 ACK=0 WINDOW=62727 RES=0x00 SYN URGP=0 OPT (020423010402080ADBFD1C1B0000000001030307)
kern :warn : [Thu Sep 21 15:01:24 2023] TRACE: mangle:PREROUTING:policy:4 IN=eth3 OUT= MAC=02:19:e6:40:fc:c8:02:55:96:c9:21:66:08:00 SRC=172.31.47.174 DST=172.31.55.27 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=26039 DF PROTO=TCP SPT=22896 DPT=8090 SEQ=1763415057 ACK=0 WINDOW=62727 RES=0x00 SYN URGP=0 OPT (020423010402080ADBFD1C1B0000000001030307)
kern :warn : [Thu Sep 21 15:01:24 2023] TRACE: nat:PREROUTING:rule:1 IN=eth3 OUT= MAC=02:19:e6:40:fc:c8:02:55:96:c9:21:66:08:00 SRC=172.31.47.174 DST=172.31.55.27 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=26039 DF PROTO=TCP SPT=22896 DPT=8090 SEQ=1763415057 ACK=0 WINDOW=62727 RES=0x00 SYN URGP=0 OPT (020423010402080ADBFD1C1B0000000001030307)
kern :warn : [Thu Sep 21 15:01:24 2023] TRACE: nat:KUBE-SERVICES:return:45 IN=eth3 OUT= MAC=02:19:e6:40:fc:c8:02:55:96:c9:21:66:08:00 SRC=172.31.47.174 DST=172.31.55.27 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=26039 DF PROTO=TCP SPT=22896 DPT=809 ...
Iostat 参数说明
iostat - Report Central Processing Unit (CPU) statistics and input/output statistics for devices and partitions.
指标的解释说明如下:
rrqm/s - wrqm/s 两个看的是的merge的请求数量, 表示发送给驱动程序并被驱动程序合并的请求数量,表示有没有进行合并,这也表示系统将随机IO请求合并成连续以提高性能。
r/s - w/s IO读写的请求数量IOPS, 发送给磁盘设备的请求数。
rKB/s - wKB/s 吞吐量, 可以使用 -m 转换成MB/s, 设备的传输数据量的吞吐量信息。
avgrq-sz 平均请求大小, 也就是IO size 的大小。单位是扇区(512B)。
rareq-sz - wareq-sz 新版本的iostat已经是这两个指标了, 这两个指标单位是 KB.
avgqu-sz 在驱动队列和设备队列中或活跃的平均请求数量。 单位是 个。
await 这个指标记录的总的延迟, 新的版本也包括 rw 两类请求的延迟。 延迟单位是 ms ,通常不应该超过10ms.
磁盘读取相关
r/s: 每秒完成的读请求数
rkB/s: 每秒读取的数据量(KB)
rrqm/s: 每秒这个设备相关的读取请求有多少被合并
%rrqm: 被合并的读取请求所占的百分比
r_await: 读取请求的平均响应时间(毫秒)
rareq-sz: 平均每次读取请求的大小(扇区数)
磁盘写入相关
w/s: 每秒完成的写请求数
wkB/s: 每秒写入的数据量(KB)
wrqm/s: 每秒这个设备相关的写入请求有多少被合并
%wrqm: 被合并的写入请求所占的百分比
w_await: 写入请求的平均响应时间(毫秒)
wareq-sz: 平均每次写入请求的大小(扇区数)
磁盘总体
d/s: 设备每秒完成的丢弃(discard)请求数(经过合并后)。丢弃请求允许存储设备回收已删除块占用的存储空间。
dkB/s: 每秒为设备丢弃的数据量(KB)。
drqm/s: 每秒合并到设备排队的丢弃请求数。
%drqm: 丢弃请求在发送到设备之前合并在一起的百分比。
d_await: 向要服务的设备发出丢弃请求的平均时间(毫秒)。
dareq-sz: 向设备发出的丢弃请求的平均大小(KB)。
其他
f/s: 每秒完成的刷新(flush)请求数(经过合并后)。这统计了磁盘执行的刷新请求数量。对于分区,不跟踪刷新请求。在合并之前,刷新操作被计为写入操作。
f_await: 完成操作的平均等待时间(以毫秒为单位)。这指的是发送到设备的刷新(flush)请求平均被服务的时间。块层会合并刷新请求,一次最多执行一个。因此,刷新操作可能会延长两倍时间:等待当前刷新请求,然后执行它,接着等待下一个。
aqu-sz: 平均请求队列长度
%util: 设备利用率百分比
以3秒的间隔显示系统磁盘设备的IO使用状况和扩展统计数据.
iostat -dx 3
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
nvme0n1 2147.33 34842.67 0.00 0.00 0.46 16.23 0.33 1.33 0.00 0.00 1.00 4.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1.00 100.00
每隔 5 秒显示一次系统 CPU(c)、设备利用率(d)、分区统计数据(p)以及扩展 IO 统计数据(x)。
iostat -dcpx 5
Linux 6.4.10-arch1-1 (arch.liarlee.site) 08/22/2023 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
5.23 0.00 2.05 0.01 0.01 92.71
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
nvme0n1 1.00 32.72 0.00 0.04 0.66 32.86 1.24 23.27 0.18 12.62 0.99 18.79 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.18
nvme0n1p1 1.00 32.72 0.00 0.04 0.66 32.86 1.24 23.27 0.18 12.62 0.99 18.79 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.18
监控数据来源: cat /proc/diskstats这些所有的指标都是 By Device 的, 与进程的部分无关,统计的是发送到设备或者发送到设备分区的请求。基于man page 中的描述, 这四个参数分别是: r/s The number (after merges) of read requests completed per second for the device. w/s The number (after merges) of write requests completed per second for the device. d/s The number (after merges) of discard requests completed per second for the device. f/s The number (after merges) of flush requests completed per second for the device. This counts flush requests executed by disks. Flush requests are not tracked for partitions. Before being merged, flush operations are counted as writes.
命令行参数的一部分解释-d 展示磁盘设备使用率的信息。-x 扩展显示更多的指标数据, 不添加这个参数不区分设备 读/写/磁盘/文件系统 这四个维度。-c 查看CPU统计的使用率指标。-p 磁盘分区的指标。-z 只是输出一些有IO的设备的统计信息。 性能之巅里面有写出这个参数。-t 来输出时间戳。
这个命令主要看如下的点:
看物理设备, 具体是那个设备上面有 IO 请求。
看 await,等待的时间长不长, 这里面的等待时间是从请求进入设备队列到请求返回成功的时间 , 通常情况下应该是在 10ms 以内, 尤其是 ssd。
看 aqu-sz, 按照 EBS 的规则,应该是每 1000 IOPS 队列数为 1 最合适。
综合看 IOPS, 块大小, 吞吐量, 使用率, 确认设备是不是达到了瓶颈。
最后切换工具定位具体是那个进程在大量的发送 IO 请求 ,大概可能的工具是 pidstat, htop , atop , sar 等等, 感觉工具还可能有 pm 的这部分工具。
vmstat 命令说明
命令说明vmstat 提供的信息是从硬件和物理参数的角度。vmstat 第一次的数据显示的是从上一次重启到现在的平均值,所以只能用来参考。标题内容就不在解释了,分别是 进程 , 内存, 交换 , IO, 系统 , 和 CPU。
详细参数如下: r - 等待运行的进程数量, 多少个进程在R状态, 并一直取得并占用CPU时间片。 b - Uninterreptable Sleep的进程数量, 有多少个处于D状态显示的进程, 通常代表有多少个进程正常等待IO资源。 swpd: VirtualMemory的值 (KB), 交换的使用量,如果未开启交换分区就会显示是 0。 这个指标和后面的 si so 是整体的, swpd 有用量, 那么si/so 就有数据, swpd 是 0, 那么永远不会有 si/so。 free: IdleMemory的值(KB), 完全可用的内存, 这里free的内存是 完全没有被分配的。total - buffer - cache - used 计算完了之后剩下的, 与 free 命令中的 free 字段是同样的含义。 buff: 被buffer使用的内存量(KB),被 buff 使用的内存空间。 cache: 被cache使用的内存量(KB), 被 cache 占用的内存空间, 这部分和buffer 一样, 是临时数据,在落盘后buffer 会被释放, cache可以直接被释放。 si: Swapin 内存从硬盘换入的数据量 (KB/s), 读取交换分区(disk)到 内存 的数据量 。 so:Swapout 内存交换到硬盘的数据量 (KB/s), 写入磁盘交换分区的数据量。 bi: blockin, 发送到块设备的块数量(blocks/s), 系统收到disk发送来的数据量, 也就是通常说的读磁盘数据。 bo: blockout , 从块设备接收的块数量(blocks/s), 系统写入disk的数据量, 也就是通常说的写磁盘数据。 in: 包括时钟在内的那每秒中断数。 cs: 进程上下文每秒切换的次数。 us:非内核代码使用的CPU百分比, 包括用户时间和Nice时间。 sy:内核代码使用的CPU时间百分比。 id: CPU的空闲时间百分比。 wa:等待IO操作花费的时间百分比。 这个容易误解的是, wa 其实cpu 是空闲的, 统计的方式是, 在收集数据的时候有多少个进程处于需要处理io或者等待处理io的状态, 当时那个时刻的百分比, 而实际上等待io的时间其实CPU没有做事, 所以在CPU的度量上, 这个时间的CPU是可以做其他事情的, 可以被其他需要进行计算的进程使用掉这部分时间。 st:虚拟化层操作花费的时间百分比。这个通常是指虚拟化层的限制。 这个指标如果有, 那么表示虚拟化层对cpu的使用进行了限制(EC2 T系列实例) 或者是 底层的资源并不完全满足需求而导致的争抢。 gu: Time spent running KVM guest code (guest time, including guest nice). , 这个是新添加的指标, 之前没有见过。 如果是KVM host os 上面这个指标还是比较有用的。
输出结果如下: ~ vmstat -w 1
--procs-- -----------------------memory---------------------- ---swap-- -----io---- -system-- ----------cpu----------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
2 0 1005492 42600 1328 1973356 4 7 77 312 1767 6 2 2 95 1 0 0
1 0 1005492 42652 1328 1973360 0 0 0 0 2519 3373 1 2 97 0 0 0
1 0 1005492 42652 1328 1973360 0 0 0 8 1001 1844 0 1 99 0 0 0
1 0 1005492 42652 1328 1973360 0 0 0 12 1056 1822 1 0 99 0 0 0
1 0 1005492 42652 1328 1973368 0 0 0 0 1308 2150 1 1 98 0 0 0
1 0 1005492 43156 1328 1973376 0 0 0 0 1394 2245 3 1 97 0 0 0
1 0 1005492 43156 1328 1973376 0 0 0 0 1125 1898 1 1 99 0 0 0
1 0 1005492 43408 1328 1973376 0 0 0 55 1229 2218 1 1 99 0 0 0
1 0 1005492 44948 1328 1973392 0 0 0 0 3544 5490 7 4 89 0 0 0
1 0 1005492 45228 1328 1973428 0 0 0 0 1410 2082 3 4 93 0 0 0分析指标的逻辑输出之后 先看前几次输出的 r 和 b。 r 有没有超过核心数; b 这里是不是有数据, 数据在运行命令的周期是不是一直存在, 数量有没有超过CPU核心数。变化的频率的幅度是什么样的。 例子: 总共观察10s , 每秒输出一次数据, 每秒都有 超过cpu 核心数的 不可中断进程, 那么这代表当前的操作系统可能存在大量io进程,被阻塞的IO进程比较多 。
然后看最后一列的CPU情况, id的数据是多少,如果这个时候id 比较小, 看 us/sy/wa ,cpu 把时间花费在了什么地方。通常的场景下, cpu 应该把时间尽可能的使用在 us 这个部分。 如果其他而部分比较多的就需要关注较多的那个部分了。
有交换就看看交换, 没有交换直接看内存相关, cache + free 总共有多少。如果内存用量是不是在oom 的边缘 ,然后再看 in/cs, 一个是硬中断次数, 一个是进程上下文切换次数, 这两个一个可能代表潜在的cpu被硬件事件终止, 另一个cpu忙于在进程之间反复横跳。 这些都可能指向当前系统的效率并不高, 或者潜在的问题。
命令示例 vmstat -m – 显示内核占用内存的分配情况。 vmstat -a – 将内存的使用量分为活动内存和非活动内存。 vmstat -n 2 10 – 展示vmstat的结果10次, 每两秒一次。
更多参考https://docs.oracle.com/cd/E19455-01/805-7229/6j6q8svh5/index.html
Kubectl Apply 报错 annotation Too long
重装 Prometheus operator 的时候报错, 提示 annotation 太长了,不能 apply
> kubectl apply -f ./setup
customresourcedefinition.apiextensions.k8s.io/alertmanagerconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/alertmanagers.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/podmonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/probes.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusrules.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/scrapeconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/thanosrulers.monitoring.coreos.com created
Warning: Detected changes to resource monitoring which is currently being deleted.
namespace/monitoring unchanged
Error from server (Invalid): error when creating "setup/0prometheusCustomResourceDefinition.yaml": CustomResourceDefinition.apiextensions.k8s.io "prometheuses.monitoring.coreos.com" is invalid: metadata.annotations: Too long: must have at most 262144 bytes
Error from server (Invalid): error when creating "setup/0prometheusagentCustomResourceDefinition.yaml": CustomResourceDefinition.apiextensions.k8s.io "prometheusagents.monitoring.coreos.com" is invalid: metadata.annotations: Too long: must have at most 262144 bytes
解决方案使用 Kubectl Create> kubectl create -f ./setup
customresourcedefinition.apiextensions.k8s.io/prometheuses.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusagents.monitoring.coreos.com created
Error from server (AlreadyExists): error when creating "setup/0alertmanagerConfigCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "alertmanagerconfigs.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/0alertmanagerCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "alertmanagers.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/0podmonitorCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "podmonitors.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/0probeCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "probes.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/0prometheusruleCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "prometheusrules.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/0scrapeconfigCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "scrapeconfigs.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/0servicemonitorCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "servicemonitors.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/0thanosrulerCustomResourceDefinition.yaml": customresourcedefinitions.apiextensions.k8s.io "thanosrulers.monitoring.coreos.com" already exists
Error from server (AlreadyExists): error when creating "setup/namespace.yaml": object is being deleted: namespaces "monitoring" already exists
使用 Kubectl Replace使用 create 命令去创建 crd ,使用 replace 更新 crd,他们都不添加 last-applied-configuration 这个字段,
> kubectl replace -f ./setup
customresourcedefinition.apiextensions.k8s.io/alertmanagerconfigs.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/alertmanagers.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/podmonitors.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/probes.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/prometheuses.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/prometheusagents.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/prometheusrules.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/scrapeconfigs.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com replaced
customresourcedefinition.apiextensions.k8s.io/thanosrulers.monitoring.coreos.com replaced
namespace/monitoring replaced
SSA 的方式创建当然还有另一个方法就是使用 server-side apply:
> kubectl apply --server-side -f ./setup
https://kubernetes.io/docs/reference/using-api/server-side-apply/