k8s网络通信
一、通信模式
一 、k8s通過CNI接口接入其他插件來實現網絡通訊。目前比較流行的插件有flannel,calico等。
CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist
插件使用的解決方案如下:
- 虛擬網橋,虛擬網卡,多個容器共用一個虛擬網卡進行通信。
- 多路復用:MacVLAN,多個容器共用一個物理網卡進行通信。
- 硬件交換:SR-LOV,一個物理網卡可以虛擬出多個接口,這個性能最好。
二、容器間通信:同一個pod內的多個容器間的通信,通過lo即可實現;
三、pod之間的通信:
- 同一節點的pod之間通過cni網橋轉發數據包。
- 不同節點的pod之間的通信需要網絡插件支持。
四、pod和service通信: 通過iptables或ipvs實現通信,ipvs取代不了iptables,因為ipvs只能做負載均衡,而做不了nat轉換。
五、pod和外網通信:iptables的MASQUERADE。
六、Service與集群外部客戶端的通信;(ingress、nodeport、loadbalancer)
二、service
1 k8s提供的dns服務插件
[root@server2 ~]# kubectl describe svc myservice [root@server2 ~]# kubectl run demo1 --image=busyboxplus -it If you don't see a command prompt, try pressing enter. / # nslookup myservice / # curl myservice [root@server2 ~]# kubectl get service kube-dns --namespace=kube-system [root@server2 ~]# dig myservice.default.svc.cluster.local. @10.96.0.102 Headless Service “無頭服務”
- Headless Service不需要分配一個VIP,而是直接以DNS記錄的方式解析出被代理Pod的IP地址。
- 域名格式:(servicename).(servicename).(servicename).(namespace).svc.cluster.local
從下圖看到沒有分配固定ip,而是直接以DNS記錄的方式解析出被代理Pod的IP地址。
3 創建service(NodePort方式)
[root@server2 ~]# vim demo.yml --- apiVersion: v1 kind: Service metadata:name: myservice spec:selector:app: myappports:- protocol: TCPport: 80targetPort: 80#clusterIP: Nonetype: NodePort---apiVersion: apps/v1 kind: Deployment metadata:name: demo2 spec:replicas: 3selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- name: myappimage: myapp:v2 [root@server2 ~]# kubectl delete -f demo.yml [root@server2 ~]# kubectl apply -f demo.yml [root@server2 ~]# kubectl get svc在ip的基礎上又加了一個端口
4. LoadBalancer 類型的 Service
從外部訪問 Service 的第二種方式,適用于公有云上的 Kubernetes 服務。這時候,你可以指定一個 LoadBalancer 類型的 Service。
在service提交后,Kubernetes就會調用 CloudProvider 在公有云上為你創建一個負載均衡服務,并且把被代理的 Pod 的 IP地址配置給負載均衡服務做后端。
將剛才的demo.yml中的類型變成LoadBalancer即可
由于我們使用的不是共有云,所以暫時不能實現,EXTERNAL-IP顯示的是pending等待分配ip狀態
5 service允許為其分配一個公有IP
在ClusterIP的基礎上,給綁定了一個外部地址,在外部可以直接訪問
[root@server2 ~]# vim demo.yml externalIPs:- 172.25.1.10
在外部主機可以通過這個ip進行訪問
6 ExternalName
從外部訪問的第三種方式叫做ExternalName
[root@server2 ~]# vim my-service.yml apiVersion: v1 kind: Service metadata:name: my-service spec:type: ExternalNameexternalName: www.baidu.com
兩種驗證方式:
三、(pod間通信)Flannel 網絡
Flannel vxlan模式跨主機通信原理
(1)VXLAN,即Virtual Extensible LAN(虛擬可擴展局域網),是Linux本身支持的一網種網絡虛擬化技術。VXLAN可以完全在內核態實現封裝和解封裝工作,從而通過“隧道”機制,構建出覆蓋網絡(Overlay Network)。
(2)VTEP:VXLAN Tunnel End Point(虛擬隧道端點),在Flannel中 VNI的默認值是1,這也是為什么宿主機的VTEP設備都叫flannel.1的原因。
(3)Cni0: 網橋設備,每創建一個pod都會創建一對 veth pair。其中一端是pod中的eth0,另一端是Cni0網橋中的端口(網卡)。
(4)Flannel.1: TUN設備(虛擬網卡),用來進行 vxlan 報文的處理(封包和解包)。不同node之間的pod數據流量都從overlay設備以隧道的形式發送到對端。
(5)Flanneld:flannel在每個主機中運行flanneld作為agent,它會為所在主機從集群的網絡地址空間中,獲取一個小的網段subnet,本主機內所有容器的IP地址都將從中分配。同時Flanneld監聽K8s集群數據庫,為flannel.1設備提供封裝數據時必要的mac、ip等網絡數據信息。
flannel網絡原理
當容器發送IP包,通過veth pair 發往cni網橋,再路由到本機的flannel.1設備進行處理。
VTEP設備之間通過二層數據幀進行通信,源VTEP設備收到原始IP包后,在上面加上一個目的MAC地址,封裝成一個內部數據幀,發送給目的VTEP設備。
內部數據楨,并不能在宿主機的二層網絡傳輸,Linux內核還需要把它進一步封裝成為宿主機的一個普通的數據幀,承載著內部數據幀通過宿主機的eth0進行傳輸。
Linux會在內部數據幀前面,加上一個VXLAN頭,VXLAN頭里有一個重要的標志叫VNI,它是VTEP識別某個數據楨是不是應該歸自己處理的重要標識。
flannel.1設備只知道另一端flannel.1設備的MAC地址,卻不知道對應的宿主機地址是什么。在linux內核里面,網絡設備進行轉發的依據,來自FDB的轉發數據庫,這個flannel.1網橋對應的FDB信息,是由flanneld進程維護的。
linux內核在IP包前面再加上二層數據幀頭,把目標節點的MAC地址填進去,MAC地址從宿主機的ARP表獲取。
此時flannel.1設備就可以把這個數據幀從eth0發出去,再經過宿主機網絡來到目標節點的eth0設備。目標主機內核網絡棧會發現這個數據幀有VXLAN Header,并且VNI為1,Linux內核會對它進行拆包,拿到內部數據幀,根據VNI的值,交給本機flannel.1設備處理,flannel.1拆包,根據路由表發往cni網橋,最后到達目標容器。
相同主機之間的pod通過cni通信
在server3上要先知道目標主機(server4)eth0的IP和mac地址
arp -n 可以查看到有server4的ip信息。
flannel支持多種后端
Vxlan
- vxlan //報文封裝,默認
- Directrouting //直接路由,跨網段使用vxlan,同網段使用host-gw模式。
host-gw://主機網關,性能好,但只能在二層網絡中,不支持跨網絡,如果有成千上萬的Pod,容易產生廣播風暴,不推薦
UDP: //性能差,不推薦
host-gw主機網關
修改配置flannel:
[root@server2 ~]# kubectl -n kube-system edit cm kube-flannel-cfg
生效:
從下圖我們可以看出本地的話直接走cni,如果是1,0網段的直接走網關etho
vxlan
[root@server2 ~]# kubectl -n kube-system edit cm kube-flannel-cfg "Type": "vxlan","Directrouting": true [root@server2 ~]# kubectl get pod -n kube-system |grep flannel | awk '{system("kubectl delete pod "$1" -n kube-system")}'
并沒有經過flannel.1
四、Service與集群外部客戶端的通信(Ingress 服務)
- 一種全局的、為了代理不同后端 Service 而設置的負載均衡服務,就是 Kubernetes 里的Ingress 服務。
- Ingress由兩部分組成:Ingress controller和Ingress服務。
- Ingress Controller 會根據你定義的 Ingress 對象,提供對應的代理能力。業界常用的各種反向代理項目,比如 Nginx、HAProxy、Envoy、Traefik 等,都已經為Kubernetes 專門維護了對應的 Ingress Controller。
官網:ingress-nginx
下載鏡像并上傳到本地倉庫,鏡像下載需要翻墻
所需的資源鏈接: yaml文件和鏡像 提取碼: nbvc
Ingress 服務部署:
[root@server1 ~]# docker load -i ingress-nginx.tar [root@server1 ~]# docker tag quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.33.0 reg.westos.org/library/nginx-ingress-controller:0.33.0 [root@server1 ~]# docker tag jettech/kube-webhook-certgen:v1.2.0 reg.westos.org/library/kube-webhook-certgen:v1.2.0 [root@server1 ~]# docker push reg.westos.org/library/nginx-ingress-controller:0.33.0 [root@server1 ~]# docker push reg.westos.org/library/kube-webhook-certgen:v1.2.0[root@server2 ~]# mkdir ingress-nginx/ [root@server2 ~]# cd ingress-nginx/ [root@server2 ingress-nginx]# kubectl apply -f deploy.yaml [root@server2 ingress-nginx]# kubectl get ns [root@server2 ingress-nginx]# kubectl get all -n ingress-nginx
創建Ingress服務
[root@server2 ~]# vim nginx.yml apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata:name: ingress-demo spec:rules:- host: www1.westos.orghttp:paths:- path: /backend:serviceName: myserviceservicePort: 80 [root@server2 ~]# kubectl apply -f nginx.yml
做好地址解析:
用DaemonSet結合nodeselector來部署ingress-controller到特定的node上,然后使用HostNetwork直接把該pod與宿主機node的網絡打通,直接使用宿主機的80/443端口就能訪問服務。
- 優點是整個請求鏈路最簡單,性能相對NodePort模式更好。
- 缺點是由于直接利用宿主機節點的網絡和端口,一個node只能部署一個ingress-controller pod。
比較適合大并發的生產環境使用。
Ingress TLS 加密配置
生成證書: [root@server2 ingress-nginx]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc" 導入證書: [root@server2 ingress-nginx]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt 查看證書: [root@server2 ingress-nginx]# kubectl get secrets
生效:
認證
[root@server2 ingress-nginx]# yum install httpd-tools.x86_64 -y [root@server2 ingress-nginx]# htpasswd -c auth sun [root@server2 ingress-nginx]# kubectl create secret generic basic-auth --from-file=auth [root@server2 ingress-nginx]# vim tls.ymlannotations:nginx.ingress.kubernetes.io/auth-type: basicnginx.ingress.kubernetes.io/auth-secret: basic-auth [root@server2 ingress-nginx]# kubectl apply -f tls.yml [root@server2 ingress-nginx]# kubectl apply -f nginx.yml
Ingress地址重寫
vim tls.yml apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata:name: nginx-testannotations:nginx.ingress.kubernetes.io/rewrite-target: /$2 spec:rules:- host: www1.westos.orghttp:paths:- backend:serviceName: myserviceservicePort: 80path: /westos(/|$)(.*)kubectl apply -f tls.yml curl www1.westos.org == curl www1.westos.org/westos- annotations參數
總結
- 上一篇: bind-utils.x86_64(di
- 下一篇: python面向对象编程(封装与继承)