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模式取代。
VXLAN:Virtual Extensible LAN,即虚拟可扩展局域网,它是Linux内核支持的一种网络虚拟化技术,因此本身就工作在内核态
VXLAN会在每台node上部署一个VTEP设备,它既有IP,也有MAC。当有新的node加入时,它的ARP信息会自动下发到其他node上,这样就不再依赖ARP学习机制。这样,node上的VTEP设备就构成了一个虚拟的二层网络
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通过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
默认情况下, service会有一个固定的cluster IP,但有时程序希望知道服务的
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集合
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
在HTTP服务中,不同的URL经常需要对应到不同的后端服务上去,这种转发机制通过service的IP:Port的形式无法实现,因此Kubernets提供了Ingress机制提供边缘路由器的功能。
Ingress Controller为后端的service提供一个统一的入口,它通常是一个DaemonSet,以hostPort的形式暴露服务入口,这样访问NodeIP:Port实际上就是访问Ingress Controller。
Ingress Controller通常不会把流量再转发到service,而是直接把流量转发给service代理的endpoint。因此,service上配置的session affinity策略在使用ingress的情况下,经常会失效。这是应该使用ingress controller的session affinity策略。
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: test-ingressspec: defaultBackend: service: name: test port: number: 80
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
首先把公私钥定义在一个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
在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 值、空值和缺少注释的对象)。