深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络

深入剖析Kubernetes读书笔记(一)基本概念和kubernetes编排调度

  • 介绍
  • 入门相关(行业发展&Docker)
    • 什么是Docker镜像
    • 实现隔离的关键
    • 容器的总结
  • 浅谈kubernetes、kubernetes部署
  • Kubernetes的编排和调度
    • Kubernetes提供的基本资源类型讲解
    • Kubernetes的PV/PVC(CSI,Container storage inferface)
    • Kubernetes的网络(CNI,Container network inferface)

介绍

kubernetes in action读的差不多了,篇幅比较大,其实是需要一开始把书读薄一些的,对kubernetes的概念讲的比较细,底层也只是大概讲了一下,不涉及源码和kubernetes的设计理念,前几天查阅资料时偶然发现一个极客时间上的教材,深入剖析kubernetes,之前也没了解过这种网课,都是xxx专家xxx架构师啥的,买一个对比一下,看看靠谱不,由于已经看过一本,所以就速读了一下,只看差异。

对比kubernetes在kubernetes调度、kubernetes网络上、kubernetes存储上讲的多一些,里面举得例子也更贴近项目一些,其他内容感觉差不太多,整体读完再评价。

入门相关(行业发展&Docker)

行业发展简单看了看,基本讲了从paas到Docker由来以及后来的kubernetes。
Docker的基础知识介绍的比kubernetes细一些,但是也只是入门级的内容,还是有必要单独对Docker做一下系统的学习,以下列出我任务比较重要的观点。

什么是Docker镜像

1、Docker的相较于传统的paas优势在于打包镜像,很好的管理/解决了应用运行时环境本地/现网一致性的问题,原有的paas平台本质也是container,支持资源的隔离,但是没有镜像的概念,在开发者层面看使用成本是比较高的。
2、相比虚拟机,Docker在可维护性和性能方面具备优势,性能上对比虚拟机少了一层(OS直接在硬件的虚拟),镜像的打包部署也很方便;但劣势是:Docker提供的容器化运行环境,并不是100%的平台可移植,只是在rootfs上做了运行时的操作系统环境依赖,而内核层面部署在一台宿主机上的容器是公用的,而且使用的就是宿主机的内核,所以内核级别无法真正隔离
深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络_第1张图片

实现隔离的关键

3、Docker运行时的容器(一个镜像)本质也是一个linux进程,这个进程经过以下3步后实现了容器化:

  • 启用linux的namespace
  • 启用linux的cgroups
  • 使用linux的change root切换目录

这三点本身也是linux的基本特性,老早就有,后来docker做了很好的封装,其他paas平台也是用的这三个特性来实现的服务资源隔离。
4、Docker镜像分层,分层的策略为Docker提供了良好的打包体验,不重复打包、底层镜像可共享,打包的过程其实就是上面提到的change root的概念,将操作系统中的 / 目录下内容压缩,然后在运行时change root,一般来说应用依赖的运行时环境基本都在这个目录下

深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络_第2张图片

  • 只读层(镜像可覆盖)
  • 可读写层(镜像可覆盖)
  • init层(镜像不覆盖,例如host、resolve.conf的修改)

所以说一层层的Docker镜像其实就是对rootfs的多次编辑、覆盖、合并过程

进入容器(k8s进入pod),本质是创建一个进程,setns,修改这个进程namespace与要进入的容器进程一致,这样在当前进程就可以共享容器进程的操作系统资源了,讲到这里就可以了解到,Docker容器在经过上述namespace、cgroups、change root之后,相关的操作系统资源如平时用到的/proc,/etc这些,都是在进程内可见,宿主机不可见,在一个容器进程实现了操作系统资源的隔离使用

  • 通过namespace,实现了对linux设备、进程的可见性控制,所有linux的设备包括磁盘、网卡、进程都可以在一个namespace进行可见性的控制,其他容器不可见
  • 通过cgroups,实现了对linxu系统资源的控制限制,也讲了以下在/sys/cgroups下可以手动编辑相关的文件进行配置,手动实现进程的资源限制
  • 通过change root实现了操作系统运行时依赖的隔离,每个容器都运行在自己的 / 根目录下,相互不影响

