主页 > 手机  > 

k8s-Flannel

k8s-Flannel
1.Flannel概念剖析

Flannel是 CoreOS 团队针对 Kubernetes 设计的一个覆盖网络(Overlay Network)工具,其目的在于帮助每一个使用 Kuberentes 的 CoreOS 主机拥有一个完整的子网。这次的分享内容将从Flannel的介绍、工作原理及安装和配置三方面来介绍这个工具的使用方法。

Flannel通过给每台宿主机分配一个子网的方式为容器提供虚拟网络,它基于Linux TUN/TAP,使用UDP封装IP包来创建Overlay网络,并借助Etcd维护网络的分配情况。Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes.

2. Flannel工作原理

Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的IP地址。

在默认的Docker配置中,每个Node的Docker服务会分别负责所在节点容器的IP分配。Node内部得容器之间可以相互访问,但是跨主机(Node)网络相互间是不能通信。

Flannel设计目的就是为集群中所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得"同属一个内网"并且"不重复的"IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。

Flannel 使用Etcd存储配置数据和子网分配信息。Flannel 启动之后,后台进程首先检索配置和正在使用的子网列表,然后选择一个可用的子网,然后尝试去注册它。Etcd也存储这个每个主机对应的IP。

Flannel 使用Etcd的watch机制监视/atomic.io/network/subnets下面所有元素的变化信息,并且根据它来维护一个路由表。为了提高性能,Flannel优化了Universal TAP/TUN设备,对TUN和UDP之间的IP分片做了代理。

3. Flannel架构介绍

Flannel默认使用8285端口作为UDP封装报文的端口,VxLan使用8472端口。 那么一个网络报文请求是怎么从一个容器发送到另外一个容器的呢?例如从node1上的Container1容器(IP:10.244.0.13)访问node2上面Container2容器(IP:10.244.1.14)容器。

Container1容器10.244.0.13直接访问目标容器Container2的IP 10.244.1.14,请求默认通过容器内部的eth0网卡发送出去。请求报文通过Veth pair(虚拟设备对)被发送到Docker宿主机VethXXX设备上。VethXXX设备是直接连接到虚拟交换机Docker0(Cni0)的,所以请求报文通过虚拟Bridge Docker0发送出去。然后查找Docker宿主机的路由表信息,同时外部容器IP的报文都会转发到Flannel0虚拟网卡,这是一个P2P的虚拟网卡,然后报文就被转发到监听在另一端的Flanneld进程。因为Flannel在Etcd中存储着子网和宿主机ip的对应关系,所以能够找到10.244.1.14对应的宿主机IP为11.101.1.3,进而开始组装UDP数据包发送数据到目的主机。 这个请求得以完成的原因每个节点上都启动着一个Flanneld udp进程,都监听着8285端口,所以node1通过Flanneld进程把数据包通过宿主机的Interface网卡发送给node2的Flanneld进程的相应端口即可。请求报文到达node2之后,继续往上传输,到传输层,交给监听在8285端口的Flanneld程序处理。请求数据被解包,然后发送给Flannel0虚拟网卡。查找路由表,发现对应容器的报文要交给Docker0(cni0)。Docker0找到连到自己的容器,把报文发送给Container2,反之同样的工作方式。 4. Kubernetes工作原理剖析

Kubernetes集群是一组节点,这些节点可以是物理服务器或者虚拟机,在其上安装Kubernetes平台。下图为了强调核心概念有所简化。Kubernetes架构图。 从上图,我们可以看到K8S组件和逻辑关系:Kubernetes集群主要由Master和Node两类节点组成。Master的组件包括:Apiserver、Controller-manager、Scheduler和Etcd等几个组件,其中Apiserver是整个集群的网关。

Node主要由kubelet、kube-proxy、docker引擎等组件组成。kubelet是K8S集群的工作与节点上的代理组件。

在企业生产环境中,一个完整的K8S集群,还包括CoreDNS、Prometheus(或HeapSter)、Dashboard、Ingress Controller等几个附加组件。其中cAdivsor组件作用于各个节点(master和node节点)之上,用于收集及收集容器及节点的CPU、内存以及磁盘资源的利用率指标数据,这些统计数据由Heapster聚合后,可以通过apiserver访问。 K8S集群中创建一个资源(Pod容器)的工作流程和步骤:

客户端提交创建(Deployment、Namespace、Pod)请求,可以通过API Server的Restful API,也可以使用kubectl命令行工具。然后API Server处理用户的请求,并且存储相关的数据(Deployment、Namespace、Pod)到Etcd配置数据库中。K8S Scheduler调度器通过API Server查看未绑定的Pod。尝试为该Pod分配Node主机资源。过滤主机 (调度预选):调度器用一组规则过滤掉不符合要求的主机。比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。主机打分(调度优选):对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把容一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等。选择主机:选择打分最高的主机,进行binding操作,结果存储到etcd中。Node节点上Kubelet根据调度结果,调用主机上的Docker引擎执行Pod创建操作,绑定成功后,Scheduler会调用APIServer的API在etcd中创建一个boundpod对象,描述在一个工作节点上绑定运行的所有pod信息。同时运行在每个工作节点上的Kubelet也会定期与etcd同步boundpod信息,一旦发现应该在该工作节点上运行的boundpod对象没有更新,则调用Docker API创建并启动pod内的容器。 5. Kubernetes 本地私有仓库实战

