对于刚接触K8s的新人来说,K8S的网络通信太复杂了,每个点都可以深入很多很多,这篇文章记录自己网络通信的一个整体认识,帮助快速上手。
根据自己的梳理画了一个图(从用户到pod的一个网络通信图,目的是快速打通网络流)
图中的概念介绍:
Node IP:Node节点的IP地址,即物理网卡的IP地址
Pod IP:Pod的IP地址,即docker容器的IP地址,此为虚拟IP地址
Cluster IP:Service的IP地址,此为虚拟IP地址。
讲得比较透彻的文章: https://ld246.com/article/1579223129877
NodeIP ping PodIP —》yes Flannel插件解决
NodeIp ping ClusterIP —>No —》k8s的kube-proxy支持iptables、ipvs模式,默认iptables模式,改为ipvs即可以实现pod与service通信
PodIp ping ClusterIp —> No —》k8s的kube-proxy支持iptables、ipvs 模式,默认iptables模式,改为ipvs即可以实现pod与service通信
外网 Ping三个Ip --> ping NodeIP(公网) OK;ping PodIP No;ping Cluster IP No;
CNI CNI(container network interface)是容器网络接口 是K8s中提供的一种通用网络标准规范,因为k8s本身不提供网络解决方案 以插件方式使用, 为用户在pod创建或者销毁时动态配置网络。
- 确保整个集群中Pod IP不重复
- 建立所有Pod的覆盖网络,使得Pod之间可以相互通信
k8s默认为iptables,从1.8版本加入了ipvs模式,
ipvs和iptables都是基于netfilter的,他们的差别为:
ipvs 为大规模集群提供了更好的可扩展性和性能
ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权轮询等)
ipvs 支持服务器健康检查和连接重试等功能
Ingress 主要分为两部分:
- Ingress Controller 是流量的入口,是一个实体软件, 一般是Nginx 和 Haproxy 。
- Ingress 描述具体的路由规则。
我们知道集群内,Pod与Pod之间的通信(服务暴露和发现):
- service会自动为pod创建环境变量,在其他Pod中可以通过该环境变量访问。要求Service在Pod只之前创建。进入Pod,可以通过Env查看环境变量。
- DNS:CoreDNS,kubelet自动为Pod设置DNS,Pod之间可以直接通过 解析域名访问,也可以自定义定义:spec.hostname spec.subdomain ----->DNS注册机制
想要直接把集群服务暴露出来,我们可以使用NodePort 和 Loadbalancer 类型的 Service
- ClusterIP 默认的,仅在集群内可用
- NodePort 暴露端口到节点,提供了集群外部访问的入口 端口范围固定 30000 ~ 32767
- LoadBalancer 需要负载均衡器(通常都需要云服务商提供) 会额外生成一个 IP 对外服务 。K8S 支持的负载均衡器:负载均衡器
- Headless 适合数据库 clusterIp 设置为 None 就变成 Headless 了,不会再分配 IP,后面会再讲到具体用法
- Ingress:在Service基础上进行一层封装,做路由配置,流量转发。
在实际应用中,重点是怎么测试网络是否联通,以下是个人采用的一些方法:总的来说,测试网络是否联通就用如下命令:ping(busybox) + curl(nginx做测试)+telnet node-ip node-port
K8S提供 CNI接口,但是不实现网络解决方案,需要使用插件解决。看安装提示语句:
初始化Master之后有明确提示:
You should now deploy a pod network to the cluster.
Run “kubectl apply -f [podnetwork].yaml” with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
我们选择最简单的。最常用的Flannel作为 K8S的CNI。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
到目前为止:解决pod与service直接的通信,跨主机,跨namespace
参考:https://blog.csdn.net/Urms_handsomeyu/article/details/106294085?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2defaultCTRLISTRate-1.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2defaultCTRLISTRate-1.pc_relevant_aa&utm_relevant_index=2
修改方法:
查看: kubectl get cm kube-proxy -n kube-system -o yaml
修改: kubectl edit configmap kube-proxy -n kube-system
metricsBindAddress: “127.0.0.1:10249”
mode: “ipvs”
删除kube-system 命名空间下的kube-proxy:kubectl -n kube-system delete pods kube-proxyxxx kube-proxyxxy kube-proxyxxz…(删除之后,会自动重新创建)
查看是否生效:kubectl logs kube-proxy-xxx, 查找关键字 Using ipvs Proxier
如下图,Service通过spec.selector去匹配Deployment中的spec.template.metadata.labels。
通过kubectl describe svc my-busybox 查看Endpoint对象,从下图中可以看出 PodIP与ClusterIP的关系。
apiVersion: v1
kind: Namespace
metadata:
name: cni-test
---
apiVersion: v1
kind: Service
metadata:
name: my-busybox
namespace: cni-test
spec:
selector:
run: app
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: cni-test
spec:
replicas: 10
selector:
matchLabels:
run: app
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox #内置的linux大多数命令,多用于测试
args:
- /bin/sh
- -c
- sleep 10; touch /tmp/healthy; sleep 30000
readinessProbe: #就绪探针
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10 #10s之后开始第一次探测
periodSeconds: 5 #第一次探测之后每隔5s探测一次
apiVersion: v1
kind: Namespace
metadata:
name: cni-test-2c
---
apiVersion: v1
kind: Service
metadata:
name: my-busybox
namespace: cni-test-2c
spec:
selector:
run: app
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: cni-test-2c
spec:
replicas: 3
selector:
matchLabels:
run: app
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox #内置的linux大多数命令,多用于测试
args:
- /bin/sh
- -c
- sleep 10; touch /tmp/healthy; sleep 30000
readinessProbe: #就绪探针
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10 #10s之后开始第一次探测
periodSeconds: 5 #第一次探测之后每隔5s探测一次
---
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: cni-test-2c
spec:
replicas: 3
selector:
matchLabels:
run: app-2
template:
metadata:
labels:
run: app-2
spec:
containers:
- name: app-2
image: busybox #内置的linux大多数命令,多用于测试
args:
- /bin/sh
- -c
- sleep 10; touch /tmp/healthy; sleep 30000
readinessProbe: #就绪探针
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10 #10s之后开始第一次探测
periodSeconds: 5 #第一次探测之后每隔5s探测一次
1、创建 nginx测试 NodePort功能
2. 外网IP:31090 ,无法访问
排查: 查看如上信息,pod、service都没问题,就是外网访问的时候,提示无法访问。
step1:Node上 curl pod资源 ---->通信OK
Step2:在Node上 curl service资源 —》通信OK
Step3:Node上 Curl 内网IP:31090 —>通信Ok
Step4:在外网上,Curl 外网IP:31090 —》No,说明在获取公网地址:端口 的时候 未获取到资源。
---- 百度查找:原因是 Linux禁止 iptables,ipvs流量转发?
对于iptables:设置 iptables -P FORWARD ACCEPT,#再查看 sudo iptables -S; 可以参考:https://www.cnblogs.com/gaoyuechen/p/14307141.html
对于ipvs:需要通过ipvsadm 管理,可以参考:
https://blog.csdn.net/cloudvtech/article/details/80199653
https://www.jianshu.com/p/865fe1469c74
还是无法解决,问题就出在 内网相关端口,或者其他不知道的什么东西没有暴露给外网,服务器本身有问题。而我的环境是 腾讯云,
WC,腾讯云创建的时候选择了一个安全组,一查,发现问题了,31090端口没暴露给外网…
解决办法: 直接将安全组设置为【放通全部端口-…】
nginx测试NodePort的yaml如下:
apiVersion: v1
kind: Namespace
metadata:
name: pod-nginx-test
---
apiVersion: v1
kind: Service
metadata:
name: my-nginx
namespace: pod-nginx-test
spec:
selector:
name: my-nginx-pod-test
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 31090
---
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-pod-test
namespace: pod-nginx-test
labels:
name: my-nginx-pod-test
spec:
containers:
- name: my-nginx-pod-test
image: nginx
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。