kubernetes/openshift 应用异常诊断指南_下

原创:蔡峰
同步发布于微信公众号:老菜

应用运行正常,但是无法访问

接上篇,继续解读应用无法访问的场景。只要捋清各个访问方式的原理及走向,问题迎刃而解。
前提:应用运行正常,在集群内部可以通过pod ip 访问应用。
场景如下:
集群外访问集群内应用:最常用的两种方式,ingress/route 访问, nodeport访问
集群内应用互相访问:通过servicename 访问

集群外访问集群内应用 ingress/route

ingress/route 分别是k8s/openshift常用的负载方式,常用来作为应用的负载均衡。
ingress controller 是k8s的应用负载均衡器,内部是nginx,会通过nodeselector 方式部署在特定的几个node节点,使用hostnetwork,默认监听node节点80 443端口,支持4层 7层负载,可以卸载证书。会将ingress 规则写入配置文件。
openshift中的负载均衡器叫router,内部是haproxy,默认部署在default namespace,infra 节点,hostnetwork方式,默认80 443端口,支持7层,可以卸载证书。

以openshift 为例创建一个应用及route

[root@master ~]# oc run tomtest --image=tomcat --port=8080
deploymentconfig.apps.openshift.io/tomtest created
[root@master ~]# oc expose dc tomtest
service/tomtest exposed
[root@master ~]# oc expose svc tomtest
route.route.openshift.io/tomtest exposed

[root@master ~]# oc get route
NAME      HOST/PORT                           PATH      SERVICES   PORT      TERMINATION   WILDCARD
tomtest   tomtest-demo.apps.origin311sz.com             tomtest    8080                    None
# 自动创建了一个域名,指向tomtest 这个service 8080端口
# ingress类似,域名需要自己指定
# 后续在配置dns或者hosts之后,可以通过域名访问到应用

流量走向
流量走router/ingress controller 通过容器网络直接到pod,不走service ip!!! 不走service ip!!!不走service ip!!!
service 只作为同步应用后端的pod ip作用,见下图这是router,ingress 也是这样

troubleshooting-ocp-router.png

router的配置信息进入到router容器中,有个haproxy配置文件,内容很清晰。
ingress的进入ingress controller容器,nginx.conf中可以查看server信息,看不到backend 应用pod ip,用dbg命令可以看,如下