Docker仓库主要用于存放Docker镜像,Docker仓库分为公共仓库和私有仓库,基于registry可以搭建本地私有仓库,使用私有仓库的优点如下: 节省网络带宽,针对于每个镜像不用去Docker官网仓库下载; 下载Docker镜像从本地私有仓库中下载; 组件公司内部私有仓库,方便各部门使用,服务器管理更加统一; 可以基于GIT或者SVN、Jenkins更新本地Docker私有仓库镜像版本。 官方提供Docker Registry来构建本地私有仓库,目前最新版本为v2,最新版的docker已不再支持v1,Registry v2使用Go语言编写,在性能和安全性上做了很多优化,重新设计了镜像的存储格式。如下为在192.168.1.147服务器上构建Docker本地私有仓库的方法及步骤: (1)下载Docker registry镜像,命令如下:

docker pull registry

(2)启动私有仓库容器,启动命令如下:

mkdir -p /data/registry/ docker run -itd -p 5000:5000 -v /data/registry:/var/lib/registry docker.io/registry

Docker本地仓库启动后台容器启动,如图24-2所示: 默认情况下,会将仓库存放于容器内的/tmp/registry目录下,这样如果容器被删除,则存放于容器中的镜像也会丢失,所以我们一般情况下会指定本地一个目录挂载到容器内的/tmp/registry下。

(3)上传镜像至本地私有仓库: 客户端上传镜像至本地私有仓库,如下以busybox镜像为例,将busybox上传至私有仓库服务器。

docker pull busybox docker tag busybox 192.168.1.147:5000/busybox docker push 192.168.1.147:5000/busybox

(4)检测本地私有仓库:

curl -XGET http://192.168.1.147:5000/v2/_catalog curl -XGET http://192.168.1.147:5000/v2/busybox/tags/list

(5)客户端使用本地私有仓库: 客户端docker配置文件添加如下代码,同时重启docker服务,获取本地私有仓库如图24-3所示:

OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false --insecure-registry 192.168.1.147:5000' ADD_REGISTRY='--add-registry 192.168.1.147:5000'

至此,docker本地私有仓库部署完毕,可以向仓库中添加或者更新Docker镜像。 在K8S Docker客户端主机添加本地仓库地址,添加方法如下: vim /etc/docker/daemon.json文件中代码如下:

{ "insecure-registries":["192.168.1.147:5000"] } 6. Kubernetes+Jenkins+Docker仓库整合

在企业生产环境中,通常会将K8S+Jenkins+Docker仓库整合起来,实现业务全自动发布。需求如下: 1)K8S云计算平台、Jenkins平台、Docker仓库平台;(提前准备好) 2)部署一套bbs.jfedu.net业务,在Jenkins创建工程-绑定SVN仓库地址-从SVN下载网站代码; 3)网站代码下载成功-制作CentOS7镜像-将网站程序打包至镜像中; 4)将制作的CentOS7镜像(网站程序)-上传至Docker仓库平台; 5)基于K8S云计算平台-部署bbs.jfedu.net业务(CentOS云主机)-NodePort端口-外网用户访问。 6)编写SHELL编程脚本,实现以上步骤整合操作,SHELL代码如下:

#进入Jenkins工程目录; cd /root/.jenkins/workspace/bbs.jfedu.net/ #查看从SVN下载网站代码; ls -l index.html #创建Dockerfile镜像制作文件; cat>Dockerfile<<EOF #2022年11月23日11:22:12 #指定基础镜像; FROM ansible/centos7-ansible:latest #指定维护者信息; MAINTAINER .jfedu.net 2022 #指定工作目录; WORKDIR /root/ #删除EPEL扩展源; RUN rm -rf /etc/yum.repos.d/epel* #安装网络工具和openssh server服务; RUN yum install -y net-tools openssh-server httpd #修改系统密码为1; RUN echo 1|passwd --stdin root #生成SSHD服务启动基础KEY文件; RUN ssh-keygen -A #将网站程序部署至镜像中; COPY index.html /var/ /html/ RUN chmod 644 /var/ /html/index.html #暴露映射目录; VOLUME /var/ /html/ #指定容器入口命令; ENTRYPOINT /usr/sbin/init CMD /usr/sbin/sshd -D EOF #制作CentOS7镜像文件; docker build -t centos7-ssh:v2 ./ #修改CentOS7镜像文件tag号; docker tag centos7-ssh:v2 10.0.12.13:5000/centos7-ssh:v2 #将CentOS7镜像上传Docker私有仓库; docker push 10.0.12.13:5000/centos7-ssh:v2 #创建K8S bbs-jfedu-net部署yaml文件; cat>bbs-jfedu-net.yaml<<EOF kind: Deployment apiVersion: apps/v1 metadata: name: bbs-jfedu-net namespace: default uid: 16adfc69-ecf1-48d3-9190-518ecffb8818 resourceVersion: '3854' generation: 1 creationTimestamp: '2022-11-23T13:02:03Z' labels: k8s-app: bbs-jfedu-net annotations: deployment.kubernetes.io/revision: '1' managedFields: - manager: dashboard operation: Update apiVersion: apps/v1 time: '2022-11-23T13:02:03Z' fieldsType: FieldsV1 fieldsV1: 'f:metadata': 'f:labels': .: {} 'f:k8s-app': {} 'f:spec': 'f:progressDeadlineSeconds': {} 'f:replicas': {} 'f:revisionHistoryLimit': {} 'f:selector': {} 'f:strategy': 'f:rollingUpdate': .: {} 'f:maxSurge': {} 'f:maxUnavailable': {} 'f:type': {} 'f:template': 'f:metadata': 'f:labels': .: {} 'f:k8s-app': {} 'f:name': {} 'f:spec': 'f:containers': 'k:{"name":"bbs-jfedu-net"}': .: {} 'f:image': {} 'f:imagePullPolicy': {} 'f:name': {} 'f:resources': {} 'f:securityContext': .: {} 'f:privileged': {} 'f:terminationMessagePath': {} 'f:terminationMessagePolicy': {} 'f:dnsPolicy': {} 'f:restartPolicy': {} 'f:schedulerName': {} 'f:securityContext': {} 'f:terminationGracePeriodSeconds': {} - manager: kube-controller-manager operation: Update apiVersion: apps/v1 time: '2022-11-23T13:02:04Z' fieldsType: FieldsV1 fieldsV1: 'f:metadata': 'f:annotations': .: {} 'f:deployment.kubernetes.io/revision': {} 'f:status': 'f:conditions': .: {} 'k:{"type":"Available"}': .: {} 'f:lastTransitionTime': {} 'f:lastUpdateTime': {} 'f:message': {} 'f:reason': {} 'f:status': {} 'f:type': {} 'k:{"type":"Progressing"}': .: {} 'f:lastTransitionTime': {} 'f:lastUpdateTime': {} 'f:message': {} 'f:reason': {} 'f:status': {} 'f:type': {} 'f:observedGeneration': {} 'f:replicas': {} 'f:unavailableReplicas': {} 'f:updatedReplicas': {} spec: replicas: 1 selector: matchLabels: k8s-app: bbs-jfedu-net template: metadata: name: bbs-jfedu-net creationTimestamp: null labels: k8s-app: bbs-jfedu-net spec: containers: - name: bbs-jfedu-net image: '10.0.12.13:5000/centos7-ssh:v2' resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullPolicy: IfNotPresent securityContext: privileged: true restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst securityContext: {} schedulerName: default-scheduler strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 25% maxSurge: 25% revisionHistoryLimit: 10 progressDeadlineSeconds: 600 status: observedGeneration: 1 replicas: 1 updatedReplicas: 1 unavailableReplicas: 1 conditions: - type: Available status: 'False' lastUpdateTime: '2022-11-23T13:02:04Z' lastTransitionTime: '2022-11-23T13:02:04Z' reason: MinimumReplicasUnavailable message: Deployment does not have minimum availability. - type: Progressing status: 'True' lastUpdateTime: '2022-11-23T13:02:04Z' lastTransitionTime: '2022-11-23T13:02:03Z' reason: ReplicaSetUpdated message: ReplicaSet "bbs-jfedu-net-598fb758b6" is progressing. EOF #创建bbs-jfedu-net-service.yaml文件; cat>bbs-jfedu-net-service.yaml<<EOF kind: Service apiVersion: v1 metadata: name: bbs-jfedu-net namespace: default uid: c259b7a1-4688-4e51-b5ce-7b9d0a600e15 resourceVersion: '4636' creationTimestamp: '2022-11-23T13:16:20Z' labels: k8s-app: bbs-jfedu-net managedFields: - manager: dashboard operation: Update apiVersion: v1 time: '2022-11-23T13:16:20Z' fieldsType: FieldsV1 fieldsV1: 'f:metadata': 'f:labels': .: {} 'f:k8s-app': {} 'f:spec': 'f:externalTrafficPolicy': {} 'f:ports': .: {} 'k:{"port":80,"protocol":"TCP"}': .: {} 'f:name': {} 'f:port': {} 'f:protocol': {} 'f:targetPort': {} 'f:selector': .: {} 'f:k8s-app': {} 'f:sessionAffinity': {} 'f:type': {} spec: ports: - name: tcp-80-80-js226 protocol: TCP port: 80 targetPort: 80 nodePort: 30286 selector: k8s-app: bbs-jfedu-net clusterIP: 10.10.232.164 clusterIPs: - 10.10.232.164 type: LoadBalancer sessionAffinity: None externalTrafficPolicy: Cluster status: loadBalancer: {} EOF #基于yaml文件部署bbs-jfedu-net业务和Service; kubectl apply -f bbs-jfedu-net.yaml kubectl apply -f bbs-jfedu-net-service.yaml #查看bbs-jfedu-net业务是否部署成功; sleep 20 kubectl get pods -n default
标签:

k8s-Flannel由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“k8s-Flannel