新闻中心

当前位置: 首页 >新闻中心 >行业相关

推荐新闻Recommend

联系我们Contact Us

kubernetes——容器网络

2021-07-08
3430次

容器网络原理

同主机容器网络

Docker会在宿主机上生成一个docker0网桥,然后借助Veth Pair技术产生两张虚拟网卡,这两张网卡好像组成了一根网线,从一端发出的包会在另一端收到,这两张网卡一张插在container中,另一张插在docker0网桥上,这样宿主机上的容器实际上构成了一个局域网,因此同一宿主机上的容器网络上是彼此联通的。

跨主机容器网络

与同主机容器网络类似,跨主机容器网络实际上是在不同主机间构建了一个彼此联通的网桥,这个特殊的网桥通常是通过配置路由表实现的。

Fannel UDP模式

  • 同一台宿主机上的所有容器的IP都属于Fannel网络的一个子网

  • 跨宿主机的容器间通信会发送到flannel0这个TUN设备上,flanneld进程接收到后包装成UDP包发送到宿主机的eth0网卡上,只要宿主机之间网络是联通的,UDP包就会被路由到目的宿主机上

  • 目的宿主机的flanneld进程收到后进行解包,把原始IP包交给docker0网关,终路由到正确的容器上

  • Fannel UDP模式的缺点在于,由于flanneld进程工作在User Space下,因此存在额外的用户态的内核态的切换和拷贝,因此效率不高,目前已经被VXLAN模式取代。

Fannel VXLAN模式


  • VXLAN:Virtual Extensible LAN,即虚拟可扩展局域网,它是Linux内核支持的一种网络虚拟化技术,因此本身就工作在内核态

  • VXLAN会在每台node上部署一个VTEP设备,它既有IP,也有MAC。当有新的node加入时,它的ARP信息会自动下发到其他node上,这样就不再依赖ARP学习机制。这样,node上的VTEP设备就构成了一个虚拟的二层网络

kubernets网络解决方案

CNI网络插件

CNI网络模型中有两个重要概念:

  • 容器:拥有独立Linux网络命名空间的环境

  • 网络:表示互联的一组实体,每个实体都拥有各自独立的IP。这些实体可以是容器、物理机或其他网络设备。

网络隔离

kubernetes通过NetworkPolicy定义网络隔离,以下面文件为例:

  • podSelector选中的pod会拒绝所有的出入连接(因为policyTypes中既有Ingress也有Egress),除非满足ingress和egress定义的规则

  • from和to的所有列表项之间都是“与”的关系

  • ipBlock是ip段的意思,并不是隔离的意思

apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:  name: test-network-policy  namespace: defaultspec:  podSelector:    matchLabels:      role: db  policyTypes:  - Ingress  - Egress  ingress:  - from:    - ipBlock:        cidr: 172.17.0.0/16        except:        - 172.17.1.0/24    - namespaceSelector:        matchLabels:          project: myproject    - podSelector:        matchLabels:          role: frontend    ports:    - protocol: TCP      port: 6379  egress:  - to:    - ipBlock:        cidr: 10.0.0.0/24    ports:    - protocol: TCP      port: 5978

Service

Service通过kube-proxy组件和iptable实现功能,它实际上是一个代理,为一组pod提供稳定的访问入口,同时满足多个pod之间的负载均衡需求。

  • 所有service的IP都在一个独立的子网中,这个子网不和任何docker0或物理网络的子网冲突

  • 所有到service的流量都会被forward到node上的一个端口,该端口由kube-proxy监听,并使用一定的负载均衡策略转发到service代理的pod上。

基本功能

  • Service通过selector来匹配一组pod,如下面例子,service会代理携带了app=hostnames标签的pod

  • port指service对外暴露的端口号,targetPort指pod中容器的端口号

  • 默认的路由策略是RoundRobin,通过设置service.spec.sessionAffinity=ClientIP可以把来自同一IP的请求路由到同一个pod上,实现了会话粘滞。

apiVersion: v1kind: Servicemetadata:  name: hostnamesspec:  selector:    app: hostnames  ports:  - name: default    protocol: TCP    port: 80    targetPort: 9376