这里主要说一下第二个点,就拿挂盘来讲,不同的容器在宿主机上其实使用的是同一块磁盘,那么如何做到一个目录在容器内可见并可用,在宿主机上不可见,其他容器也不可见?用到了也是linux的绑定挂载,比如在容器运行时,将容器内的/test目录挂载在宿主机的/temp(命令可以实现),当在容器内attach一个1.txt时,容器内的/test可以看到这个文件,在宿主机上的/var/lib/docker/xxxx(容器id)/test目录下是空的,但是在宿主机的/temp下是可以看到的。

容器的总结

对容器的总结有一个比较容易理解的说法,是否严谨就不好说了,但是很好理解。

  • 从静态试图看,容器是一组挂载在/var/lib/docker/mnt/xxxx(容器id)的rootfs(操作系统 / 的拷贝),这一部分称之为“容器镜像”
  • 从动态试图看,容器是一个有namespace + cgroups 构成的隔离环境(一个进程),这部分称之为“容器运行时”

浅谈kubernetes、kubernetes部署

这部分都是一些简单的罗列,环境搭建也没有太细看,工程性太强。

以上内容,对比kubernetes in action,是比较好的,主要是介绍了一些Docker的基本概念,因为有一部分读者确实是单纯从工程应用角度去学习了解kubernetes的,所以肯定对Docker和kubernetes的关系不了解,比如pod的request limit是怎么实现的,pod的网络是怎么实现的,这些都和Docker紧密相关,不过kubernetes in action的作者应该是假设读者具备这一些基本概念了,学习顺序也应该是先Docker后kubernetes,但在实际的生产活动中可能不会有很多读者有意愿去系统学习。

Kubernetes的编排和调度

这部分内容讲的脉络是,从kubernetes提供的一些基本的资源类型,逐步讲到kubernetes的管理面服务如api-server、scheduler、controller等,然后逐步引出了CRD/CRI/CSI,最终用一个operator的基本实现来整体描述了一下,对比kubernetes in action,kubernetes提供的基本资源讲的不是很细,与原理/流程相关的东西能细一些,不过还是得有一些基础看才会比较有感觉。

Kubernetes提供的基本资源类型讲解

这部分讲的由浅入深,从kubernetes提供的基本资源类型讲到CRD/operator,这里只阐述一下一些核心观点的理解总结:

1、对于为什么要有pod,为什么要通过pod管理多个容器,解释是为了解决亲密服务的问题,能够让需要共部署/进程间通信这样的服务能够在一个运行环境里,为了实现这一过程,kubernetes搞了一个infra容器来作为基础容器,声明周期与pod相同,创建了一套namespace、cgroups、rootfs环境,再创建其他的容器共享infra容器的系统资源,整体称之为pod,所以pod的定义是:一组共享namespace、cgroups、rootfs的容器集合

2、pod的基本用法讲了一下,不过比较感兴趣的是podPreset,这个之前没有看过,可以批量的通过selector对一组pod进行修改

3、提到了“声明式API”的概念,提了一个概念比较有趣,pod中的ownerrefrence用来保存这个pod的owner信息,controller(RS controller)也是通过这个字段能控制pod

4、讲了deployment如何通过RS实现的scale和滚动升级

5、讲了statefulset,想表达两个观点,statefulset创建有序(拓扑有序),statefulset可以提供稳定服务,提到稳定的服务是通过headless service表达的,即直接在DNS写pod的ip,不走endPoint

6、描述了statefulset的存储有状态,提到了PVC/PV,不过基本是照着现象过了一遍

7、讲了一个例子,如何在集群里部署一个mysql,多实例,单个pod负责写,其他pod负责读,读pod实时同步写pod更新,这里将statefulset、init container、sidecar、configmap、健康检查、pvc/pv、rook、storageClass用了一遍,最后提了一嘴operator。

以上内容,对比kubernetes in action,讲的不够循序渐进,上来直接deployment、pvc啥的读者容易懵,没有从RC/RS这种简单的开始,另外也没有提到api-server、etcd这个过程中的作用,不过如果有基础看起来还行。

下面继续:
1、讲到了daemonSet,通过Toleration、nodeAffinity字段再加上DaemonSetController实现的每个节点均部署的能力,通知描述了DaemonSet是通过DaemonSet controller + ControllerRevision来实现对pod管理。

