一、K8S的网络组件
1.1 flannel是什么?有什么模式?
- flannel是k8s的pod能够实现跨Node节点通信的cni网络插件
- 模式有:UDP(默认模式)、VXLAN(推荐使用的模式)、Host-gw(Host-gateway)(性能最好,但是配置繁琐)
- 由于UDP模式是在用户态做转发,会多一次报文隧道封装,因此性能上会比内核态做转发的VXLAN模式差。
① flannel的udp模式工作原理(端口号默认8285)
- 应用数据从源主机的Pod发出,经过cni0网桥接口,再由cni0转发到flannel0虚拟网卡接口
- flannel的服务会监听flannel0接口的数据,flannel服务会将内部数据包(由Pod发出的)封装到udp报文中
- 根据flannel在etcd维护的路由表,通过物理网卡,转发到目标主机(通过flannel在etcd中维护的路由表查询到目标Pod所在的节点IP,在udp报文外再封装节点的IP报文与MAC报文后转发到目标节点)
- udp报文送到到目标主机的flannel的服务后,会将udp报文进行解封装,然后会通过目标主机的flannel0转发到目标主机的cni0网桥,最后再通过cni0网桥转发到目标的Pod
② flannel的VXLAN模式工作原理(官方预留端口号默认4789)(实际使用端口8472)
- pod将数据帧(包含IP头部与报文)转发到cni0网桥,再转发到flannel.1虚拟网卡接口,flannel.1网卡会在数据帧上添加VXLAN头部作为标识,再将数据帧封装到UDP报文中
- 根据flannel在etcd维护的路由表,封装目标主机的IP地址和MAC地址,通过物理网卡,转发到目标主机
- 目标主机解析报文后,会通过8472端口,将数据包发送到flannel.1虚拟网卡接口,flannel.1会将udp报文进行解封装,并且解封装VXLAN头部信息,转发到网桥cni0,cni0网桥将数据帧转发到连接在网桥上的目标pod
1.2 k8s组网方案对比
-
flanne1方案
- 需要在每个节点上把发向容器的数据包进行封装后,再用隧道将封装后的数据包发送到运行着目标Pod的node节点上。目标node节点再负责去掉封装,将去除封装的数据包发送到目标Pod上。数据通信性能则大受影响。
-
calico方案
- calico不使用隧道或NAT来实现转发,而是把Host当作Internet中的路由器,使用BGP同步路由,并使用iptables来做安全访问策略,完成跨Host转发。
- 采用直接路由的方式,这种方式性能损耗最低,不需要修改报文数据,但是如果网络比较复杂场景下,路由表会很复杂,对运维同事提出了较高的要求。
1.3 flannel和calico 区别?
-
flannel使用的三种模式 udp、vxlan、host-gw
- flannel 通常使用 vxlan 模式,采用的是叠加网络,IP隧道方式传输数据,可以实现跨子网进行传输。传输过程中需要进行封包和解包的过程,对性能有一定的影响。
- 功能简单配置方便,利于管理,但不具有复杂的网络策略规则配置的能力
-
calico使用的三种模式 ipip、bgp、混合模式
- calico的ipip模式,同样可以实现跨子网传输(同样采用叠加网络),但传输过程中一样需要进行封装和解封装的操作,对性能有一定的影响
- calico的bgp模式可以直接根据bgp路由规则转发,并且传输过程中不需要封装和解封装,因此性能较好,但是只能在同一子网中使用,无法进行跨网使用;bgp模式具有更丰富的网络策略配置管理能力;但是维护起来较为复杂
-
所以对于较小规模且网络要求简单的k8s集群,我们可以采用flannel,对于集群规模较大且要求更多的网络策略时,可以采用功能更全面的calico
二、网络组件calico
2.1 calico的模式
- IPIP模式:在原有IP报文中封装一个新的IP报文,新的IP报文中将源地址IP和目的地址IP都修改为对端宿主机IP。calico 默认使用IPIP的模式。
- BGP模式:将节点做为虚拟路由器通过BGP路由协议来实现集群内容器之间的网络访问。
- cross-subnet ( ipip-bgp 混合模式):IPIP模式和BGP 模式都有对应的局限性,对于一些主机跨子网而又无法使网络设备使用BGP的场景可以使用cross-subnet
2.2 calico的组成部分
- Calico CNI插件:主要负责与kubernetes对接,供kubelet 调用使用。
- Felix:负责维护宿主机上的路由规则、FIB转发信息库等。
- BIRD:负贵分发路由规则,类似路由器。
- Confd:配置管理组件。
2.3 calico的工作原理
- IPIP模式:
- Calico会将容器的IP 包通过内核的IPIP 驱动直接在封装宿主机网络的IP包中,并根据路由通过tunl0 网卡发送给其他节点,这样到达目标节点以后再通过IPIP 驱动解包得到原始容器IP包,然后通过路由规则发送给veth pair设备到达目标容器。
-
BGP模式:
- Calico是通过路由表来维护每个pod 的通信。calico的CNI插件会为每个容器设置一个veth pair设备,然后把另一端接入到宿主机网络空间,由于没有网桥,CNI插件还需要在宿主机上为每个容器的veth pair设备配置一条路由规则,用于接收传入的IP包
- 有了这样的veth pair设备以后,容器发出的IP包就会通过,veth pair设备到达宿主机,然后宿主机根据路由规则的下一跳地址,发送给正确的网关,然后到达目标宿主机,再到达目标容器。
- 这些路由规则都是Felix(维护BGP路由规则)维护配置的,而路由信息则是Calico BIRD组件(负责路由分发)基于BGP分发而来。
- calico实际上是将集群里所有的节点都当做边界路由器来处理,他们一起组成了一个全互联的网络,彼此之间通过BGP交换路由,这些节点我们叫做BGP Peer。
-
相比IPIP模式, BGP模式下不需要tunl0设备参与报文传输,报文直接通过物理网卡(比如ens33)转发到目标机器上,不会进行二次IP报文的封装,因此从性能上来看,BGP是占优势的。但是由于没有二次封包,BGP模式只能在同一个子网内使用,无法跨网段使用。
-
目前比较常用的CNI网络组件是flannel和calico,flannel 的功能比较简单,但不具备复杂的网络策略配置能力。但calico以其性能、灵活性而闻名。Calico的功能更为全面,不仅提供主机和pod之间的网络连接,还涉及网络安全和管理,但具备复杂网络配置能力的同时,往往意味着本身的配置比较复杂,所以相对而言,比较小而简单的集群使用flannel,考虑到日后扩容,未来网络可能需要加入更多设备,配置更多网络策略,则使用calico更好。
2.4 flannel下的跨界点通讯示例
① master节点查看目前节点状态
kubectl get nodes #查看节点服务器状态
kubectl get pods -A #查看安装插件
② master节点创建资源
kubectl create deployment testapp --image=soscscs/myapp:v1 --replicas=3
#创建一个pod控制器为deployment(用于部署无状态应用),创建一个资源名为testapp,指定pod使用的镜像为image=soscscs/myapp:v1 ,创建3个副本
kubectl get all #查看所有已存在的资源
kubectl get pods #查看当前默认命名空间中的pod
kubectl get pods -owide #查看当前默认命名空间中的pod的地址
③ work node两个节点操作
docker exec -it ca8267e568ed sh
ip a
#两个node节点分别进入创建好的容器当中,查看容器的IP
通过上图可以看见不同节点的pod可以实现正常通信,其中是制定了一套CNI接口规范,开放其他节点来实现通信。
三、部署 Calico
① 在 master01 节点上操作
#首先,卸载flannel服务
cd /opt/k8s/
kubectl delete -f kube-flannel.yml #删除flannel配置文件,即可删除flannel服务
#在 master01 节点上操作
#上传 calico.yaml 文件到 /opt/k8s 目录中,部署 CNI 网络
cd /opt/k8s
vim calico.yaml
#修改里面定义Pod网络(CALICO_IPV4POOL_CIDR),与前面kube-controller-manager配置文件指定的cluster-cidr网段一样
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"
kubectl apply -f calico.yaml
#等 Calico Pod 都 Running,节点也会准备就绪
kubectl get nodes
四、部署多master节点的K8S环境(实现高可用)
4.1 服务器准备
| 服务器 | IP地址 |
|---|---|
| K8s集群master01(已部署) | 192.168.142.10 |
| K8s集群node01(已部署) | 192.168.142.40 |
| K8s集群node02(已部署) | 192.168.142.100 |
| K8s集群master02(新添加) | 192.168.142.10 |
| K8s集群负载均衡器MASTER(新添加) | 192.168.142.30 |
| K8s集群负载均衡器BACKUP(新添加) | 192.168.142.50 |
4.2 master02操作系统初始化配置
#关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
#关闭selinux
setenforce 0
sed -i 's/enforcing/disabled/' /etc/selinux/config
#关闭swap
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
#根据规划设置主机名
hostnamectl set-hostname master02
#在master添加hosts,添加各个节点的映射关系
cat >> /etc/hosts << EOF
192.168.142.10 master01
192.168.142.20 master02 #关于已经配置好的其他节点需要在映射关系文件中添加改行
192.168.142.40 node01
192.168.142.100 node02
EOF
#调整内核参数
cat > /etc/sysctl.d/k8s.conf << EOF
#开启网桥模式,可将网桥的流量传递给iptables链
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
#关闭ipv6协议
net.ipv6.conf.all.disable_ipv6=1
net.ipv4.ip_forward=1
EOF
sysctl --system
#时间同步
yum install ntpdate -y
ntpdate time.windows.com
4.3 将master01中的配置文件复制到master02上
# master01操作
scp -r etcd/ kubernetes/ master02:/opt
#将/opt目录下的etcd和kubernetes两个目录移动到master02节点的/opt目录下
# 将kubectl的配置文件复制到master02节点下
cd ~ #到达家目录下
ls -A
#将.kube目录移至master02节点家目录下
scp -r .kube/ master02:/root
cd /lib/systemd/system
scp kube-* master02:`pwd` #将服务文件移至master02节点
4.4 修改master节点监听地址
cd /opt/kubernetes/cfg/
vim kube-apiserver #修改apiserver的监听地址
#若服务文件配置内容为127.0.0.1本机地址,则不做以下两个文件内容的修改
vim kube-controller-manager
vim kube-scheduler
#配置文件都修改结束后,启动服务
systemctl enable --now kube-apiserver.service
systemctl enable --now kube-controller-manager.service
systemctl enable --now kube-scheduler.service
cd /opt/kubernetes/
ln -s /opt/kubernetes/bin/* /usr/local/bin/ #将目录下的文件放入shell中进行系统的管理
4.5 主备负载均衡器配置
#关闭防火墙,并关闭开机自启
systemctl disable --now firewalld.service
#关闭开机自启
setenforce 0
#将nginx官方源镜像文件,导入/etc/yum.repos.d目录下
##实现负载均衡配置如下##
#两个负载均衡服务器下载nginx及keepalived服务
yum install -y nginx keepalived
cd /etc/nginx/
#在nginx配置文件中,进行简单的四层代理配置
vim nginx.conf
#在http块上方同级块中,添加以下配置:
stream {
upstream apiservers {
server 192.168.142.10:6443;
server 192.168.142.20:6443;
}
server {
listen 6443;
proxy_pass apiservers;
}
}
#配置完成后,检查配置文件语法错误,并进行nginx服务开启
nginx -t #查看配置文件语法错误,有以下两行内容,即文件语法没错误
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
systemctl enable --now nginx #开启nginx服务并开启开机自启
netstat -natp | grep nginx #查看nginx服务是否开启
netstat -natp | grep :6443 #查看6443端口是否绑定
###实现高可用###
cd /etc/keepalived/ #keepalived主配置文件目录
vim check_nginx.sh #做一个检测脚本,控制keepalived服务
#!/bin/bash
#判断nginx服务是否被关闭,如果服务被关闭或掉线则关闭keepalived服务
killall -0 nginx &> /dev/null
if [ $? -ne 0 ]; then
systemctl stop keepalived
fi
chmod +x check_nginx.sh #给予脚本执行权限
#修改keepalived主配置文件(主备调度器文件内容有区别)
vim keepalived.conf #主配置文件仅保留以下内容
! Configuration File for keepalived
#设置route id名称
global_defs {
router_id NGINX_MASTER #设置router id(backup调度器名称为NGINX_BACKUP)
}
#设置监控脚本的路径
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER #设置组的角色名称(backup调度器名称为BACKUP)
interface ens33 #设置网卡信息/名称
virtual_router_id 51
priority 100 #设置优先级(backup调度器优先级调整为90)
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
#设置VIP地址
virtual_ipaddress {
192.168.142.120
}
#跟踪脚本
track_script {
check_nginx
}
}
#主备调度器配置完成后,启动keepalive服务
systemctl start keepalived.service
systemctl enable keepalived.service
实现高可用后,对主调度器进行nginx服务的关闭,验证VIP的转移:
4.6 修改node节点组件配置
#两个node节点均做以下修改
cd /opt/kubernetes/cfg/
#修改kubeconfig结尾的集群配置文件
vim bootstrap.kubeconfig
vim kubelet.kubeconfig
vim kube-proxy.kubeconfig
#将以上三个配置文件中的server修改为VIP地址
#修改完成后,重启kubelet服务与kube-proxy服务
systemctl restart kubelet.service kube-proxy.service
此时,查看调度器节点的nginx服务状态
netstat -natp | grep nginx
上方查看nginx状态可以看到,两个node节点向调度器进行请求连接的状态
之后调度器与node节点成功建立连接后,调度器会再去与master节点建立连接
最后将node节点的请求转发到master节点上
验证成功,高可用负载均衡K8S集群就已经搭建完毕
五、部署 Dashboard
5.1 Dashboard介绍
仪表板是基于Web的Kubernetes用户界面。我们可以使用仪表板将容器化应用程序部署到Kubernetes集群,对容器化应用程序进行故障排除,并管理集群本身及其伴随资源。您 可以使用仪表板来概述群集上运行的应用程序,以及创建或修改单个Kubehetes资源(例如deployment,job, daemonset等)。例如,我们可以使用部署向导扩展部署,启动滚 动更新,重新启动Pod或部署新应用程序。仪表板还提供有关群集中KubeInetes资源状态以及可能发生的任何错误的信息。
5.2 CoreDNS介绍
-
CoreDNS 是一个灵活可扩展的 DNS 服务器,可以作为 Kubernetes 集群 DNS,在Kubernetes1.12版本之后成为了默认的DNS服务。 与 Kubernetes 一样,CoreDNS 项目由 CNCF 托管。
-
CoreDNS在K8S中的用途,主要是用作服务发现,也就是服务(应用)之间相互定位的过程。
-
在k8s中,用service资源代理pod,通过暴露service资源的固定地址(集群IP),来解决以上POD资源变化产生的IP变动问题,但是针对service还存在以下问题:
- service IP地址难以记忆
- service资源可能也会被销毁和创建
- pod ip本身也有需要暴漏的需求
-
为了解决以上问题,引入了coredns,在K8S,其主要用于服务发现,也就是服务(应用)之间相互定位的过程
5.3 部署CoreDNS
① node节点安装镜像
#在所有 node 节点上操作
#上传 coredns.tar 到 /opt 目录中
cd /opt
docker load -i coredns.tar
② master节点运行
#在 master01 节点上操作
#上传 coredns.yaml 文件到 /opt/k8s 目录中,部署 CoreDNS
cd /opt/k8s
kubectl apply -f coredns.yaml
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-659bd7879c-fz4lz 1/1 Running 0 13m
calico-node-65m8m 1/1 Running 0 13m
calico-node-c2zgk 1/1 Running 0 13m
coredns-6954c77b9b-rjsrp 1/1 Running 0 21s
#DNS 解析测试
kubectl get svc -A #查看集群中的服务信息(包括服务名称,所属命名空间)
kubectl get pods #查看集群中的容器,并使用容器id进入容器
kubectl exec -it testapp-75bb94f97b-mjrc4 sh #进入容器中进行解析操作
#进入容器后进行解析
/ # nslookup kube-dns.kube-system.svc.cluster.local #解析格式nslookup 服务名称.命名空间.完整的域名
nslookup: can't resolve '(null)': Name does not resolve
#上方报错可以忽略,下方为正常解析内容
Name: kube-dns.kube-system.svc.cluster.local
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
5.3 部署 Dashboard
//在 master01 节点上操作
#上传 recommended.yaml 文件到 /opt/k8s 目录中,部署 CoreDNS
cd /opt/k8s
vim recommended.yaml
#默认Dashboard只能集群内部访问,修改Service为NodePort类型,暴露到外部:
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
nodePort: 30001 #添加
type: NodePort #添加
selector:
k8s-app: kubernetes-dashboard
#加载配置
kubectl apply -f recommended.yaml
#创建service account并绑定默认cluster-admin管理员集群角色
kubectl create serviceaccount dashboard-admin -n kube-system #创建serviceaccount资源账户dashboard-admin,并且在kube-system命名空间当中进行创建
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin #做个RBAC资源绑定,进行角色绑定,资源名称为dashboard-admin,用户为kube-system:dashboard-admin
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
#使用输出的token登录Dashboard
https://192.168.142.40:30001
#登录不要使用谷歌浏览器,谷歌浏览器内置会自动拦截该服务
#如何获取进入Dashboard界面的token信息
kubectl get secret -n kube-system #获取资源的名称
kubectl describe secrets -n kube-system dashboard-admin-token-xlc5b #获取该资源的token信息