k8s学习-Kubernetes的网络

Kubernetes作为编排引擎管理着分布在不同节点上的容器和Pod。Pod、Service、外部组件之间需要⼀种可靠的方找到彼此并进行通信,Kubernetes网络则负责提供这个保障。

1.1 Kubernetes网络模型

  1. Container-to-Container的网络
    当Pod被调度到某个节点,Pod中的所有容器都在这个节点上运行,这些容器共享相同的本地问件系统、IPC和网络命名空间。不同Pod之间不存在端口冲突的问题,因为每个Pod都有自己的IP地址。当某个容器使用localhost时,意味着使用的是容器所属Pod的地址空间。
  1. Pod之间的通信

Pod的IP是集群可见的,即集群中的任何其他Pod和节点都可以通过IP直接与Pod通信,这种通信不需要借助任何网络地址转换、隧道或代理技术。Pod内部和外部使用的是同⼀个IP,这也意味着标准的命名服务和发现机制,比如如DNS可以直接使用

数据包的传递:Pod-to-Pod,同节点

在 network namespace 将每一个 Pod 隔离到各自的网络堆栈的情况下,虚拟以太网设备(virtual Ethernet device)将每一个 namespace 连接到 root namespace,网桥将 namespace 又连接到一起,此时,Pod 可以向同一节点上的另一个 Pod 发送网络报文了。下图演示了同节点上,网络报文从一个Pod传递到另一个Pod的情况。

数据包的传递:Pod-to-Pod,跨节点

在了解了如何在同节点上 Pod 之间传递数据包之后,我们接下来看看如何在跨节点的 Pod 之间传递数据包。Kubernetes 网络模型要求 Pod 的 IP 在整个网络中都可访问,但是并不指定如何实现这一点。实际上,这是所使用网络插件相关的,但是,仍然有一些模式已经被确立了。

  1. Pod与Service的通信

在Kubernetes集群中,Pod可能会频繁地销毁和创建,也就是说Pod的IP不是固定的。为了解决这个问题,Service提供了访问Pod的抽象层。无论后端的Pod如何变化,Service都作为稳定的前端对外提供服务。同时,Service还提供了高可用和负载均衡功能,Service负责将请求转发给正确的Pod。

  1. 外部访问
    无论是Pod的IP还是Service的Cluster IP,它们只能在Kubernetes集群中可见,对集群之外的世界,这些IP都是私有的。

Kubernetes提供了两种方式让外界能够与Pod通信:

  • NodePort。Service通过Cluster节点的静态端口对外提供服务。
    外部可以通过:访问Service。
  • LoadBalancer。Service利用cloudprovider提供的loadbalancer对外提供服务,cloudprovider负责将loadbalancer的流量导向Service。目前支持的cloudprovider有GCP、AWS、Azur等。

参考:kubernetes基本概念

1.2 各种网络方案

为了保证网络方案的标准化、扩展性和灵活性,K8S采用了CNI(Container Networking Interface)规范。CNI是一个Pod网络集成标准,简化了K8S和不同Pod网络实现技术的集成。

CNI最大的优点就是支持多种容器runtime,而不仅仅是Docker。目前已经有多种支持K8S的网络方案,包括 Flannel、Calico、Canal等,它们都实现了CNI规范,因此无论我们选择哪种具体方案,它们的网络模型都是一致的。

1.3 Network Policy

Network Policy是K8S的一种资源,它使K8S可以通过Label选择Pod,并指定其他Pod或外界如何与这些Pod通信。换句话说,当Pod被定义了Network Policy时,只有Policy允许的流量才能访问Pod(默认情况下,任何来源的流量都可以访问Pod,是没有限制的)即帮助K8S实现更为精细的流量控制,实现租户隔离机制。

但是,并不是所有K8S网络方案都支持Network Policy,比如Flannel就不支持,而Calico是支持的。

1.4 Network Policy实践

1.5 部署Canal

想要部署Canal,需要切换网络方案,这里我们使用最简单粗暴的方式:重建当前K8S集群

bash 复制代码
kubeadm reset # 在每个节点上执行一次

然后,重新对Master节点进行初始化:

bash 复制代码
kubeadm init \
--apiserver-advertise-address=192.168.200.128 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16

在两个Node节点上执行以下命令重新加入集群:

kubeadm join 192.168.200.160:6443 --token ekqxk2.iiu5wx5bbnbdtxsw --discovery-token-ca-cert-hash

sha256:c50bb83d04f64f4a714b745f04682b27768c1298f331e697419451f3550f2d05

最后,通过以下命令部署Canal:

kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/canal.yaml

1.6 部署测试应用

这里通过一个httpd应用来演示Network Policy,该应用的yaml定义如下:

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
spec:
  replicas: 3
  selector:
    matchLabels:
      name: networkpolicy-demo
  template:
    metadata:
      labels:
        name: networkpolicy-demo
    spec:
      containers:
      - name: httpd
        image: httpd:latest
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent

---

kind: Service
apiVersion: v1
metadata:
  name: httpd-svc
spec:
  type: NodePort
  ports:
    - protocol: TCP
      nodePort: 33000
      port: 8080
      targetPort: 80
  selector:
    name: networkpolicy-demo

通过kubectl将其部署到K8S集群:

yaml 复制代码
kubectl apply -f httpd-demo.yaml
bash 复制代码
[root@k8s-master ~]# kubectl get pod -o wide
NAME                                   READY   STATUS         RESTARTS   AGE     IP             NODE        NOMINATED NODE   READINESS GATES
httpd-595dc58589-c4hcv                 1/1     Running        5          2d2h    10.244.1.157   k8s-node1   <none>           <none>
httpd-595dc58589-lxj9w                 1/1     Running        6          2d2h    10.244.1.156   k8s-node1   <none>           <none>
httpd-595dc58589-v6wzw                 1/1     Running        11         4d20h   10.244.1.153   k8s-node1   <none>           <none>

1.7 测试Network Policy有效性

现在我们创建一个Network Policy,其配置文件yaml如下:

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-httpd
spec:
  podSelector:
    matchLabels:
      name: networkpolicy-demo
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"
    ports:
    - protocol: TCP
      port: 80

该Network Policy定义了如下规则:

(1)应用于所有 label 为 name : networkpolicy-demo 的Pod,这里即刚刚创建的三个httpd pod。

(2)ingress中定义了只有 label 为 access : "true" 的Pod才能访问应用。

(3)即使通过Policy也只能访问80端口

通过kubectl将其应用到K8S集群中:

bash 复制代码
kubectl apply -f networkpolicy.yaml

下面再次在busybox pod中验证Network Policy的有效性:

bash 复制代码
[root@k8s-master ~]# kubectl run busvbox --rm -it --image=busybox bin/sh
/ #  wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.1.216.8:8080)
wget: can't connect to remote host (10.1.216.8) Connection timed out

从上可以看到,已经无法再成功访问Service,也无法再ping通三个Pod节点。

这个时候,集群外也无法再通过NodePort访问到Service。

如果想要让测试Pod(busybox)能访问到应用了Network Policy的httpd应用,我们可以对busybox pod加一个label就可以:

bash 复制代码
[root@k8s-master ~]# kubectl run busybox --rm -it --image=busybox --labels="access=true" /bin/sh
/ #  wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.1.216.8:8080)
saving to 'index.html'
index.html           100% |**************************************************************************************************|    45  0:00:00 ETA
'index.html' saved

运行后的验证结果如下,可以访问到Service,但Ping却被禁止:

bash 复制代码
/ # ping -c 3 10.244.1.150
PING 10.244.1.150 (10.244.1.150): 56 data bytes
--- 10.244.1.150 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

但是,此时集群节点(k8s-master与两个node)与集群仍然无法访问到应用了Network Policy的httpd应用,如果想要让它们也访问到,则需要修改Network Policy做一个类似于开防火墙白名单的操作(注意下面的ipBlock配置):

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-httpd
spec:
  podSelector:
    matchLabels:
      name: networkpolicy-demo
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"
    - ipBlock:
        cidr: 192.168.200.0/24
    ports:
    - protocol: TCP
      port: 80

再次应用到K8S集群后,再来通过集群访问试试:

bash 复制代码
[root@k8s-master ~]# kubectl exec -it busvbox -- /bin/sh
/ # ping -c 3 10.244.1.150
PING 10.244.1.150 (10.244.1.150): 56 data bytes
64 bytes from 10.244.1.150: seq=0 ttl=62 time=2.633 ms
64 bytes from 10.244.1.150: seq=1 ttl=62 time=0.288 ms
64 bytes from 10.244.1.150: seq=2 ttl=62 time=0.319 ms

--- 10.244.1.150 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.288/1.080/2.633 ms
相关推荐
Flying_Fish_roe18 分钟前
linux-网络管理-网络配置
linux·网络·php
Ylucius1 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
LvManBa2 小时前
Vue学习记录之六(组件实战及BEM框架了解)
vue.js·学习·rust
hellojackjiang20112 小时前
即时通讯框架MobileIMSDK的H5端开发快速入门
网络·即时通讯·im开发
LvManBa2 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
有时间要学习2 小时前
Linux——应用层自定义协议与序列化
linux·服务器·网络
Tony聊跨境2 小时前
什么是 SSL 代理?
网络·网络协议·ssl
知识分享小能手3 小时前
mysql学习教程,从入门到精通,SQL DISTINCT 子句 (16)
大数据·开发语言·sql·学习·mysql·数据分析·数据库开发
我叫啥都行3 小时前
计算机基础知识复习9.7
运维·服务器·网络·笔记·后端