# 先创建deployment,svc,ingress
[root@master ~]# kubectl -n ingress-nginx exec -it nginx-ingress-controller-86b96b86fb-45kn8 bash
www-data@node1:/etc/nginx$ /dbg backends list
default-tom-8080
upstream-default-backend
www-data@node1:/etc/nginx$
www-data@node1:/etc/nginx$ /dbg backends get default-tom-8080
{
  "endpoints": [
    {
      "address": "10.250.11.75",
      "port": "8080"
    },
    {
      "address": "10.250.11.76",
      "port": "8080"
    }
  ],
  ......

那么异常分析流程就很清晰了:

  1. 首先确认域名解析正常,通过nslookup,dig工具确认域名是解析到了router/ingress controller 所在的node节点ip。 因为使用的hostnetwork,所以router/ingress controller 的ip也就是所在node节点的ip。
    或者没有使用dns解析,那么本地hosts 需要手动配置下,将域名解析到 router/ingress controller 的ip
  2. 确认 router/ingress controller 容器运行正常,看下容器日志。并确认网络为hostnetwork,oc get pod -owide 要看到ip是node节点ip
  3. 确认 router/ingress controller 节点能够访问异常应用的pod ip,若异常,则排查容器网络 calico或者openvswitch等。

集群外访问集群内应用 nodeport

nodeport方式不依赖于router/ingress controller。 是配置在service中。配置后,访问任意节点IP(包含master)加nodeport 端口,即可访问到应用。
端口默认范围: 30000~32767

# kubectl run tomnp --image=tomcat --port=8080 --replicas=3
[root@master ~]# kubectl expose deploy tomnp --type=NodePort
service/tomnp exposed
[root@master ~]# kubectl get svc
NAME    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
tomnp   NodePort   10.102.171.245   <none>        8080:31086/TCP   9s
# kubectl get po -owide
NAME                    READY   STATUS    RESTARTS   AGE    IP             NODE      NOMINATED NODE   READINESS GATES
tomnp-679765679-68zx7   1/1     Running   0          102s   10.244.0.49    master1   <none>           <none>
tomnp-679765679-d9nwb   1/1     Running   0          102s   10.244.1.114   node1     <none>           <none>
tomnp-679765679-whzhm   1/1     Running   0          102s   10.244.0.50    master1   <none>           <none>

自动分配了一个端口31086,也可以手动指定。那么访问 任意节点ip:31086 即可访问应用。
原理:创建service后,kube-proxy会写入一些规则到每个节点的iptables,使得访问节点的31086端口的流量转发到各个pod。kube-proxy容器在kube-system namespace下。可以通过查询iptables来缕清楚规则。

# 首先通过nodeport 31086 访问会进入下面链路
# iptables -S -t nat |grep 31086
-A KUBE-NODEPORTS -p tcp -m comment --comment "demo-test/tomnp:" -m tcp --dport 31086 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "demo-test/tomnp:" -m tcp --dport 31086 -j KUBE-SVC-MQE7U74K2IT7EWQJ

# 查看svc对应的链,有0.333概率进入KUBE-SEP-KZ2UNP3ZNMYH722J 
# 0.67概率的0.50 会进入 KUBE-SEP-ITOYRBWPRT5JVIJ6
# 还未命中的都进入 KUBE-SEP-7RMBKNPQ7TIOQL4S,算下来每个概率都是0.33
# iptables -S -t nat |grep KUBE-SVC-MQE7U74K2IT7EWQJ
-N KUBE-SVC-MQE7U74K2IT7EWQJ
-A KUBE-NODEPORTS -p tcp -m comment --comment "demo-test/tomnp:" -m tcp --dport 31086 -j KUBE-SVC-MQE7U74K2IT7EWQJ
-A KUBE-SERVICES -d 10.102.171.245/32 -p tcp -m comment --comment "demo-test/tomnp: cluster IP" -m tcp --dport 8080 -j KUBE-SVC-MQE7U74K2IT7EWQJ
-A KUBE-SVC-MQE7U74K2IT7EWQJ -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-KZ2UNP3ZNMYH722J
-A KUBE-SVC-MQE7U74K2IT7EWQJ -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-ITOYRBWPRT5JVIJ6
-A KUBE-SVC-MQE7U74K2IT7EWQJ -j KUBE-SEP-7RMBKNPQ7TIOQL4S

# 三个kube-sep分别对应三个pod地址
[root@master1 ~]# iptables -S -t nat |grep KUBE-SEP-KZ2UNP3ZNMYH722J
-N KUBE-SEP-KZ2UNP3ZNMYH722J
-A KUBE-SEP-KZ2UNP3ZNMYH722J -s 10.244.0.49/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-KZ2UNP3ZNMYH722J -p tcp -m tcp -j DNAT --to-destination 10.244.0.49:8080
[root@master1 ~]# iptables -S -t nat |grep KUBE-SEP-ITOYRBWPRT5JVIJ6
-N KUBE-SEP-ITOYRBWPRT5JVIJ6
-A KUBE-SEP-ITOYRBWPRT5JVIJ6 -s 10.244.0.50/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-ITOYRBWPRT5JVIJ6 -p tcp -m tcp -j DNAT --to-destination 10.244.0.50:8080
[root@master1 ~]# iptables -S -t nat |grep KUBE-SEP-7RMBKNPQ7TIOQL4S
-N KUBE-SEP-7RMBKNPQ7TIOQL4S
-A KUBE-SEP-7RMBKNPQ7TIOQL4S -s 10.244.1.114/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-7RMBKNPQ7TIOQL4S -p tcp -m tcp -j DNAT --to-destination 10.244.1.114:8080

异常分析:

  1. 确认ip forward 是打开的
如何诊断
# 检查 ipv4 forwarding 是否开启
sysctl net.ipv4.ip_forward
# 0 意味着未开启
net.ipv4.ip_forward = 0

如何修复
# this will turn things back on a live server
sysctl -w net.ipv4.ip_forward=1
# on Centos this will make the setting apply after reboot
echo net.ipv4.ip_forward=1 >> /etc/sysconf.d/10-ipv4-forwarding-on.conf

# 验证并生效
sysctl -p
  1. 确认node节点存在nodeport相关iptables,方法上面有,若iptables规则不正常,则检查kube-proxy容器运行状态及日志。
  2. 以上都正常,那么很有可能是容器网络出问题了。排查calico容器日志,及pod,service ip段是否规划有误。

集群内应用互相访问

场景: 创建deployment A,名为 tomcat,端口8080 ,创建对应service 名为tomsvc,端口 8080
创建deployment B,名为 nginx,端口80,创建对应service,名为 ngsvc, 端口 80
应用A B 互相访问使用对方servicename+端口即可。无需再通过ingress或者nodeport方式。此原理依赖于集群内部dns。(k8s 是coredns容器--之前是kubedns,openshift 是dnsmasq,是系统服务不是容器)

# kubectl run tomcat --image=tomcat --port=8080
# kubectl expose deploy tomcat --name=tomsvc
# kubectl run nginx --image=nginx --port=80
# kubectl expose deploy nginx --name=ngsvc
# kubectl get svc
NAME     TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
ngsvc    ClusterIP   10.108.15.66   <none>        80/TCP     15s
tomsvc   ClusterIP   10.104.225.1   <none>        8080/TCP   66s

# tomcat通过ngsvc:80 访问nginx
# kubectl exec -it tomcat-5ccb865777-xrmlv bash
root@tomcat-5ccb865777-xrmlv:/usr/local/tomcat# curl ngsvc:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
......

功能测试:
可以通过运行一个busybox:1.28来测试dns解析,里面带nslookup
注意用1.28的,有的版本里面nslookup不好使

# kubectl run busybox --image=busybox:1.28 --command sleep 36000
# kubectl exec -it busybox-7fc57b9d54-j4tbq sh
/ # nslookup ngsvc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      ngsvc
Address 1: 10.108.15.66 ngsvc.demo-test.svc.cluster.local

可以看到ngsvc的完整域名是ngsvc.demo-test.svc.cluster.local
demo-test 是namespace 名称
为什么ngsvc也能解析成功,看下/etc/resolv.conf文件
nameserver 指向的是coredns的svc 地址,这没问题
主要在于search,查询主机名,因为主机名后面没有点,就认为是主机名,所以先添加search里的每一项依次组成FQDN(完全合格域名)来查询,完全合格域名查询未找到,就再认为主机名是完全合格域名来查询。
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search demo-test.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

跨namespace访问,在service名称后接上namespace名称
/ # 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

所以异常处理的顺序,k8s和openshift中dns server有些差异,分开写,实现的功能是一致的:
1.1 k8s -- 确认集群内部dns服务正常,在master或者node节点上做

# nslookup kubernetes.default.svc.cluster.local 10.96.0.10
Server:     10.96.0.10
Address:    10.96.0.10#53

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

域名写完成的,因为节点的/etc/resolv.conf里面是没有那些search内容的, 10.96.0.10 是coredns/kubedns的service ip
解析成功说明dns服务是正常的,反之则排查dns服务容器

1.2 k8s -- 确认容器内部的dns地址指向

# kubectl exec -it tomcat-5ccb865777-xrmlv bash
# cat /etc/resolv.conf
nameserver 10.96.0.10
search demo-test.svc.cluster.local svc.cluster.local cluster.local

nameserver 的地址 需要与 kubectl -n kube-system get svc kube-dns 获取的CLUSTER-IP 一致
这个nameserver 地址及 search cluster.local 是在各个节点kubelet服务中定义的。 通过systemctl status kubelet 能够追查到,文件是 /var/lib/kubelet/config.yaml

同时可以配合busybox:1.28的容器进行诊断

2.1 openshift -- 确认集群内部dns服务正常,在异常访问到pod所在node节点上做

因为openshift 每个节点的dns server及节点上的pod dns server都是指向这台节点的ip的,原因可以查看dnsmasq服务
[root@node1 ~]# hostname -i
192.168.1.186
[root@node1 ~]# cat /etc/resolv.conf
# nameserver updated by /etc/NetworkManager/dispatcher.d/99-origin-dns.sh
# Generated by NetworkManager
search cluster.local origin311sz.com
nameserver 192.168.1.186
[root@node1 ~]# nslookup kubernetes.default.svc.cluster.local
Server:     192.168.1.186
Address:    192.168.1.186#53

Name:   kubernetes.default.svc.cluster.local
Address: 172.30.0.1

dns能够解析service name

注意openshift不能关闭NetworkManager服务,部署文档都有说明。resolv.conf文件就是靠他来更新的。

2.2 openshift -- 确认容器内部的dns地址指向
nameserver地址是pod所在node的主机ip才是正确的,openshift中pod的resolv.conf 中nameserver 默认是从所在节点的/etc/resolv.conf获取,若pod中的尚未更新,重启下openshift node服务。然后delete 相关pod再看resolv.cof

# oc rsh tomtest-1-bg782
$ cat /etc/resolv.conf
nameserver 192.168.1.187
search demo.svc.cluster.local svc.cluster.local cluster.local origin311sz.com
options ndots:5

openshift node服务
systemctl status origin-node  #社区版
systemctl status atomic-openshift-node  #企业版

同上,同时可以配合busybox:1.28的容器进行诊断

openshift的更多dns相关的知识可以查看这篇文章。
https://www.cnblogs.com/sammyliu/p/10056035.html

故障诊断篇完结。下一篇大概是openshift template。
本篇上下完整版本可查询github,后续若有补充会更新在这
https://github.com/cai11745/k8s-ocp-yaml/blob/master/kubernetes-docs/2019-07-27-openshift-k8s-troubleshooting.md

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351