CheatSheet_Kubernetes
移除所有失败的podkubectl delete pod --field-selector="status.phase==Failed"
查看证书信息查看 AWS LoadBalancer 证书的信息,检查证书的有效期:
kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io aws-load-balancer-webhook -ojsonpath={.webhooks[0].clientConfig.caBundle} | base64 -d | openssl x509 -noout -text
使用 Debug 容器# 给特定的容器附加一个Sidecar, 并启动shell。
kubectl debug -it --image=public.ecr.aws/amazonlinux/amazonlinux:latest aws-node-cpmck
# netshoot容器, 比较方便的用来进行网络部分的调试。
# 项目仓库地址: https://github.com/nicolaka/netshoot
kubectl debug mypod -it --image=nicolaka/netshoot
查看EKS集群插件的兼容范围aws eks describe-addon-versions --kubernetes-version 1.25 --addon-name vpc-cni | grep addonVersion
列出节点上所有容器的镜像名称# ssh 到节点上面执行
nerdctl inspect $(nerdctl ps -a -q) | grep -i "image.:" | sort -f
# 清理节点上未使用的镜像,不仅仅是 dangling image
nerdctl image prune -af
# 设置 nerdctl 命令的自动补全
nerdctl completion bash > /etc/bash_completion.d/nerdctl
Nsenter 进入容器~]$ nerdctl inspect 02182f3e9137 | grep -i pid
"Pid": 10306,
~]$ nsenter -t 10306 -n
CheatSheet_Linux
PS 查看 Cpu, Mem 最高几个进程# Top CPU users
ps auxwww --sort -%cpu | head -20
# Top memory users
ps auxwww --sort -rss | head -20
ps auxf --width=200
or
ps auxwwwf
Curl 显示详细的http连接时间curl -o /dev/null -s -w "time_namelookup:%{time_namelookup}\ntime_connect: %{time_connect}\ntime_appconnect: %{time_appconnect}\ntime_redirect: %{time_redirect}\ntime_pretransfer: %{time_pretransfer}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n" http://nginx.liarlee.site/Fedora-Workstation-Live-x86_64-38_Beta-1.3.iso
Sysctl 查看 Tcp 相关的内核参数sysctl -a | egrep "rmem|wmem|tcp_mem|adv_win|moderate|slow_start"
查看系统内所有用户的Crontab~]$ cat /etc/passwd | cut -f 1 -d : | xargs -I {} crontab -l -u {}
no crontab for root
no crontab for bin
no crontab for daemon
no crontab for adm
no crontab for lp
no crontab for sync
no crontab for shutdown
no crontab for halt
no crontab for mail
no crontab for operator
no crontab for games
no crontab for ftp
no crontab for nobody
no crontab for systemd-network
no crontab for dbus
no crontab for rpc
no crontab for libstoragemgmt
no crontab for sshd
no crontab for rpcuser
no crontab for nfsnobody
no crontab for rngd
no crontab for ec2-instance-connect
no crontab for postfix
no crontab for chrony
no crontab for tcpdump
no crontab for ec2-user
no crontab for tss
no crontab for netdata
no crontab for cwagent
no crontab for ssm-user
查看AWS EC2 的 Billing Code对于EC2来说,Redhat 或者 SUSE 的 Enterprise版本是有Billing Code的, 这标记了是否是已经付费过的版本, 有没有安全补丁和技术支持。
# IDMSv1可以使用如下命令:
curl http://169.254.169.254/latest/dynamic/instance-identity/document
# IDMSv2可以使用:
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` && curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/dynamic/instance-identity/document
查看SUSE的注册情况,以及是否启用 LTSSsudo SUSEConnect --list-extensions
Linux 查看网络可能存在的丢包和异常。> ip -s link show wlan0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc cake state UP mode DORMANT group default qlen 1000
link/ether dc:a6:32:a2:77:a1 brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped missed mcast
1479773800 3264136 0 0 0 29898
TX: bytes packets errors dropped carrier collsns
2132719784 3716055 0 0 0 0
> ethtool -S end0 | grep drop
rx_dropped: 0
tx_dropped: 0
rxq0_dropped: 0
rxq1_dropped: 0
rxq2_dropped: 0
rxq3_dropped: 0
rxq16_dropped: 0
Openssl 建立连接测试openssl s_client -debug --connect some.domain.com:443
# 指定算法和协议版本
openssl s_client -debug --connect some.domain.com:443 -tls1_2 -cipher RC4
查看系统内的日志, 不同级别# 查看启动以来的内核日志
journalctl -xeak
# 查看error级别的日志( 这个日志级别不是所有的应用程序都按照规则设定, 有的程序都是info级别, 没有做区分。
journalctl -xeak -p3
# 日志级别的补充说明:
# FROM..TO. The log levels are the usual syslog log levels as documented in syslog(3), i.e. "emerg" (0), "alert" (1), "crit" (2), "err" (3), "warning" (4), "notice" (5), "info" (6), "debug" (7). If a
# single log level is specified, all messages with this log level or a lower (hence more important) log level are shown. If a range is specified, all messages within the range are shown, including both
# the start and the end value of the range. This will add "PRIORITY=" matches for the specified priorities.
# 输出所有重启的历史记录
# 命令会通过序号的方式标记重启的记录, 0, -1, -2, -3 等等
journalctl --list-boots
0 cfa4ea7ba29d44879e21e0406455bd50 Wed 2024-01-31 17:41:24 UTC—Thu 2024-02-01 05:58:11 UTC
# 输出上次系统启动的日志
journalctl -xeab -1
# 输出到console不是pager进行分页, 可以接 grep
journalctl -xea --no-pager
# 输出kubelet这个 service 日志
journalctl -xeau kubelet
# 追踪这个服务的日志, 相当于 tail -f
journalctl -xeafu kubelet
# 显示100行
journalctl -xeau kubelet -n 100 --no-pager
# 显示从什么时间开始的日志 或者 到什么时间为止的日志。
# Format: 2012-10-30 18:17:16
# 可以仅仅提供日期字段, 时间会默认全0
-S, --since=, -U, --until=
journalctl -xea --no-pager -S "2024-01-31 18:20:00" -U "2024-01-31 18:40:00"
# 更多:
journalctl -xea -u kubelet --no-pager -S "2024-01-31 17:40:00" -U "2024-01-31 23:40:00"
Tshark 命令简单说明tshark -i ens5 -n -f 'tcp dst port 32123' -T fields -e frame.number -e frame.time_epoch -e frame.time_delta_displayed -e ip.src -e tcp.srcport -e ip.dst -e tcp.dstport -e tcp.time_delta -e tcp.stream -e tcp.len -e tcp.analysis.ack_rtt
# 抓取 dns 请求, 并显示 IP TTL 以及 DNS TTL, 格式化输出
> sudo tshark -i ens5 -Y 'dns' -T fields -e ip.src -e ip.dst -e dns.qry.name -e ip.ttl -E header=y -E separator='/t' -E quote='d' -E occurrence=f
Iptables 常用命令关于 iptables 的扩展内容: [[Linux/Linux_Iptables-and-conntrack|Linux_Iptables-and-conntrack]]
清理Kubernetes所有的路由条目(流量会中断iptables -X && iptables -F && iptables -Z && iptables -t nat -F && iptables -t nat -X && iptables -t nat -Z
查看 Iptables 中的规则,并标记显示行号# 查看 nat 表
iptables -t nat -nvL --line-number
# 爱看 filter 表
iptables -nvL --line-number
# 查看 raw 表
iptables -t raw -nvL --line-number
增加、 ...
CheatSheet_awscli
查看实例和对应实例的系统平台信息aws ec2 describe-instances --query "Reservations[*].Instances[*].{InstanceId:InstanceId,PlatformDetails:Platform}" --output table
查看实例和EBS的关联关系aws ec2 describe-volumes --query 'Volumes[*].[VolumeId, Attachments[0].InstanceId, Size]' --output table
Portainer 使用记录
创建并启动 Portainer在这里直接使用了dockercompose直接运行, 这个dockercompose 是自己配置的, 其他的服务可以托管给 portainer , 但是 portainer 自己貌似不太能托管自己.
创建compose文件: touch /opt/portainer/docker-compose.yaml
写入配置文件: ---
version: "3.8"
services:
portainer:
image: portainer/portainer-ce:latest
restart: always
environment:
- UUID=0
- GUID=0
- TZ=Asia/Shanghai
volumes:
- /run/docker.sock:/var/run/docker.sock
- /etc/localtime:/etc/localtime:ro
- /opt/Portainer/portainer_data:/data
network_mode: host
cap_add:
- ALL
运行 dockercompose updocker-compose down --remove-orphans
&& \
docker-compose up -d
启动 Portainer Agent在需要管理的其他节点上面, 运行下面的命令:
docker run -d \
-p 9001:9001 \
--name portainer_agent \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
reg.liarlee.site/docker.io/portainer/agent:2.19.4
MySQL 无法重连问题的分析
复现方法我的测试环境是完全使用容器的, 还是遇到了一点点小差异.
案例来自一次故障的诊断过程–实验重现 2024年必做实验 的过程, 看看自己差在哪儿.
使用下面的命令运行并进行测试:分离了 server 和 client 在不同的实例上, 开始是放在一起的, 后来为了方便确认范围, 就给分开了.
创建 docker 容器, 运行 MySQL.docker run -it -d --net=host -e MYSQL_ROOT_PASSWORD=123 --name=mysql-server regprox.liarlee.site/docker.io/mysql
连接并创建数据库.mysql -h127.1 --ssl-mode=DISABLED -utest -p123 -e "create database test"
sysbenchdocker run --net=host --privileged -it regprox.liarlee.site/docker.io/phantooom/plantegg:sysbench-lab bash
sysbench --mysql-user='root' --mysql-password='123' --mysql-db='test' --mysql-host='127.0.0.1' --mysql-port='3306' --tables='16' --table-size='10000' --range-size='5' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --time='1180' --report-interval='1' --histogram='on' --threads=1 oltp_read_only prepare
sysbench --mysql-user='root' --mysql-password='123' --mysql-db='test' --mysql-host='127.0.0.1' --mysql-port='3306' --tables='16' --table-size='10000' --range-size='5' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --time='1180' --report-interval='1' --histogram='on' --threads=1 oltp_read_only run
查看客户端进程.( 这个记录还是在同一个节点上面测试的记录.MySQL [(none)]> show processlist;
+----+-----------------+---------------------+------+---------+------+------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+---------------------+------+---------+------+------------------------+------------------+
| 5 | event_scheduler | localhost | NULL | Daemon | 336 | Waiting on empty queue | NULL |
| 11 | root | 127.0.0.1:40666 | test | Sleep | 0 | | NULL |
| 12 | root | 172.31.47.174:53264 | NULL | Query | 0 | init | show processlist |
+----+-----------------+---------------------+------+---------+------+------------------------+------------------+
3 rows in set, 1 warning (0.000 sec)
kill进程MySQL [(none)]> kill 11;
Query OK, 0 rows affected (0.001 sec)
MySQL [(none)]> show processlist;
+-----+----------------------+---------------------+------+---------+------+------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-----+----------------------+---------------------+------+---------+------+------------------------+------------------+
| 5 | event_scheduler | localhost | NULL | Daemon | 435 | Waiting on empty queue | NULL |
| 14 | root | 172.31.47.174:56052 | NULL | Query | 0 | init | show processlist |
| 15 | unauthenticated user | 127.0.0.1:48256 | NULL | Connect | 3 | Receiving from client | NULL |
| 16 | unauthenticated user | 127.0.0.1:48258 | NULL | Connect | 3 | Receiving from client | NULL |
| 17 | unauthenticated user | 127.0.0.1:48274 | NULL | Connect | 3 | Receiving from client | NULL |
| 18 | unauthenticated user | 127.0.0.1:48284 | NULL | Connect | 3 | Receiving from client | NULL |
| 19 | unauthenticated user | 127.0.0.1:48294 | NULL | Connect | 3 | Receiving from client | NULL |
| 20 | unauthenticated user | 127.0.0.1:48298 | NULL | Connect | 3 | Receiving from client | NULL |
| 21 | unauthenticated user | 127.0.0.1:48308 | NULL | Connect | 3 | Receiving from client | NULL |
| 22 | unauthenticated user | 127.0.0.1:48310 | NULL | Connect | 3 | Receiving from client | NULL |
| 23 | unauthenticated user | 127.0.0.1:48316 | NULL | Connect | 3 | Receiving from client | NULL |
| 24 | unauthenticated user | 127.0.0.1:48332 | NULL | Connect | 3 | Receiving from client | NULL |
| 25 | unauthenticated user | 127.0.0.1:48338 | NULL | Connect | 3 | Receiving from client | NULL |
| 26 | unauthenticated user | 127.0.0.1:48346 | NULL | Connect | 3 | Receiving from client | NULL |
| 27 | unauthenticated user | 127.0.0.1:48360 | NULL | Connect | 3 | Receiving from client | NULL |
| 28 | unauthenticated user | 127.0.0.1:48366 | NULL | Connect | 3 | Receiving from client | NULL |
| 29 | unauthenticated user | 127.0.0.1:48372 | NULL | Connect | 3 | Receiving from client | NULL |
| 30 | unauthenticated user | 127.0.0.1:48386 | NULL | Connect | 3 | Receiving from client | NULL |
| 31 | unauthenticated user | 127.0.0.1:48394 | NULL | Connect | 3 | Receiving from client | NULL |
| 32 | unauthenticated user | 127.0.0.1:48398 | NULL | Connect | 3 | Receiving from client | NULL |
| 33 | unauthenticated user | 127.0.0.1:48404 | NULL | Connect ...
AWS-CNI 集成 Calico 并启用 WireGuard 加密
看了下说明, 这个东西的主要作用是用于节点间Pod流量的加密。
启动集群略
Helm命令安装 Calico
添加一个helm repohelm repo add projectcalico https://docs.tigera.io/calico/charts
创建一个 value.yamlcat > values.yaml <<EOF
installation:
kubernetesProvider: EKS
registry: reg.liarlee.site/docker.io
EOF
helm show values projectcalico/tigera-operator --version v3.27.2
通过命令安装kubectl create namespace tigera-operator
helm install calico projectcalico/tigera-operator --version v3.27.2 -f values.yaml --namespace tigera-operator
watch kubectl get pods -n calico-system
启用 WireGuardkubectl patch felixconfiguration default --type='merge' -p '{"spec":{"wireguardEnabled":true}}'
# 在节点上面可以看到 wireguard 的网卡 和 内核模块, 说明已经成功了。
# EKS 默认的 AMI 里面是带这个模块的, 不需要手动安装, 可以自动按需装载。
~]$ lsmod | grep wireguard
wireguard 98304 0
curve25519_x86_64 36864 1 wireguard
libcurve25519_generic 49152 2 curve25519_x86_64,wireguard
libchacha20poly1305 16384 1 wireguard
ip6_udp_tunnel 16384 1 wireguard
udp_tunnel 28672 1 wireguard
~]$ ip ad
35: wireguard.cali: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 8941 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 192.168.137.134/32 scope global wireguard.cali
valid_lft forever preferred_lft forever
# 或者可以查看
> kubectl get felixconfiguration default -o yaml
apiVersion: projectcalico.org/v3
kind: FelixConfiguration
...
spec:
bpfConnectTimeLoadBalancing: TCP
bpfHostNetworkedNATWithoutCTLB: Enabled
bpfLogLevel: ""
floatingIPs: Disabled
healthPort: 9099
logSeverityScreen: Info
reportingInterval: 0s
routeTableRange:
max: 99
min: 65
vxlanVNI: 4096
wireguardEnabled: true
参考文档Project Calico:https://docs.tigera.io/calico/3.25/network-policy/encrypt-cluster-pod-traffic#enable-wireguard-for-a-cluster
使用 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 。
rp_filter参数用于控制系统是否开启对数据包源地址的校验。rp_filter参数有三个值,0、1、2,具体含义:0:不开启源地址校验。1:开启严格的反向路径校验。对每个进来的数据包,校验其反向路径是否是最佳路径。如果反向路径不是最佳路径,则直接丢弃该数据包。2:开启松散的反向路径校验。对每个进来的数据包,校验其源地址是否可达,即反向路径是否能通(通过任意网口),如果反向路径不同,则直接丢弃该数据包。
默认的情况下, 这个参数是1, 因此 :数据包发到了eth1网卡,如果这时候开启了rp_filter参数,并配置为1,则系统会严格校验数据包的反向路径。从路由表中可以看,返回响应时数据包要从eth0网卡出,即请求数据包进的网卡和响应数据包出的网卡不是同一个网卡,这时候系统会判断该反向路径不是最佳路径,而直接丢弃该请求数据包。
排查路由表 和 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 eni1658effeb9c scope link
172.31.55.135 dev enibe97b10ca0d scope link
172.31.55.235 dev eni179f5c3696c scope link
172.31.56.137 dev eni099fbf41bd0 scope link
172.31.57.72 dev eni10574b2dfef scope link
172.31.58.18 dev eni5434103f7b9 scope link
172.31.58.47 dev enif4a18529a5f scope link
172.31.59.200 dev eni308c9b2c04f scope link
172.31.59.203 dev enia94f8f21d94 scope link
172.31.60.128 dev eni11239f98883 scope link
172.31.61.61 dev eni84312c21e65 scope link
172.31.61.216 dev enid75abf4f5e0 scope link
172.31.63.97 dev eni3ea3753c729 scope link
172.31.63.121 dev eni8bac6c0ff3f scope link
172.31.63.248 dev enie5c85d50c09 scope link
查看 table 3 的内容:
[root@ip-172-31 ...
配置自管理的Tailscale网络
Tailscale 虽然是 mesh 的网络模式, 可以点对点的连接所有设备, 能直连会尽量直接连接, 然鹅还是需要一个默认的server来进行服务发现和临时中转流量.
那么大概的配置框架就已经出现了, 一个服务发现中心, 和多个不同的客户端.开始的时候直接使用的tailscale + github账户登录的方式使用, 然后发现 github 账户直接托管的中心服务不能关闭国外的中转服务器, 这就比较难受, 本来可以直通的线路走了国外的中转不稳定, 会断, 最后还是走国内的便宜云服务器自己维护了一个开源的headscale作为中心服务.
大概的步骤如下吧:
安装headscale官方文档
现在的 docker 的版本是有问题的。。。。别用
我准备了这些:
域名, 域名证书
一台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
安装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)里面执行一下,节点就注册进来了.
更新现在已经存在的设置最近需要更新我的一个节点, 发布 VPC内的 CIDR 块, 这个设置之前没有 advertise-route, 已经跑了很久, 是是否更新一下了 。这个实例在我的默认VPC里面, 这样的话这个实例就直接变成了这个VPC内的IGW, 流量会通过这个实例发送到VPC内, 试了一下, 可以直接将这个网络范围内的DNS指向VPC内的.2, 甚至可以直接在家用 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
archlinux 使用 tailscale + Sunshine 串流
接上面的测试, 既然显卡都已经能用了, 为啥不能直接启动一个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给玩儿没了.. 现在连不上了…闹心