2、讲到了job,管家年提到了job涉及的pod也是直接由controller管理的,和RS无关,顺便介绍了几种job常用方法,例如固定任务数场景、队列消费场景

这部分内容收获不是很大,也是比较偏应用,这些内容大多数书里都有。下面介绍的一些内容非常不错,和kubernetes的设计方法、实现原理、流程相关性强一些,不过阅读过程最好有go语言基础,不然看完容易忘

1、kubectl create/apply/replace有啥区别,create不是声明式的更新,而是心创建了一个资源对象,其他两个都是基于原有对象修改etcd中的内容,通过controller进行的声明式修改。所以最好用后两者,用create的过程中为了避免在集群中出现重复的资源,所以内部是有锁的,而其他两者是可以并发以及同一对象修改merge的。

2、介绍api-server接口定义,这部分内容在kubernetes in action也有,接口:组/版本/资源,包括api-server收到请求后基本流程是啥,如何对组/版本/资源进行处理的。这里讲了一个CRD(custom resource definition)的例子,这个例子就得非常好,引出了api-server的核心用法,通过创建一个network的CRD,也能让读者明白其他kubernetes的资源如statefulset、deployment大概是个啥。

3、顺着CRD继续讲,创建出来的CRD,kubernetes是如何对这个CRD进行声明式的管理的?引出了controller,通过一个go语言写的自定义的controller来描述kubernetes的controller是如何工作的,平时用到的statefulset、deployment是怎么和pod搭上边的。

4、RBAC的内容和安全相关没太看

还是那句话,得学一下go,不然看着费劲。

5、讲operator,接着上面的逻辑,用户可以见一个CRD了,可以见一个controller,那就可以很自由的使用kubernetes,我们可以根据自己的需求,定制自己的pod,定制自己的controller,对自己的应用类型进行管理,如果想把CRD/CONTROLLER以及其他相关的内容都做隐藏呢?提出了operator的概念。文中讲的是一个etcd的operator部署的例子,因为etcd本身是一个分部署的存储引擎,支持高可用,在部署过程中和主从mysql、zk、kafka差不多,得搞一些配置,通过一个operator就能把这些东西都封装起来,而且封装的主体也是一个kubernetes的资源对象(deployment)

之前做过spark-operator,其实就是在kubernetes中创建一个deployment,这个deployment对应的pod去做两件事:
1、创建CRD
2、创建controller,管理CRD/pod

讲到这里,kubernetes调度、管理相关的东西差不多完了,还差的是scheduler,应该在后面会有讲到,这里总结两点:

  1. 通过operator的实现可以很好的理解kubernetes对资源类型的管理实现流程,但是得学一下go
  2. 自始至终都和容器(Docker)紧密相关,从pod定义就能看出来,kubernetes本质上是对CRI/CNI/CSI的应用(CNI/CSI后面会讲)
  3. 对linux的特性需要仔细了解,cgroups、namespace、change root、veth pair、mount volume等等,不然也等于是看看简介
  4. 最后,如果想深入了解,得学习一下go,然后上手,再读读源码,不然也就只能到这了。

Kubernetes的PV/PVC(CSI,Container storage inferface)

PV/PVC花了不少篇幅来讲,一方面这个东西确实有点绕,在应用过程中也搞不太明白关系,在kubernetes in action中也废了不少内容讲这个,讲的非常细,步骤一步步的。这里相对还算少的。不过在PV/PVC与persistVolumeController、kubelet、Docker的关系上讲到了一些点,值得总结:

  1. pod中对PVC进行配置----为什么不配置pv,为了在pod层面隐藏存储实现细节

  2. persistVolumeController检查PV/PVC是否绑定,没绑定就绑定一个PV的

    a.PV手动要自己创建,这样persistVolumeController才会去匹配,匹配不上pod就起不来
    b.配置了storageClass就能自动创建pv

  3. pod调度到某个节点后,不会立刻启动容器,kubelet会做一件事:通过代码中的VolumeManagerReconciler检查是否需要mount volume(也就是配置的PVC对应的PV)

    这里分两步:
    a.把PV作为一个块设备挂载
    b.把挂载好的块设备mount的到docker容器的volume上
    $ mount -t nfs :/ /var/lib/kubelet/pods//volumes/kubernetes.io~/

    但不是所有的PV都需要作为块设备挂在,NFS就可以直接当成目录进行mount。mount后,改pod所使用的磁盘空间就相当于指向了PV提供的目录。

  4. pod用的磁盘准备好了,最后再通过**CRI**启动容器,则容器内就可以正常使用磁盘空间了

    $ docker run -v /var/lib/kubelet/pods//volumes/kubernetes.io~/:/<容器内的目标目录> 我的镜像 …