Headless Service

默认情况下, service会有一个固定的cluster IP,但有时程序希望知道服务的

Service和DNS

Kubernetes会为每个Service和Pod创建一条DNS A记录,即从域名到IP的mapping关系记录:

  • 对于clusterIP Service,A记录的格式是..svc.cluster.local,当访问它时会返回service的VIP地址。

  • 对于headless Service(clusterIP=None),它的格式也是..svc.cluster.local,访问它会返回Service所代理Pod的IP集合

NodePort

apiVersion: v1kind: Servicemetadata:  name: my-nginx  labels:    run: my-nginxspec:  type: NodePort  ports:  - nodePort: 8080    targetPort: 80    protocol: TCP    name: http  - nodePort: 443    protocol: TCP    name: https  selector:    run: my-nginx

Ingress

在HTTP服务中,不同的URL经常需要对应到不同的后端服务上去,这种转发机制通过service的IP:Port的形式无法实现,因此Kubernets提供了Ingress机制提供边缘路由器的功能。

Ingress官方文档

Ingress Controller

  • Ingress Controller为后端的service提供一个统一的入口,它通常是一个DaemonSet,以hostPort的形式暴露服务入口,这样访问NodeIP:Port实际上就是访问Ingress Controller。

  • Ingress Controller通常不会把流量再转发到service,而是直接把流量转发给service代理的endpoint。因此,service上配置的session affinity策略在使用ingress的情况下,经常会失效。这是应该使用ingress controller的session affinity策略。

Ingress策略配置

转发到单个后端服务

apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: test-ingressspec:  defaultBackend:    service:      name: test      port:        number: 80

同域名下不同URL路径转发到不同服务


apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: simple-fanout-examplespec:  rules:  - host: foo.bar.com    http:      paths:      - path: /foo        pathType: Prefix        backend:          service:            name: service1            port:              number: 4200      - path: /bar        pathType: Prefix        backend:          service:            name: service2            port:              number: 8080

不同域名转发到不同服务


apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: name-virtual-host-ingressspec:  rules:  - host: foo.bar.com    http:      paths:      - pathType: Prefix        path: "/"        backend:          service:            name: service1            port:              number: 80  - host: bar.foo.com    http:      paths:      - pathType: Prefix        path: "/"        backend:          service:            name: service2            port:              number: 80

无域名转发

  • 当rules中没有任何host时,所有发往Ingress Controller的流量都会进来

  • 无域名转发会强制使用https,除非使用ingress.kubernetes.io/ssl-redirect=false关闭强制使用HTTPS的设置

apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: name-virtual-host-ingress-no-third-hostspec:  rules:  - http:      paths:      - pathType: Prefix        path: "/demo"        backend:          service:            name: service3            port:              number: 80

使用TLS

  • 首先把公私钥定义在一个secret中

apiVersion: v1kind: Secretmetadata:  name: testsecret-tls  namespace: defaultdata:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded keytype: kubernetes.io/tls
  • 然后在ingress定义中引用定义好的secret

apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: tls-example-ingressspec:  tls:  - hosts:      - https-example.foo.com    secretName: testsecret-tls  rules:  - host: https-example.foo.com    http:      paths:      - path: /        pathType: Prefix        backend:          service:            name: service1            port:              number: 80

常用的ingress controller

trafik

  • 在Traefik和其他Ingress控制器实现之间。有时Traefik会与其他Ingress控制器实现一起运行。其中一个例子是当 Traefik 和云提供商的 Ingress 控制器都处于活动状态时。

  • kubernetes.io/ingress.class注解可以附加到任何Ingress对象,以控制Traefik是否应该处理它。如果注释缺失、包含一个空值或值traefik,那么Traefik控制器将负责并处理相关的Ingress对象。

  • 也可以将Traefik中的ingressClass选项设置为一个特定的值。Traefik将只处理匹配的Ingress对象。例如,将该选项设置为 traefik-internal 会使 Traefik 处理具有相同kubernetes.io/ingress.class 注释值的 Ingress 对象,而忽略所有其他对象(包括具有 traefik 值、空值和缺少注释的对象)。


联系我们contact us