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镜像,命令如下:

bash 复制代码
docker pull registry

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

bash 复制代码
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上传至私有仓库服务器。

bash 复制代码
docker   pull    busybox
docker   tag    busybox  192.168.1.147:5000/busybox
docker   push  192.168.1.147:5000/busybox

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

bash 复制代码
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所示:

bash 复制代码
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文件中代码如下:

bash 复制代码
{
"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代码如下:

bash 复制代码
#进入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 www.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/www/html/
RUN chmod 644 /var/www/html/index.html
#暴露映射目录;
VOLUME /var/www/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
相关推荐
lizhou82811 分钟前
win10下使用docker、k8s部署java应用
java·docker·kubernetes
wydydgh1 小时前
docker 升级步骤
运维·docker·容器
2401_840192272 小时前
在k8s中,客户端访问服务的链路流程,ingress--->service--->deployment--->pod--->container
云原生·容器·kubernetes
_.Switch3 小时前
构建现代应用的Python Serverless架构详解
运维·开发语言·python·云原生·架构·serverless·restful
小诸葛的博客3 小时前
istio中使用serviceentry结合egressgateway实现多版本路由
云原生·istio
jonssonyan4 小时前
稳了,搭建Docker国内源图文教程
运维·docker·容器
福大大架构师每日一题4 小时前
16.2 k8s容器基础资源指标讲解
云原生·容器·kubernetes·prometheus
周湘zx4 小时前
k8s中的微服务
linux·运维·服务器·微服务·云原生·kubernetes
工业甲酰苯胺5 小时前
k8s 中的 Ingress 简介
云原生·容器·kubernetes
周湘zx5 小时前
k8s中的存储
linux·运维·云原生·容器·kubernetes