[toc]
kubernetes 操作记录五
配置网络插件flannel
在Kubernetes集群中要解决四种通信的问题;
Kubernetes网络通信:
(1) 容器间通信: 同一个Pod内的多个容器间的通信,lo
(2) Pod通信: Pod IP <—> Pod IP
(3) Pod与 Service通信: PodIP <—> ClusterIP,不在同一网段,通过iptables规则实现通信
(4) Service 与集群外部客户端的通信;
CNI: (Container Network Interface)
flannel,calico,canel,kube-router …
# kubectl get configmap kube-proxy -n kube-system -o yaml mode: "" # 改为ipvs 就可以了
解决方案:
虚拟网桥: 纯软件的方式,实现一个虚拟网卡接到网桥上去;
多路复用: MacVlAN 配置多个Mac物理地址,使得一个物理网卡,可以承载多个容器去使用;
硬件交换: SR-IOV 单根IO虚拟化;
kubelet, /etc/cin/net.d/
# cat /etc/cni/net.d/10-flannel.conflist { "name": "cbr0", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ] }
flannel:
支持多种后端
VxLAN
host-gw: Host Gateway
# kubectl get daemonset -n kube-system NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE kube-flannel-ds 3 3 3 3 3 beta.kubernetes.io/arch=amd64 31d kube-flannel-ds-amd64 4 4 4 4 4 beta.kubernetes.io/arch=amd64 31d kube-flannel-ds-arm 0 0 0 0 0 beta.kubernetes.io/arch=arm 31d kube-flannel-ds-arm64 0 0 0 0 0 beta.kubernetes.io/arch=arm64 31d kube-flannel-ds-ppc64le 0 0 0 0 0 beta.kubernetes.io/arch=ppc64le 31d kube-flannel-ds-s390x 0 0 0 0 0 beta.kubernetes.io/arch=s390x 31d kube-proxy 4 4 4 4 4 <none> 31d
# kubectl get pods -n kube-system -o wide | grep "flannel" kube-flannel-ds-amd64-45rhc 1/1 Running 2 31d 10.1.87.80 bj-zb-vm-ops-test5 <none> <none> kube-flannel-ds-amd64-4cs6r 1/1 Running 0 31d 10.1.87.83 node03 <none> <none> kube-flannel-ds-amd64-bst7g 1/1 Running 0 31d 10.1.87.81 node01 <none> <none> kube-flannel-ds-amd64-gqvz2 1/1 Running 0 31d 10.1.87.82 node02 <none> <none> kube-flannel-ds-brzp7 2/2 Running 0 31d 10.1.87.83 node03 <none> <none> kube-flannel-ds-khpr5 2/2 Running 2 31d 10.1.87.82 node02 <none> <none> kube-flannel-ds-q6z65 2/2 Running 0 31d 10.1.87.81 node01
kube-flannel-cfg 用来配置以上flannel Pod是如何运行的;
flannel的配置参数:
Network: flannel使用的CIDR格式的网络地址,用于为Pod的配置网络功能;
10.244.0.0/16 ->
master: 10.244.0.0/24
node01:10.244.1.0/24
…
node255: 10.244.255.0./24
SubnetLen: 把Network切分子网供各节点使用时,使用多长的掩码进行切分,默认为24位;
SubnetMin: 10.244.10.0/24 指定子网使用起始,从哪里开始;
SubnetMax: 10.244.10.0/24 指定子网使用最大限制;
Backend: 各Pod通信时使用什么方式进行通信: vxlan, host-gw , udp
测试
# kubectl get pods -o wide # kubectl get pods -o wide | grep "myapp-deploy" myapp-deploy-675558bfc5-947g6 1/1 Running 0 4d1h 10.244.1.173 node01 <none> <none> myapp-deploy-675558bfc5-9xfdm 1/1 Running 0 4d6h 10.244.3.176 node03 <none> <none> myapp-deploy-675558bfc5-qhl4w 1/1 Running 0 5h41m 10.244.2.195 node02 <none> <none>
接入一个容器ping另一容器的ip
# kubectl exec -it myapp-deploy-675558bfc5-947g6 -- /bin/sh / # ping 10.244.2.195 PING 10.244.2.195 (10.244.2.195): 56 data bytes 64 bytes from 10.244.2.195: seq=0 ttl=62 time=0.871 ms 64 bytes from 10.244.2.195: seq=1 ttl=62 time=0.925 ms 64 bytes from 10.244.2.195: seq=2 ttl=62 time=0.886 ms 64 bytes from 10.244.2.195: seq=3 ttl=62 time=1.171 ms
在容器所在的物理服务器上抓包,
# tcpdump -i cni0 -nn icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on cni0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:52:45.457148 IP 10.244.1.173 > 10.244.2.195: ICMP echo request, id 3328, seq 0, length 64 16:52:45.457743 IP 10.244.2.195 > 10.244.1.173: ICMP echo reply, id 3328, seq 0, length 64 16:52:46.457445 IP 10.244.1.173 > 10.244.2.195: ICMP echo request, id 3328, seq 1, length 64 16:52:46.457948 IP 10.244.2.195 > 10.244.1.173: ICMP echo reply, id 3328, seq 1, length 64 16:52:47.457722 IP 10.244.1.173 > 10.244.2.195: ICMP echo request, id 3328, seq 2, length 64 16:52:47.458313 IP 10.244.2.195 > 10.244.1.173: ICMP echo reply, id 3328, seq 2, length 64 16:52:48.458036 IP 10.244.1.173 > 10.244.2.195: ICMP echo request, id 3328, seq 3, length 64
# tcpdump -i flannel.1 -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes 17:01:13.757750 IP 10.244.1.0 > 10.244.2.195: ICMP echo request, id 2, seq 37, length 64 17:01:13.758396 IP 10.244.2.195 > 10.244.1.0: ICMP echo reply, id 2, seq 37, length 64 17:01:14.758058 IP 10.244.1.0 > 10.244.2.195: ICMP echo request, id 2, seq 38, length 64 17:01:14.758791 IP 10.244.2.195 > 10.244.1.0: ICMP echo reply, id 2, seq 38, length 64 17:01:15.758376 IP 10.244.1.0 > 10.244.2.195: ICMP echo request, id 2, seq 39, length 64 17:01:15.759072 IP 10.244.2.195 > 10.244.1.0: ICMP echo reply, id 2, seq 39, length 64 17:01:16.758661 IP 10.244.1.0 > 10.244.2.195: ICMP echo request, id 2, seq 40, length 64
# tcpdump -i eth0 -nn host 10.1.87.82 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 17:03:44.145010 IP 10.1.87.81.44247 > 10.1.87.82.8472: OTV, flags [I] (0x08), overlay 0, instance 1 IP 10.244.1.0 > 10.244.2.195: ICMP echo request, id 3, seq 0, length 64 17:03:44.145551 IP 10.1.87.82.8942 > 10.1.87.81.8472: OTV, flags [I] (0x08), overlay 0, instance 1 IP 10.244.2.195 > 10.244.1.0: ICMP echo reply, id 3, seq 0, length 64 17:03:45.145300 IP 10.1.87.81.44247 > 10.1.87.82.8472: OTV, flags [I] (0x08), overlay 0, instance 1 IP 10.244.1.0 > 10.244.2.195: ICMP echo request, id 3, seq 1, length 64 17:03:45.145854 IP 10.1.87.82.8942 > 10.1.87.81.8472: OTV, flags [I] (0x08), overlay 0, instance 1
Flannel VxLAN的Direct routing模式配置
# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml # vim kube-flannel.yml net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan", "Directrouting": true # 添加字段 } } # kubectl delete -f kube-flannel.yml # kubectl apply -f kube-flannel.yml # ip route show default via 10.1.87.1 dev eth0 10.1.87.0/24 dev eth0 proto kernel scope link src 10.1.87.80 10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1 10.244.1.0/24 via 10.1.87.81 dev eth0 10.244.2.0/24 via 10.1.87.82 dev eth0 10.244.3.0/24 via 10.1.87.83 dev eth0
注: 在生产环境中不可以这么做,会影响到Pod的网络环境。生产环境一般在使用前会考虑并初始化好网络环境,也就是说先修改 flannel 才开始使用创建Pod;
calico 安装使用
Canal/flannel Hosted Install 官方文档
# kubectl apply -f https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/canal/rbac.yaml # kubectl apply -f https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/canal/canal.yaml
创建名称空间
podSelector: {} 为空时,代表所有Pod
# kubectl create namespace dev namespace/dev created # kubectl create namespace prod namespace/prod created # vim ingress-def.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress spec: podSelector: {} policyTypes: - Ingress # kubectl apply -f ingress-def.yaml -n dev # kubectl get netpol -n dev NAME POD-SELECTOR AGE deny-all-ingress <none> 93s
# vim pod-a.yaml apiVersion: v1 kind: Pod metadata: name: pod1 spec: containers: - name: myapp image: ikubernetes/myapp:v1 # kubectl apply -f pod-a.yaml -n dev # kubectl get pods -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod1 1/1 Running 0 54s 10.244.3.2 node03 <none> <none>
这是请求10.244.3.2 发现是请求不通的
# curl 10.244.3.2 curl: (7) Failed connect to 10.244.3.2:80; Connection timed out
而把 pod-a.yaml 创建在prod 名称空间,此时prod名称空间是没有定义的
# kubectl apply -f pod-a.yaml -n prod pod/pod1 created # kubectl get pods -n prod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod1 1/1 Running 0 17s 10.244.3.3 node03 <none> <none>node
请求10.244.3.3名称空间的可以请求通
# curl 10.244.3.3 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
当允许dev名称空间的Pod 都可以访问时,只需加 ingress: - {}
就可以了
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress spec: podSelector: {} ingress: - {} policyTypes: - Ingress # kubectl apply -f ingress-def.yaml -n dev # curl 10.244.3.2 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
定义允许访问一组Pod,使用标签来实现
# kubectl label pods pod1 app=myapp -n dev pod/pod1 labeled
还原ingress-def 为默认,拒绝所有dev 名称空间所有Pod的访问
# vim ingress-def.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress spec: podSelector: {} policyTypes: - Ingress # kubectl apply -f ingress-def.yaml -n dev # curl 10.244.3.2 curl: (7) Failed connect to 10.244.3.2:80; Connection timed out
配置测略,允许某网段允许访问指定策略
# vim allow-netpol-demo.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-myapp-ingress spec: podSelector: matchLabels: app: myapp ingress: - from: - ipBlock: cidr: 10.244.0.0/16 except: - 10.244.1.2/32 ports: - protocol: TCP port: 80 - protocol: TCP port: 443 # kubectl apply -f allow-netpol-demo.yaml -n dev # kubectl get netpol -n dev NAME POD-SELECTOR AGE allow-myapp-ingress app=myapp 2m deny-all-ingress <none> 34m # curl 10.244.3.2:80 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
管控出站流量的方式
# vim egress-def.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-egress spec: podSelector: {} policyTypes: - Egress # kubectl apply -f egress-def.yaml -n prod networkpolicy.networking.k8s.io/deny-all-egress created # kubectl apply -f pod-a.yaml -n prod # 将之前的pod-a.yaml 创建到prod名称空间 pod/pod1 unchanged # kubectl get pods -n prod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod1 1/1 Running 0 34m 10.244.3.3 node03 <none> <none>node # kubectl exec pod1 -it -n prod -- /bin/sh / # ping 10.1.87.81 PING 10.1.87.81 (10.1.87.81): 56 data bytes ^C --- 10.1.87.81 ping statistics --- 4 packets transmitted, 0 packets received, 100% packet loss / #
# vim egress-def.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-egress spec: podSelector: {} egress: - {} policyTypes: - Egress # kubectl apply -f egress-def.yaml -n prod # kubectl exec pod1 -it -n prod -- /bin/sh / # ping 10.1.87.81 PING 10.1.87.81 (10.1.87.81): 56 data bytes 64 bytes from 10.1.87.81: seq=0 ttl=63 time=0.660 ms 64 bytes from 10.1.87.81: seq=1 ttl=63 time=0.564 ms ^C --- 10.1.87.81 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.564/0.612/0.660 ms
可以看到放行所有Pod出站规则,网络是通的;
网络策略:
名称空间:
拒绝所有出站,入站;
放行所有出站目标本名称空间内的所有Pod;