应用层场景

dns

Linux 上 DNS 相关配置就是 /etc/resolv.conf 文件里的 nameserver ,而里面所有可配置项目见 man 手册页 ,常见的就是下面的选项:

nslookup

nslookup 分为交互和非交互模式,不带任何选项和参数执行就是交互模式,交互模式能力稍微强点:

$ nslookup www.baidu.com
Server:		127.0.0.53
Address:	127.0.0.53#53

Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com.
Name:	www.a.shifen.com
Address: 183.2.172.42
Name:	www.a.shifen.com
Address: 183.2.172.185

此处 DNS server IP 是 127.0.0.53 是因为有些 Linux 发行版会使用 systemd-resolved 在本机起一个 DNS server,通过命令来配置上游 DNS :

$ cat /etc/resolv.conf
nameserver 127.0.0.53
options edns0 trust-ad
# 使用 resolvectl 命令查看
$ resolvectl -h
$ resolvectl  --no-pager status
$ resolvectl  --no-pager statistics

在一些 initContainer 里有些人喜欢做一些前置依赖检查 service 域名解析可用性,而早期 K8S 官方文档里推荐使用 busybox:1.28 里的 nslookup,后续有不少人发现升级 busybox 后无法解析了:

# busybox:1.28
$ nslookup kubernetes.default
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes.default
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local

# busybox:1.31.1
$ nslookup kubernetes.default
Server:         10.96.0.10
Address:        10.96.0.10:53

** server can't find kubernetes.default: NXDOMAIN

*** Can't find kubernetes.default: No answer

command terminated with exit code 1

这个问题是见 issue docker-library/busybox#48,所以一般 DNS 排查过程中不推荐使用 nslookup 命令,但是只是简单解析的话,可以找个 glibc 镜像,使用以下黑科技:

# https://github.com/bitnami/containers/blob/main/bitnami/git/2/debian-12/prebuildfs/opt/bitnami/scripts/libnet.sh#L26
$ getent ahostsv4 kubernetes.default | awk '/STREAM/ {print $1;exit; }'
10.96.0.1
$ getent ahostsv4 kube-dns.kube-system | awk '/STREAM/ {print $1;exit; }'
10.96.0.10

dig

排查 DNS 问题建议使用更强大的 dig @server name type 命令,很多程序的 DNS 解析行为都是用的 glibc 提供的库,而避免因素干扰,dig 可以完全从命令行来指定 DNS 的解析逻辑:

# 使用默认的 DNS 解析
$ dig www.baidu.com

; <<>> DiG 9.16.48-Ubuntu <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21504
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;www.baidu.com.			IN	A

;; ANSWER SECTION:
www.baidu.com.		60	IN	CNAME	www.a.shifen.com.
www.a.shifen.com.	59	IN	A	183.2.172.42
www.a.shifen.com.	59	IN	A	183.2.172.185

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Mon Jul 15 14:53:38 CST 2024
;; MSG SIZE  rcvd: 101

# 简洁输出,缺省是查询 A 记录
$ dig +short baidu.com
39.156.66.10
110.242.68.66

# tcp dns 解析
$ dig +short +tcp baidu.com
# 使用指定 DNS 解析
$ dig @223.5.5.5 +short baidu.com

# 使用指定端口解析
$ dig @223.5.5.5 -p 53 baidu.com

# Pod 容器内使用 resolv.conf 里的 search 查找,因为默认行为是 +nosearch 的
$ dig +short kubernetes.default +search

例如宿主机上有 dig 命令,测试 coredns 能否解析:

$ dig @10.96.0.10 +short kubernetes.default.svc.cluster.local
# 或者绕过 svc,使用指定 coredns POD_IP 还不通就是 CNI 或者跨节点的问题
$ dig @<POD_IP> +short kubernetes.default.svc.cluster.local

curl

当然,在面对更复杂的 http 接口排错时候,更多还是使用 curl 命令发送或者模拟 http 请求,curl 命令不单单是支持 http 协议,还支持其他协议,这里暂不讨论:

