目录
[二. 组件介绍](#二. 组件介绍)
[1. Kubernetes概述](#1. Kubernetes概述)
[2. K8S架构与组件](#2. K8S架构与组件)
[master 节点组件](#master 节点组件)
[Controller Runtime](#Controller Runtime)
[3. K8S核心概念](#3. K8S核心概念)
[4. Kubetnetes 涉及的端口](#4. Kubetnetes 涉及的端口)
[三. 网络概述](#三. 网络概述)
[Weave Net](#Weave Net)
[四. 网络原理](#四. 网络原理)
[1. K8s网络模型](#1. K8s网络模型)
[2. Docker的网络模型](#2. Docker的网络模型)
[3. 网络的命名空间](#3. 网络的命名空间)
[4. Veth设备对](#4. Veth设备对)
[5. 网桥](#5. 网桥)
[6. Iptables/Netfilter](#6. Iptables/Netfilter)
[7. 路由](#7. 路由)
[8. Docker的网络实现](#8. Docker的网络实现)
[9. K8s的网络实现](#9. K8s的网络实现)
一.故事背景
之前的内容完成了全部应用相关的讲解,接下来该了解新内容组件与网络
二. 组件介绍
1. Kubernetes概述
Kubernetes 简称 k8s,是支持云原生部署的一个平台,起源于谷歌。谷歌早在十几年之前就对其应用,通过容器方式进行部署。
k8s 本质上就是用来简化微服务 的开发和部署的,关注点包括自愈和自动伸缩、调度和发布、调用链监控、配置管理、Metrics 监控、日志监控、弹性和容错、API 管理、服务安全等,k8s 将这些微服务的公共关注点以组件形式封装打包到 k8s 这个大平台中,让开发人员在开发微服务时专注于业务逻辑的实现,而不需要去特别关心微服务底层的这些公共关注点,大大简化了微服务应用的开发和部署,提高了开发效率。
K8S的由来
-
K8S由google的Borg系统(博格系统,google内部使用的大规模容器编排工具)作为原型,后经GO语言延用Borg的思路重写并捐献给CNCF基金会开源。
-
云原生基金会(CNCF)于2015年12月成立,隶属于Linux基金会。CNCF孵化的第一个项目就是Kubernetes,随着容器的广泛使用,Kubernetes已经成为容器编排工具的事实标准。
K8S的功能
-
跨主机编排容器。
-
更充分地利用硬件资源来最大化地满足企业应用的需求。
-
控制与自动化应用的部署与升级。
-
为有状态的应用程序挂载和添加存储器。
-
线上扩展或缩减容器化应用程序与它们的资源。
-
声明式的容器管理,保证所部署的应用按照我们部署的方式运作。
-
通过自动布局、自动重启、自动复制、自动伸缩实现应用的状态检查与自我修复。
-
为多个容器提供服务发现和负载均衡,使得用户无需考虑容器IP问题。
K8S解决的问题
K8S 解决了裸跑 Docker 的若干痛点:
-
单机使用,无法有效集群
-
随着容器数量的上升,管理成本攀升
-
没有有效的容灾、自愈机制
-
没有预设编排模板,无法实现快速、大规模容器调度
-
没有统一的配置管理中心工具
-
没有容器生命周期的管理工具
-
没有图形化运维管理工具
K8S 提供了容器编排,资源调度,弹性伸缩,部署管理,服务发现等一系列功能。
K8S的特性
- 弹性伸缩
使用命令、UI 或者基于 CPU 使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性;业务低峰时回收资源,以最小成本运行服务。
- 自我修复
在节点故障时重新启动失败的容器,替换和重新部署,保证预期的副本数量;杀死健康检查失败的容器,并且在未准备好之前不会处理客户端请求,确保线上服务不中断。
- 自动发布(默认滚动发布模式)和回滚
K8S 采用滚动更新策略更新应用,一次更新一个 Pod,而不是同时删除所有 Pod,如果更新过程中出现问题,将回滚更改,确保升级不影响业务。
- 集中化配置管理和密钥管理
管理机密数据和应用程序配置,而不需要把敏感数据暴露在镜像里,提高敏感数据安全性。并可以将一些常用的配置存储在 K8S 中,方便应用程序使用。
- 存储编排,支持外挂存储并对外挂存储资源进行编排
挂载外部存储系统,无论是来自本地存储,公有云(如 AWS),还是网络存储(如 NFS、GlusterFS、Ceph)都作为集群资源的一部分使用,极大提高存储使用灵活性。
- 任务批处理运行
提供一次性任务,定时任务;满足批量数据处理和分析的场景。
2. K8S架构与组件
K8S架构
k8s 总体架构采用了经典的 maste/slave 架构模式,分 master 节点和 worker 节点,节点可以是虚拟机也可以是物理机。

K8S组件
master 节点组件
Kube-apiserver
-
用于暴露 Kubernetes API,任何资源请求或调用操作都是通过 kube-apiserver 提供的接口进行。以 HTTPRestful API 提供接口服务,所有对象资源的增删改查和监听操作都交给 API Server 处理后再提交给 Etcd 存储。
-
可以理解成 API Server 是 K8S 的请求入口服务。API Server 负责接收 K8S 所有请求(来自 UI 界面或者 CLI命令行工具), 然后根据用户的具体请求,去通知其他组件干活。可以说 API Server 是 K8S 集群架构的大脑。
Kube-controller-manager
-
运行管理控制器,是 K8S 集群中处理常规任务的后台线程,是 K8S 集群里所有资源对象的自动化控制中心。在 K8S 集群中,一个资源对应一个控制器,而 Controller manager 就是负责管理这些控制器的。
-
由一系列控制器组成,通过 API Server 监控整个集群的状态,并确保集群处于预期的工作状态,比如当某个 Node意外宕机时,Controller Manager 会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。
控制器类型 | 作用 |
---|---|
Node Controller(节点控制器) | 负责在节点出现故障时发现和响应。 |
Replication Controller(副本控制器) | 负责保证集群中一个 RC(资源对象 Replication Controller)所关联的 Pod 副本数始终保持预设值。可以理解成确保集群中有且仅有 N 个 Pod 实例,N 是 RC 中定义的 Pod 副本数量。 |
EndpointsController(端点控制器) | 填充端点对象(即连接 Services 和 Pods),负责监听 Service 和对应的 Pod副本的变化。 可以理解端点是一个服务暴露出来的访问点,如果需要访问一个服务,则必须知道它的 endpoint。 |
Service Account & Token Controllers(服务帐户和令牌控制器) | 为新的命名空间创建默认帐户和 API 访问令牌。 |
ResourceQuota Controller(资源配额控制器) | 确保指定的资源对象在任何时候都不会超量占用系统物理资源。 |
Namespace Controller(命名空间控制器) | 管理 namespace 的生命周期。 |
Service Controller(服务控制器) | 属于 K8S 集群与外部的云平台之间的一个接口控制器。 |
Kube-scheduler
-
是负责资源调度的进程,根据调度算法为新创建的 Pod 选择一个合适的 Node 节点。
-
可以理解成 K8S 所有 Node 节点的调度器。当用户要部署服务时,Scheduler 会根据调度算法选择最合适的 Node 节点来部署 Pod。
-
预选策略(predicate)
-
优选策略(priorities)
etcd
- K8S 的存储服务。etcd 是分布式键值存储系统,存储了 K8S 的关键配置和用户配置,K8S 中仅 API Server 才具备读写权限,其他组件必须通过 API Server 的接口才能读写数据。
node节点组件
在 Kubernetes 集群中,在每个 Node(又称 Worker Node)上都会启动一个 kubelet 服务进程。该进程用于处理 Master 下发到本节点的任务,管理 Pod 及 Pod 中的容器。每个 kubelet 进程都会在 API Server 上注册节点自身的信息,定期向 Master 汇报节点资源的使用情况,并通过 cAdvisor 监控容器和节点资源。
Kubelet
-
Node 节点的监视器,以及与 Master 节点的通讯器。Kubelet 是 Master 节点安插在 Node 节点上的"眼线",它会定时向 API Server 汇报自己 Node 节点上运行的服务的状态,并接受来自 Master 节点的指示采取调整措施。
-
从 Master 节点获取自己节点上 Pod 的期望状态(比如运行什么容器、运行的副本数量、网络或者存储如何配置等), 直接跟容器引擎交互实现容器的生命周期管理,如果自己节点上 Pod 的状态与期望状态不一致,则调用对应的容器平台接口(即 docker 的接口)达到这个状态。
-
管理镜像和容器的清理工作,保证节点上镜像不会占满磁盘空间,退出的容器不会占用太多资源。
Kube-Proxy
-
在每个 Node 节点上实现 Pod 网络代理,是 Kubernetes Service 资源的载体,负责维护网络规则和四层负载均衡工作。 负责写入规则至iptables、ipvs实现服务映射访问的。
-
Kube-Proxy 本身不是直接给 Pod 提供网络,Pod 的网络是由 Kubelet 提供的,Kube-Proxy 实际上维护的是虚拟的 Pod 集群网络。
-
Kube-apiserver 通过监控 Kube-Proxy 进行对 Kubernetes Service 的更新和端点的维护。
-
在 K8S 集群中微服务的负载均衡是由 Kube-proxy 实现的。Kube-proxy 是 K8S 集群内部的负载均衡器。它是一个分布式代理服务器,在 K8S 的每个节点上都会运行一个 Kube-proxy 组件。
Controller Runtime
-
容器引擎,如:docker、containerd,运行容器,负责本机的容器创建和管理工作。
-
当 kubernetes 把 pod 调度到节点上,节点上的 kubelet会指示 docker 启动特定的容器。接着,kubelet 会通过 docker 持续地收集容器的信息, 然后提交到主节点上。docker 会如往常一样拉取容器镜像、启动或停止容器。不同点仅仅在于这是由自动化系统控制而非管理员在每个节点上手动操作的。
Pod
k8s 中特有的一个概念,可以理解为对容器的包装,是 k8s 的基本调度单位,一个 Pod 代表集群上正在运行的一个进程,实际的容器是运行在 Pod 中的, 可以把 Pod 理解成豌豆荚,而同一 Pod 内的每个容器是一颗颗豌豆。一个节点可以启动一个或多个 Pod。生产环境中一般都是单个容器或者具有强关联互补的多个容器组成一个 Pod。
3. K8S核心概念
概念 | 作用 |
---|---|
cluster | 集群,Cluster指的是由Kubernetes管理的一组节点和资源池。 由Master和多个Worker节点组成,Master用于集群管理和控制,而Worker节点用于运行应用程序和Pod。提供了一种可扩展的、弹性的平台,用于分布式应用程序和容器的部署和管理。 |
node | 节点,是集群中的工作节点,用于运行Pod和容器。 是物理或虚拟机器,具有足够的资源(CPU、内存、存储)来运行容器化的应用。Kubernetes会自动将Pod调度到可用的节点上,以实现负载均衡和高可用性。 |
Container | 容器, 容器是一种轻量级的虚拟化技术,用于隔离和运行应用程序及其依赖项。将应用程序与其运行时环境进行隔离,并提供了一个独立的运行空间,使得应用程序可以在不同的环境中移植和部署。 |
Namespace | 命名空间, Namespace用于在Kubernetes集群中划分虚拟的资源隔离区域。 可用于组织和管理资源,以及为不同的团队、项目或环境提供逻辑分离。 在一个集群中,可以有多个命名空间,每个命名空间都有自己的一组资源和访问策略。 |
Pod | 容器组,Kubernetes基本调度单位,可以包含一个或多个容器。这些容器共享相同的网络和存储资源,并运行在同一主机上。 提供了一个隔离的运行环境,为容器提供了共享的IP地址和端口空间。 通常,Pod用于运行关联的容器,例如共享相同的资源和上下文的应用程序。 |
Service | 服务, Service定义了一组Pod的稳定网络终点,通过标签选择器与这些Pod进行关联。充当入口和负载均衡器,封装了一组Pod,并提供一个持久的访问地址(Cluster IP或Node IP)。 还支持内部服务发现和跨集群通信。 |
ReplicaSet | 副本集,ReplicaSet用于定义Pod的副本数量和在集群中的运行策略,确保指定的Pod副本数始终运行,并根据需要进行自动扩展或收缩。当Pod由于故障或节点故障而终止时,ReplicaSet会自动重新启动新的Pod副本。 |
Deployment | 部署,Deployment是一种用于声明化管理Pod和ReplicaSet的资源对象。可以定义Pod的期望状态,自动创建和更新ReplicaSet,并实现滚动升级和回滚策略,以确保无缝的应用程序更新。 |
ConfigMap | 配置映射,ConfigMap是一种存储配置数据的资源对象,用于将配置参数传递给应用程序。可以存储环境变量、配置文件、命令行参数等。 可以与Pod或容器相关联,并在容器启动时注入相关的配置信息。 |
Secrets | 密钥用于安全地存储和管理敏感信息,如密码、凭证等。 -Kuberentes中的Secret是一种资源对象,用于存储和传递加密的数据。 -密钥可以被挂载到容器中,用于应用程序的配置文件或认证凭证。 |
DaemonSet | DaemonSet是Kubernetes中的一个重要概念,提供了一种简单且可靠的方式来在集群的所有节点上运行相同的Pod,适用于许多系统级任务和后台进程的部署场景。 1.每个节点一个Pod副本:DaemonSet会在集群的每个节点上启动一个Pod副本,以确保每个节点都有该Pod的运行实例。 2. 系统级任务和守护进程:DaemonSet通常用于运行系统级任务和守护进程,例如日志收集器、监控代理和网络代理等。这些任务通常需要在每个节点上运行,并且要与节点的生命周期同步。 3. 自动扩缩容:当有新节点加入集群或某个节点从集群中移除时,DaemonSet会自动检测节点的状态变化,并相应地启动或终止Pod副本。 4. 节点亲和性规则:可以通过节点亲和性规则来选择在哪些节点上运行DaemonSet的Pod。这允许你将特定的任务或服务与特定类型的节点关联起来。 5. 资源限制和调度约束:可为DaemonSet中的Pod指定资源限制和调度约束,以确保它们在节点上均匀分布并满足资源需求。 |
4. Kubetnetes 涉及的端口
角色 | 协议 | 方向 | 端口范围 | 组件 | 使用者 |
---|---|---|---|---|---|
master | TCP | 入站 | 6443 | kube-apiserver | 所有 |
TCP | 入站 | 2379~2380 | etcd | kube-apiserver | |
TCP | 入站 | 10250 | kubelet | kube-apiserver,自身 | |
TCP | 入站 | 10259 | kube-scheduler | 自身 | |
TCP | 入站 | 10257 | kube-controller-manager | 自身 | |
node | TCP | 入站 | 10250 | kubelet | kube-apiserver |
TCP | 入站 | 30000~32767 | Service NodePort | 自身 |
三. 网络概述
Kubernetes (K8s) 网络解决方案是指在 Kubernetes 集群中实现容器网络通信的各种技术和工具。这些解决方案的设计目的是为了满足 Kubernetes 网络模型的要求,即:
-
所有 Pod 都必须能够无需 NAT 就能互相通信。
-
所有节点必须能够无需 NAT 就能与所有 Pod 通信。
-
Pod 在重新调度时保持相同的 IP 地址。
这些网络解决方案遵循 CNI(Container Network Interface)规范,提供插件以集成不同的网络技术。下面是一些主要的 Kubernetes 网络解决方案及其底层原理、优缺点:
Calico
-
原理 :Calico 使用纯三层网络来提供 Pod 间通信,通过使用 IP 路由而不是覆盖网络,以减少网络复杂性和性能开销。它使用 BGP(边界网关协议)来广播和学习路由,支持网络策略来控制 Pod 间的流量。
-
优点 :高性能,支持大规模集群;丰富的网络策略;直接使用物理网络,不需要封包解包的开销。
-
缺点:配置和管理相对复杂,对网络知识要求较高;在某些环境下(如较老的数据中心),对 BGP 的支持可能受限。
Flannel
-
原理:Flannel 是一个简单的覆盖网络解决方案,为每个 Pod 提供一个唯一的 IP。它使用 etcd 存储网络配置信息,支持多种后端,如 VXLAN、IPsec 和 AWS VPC。
-
优点:部署和配置简单,适合小型到中型集群;对新手友好。
-
缺点:性能不如基于路由的解决方案;覆盖网络可能会增加一些网络延迟。
Weave Net
-
原理:Weave Net 创建一个虚拟网络,连接不同 Docker 容器。它自动发现和管理集群中的容器,无需额外配置,支持网络策略,并提供服务发现机制。
-
优点:安装配置简单;自动处理网络分区和故障恢复;不依赖于集群底层的网络基础设施。
-
缺点:相较于其他解决方案,性能可能较低;在大规模集群中可能面临管理挑战。
Cilium
-
原理:Cilium 基于最新的 Linux 内核技术 BPF(Berkeley Packet Filter),提供网络安全、可观测性和负载均衡。它能够理解应用层(Layer 7)的协议,并在此基础上实施安全策略。
-
优点:提供应用层的网络策略和安全;支持多种网络模式,包括透明的服务网格;高性能和可扩展性;丰富的可观测性和监控功能。
-
缺点:较新的项目,社区相对较小;需要较新的 Linux 内核支持 BPF。
选择网络解决方案
选择合适的 Kubernetes 网络解决方案时,需要考虑以下因素:
-
集群规模:大型集群可能更适合使用 Calico 或 Cilium 这样的基于路由的解决方案。
-
性能需求:对于对网络性能有高要求的应用,基于路由的解决方案通常比覆盖网络性能更好。
-
网络策略:如果需要丰富的网络策略支持,Calico 和 Cilium 是较好的选择。
-
环境兼容性:需要考虑解决方案是否支持当前的基础设施和云环境。
-
易用性和管理:对于小型或测试环境,Flannel 或 Weave Net 可能因其简单性而更受青睐。
综合考虑这些因素后,你可以根据具体需求和偏好选择最合适的 Kubernetes 网络解决方案。
覆盖网络
覆盖网络(Overlay Network)是一种网络虚拟化技术,它在现有的网络基础设施之上创建了一个虚拟的网络层。这个虚拟网络使得网络上的设备(如服务器、容器或虚拟机)能够彼此通信,就像它们连接在同一个物理网络一样,即使实际上它们可能分布在不同的物理网络中。
工作原理
-
数据封装:覆盖网络通过封装原始数据包来工作。当数据从一个设备发送到另一个设备时,原始数据包会被封装在另一个数据包中。这个外层的数据包有自己的头部信息,指定了虚拟网络内的源地址和目的地址。
-
隧道技术:封装后的数据包通过隧道在物理网络中传输。这些隧道可以跨越不同的网络和互联网,允许分布在不同位置的设备安全地进行通信。
-
数据解封装:当封装的数据包到达目的地后,外层的数据包会被去除(解封装),恢复原始数据包,然后将其传递给接收设备。
常用技术
-
VXLAN (Virtual Extensible LAN):一种广泛使用的覆盖网络技术,可以支持大规模的虚拟网络。
-
NVGRE (Network Virtualization using Generic Routing Encapsulation):另一种覆盖网络技术,使用 GRE 封装来虚拟化网络层。
-
STT (Stateless Transport Tunneling):专为虚拟化环境设计的覆盖网络协议,优化了数据中心内的通信。
优点
-
灵活性:覆盖网络允许你在不改变底层物理网络基础设施的情况下创建复杂的网络拓扑。
-
可扩展性:可以轻松跨越不同的物理网络和数据中心创建虚拟网络,支持大规模部署。
-
安全性:封装技术和隧道技术提供了数据传输的隔离和安全保护。
缺点
-
性能开销:数据封装和解封装过程增加了额外的计算开销,可能会影响网络性能。
-
复杂性:管理覆盖网络的复杂性随着网络规模和使用的技术而增加。
应用场景
覆盖网络在多种环境和用例中非常有用,尤其是在需要高度灵活性和跨网络通信能力的场景,例如:
-
云计算和数据中心:在不同物理位置的虚拟机或容器之间提供灵活的网络通信。
-
多租户环境:在共享的物理网络基础设施上创建隔离的网络环境,为每个租户提供独立的网络空间。
-
容器编排:在 Kubernetes 等容器编排系统中,覆盖网络使得跨主机的容器可以无缝通信。
覆盖网络通过提供额外的虚拟化网络层,解决了现代数据中心和云环境中网络通信和隔离的挑战,使得网络设计和管理更加灵活和动态。
Flannel
Flannel 是一个简单的 Kubernetes 网络解决方案,用于为集群中的 Pod 提供一个覆盖网络。它让 Pod 能够无视底层网络基础设施,相互之间进行通信,就好像它们在同一个以太网交换机上一样。Flannel 是由 CoreOS 开发的,现在是 CNCF(云原生计算基金会)的一部分。
工作原理
Flannel 在 Kubernetes 集群的每个节点上运行一个代理进程,这些代理负责维护 Pod 网络的配置和状态。Flannel 使用一种中央数据存储(如 etcd)来保持集群的网络配置信息。
-
网络分配:当 Flannel 启动时,它会从中央数据存储中获取一个全局网络配置,包括整个 Pod 网络的 CIDR。然后,Flannel 为每个加入集群的节点分配一个子网,确保节点间的子网不会重叠。
-
数据封装:Flannel 使用数据包封装技术(如 VXLAN)在物理网络之上创建一个虚拟网络层。每当 Pod 间通信时,它的数据包会被封装在一个外部数据包中,然后通过物理网络路由到目的地节点,最后被解封装并传递给目标 Pod。
-
路由配置:Flannel 会配置节点的路由表,以便封装后的数据包可以通过物理网络正确路由到目标节点。每个节点知道如何将封装的数据包路由到集群中的任何其他节点。
核心组件
-
flanneld:Flannel 的主要代理,运行在 Kubernetes 集群的每个节点上。它负责分配子网、封装和解封装数据包以及更新路由表。
-
etcd:用作 Flannel 的中央数据存储,存储网络配置和每个节点的子网分配信息。
特点
-
简单性:Flannel 旨在提供简单而又可靠的覆盖网络,易于安装和配置。
-
灵活性:支持多种后端,包括 VXLAN(默认)、IPSec、Direct routing 等,允许用户根据需要选择最适合他们环境的数据封装技术。
-
可扩展性:虽然 Flannel 更适合小到中等规模的集群,但它也可以通过适当的调整和优化支持较大的部署。
使用场景
Flannel 适用于需要简单、易于设置的 Kubernetes 网络解决方案的场景。它特别适用于:
-
小到中等规模的 Kubernetes 部署。
-
开发和测试环境,其中网络性能和高级网络特性不是首要考虑因素。
-
对网络解决方案的定制要求不高的环境。
总的来说,Flannel 提供了一种简单且有效的方式来实现 Kubernetes Pod 网络,使得 Pod 能够跨越不同节点进行通信,而无需考虑底层的网络基础设施细节。
Calico
Calico 是一个广泛使用的、开源的网络和网络安全解决方案,专为容器、虚拟机和原生主机环境设计,非常适用于大规模 Kubernetes 集群。它提供了高性能的网络通信以及高级的网络策略管理,使得它成为构建和维护大型、复杂 Kubernetes 集群网络的流行选择。
工作原理
Calico 的核心原理包括:
-
纯三层网络:Calico 使用标准的 IP 路由而不是覆盖网络(如 VXLAN)来处理 Pod 间的通信,这意味着每个 Pod 都分配有一个唯一的 IP 地址。这种方法简化了路由过程,减少了封装和解封装的开销,提高了网络性能。
-
BGP(边界网关协议):Calico 使用 BGP 来分发路由信息。在一个 Calico 网络中,每个节点都可以作为一个 BGP 对等体,它会向集群中的其他节点宣告自己所负责的 Pod IP 范围。这使得集群内的每个节点都能了解如何将流量路由到任何特定的 Pod,无论这个 Pod 位于哪个节点上。
-
网络策略:Calico 提供了强大的网络策略管理功能,允许细粒度控制 Pod 间的通信。这些策略可以基于多种标准进行定义,包括命名空间、Pod 标签和选择器等。策略可以实施白名单或黑名单规则,以确保网络的安全性和合规性。
-
IPAM(IP 地址管理):Calico 提供了灵活的 IPAM 解决方案,支持静态和动态 IP 分配。Calico 可以与 Kubernetes 的 CNI 插件集成,自动为每个 Pod 分配 IP 地址,并确保这些地址在集群中的唯一性。
-
IPIP 封装(可选):尽管 Calico 通常使用无封装的纯三层路由,但它也支持 IPIP 封装,以允许在不支持直接路由的环境中跨越不同子网的 Pod 通信。
特点
-
高性能和可扩展性:Calico 提供了接近原生网络性能的通信能力,非常适合需要高吞吐量和低延迟的应用,且能够轻松扩展到数千个节点。
-
细粒度的网络安全策略:Calico 允许你定义详细的网络安全规则,控制 Pod 之间的流量流动,从而增强集群的安全性。
-
跨平台兼容性:Calico 不仅支持 Kubernetes,还可以用于其他容器编排工具(如 Docker Swarm)和传统的 VM 或裸机环境,使其成为多环境中的理想选择。
使用场景
-
大规模 Kubernetes 集群:Calico 特别适合于大型或高密度的 Kubernetes 集群,需要高性能网络通信和复杂的网络策略管理。
-
多云和混合云环境:Calico 的灵活性使其适用于多云和混合云环境,能够跨越不同云平台和数据中心实现网络通信和策略一致性。
-
需要高级网络策略管理的应用:对于需要细粒度网络控制和安全隔离的应用,Calico 提供了强大的工具集。
总的来说,Calico 以其高性能、可扩展性和强大的网络策略功能,在 Kubernetes 环境中提供了一种高效的网络解决方案。
四. 网络原理
1. K8s网络模型
K8s网络模型设计的一个基础原则是:
-
每个Pod都拥有一个独立的IP地址,而且假定所有Pod都在一个可以直接连通的、扁平的网络空间中。
-
同一个Pod内的不同容器将会共享一个网络命名空间,也就是说同一个Linux网络协议栈。意味着同一个Pod内的容器可以通过localhost来连接对方的端口。
2. Docker的网络模型
Docker使用到的与Linux网络有关的主要技术:
-
Network Namespace(网络命名空间)
-
Veth设备对
-
Iptables/Netfilter
-
网桥
-
路由
3. 网络的命名空间
为了支持网络协议栈的多个实例,Linux中网络栈中引入了网络命名空间(Network Namespace),这些独立的协议栈被隔离到不同的命名空间中,处于不同命名空间的网络栈是完全隔离的,彼此之间无法通信。通过这种对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境。
Docker正是利用了网络的命名空间特性,实现了不同容器之间网络的隔离。
Linux的网络命名空间内可以有自己独立的路由表及独立的Iptables/Netfilter设置来提供包转发、NAT及IP包过滤等功能。
为了隔离出独立的协议栈,需要纳入命名空间的元素有进程、套接字、网络设备等。进程创建的套接字必须属于某个命名空间,套接字的操作也必须在命名空间内进行。同样,网络设备也必须属于某个命名空间。因为网络设备属于公共资源,所以可以通过修改属性实现这命名空间之间移动。当然是否允许移动和设备的特征有关。
1.网络命名空间的实现
Linux实现网络命名空间的核心:Linux的网络协议十分复杂,为了支持独立的协议栈,相关的全局变量都必须修改为协议栈私有。最好的办法就是让全局变量成为一个Net Namespace变量的成员,然后为协议栈私有。最好的办法就是让这些全局变量成为一个Net Namespace变量的成员,然后为协议栈的函数调用加入一个Namespace参数。
所有的网络设备(物理的或虚拟接口、桥等着内核里都叫作Net Device)都只能属于一个命名空间。通常物理的设备只能关联到root这个命名空间中,虚拟的网络设备(虚拟的以太网接口或者虚拟网口对)则可以被创建并关联到一个给定的命名空间中,而且可以在命名空间之间移动。
网络命名空间代表的是一个独立的协议栈,它们之间是相互隔离的,彼此无法通信,在协议栈内部都看不到对方。打破这种限制,让处于不同命名空间的网络相互通信,甚至和外部的网络进行通信的方法就是:Veth设备对。
Veth设备对重要作用就是:打破相互看不到的协议栈之间的壁垒,就像一个管子,一端连着这个网络命名空间的协议栈,一端连着另一个网络命名空间的协议栈。
所以如果想在两个命名空间之间进行通信,就必须有一个Veth设备对。
2.网络命名空间的操作
命令需要root用户运行
创建一个命名空间:
ip nets add <name>
在命名空间内执行命令:
ip netns exec <name> <command>
如果想执行多个命令,可以先进入内部sh,然后执行:
ip netns exec <name> bash
之后就是在新的命名空间内进行操作了,退出到外面的命名空间,输入exit
3.网络命名空间的一些技巧
可以在不同的网络命名空间之间转移设备,例如Veth设备对的转移。设备里面有一个重要属性:NETIF_F_ETNS_LOCAL,这个属性为"on",则不能转移到其他命名空间内。Veth设备属于可以转移的设备,很多其他设备如lo设备、vxlan设备、ppp设备、bridge设备等都是不可以转移的。
使用ethtool工具可以查看:
ethtool -k br0
netns-local: on [fixed]
netns-local的值是on,就说明不可以转移,否则可以
4. Veth设备对
引入Veth设备对是为了在不同的网络命名空间之间进行通信,利用它可以直接将两个网络命名空间连接起来。由于要连接两个网络命名空间,所以veth设备都是成对出现的,很像一对以太网卡,并且中间有一个直连的网线。既然是一对网卡,将其中一端称为另一端的peer,在Veth设备的一端发送数据时,会将数据直接发送到另一端,并触发另一端的接收操作。
1.Veth设备对的操作命令
创建Veth设备对,连接到不同的命名空间,并设置它们的地址,让它们通信。
创建Veth设备对:
ip link add veth0 type veth peer name veth1
创建后查看Veth设备对的信息,使用ip link show命令查看所有网络接口:
ip link show
会生成两个设备,一个是veth0,peer是veth1 两个设备都在同一个命名空间,将Veth看作是有两个头的网线,将另一个头甩给另一个命名空间
ip link set veth1 netns netns1
再次查看命名空间,只剩下一个veth0:
ip link show
在netns1命名空间可以看到veth1设备,符合预期。
现在看到的结果是两个不同的命名空间各自有一个Veth的网线头,各显示为一个Device。(Docker的实现里面,除了将Veth放入容器内)
下一步给两个设备veth0、veth1分配IP地址:
ip netns exec netns1 ip addr add 10.1.1.1/24 dev veth1
ip addr add 10.1.1.2/24 dev veth0
现在两个网络命名空间可以互相通信了:
ping 10.1.1.1
ip netns exec netns1 ping 10.1.1.2
至此两个网络命名空间之间就完全相通了。至此就能够理解Veth设备对的原理和用法了。在Docker内部,Veth设备对也是联系容器到外面的重要设备,离开它是不行的。
2.Veth设备对如何查看对端
一旦将Veth设备对的peer端放入另一个命名空间,在本命名空间就看不到了,想查看peer端连接的命名空间,可以使用ethtool工具来查看。
首先在一个命名空间中查询Veth设备对端接口在设备列表中的序列号:
ip nets exec netns1 ethtool -S veth1
NIC statistics:
peer_ifindex: 5
得知另一端的接口设备的序列号是5,再到命名空间中查看序列号5代表的设备:
ip netns exec netns2 ip link | grep 5
veth0
现在就找到下标为5的设备了,是veth0,另一端自然就是另一个命名空间中的veth1了,互为peer。
5. 网桥
Linux可以支持多个不同的网络,网络之间能够相互通信,网桥将这些网络连接起来并实现网络中主机的相互通信。
网桥是一个二层的虚拟网络设备 ,把若干个网络接口"连接起来",以使得网口之间的报文能够互相转发。**网桥能够解析收发的报文,读取目标MAC地址的信息,和自己记录的MAC表结合,来决策报文的转发目标网口。**为了实现这些功能,网桥会学习源MAC地址(二层网桥转发的依据就是MAC地址)。在转发报文时,网桥只需要向特定的网口进行转发,避免不必要的网络交互。网桥如果遇到一个未学习到的地址,就无法知道这个报文应该向哪个网口转发,就将报文广播给所有的网口(报文来源的网口除外)。
在实际网络中,网络拓扑不可能永久不变。网桥需要对学习到的MAC地址表加上超时时间(默认为5分钟),如果网桥收到了对应端口MAC地址回发的包,则重制超时时间,否则过了超时时间后,就认为设备已经不在那个端口上了,就会重新广播发送。
Linux内核支持网口的桥接,与单纯的交换机不同,交换机只是一个二层设备,对于接收到的报文,要么转发,要么丢弃。运行着linux内核的机器本身就是一台主机,有可能是网络报文的目的地,收到的报文除了转发和丢弃,还可能被送到网络层协议栈的上层(网络层),从而被主机本身的协议栈消化,既可以把网桥看作一个二层设备,也可以看作一个三层设备。
1.Linux网桥的实现
Linux内核是通过一个虚拟的网桥设备(Net Device)来实现桥接的。虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接起来。
虚拟的网桥设备和普通设备的不同,最明显的一个特性是可以有一个IP地址:

网桥br0绑定了eth0和eth1。对于网络协议栈的上层来说,只看的到br0。桥接是在数据链路层实现的,上层不需要关心桥接的细节,协议栈上层需要发送的报文被送到br0,网桥设备的处理代码判断报文该被转发到eth0还是eth1,或者两者皆转发。协议栈的上层需要发送的报文被提交给网桥的处理代码,在这里会判断报文应该被转发,丢弃还是提交到协议栈上层。
有时eth0、eth1也可能会作为报文的源地址或目的地址,直接参与报文的发送与接收,从而绕过网桥。
2.网桥的常用操作命令
Docker自动完成了对网桥的创建和维护。
新增一个网桥设备:
brctl addbr xxxxx
为网桥增加网口,在Linux中,一个网口其实就是一个物理网卡,将物理网卡和网桥连接起来。
brctl addif xxxxx ethx
网桥的物理网卡作为一个网口,由于在链路层工作,就不再需要IP地址了,这样上面的IP地址自然失效。
ifconfig ethx 0.0.0.0
给网桥配置一个IP地址:
Ifconfig brxxx xxx.xxx.xxx.xxx
这样网桥就有一个IP地址,连接到上面的网卡就是一个纯链路层设备了。
6. Iptables/Netfilter
Linux提供了一套机制来为用户实现自定义的数据包处理过程。
在linux网络协议中有一组回调函数挂接点,通过这些挂接点挂接的钩子函数可以在linux网络栈处理数据包的过程中对数据进行一些操作,例如过滤、修改、丢弃等。整个挂接点技术叫作Netfilter和Iptables。
Netfilter负责在内核中执行各种挂接的规则,运行在内核模式中。而Iptables是在用户模式下运行的进程,负责协助维护内核中Netfilter的各种规则表。通过二者的配合来实现整个Linux网络协议栈中灵活的数据包处理机制。
四表:raw、mangle、nat、filter
Netfilter可以挂接的规则点有5个(链):
-
INPUT
-
OUTPUT
-
FORWARD
-
PREROUTING
-
POSTROUTING
-
流入:PREROUTING -> INPUT
-
流出:OUTPUT -> POSTROUTING
-
转发:PREROUTING -> FORWARD -> POSTROUTING

7. 路由
Linux系统包含一个完整的路由功能。当IP在处理数据发送或者抓发时,会使用路由表来决定发往哪里。通常情况下,如果主机与目的主机直接相连,那么主机可以直接发送IP报文到目的主机,这个过程比较简单。例如,通过点对点的链接或通过网络共享,如果主机与目的主机没有直接相连,那么主机会将IP报文发送给默认的路由器,然后由路由器来决定往哪发送IP报文。
路由功能由IP层维护的一张路由表来实现。当主机收到数据报文时,用此表来决策接下来应该做什么操作。当从网络侧接收到数据报文时,IP层首先会检查报文的IP地址是否与主机自身的地址相同。如果数据报文中的IP地址是主机自身的地址,那么报文将被发送到传输层相应的协议中去。如果报文中的IP地址不是主机自身的地址,并且配置了路由功能,那么报文将被转发,否则,报文将被丢弃。
路由表中的数据一般是以条目形式存在的。一个典型的路由表条目通常包含以下主要的条目项。
-
目的IP地址:此字段表示目标的IP地址。这个IP地址可以是某台主机的地址,也可以是一个网络地址。如果这个条目包含的是一个主机地址,那么主机ID将被标记为非零。如果这个条目包含的是一个网络地址,主机ID将被标记为零。
-
下一个路由器的IP地址:下一个路由器并不总是最终的目的路由器,很可能是一个中间路由器。条目给出下一个路由器的地址用来转发从相应接口收到的IP数据报文。
-
标志:这个字段提供了另一组重要信息,例如目的IP地址是一个主机地址还是一个网络地址。从标志中可以得知下一路由器是一个真实的路由器还是一个直接相连的接口。
-
网络接口规范:数据报文的网络接口规范,该规范将与该报文一起被转发。
1.路由表的创建
Linux的路由表至少包括两个表:一个是LOCAL,另一个是MAIN。在LOCAL表中会包含所有的本地设备地址。LOCAL路由表是在配置网络设备地址时自动创建的。LOCAL表用于供Linux协议栈识别本地地址,以及进行本地各个不同网络接口之间的数据转发。
可以通过下面的命令查看LOCAL表的内容:
ip route show table local type local
MAIN表用于各类网络IP地址的转发。MAIN表的建立可以使用静态配置生存,也可以使用动态路由发现协议生成。
2.路由表的查看
使用ip route list命令查看当前的路由表。
ip route list
另一个查看路由表的工具:
netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 10.128.232.1 0.0.0.0 UG 0 0 0 ens5
10.128.232.0 0.0.0.0 255.255.252.0 U 0 0 0 ens5
标志是U,说明是可达路由,标志是G,说明这个网络接口连接的是网关,否则说明是直连主机。
8. Docker的网络实现
Docker支持以下4类网络模式:
-
host模式:使用--net=host指定
-
containe模式:使用--net=container:NAME_or_ID指定
-
none模式:使用--net=none指定
-
bridge模式:使用--net=bridge指定,为默认设置
在K8s管理模式下,通常只会使用bridge模式,在bridge模式下,Docker Daemon第一次启动时会创建一个虚拟的网桥,默认的名字是docker0,在私有网络空间中给这个网桥分配一个子网。
针对由Docker创建出来的每一个容器,都会创建一个虚拟的以太网设备(Veth设备对),其中一端关联到网桥上,另一端使用Linux的网络命名空间技术,映射到容器内的eth0设备,然后从网桥的地址段内给eth0接口分配一个IP地址。

-
ip1是网桥的IP地址,Docker Daemon会在几个备选地址段里选一个,通常是172开头的一个地址。ip2是Docker在启动容器时,在这个地址段随机选择的一个没有使用的IP地址。相应的MAC地址也根据这个IP地址,在02:42:ac:11:00:00和02:42:ac:11:ff:ff的范围内生存,可以确保不会有ARP的冲突。
-
启动后,Docker还将Veth对的名字映射到eth0网络接口。ip3就是主机的网卡地址。
-
ip1、ip2和ip3是不同的IP段,外部是看不到ip1和ip2的。同一台机器内的容器之间可以相互通信。不同主机上的容器不能够相互通信。
-
为了跨节点互相通信,必须在主机的地址上分配端口,然后通过这个端口路由代理到容器上,这种做法显然意味着一定要在容器之间小心谨慎地协调好端口的分配,或者使用动态端口分配技术。
1.查看Docker启动后的系统情况
Docker网络中bridge模式下Docker Daemon启动时创建docker0网桥,并在网桥使用的网段为容器分配IP。
ip addr
iptables-save
Docker创建了docker0网桥,并添加了Iptables规则。
2.查看容器启动后的情况(容器无端口映射)
docker run --name register -d registry
ip addr
iptables-save
ip route
可以看到如下情况。
-
宿主机器上的Netfilter和路由表都没有变化,说明在不进行端口映射时,Docker的默认网络上没有特殊处理的。相关的NAT和FILTER两个Netfilter链还是空的。
-
宿主机上的Veth对已经建立,并连接到了容器内。
进入容器,查看网络栈,容器内部的IP地址和路由如下:
ip route
ip addr
可以看到,默认停止的回环设备lo已经被启动,外面宿主机连接进来的Veth设备也被命名成了eth0,并且已经配置了地址172.17.0.10。
3.查看容器启动后的情况(容器端口映射)
用带端口映射的命令启动registry
docker run --name register -d -p 1180:5000 registry
启动后查看Iptables的变化
iptables-save
-
Docker服务在NAT和FILTER两个表内添加的两个Docker子链都是给端口映射用的。例如需要把宿主机的1180端口映射到容器的5000端口。
-
无论是宿主机接收还是宿主机本地协议栈发出的,目标地址是本地IP地址的包都会经过NAT表中的DOCKER子链。Docker为每一个端口映射都在这个链上增加了到实际容器目标地址和目标端口的转换。
-
经过这个DNAT的规则修改后的IP包,会重新经过路由模块的判断进行转发。由于目标地址和端口已经是容器的地址和端口,所以数据自然就送到docker0上,从而送到对应的容器内部。
-
在Forward时,需要在Docker子链中添加一条规则,如果目标端口和地址是指定容器的数据,则允许通过。
-
在Docker按照端口映射的方式启动容器时,主要的不同就是上述Iptables部分。从而容器内部的路由和网络设备,都和不做端口映射时一样,没有任何变化。
9. K8s的网络实现
K8s网络的设计主要致力于解决以下场景:
-
容器到容器之间的直接通信
-
抽象的pod到pod之间的通信
-
Pod到Service之间的通信
-
集群外部与内部组件之间的通信
1.容器到容器的通信
在同一个Pod内的容器共享同一个网络命名空间,共享同一个linux协议栈。对于网络的各类操作,就和它们在同一台机器上一样,设置可以用localhost地址访问彼此的端口。
容器1和容器2共享网络命名空间,打开的端口不会有冲突,可以直接使用linux的本地IPC进行通信(例如消息队列或者管道),互相访问只需要使用localhost就可以了。
2.Pod之间的通信
每一个Pod都有一个真实的全局IP地址,同一个Node内的不同Pod之间可以直接采用对方Pod的IP地址通信,而且不需要使用其他发现机制,例如DNS或者etcd。
Pod容器既有可能在同一个Node上运行,也有可能在不同的Node上运行,通信分为两类:
- 同一个Node内的Pod之间的通信和不同Node上的Pod之间的通信
1) 同一个Node内的Pod之间的通信
-
Pod1和Pod2都是通过Veth连接在同一个docker0网桥上的,IP地址IP1、IP2都是从docker0到网段上动态获取的,和网桥本身的IP3是同一个网段的。
-
在Pod1、Pod2的Linux协议上,默认路由都是docker0的地址,也就是说所有非本地地址的网络数据,都会被默认发送到dockero网桥上,由docker0网桥直接中转。
-
综上所述,Pod1和Pod2关联在同一个docker0网桥上,地址段相同,所以Pod1和Pod2之间是能直接通信的。
2)不同Node上的Pod之间的通信
Pod的地址是与docker0在同一个网段内的,docker0网段与宿主机网卡是两个完全不同的IP网段,并且不同Node之间通信只能通过宿主机的物理网卡进行,因此要实现位于不同Node上的Pod容器之间通信,就必须想办法通过主机的这个IP地址来进行寻址和通信。
K8s会记录所有正在运行Pod的IP分配信息,并将这些信息保存在etcd中(作为Service的Endpoint)。要想支持不同Node上的Pod之间的通信,就要达到两个条件:
-
在整个K8s集群中对Pod的IP分配进行规划,不能有冲突
-
将Pod的IP和所在Node的IP关联起来,通过这个关联让Pod可以互相访问
根据条件1,需要在部署k8s时,对docker0的IP地址进行规划,保证每一个Node上的docker0地址没有冲突。可以在规划后手工配置到每个Node上,或者做一个分配规则,由安装的程序自己去分配占用。例如K8s的网络增强开源软件Flannel就能够管理资源池的分配。
根据条件2:Pod中的数据中发出时,需要有一个机制能够知道对方Pod的IP地址,挂在哪个具体的Node上。也就是先要找到Node对应宿主机的IP地址,将数据发送到宿主机的网卡上,然后在宿主机上将相应的数据转到具体的docker0上,一旦数据到达宿主机Node,则那个Node内部的docker0便知道如何将数据发送到Pod。
五.总结
Kubernetes(K8s)是云原生部署的核心平台,源自Google的Borg系统,通过容器化简化微服务开发与部署,提供自愈、调度、监控等功能。其架构分为Master(控制节点)和Worker(工作节点),核心组件包括API Server、Controller Manager、Scheduler和etcd存储。Node节点运行kubelet、kube-proxy等组件管理Pod生命周期及网络通信。
K8s网络模型要求所有Pod直接互通,需依赖CNI插件(如Calico、Flannel)实现跨节点通信。Calico基于BGP协议提供高性能路由和网络策略;Flannel通过覆盖网络简化部署。覆盖网络(如VXLAN)封装数据包实现跨主机通信,但存在性能开销。Pod间通信依赖Linux网络命名空间、Veth设备对及网桥技术,Docker默认使用bridge模式为容器分配独立IP。
K8s网络需满足容器-Pod-Service多层通信,通过etcd记录Pod IP并借助路由或覆盖网络实现跨节点访问,结合iptables/Netfilter规则确保数据转发与安全策略。网络方案选择需考虑集群规模、性能及策略需求。