引言
一个数据中心基本上都有成百上干个容器,这么多的容器需要运维人员集中管理
在云计算的世界中,计算最基础,存储最重要,网络最复杂
Kubernetes集群的网络依赖于第三方网络插件来实现
设计原则
1.每个Pod都拥有一个独立的IP地址
2.假定所有Pod都在一个可以直接连通的、扁平的网络空间中
Kubernetes对集群网络的要求
1.所有的容器都可以在不用NAT的方式下同别的容器通讯
2.所有节点都可在不用NAT的方式下同所有容器通讯
3.容器的地址和别人看到的地址是同一个地址
技术 | 作用 |
---|---|
网络命名空间 | 将独立的网络协议栈割刀不同的命名空间中,处于不同命名空间的网络栈是完全隔离的,彼此之间无法通信 |
Veth设备对 | 实现不同网络命名空间的通信,可以直接将两个网络命名空间连接起来,Veth设备都是成对出现的 |
网桥 | 是一个二层网络设备,通过网桥可以将Linux支持的若干个网络端口“连接”起来,使得网络接口之间的报文能够相互转发 |
Iptables/Netfilter | Netfilter负责在内核中执行各种挂接的规则,运行在内核模式中;Iptables是在用户模式下运行的进程,负责协助维护内核中Netfilter的各种规则表,通过二者的配合实现整个Linux网络协议栈中的灵活的数据包处理机制 |
路由 | Linux系统包含一个完整的路由功能,当Ip层在处理数据发送或转发的时候,会使用路由表来决定发往的目的地 |
在同一个 Pod 内的容器(Pod 内的容器是不会跨宿主机的)共享同一个网络命令空间, 所以对于网络的各类操作,就和它们在同一台机器上一样,甚至可以用 localhost 地址访问
同一个 Node 内 Pod 之间的通信
每个 Pod 都有一个真实的全局 IP 地址,同一个 Node 内的不同 Pod 之间可以直接采用对方 Pod 的 IP 地址进行通信,不需要采用其他发现机制。
不同 Node 上 Pod 之间的通信
Pod 地址与 docker0 在同一网段,docker0 网段与宿主机网卡是两个不同的网段,且不同 Node 之间的通信只能通过宿主机的物理网卡进行。要想实现不同 Node 上 Pod 之间的通信,就必须想办法通过主机的这个 IP 地址进行寻址和通信。因此不同 Node 中 Pod 间通信要满足两个条件: Pod 的 IP 不能冲突;将 Pod 的 IP 和所在的 Node 的 IP 关联起来,通过这个关联让 Pod 可以互相访问。
Service 是一个抽象的实体,Kubernetes 在创建 Service 时,会为其分配一个虚拟 IP 地址。
当外界需要访问 Pod 里的容器提供的功能时,不直接访问 Pod 的 IP 地址和端口,而是访问 Service 的虚拟 IP 地址和端口,由 Service 把请求转发给它背后的 Pod。Kubernetes 在创建 Service 时,根据 Service 的标签选择器(Label Selector)来查找 Pod,据此创建与Service 同名的 EndPoints 对象。当 Pod 的地址发生变化时,EndPoints 也随之变化。Service接受到请求时,就能通过 EndPoints 找到对应的 Pod。Service 的虚拟 IP 就是由 kube-proxy 实现的
kube-proxy 有两种请求转发模式:userspace 模式和 iptables 模式。
类型 | 通信实现 |
---|---|
ClusterIP 类型 | 这种类型的 Service 只会得到虚拟的IP 和端口,只能在 Kubernetes集群内部被访问,此模型是为默认类型 |
NodePort 类型 | 这种类型的 Service 除了会得到虚拟的 IP 和端口,Kubernetes 还 会 在 所 有 Node 节 点 上 为 其 分 配 端 口 。 分 配 的 端 口 的 值 可 以 通 过spec.ports[*].nodePort 指定,或由 Kubernetes 在配置好的区间里分配(默认为30000-32767)。这种 Service 即可以从 Kubernetes 集群通过虚拟 IP:端口访问, 也可以从集群外部通过 Node 节点的 IP:nodePort 访问 |
LoadBalancer 类型 | 这种类型的 Service 除了会得到虚拟的IP 和端口,Kubernetes还会在所有 Node 节点上为其分配端口,然后为其开通负载均衡。这种 Service 即可以从 Kubernetes 集群通过虚拟 IP:端口访问,也可以从集群外部通过 Node 节点的 IP:nodePort 访问,还可以通过负载均衡的 IP 访问 |
K8S 网络的实现不是集群内部自己实现,而是依赖于第三方网络插件----CNI(Container Network Interface),例如 Flannel、Calico 等。下面分别介绍这两种网络插件。
flannel概述
Flannel 是 CoreOS 团队针对 Kubernetes 设计的一个网络规划服务
目的是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址
是一种 ”覆盖网络(overlay network)“
目前支持UDP、VXLAN、AWS VPC和GCE路由等数据转发方式
节点间默认的数据通信方式是UDP转发
Calico概述
Calico 是一种基于 BGP 的、纯三层的、容器间互通的网络方案。与 OpenStack、Kubenetes、AWS、GCE 等云平台都能够良好的集成。在虚拟化平台中,如 OpenStack、Docker 等都需要实现 workloads 之间互连,但同时也需要对容器做隔离控制,就像在Internet 中的服务仅开放 80 端口、公有云的多租户一样,提供隔离和管控机制。
Calico网络模型工作组件
工作组件 | 作用 |
---|---|
Felix | Calico Agent,运行在每个Node上,负责为容器设置Ip地址、路由规则、IP tables规则等网络资源,保证跨主机容器网络互通 |
etcd | Calico使用的后端存储 |
BGP Client(BIRD) | 负责把Felix在各Node上设置的路由信息通过BGP协议广播到Calico网络 |
BGP Route Reflector | 通过一个或多个BGP Route Reflector来完成大规模集群的分级路由分发 |
CalicoCtl | Calico 命令行管理工具 |
IPIP | 相当于一个基于 IP 层的网桥.一般来说,普通的网桥是基于 mac 层的, 根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来 |
BGP | 边界网关协议(Border Gateway Protocol, BGP)是互联网上一个核心的去中心化自治路由协议。它通过维护 IP 路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。BGP,通俗的讲就是讲接入到机房的多条线路(如电信、联通、移动等)融合为一体,实现多线单 IP。 BGP 机房的优点:服务器只需要设置一个 IP 地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统。 |
Calico网络架构
资源列表
操作系统 | 配置 | 主机名/IP |
---|---|---|
Centos 7.9 | 2G2C | master/172.16.10.10 |
Centos 7.9 | 2G2C | node01/172.16.10.11 |
Centos 7.9 | 2G2C | node02/172.16.10.12 |
k8s集群所有节点都执行
hostnamectl set-hostname master hostnamectl set-hostname node01 hostnamectl set-hostname node02
systemctl stop firewalld systemctl disable firewalld
sed -i "s/.*SELINUX=.\*/SELINUX=disabled/g" /etc/selinux/config # 重启系统 reboot
# 关闭swap分区 swapoff -a # 关闭开启自启 vim /etc/fstab ##swap分区前加上注释“#” #/dev/mapper/cl-swap swap swap defaults 0 0
# 修改内核机制 vim /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 # 刷新 sysctl --system
vim /etc/hosts 172.16.10.10 master 172.16.10.11 node01 172.16.10.12 node02
# 安装并启动docker yum -y install wget wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo yum -y install docker-ce-18.09.9-3.el7 # 启动docker,并设置docker开机自启 systemctl start docker systemctl enable docker # 添加docker加速器及驱动 cat > /etc/docker/daemon.json <2.1.8 配置k8s yum源
# 配置k8s yum源 cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF2.2 部署k8s集群
2.2.1 安装k8s-1.18.0版本
# 这里指定了k8s-1.18.0版本号,若需要其他版本的可自行更改(集群所有节点执行) yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0 # 设置开启自启 systemctl enable kubelet # 初始化k8s(仅master节点执行) kubeadm init \ --apiserver-advertise-address=172.16.10.10 \ --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 ##执行后会报以下信息 Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: ## 使用K8S的话,必行执行以下3条命令 mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: ##节点加入集群要执行下面的命令 kubeadm join 172.16.10.10:6443 --token sw1lqg.guily84o5q87lmv8 \ --discovery-token-ca-cert-hash sha256:6315a98f2ab7e63a1780ccecaa94227e9b16bc91d9e32f812fd65b694a3a82b32.2.2 安装calico网络插件
# 上传calico 配置文件 calico-3.13.1.yaml # 应用calico 网络插件 kubectl apply -f calico-3.13.1.yaml # 实时监控pod 状态 watch kubectl get pod -A ##当所有容器为running 状态时表示所有容器正常运行2.3 部署nginx服务,并可以访问
# 创建命名空间 kubectl create ns policy-demo # 查看命名空间 kubectl get ns # 应用加载nginx yaml文件,创建生成容器 kubectl apply -f nginx-deployment.yaml # 查看pod kubectl get pod -n policy-demo # 创建service ,暴露服务 kubectl expose -n policy-demo deployment nginx --port=80 # 查看service kubectl get svc -n policy-demo # 查看deployment kubectl get deployment -n policy-demo kubectl get deploy -n policy-demo # 使用kubectl run 创建busybox容器,并访问nginx kubectl run -n policy-demo access -it --rm --image busybox /bin/sh / # wget -q nginx -O -2.4 kubectl 集群管理相关操作
# 创建命名空间 kubectl create ns policy-demo # 查看命名空间 kubectl get ns # 删除命名空间 kubectl delete ns policy-demo # 应用加载nginx yaml文件,创建生成容器 kubectl apply -f nginx-deployment.yaml # 删除已加载的yaml文件 kubectl delete -f nginx-deployment.yaml # 查看pod kubectl get pod -n policy-demo # 查看pod标签 kubectl get pod -n policy-demo --show-labels # 查看deployment kubectl get deployment -n policy-demo kubectl get deploy -n policy-demo # 查看某个deployment 的详细信息 kubectl describe deploy nginx -n policy-demo # 创建service ,暴露服务 kubectl expose -n policy-demo deployment nginx --port=80 # 查看service kubectl get svc # 使用kubectl run 创建busybox容器,并访问nginx kubectl run -n policy-demo access -it --rm --image busybox /bin/sh / # wget -q nginx -O -2.5 kubectl 服务网络策略
# kubectl 服务网络策略 kubectl create -f - <