$ curl -V
curl 7.68.0 (x86_64-pc-linux-gnu) libcurl/7.68.0 OpenSSL/1.1.1f zlib/1.2.11 brotli/1.0.7 libidn2/2.2.0 libpsl/0.21.0 (+libidn2/2.2.0) libssh/0.9.3/openssl/zlib nghttp2/1.40.0 librtmp/2.3
Release-Date: 2020-01-08
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
# ↑ 这里是协议支持
Features: AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets

只看返回的头部,也就是 HEAD 请求

-v 选项打印详细信息,包含域名解析到的 IP,https 证书,发起的头部信息,然后接口 http://httpbin.org/get 会返回客户端的 header 信息

$ curl -I http://httpbin.org
$ curl -v http://httpbin.org/get
*   Trying 35.173.225.247:80...
* TCP_NODELAY set
* Connected to httpbin.org (35.173.225.247) port 80 (#0)
> GET /get HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Mon, 15 Jul 2024 08:05:33 GMT
< Content-Type: application/json
< Content-Length: 254
< Connection: keep-alive
< Server: gunicorn/19.9.0
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< 
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.68.0", 
    "X-Amzn-Trace-Id": "Root=1-6694d84d-29cfb5b87bcaeb267f3b918f"
  }, 
  "origin": "178.xx.xx.xx", 
  "url": "http://httpbin.org/get"
}

-H key: value 设置 header 

$ curl  http://httpbin.org/get -H 'test: 11111111111111'
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "Test": "11111111111111", 
    "User-Agent": "curl/7.68.0", 
    "X-Amzn-Trace-Id": "Root=1-6694d921-0449f11d77d437e71b7113fc"
  }, 
  "origin": "178.236.xx.xx", 
  "url": "http://httpbin.org/get"
}

-X method ,例如发送 post 请求

$ curl -XPOST  http://httpbin.org/post?a=123 --data-raw '{"key":"value"}'
{
  "args": {
    "a": "123"
  }, 
  "data": "", 
  "files": {}, 
  "form": {
    "{\"key\":\"value\"}": ""
  }, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "15", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.68.0", 
    "X-Amzn-Trace-Id": "Root=1-6694d982-180db3df277a1ce879676d16"
  }, 
  "json": null, 
  "origin": "178.236.xx.xx", 
  "url": "http://httpbin.org/post?a=123"
}

一些其他常见选项:

  • -o file 把 body 内容存到文件,下载文件时候使用
  • -k, --insecure 允许非安全连接,通常 https 由非权威 ca 签署证书,例如 kubernetes 的接口,curl -k https://10.96.0.1
  • -L --location 跟随重定向

而对于浏览器触发的请求,我们也可以 F12 network 里拷贝成 curl 命令格式,如下图:

然后更改一些参数 curl 发请求,调试后端逻辑之类的。需要注意的是,有些后端逻辑会有防重放防御,也就是一个 http 请求发送后,再发送就无效了。

--resolve 选项方便你来不修改 hosts 来指定域名的 IP :

# curl --resolve <host:port:address> <URL>
$ curl --resolve example.com:80:127.0.0.1 http://example.com

一个要注意点的是,有时候后端逻辑会根据 User-Agent 做判断,浏览器看到的是 html 页面,curl 或者一些编程语言的 http 库请求后是 json 接口信息,当然不单单是 UA 字段。

还有有些网站避免爬虫,会利用浏览器的一些功能做人机校验,curl 是做不到那些的。

负载均衡

软硬件实现手段为:

  • 云上 SLB 之类的
  • 硬件 LB
  • 软件负载均衡,nginx、haproxy、keepalived + haproxy、Envoy....
  • 内核能力 lvs 之类的
  • 以及网络设备配置 ospf 和服务器 lvs 结合 ...


  • 无标签

0 评论

你还没有登录。你所做的任何更改会将作者标记为匿名用户。 如果你已经拥有帐户,请登录