这里附一篇CRI/CSI/CNI的文章

讲完这个基本概念和流程后,又举了一个CSI实现的例子,如何定义自己的PV/PVC,包括storageClass,这里没有太细看,原理上应该都差不多,用到的linux相关的技术应该是和磁盘设备控制、目录权限控制、目录挂载有关的内容。

Kubernetes的网络(CNI,Container network inferface)

深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络_第3张图片

对比kubernetes讲的比较细,偏底层一些,介绍了几个重点概念:
1、docker0作为网桥的主要作用是逻辑交换机
2、vethPair的两端,一端是container的eth0,一端是物理机创建的虚拟网卡vethxxxxxxxx
3、基于匹配到网桥的虚拟网卡“降级”特征,就能实现数据包发送的ARP过程
4、容器对外部的访问,也要通过docker0再到主机的eth0

单机上的容器通信介绍一个最基本的流程,然后就是多主机多容器的场景,用flannel举了个例子(先介绍了flannel的目的就是创建一个跨主机的overlay网络):
1、flannel的UDP模式,即在主机eth0和docker0之间再创建了一个flannel0的TUN设备,TUN设备在ETCD中统一维护,建立子网关系(随之而来的性能问题也主要来源于TUN设备的用户/内核态切换)
深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络_第4张图片

深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络_第5张图片
2、flannel的VXLAN模式,其实和上面的差不多,TUN换成了VTEP,全部在内核态(对数据包进行修改),提高了性能

深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络_第6张图片

讲完了flannel基本流程,引出了CNI的概念,kubernetes就是为了避免在P层的调度管理逻辑和docker强绑定,所以对docker0这个网桥做了解耦,提供了CNI的接口,任意网络插件都能够实现一个自己的“docker0”,在kubernetes里叫cni0,因此在kubernetes下的pod创建时,就会调用网络插件(dockershim来做的)对pod内容的网络环境进行初始化(就是一大堆linux命令,创建容器内eht0,创建容器外的veth pair,安装到cni0上,同时flush到etcd等等)。

在VXLAN和UDP讲完之后,有介绍了一种更简单的方案,host-gw模式,其实就是省去了一个TUN/VTEP的设备转发过程,提高了性能,同时,替代TUN/VTEP的对象是route,通过配置route规则,让容器的虚拟网络地址都能正确的指向一个没毛病的物理地址,而这个虚拟地址到对应的正确的物理地址关系,是在etcd记录的,flannel插件的作用就是维护这个关系,及时更新到整个kubernetes集群的每个节点上,如图:
深入剖析Kubernetes读书笔记(一)基本概念、容器编排、kubernetes的持久化和网络_第7张图片
最后,介绍了BGP,边界网关协议,一种连网桥都不用创建的容器网络,原理简单理解:
1、DaemonSet收集各个节点的ip和容器ip,共享信息
2、容器eth0创建veth pair到主机,主机端的虚拟网卡不挂网桥,直接挂到主机eth0
3、定期更新主机的router table,让数据包能直接通过eth0发出去

关于ingress/egress在kubernetes容器网络中的生效原理,没细看,基本上也是基于linux的基本特性做的,回头有用再看。整体来看这一章讲的很好,不是普通教材能体现的,前几天和同事还在聊,像这种内容的东西,是不是可以出书的,市面上的数据都是一些基本的应用和介绍,都是比较基于一项技术较为封闭的结构性介绍,缺少这种基于一个技术点,发散性的讲解,可能是这些内容出书的话没人看吧,可能大多数人能把教材看完就不错了,另外就是这些内容看起来高大上,其实在应用过程中比较少用,除非遇到了很奇怪的bug,我觉得这样的内容对于实际的编码过程可能作用不是很大,但是对于软件设计来说还是有一些帮助,在了解机制的前提下,往往能想到更简单更直接扩展性更好的方法。

你可能感兴趣的:(kubernetes)