前言

久闻K8S大名,受限于docker知识的欠缺,所以对K8S的探索一直处于逡巡不前的状态,这一拖就是好久,最近这段时间公司准备上K8S集群了,我被安排来负责这件事情的推进。终于有幸可以真正学习下K8S,一睹K8S的芳容了。

由于之前缺乏必要的docker相关知识的储备,加上K8S本身内容复杂庞大,所以在学习的过程中费了很大的劲,走了很多弯路才勉强将基本流程搞通,能跑起来一整套服务,下面就根据我的学习以及填坑历程和大家分享下,希望对想入坑K8S的小伙伴们有所帮助,别再走或者少走一些弯路。

正文

什么是K8S

首先先简单科普下K8S:

kubernetes,简称K8s,是用8代替名字中间的8个字符“ubernete”而成的缩写(此处I18n表示终于找到战友了)。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。

具体来说,主要包括以下几点:

  • 服务发现与调度

  • 负载均衡

  • 服务自愈

  • 服务弹性扩容

  • 横向扩容

  • 存储卷挂载

K8S常用概念

首先声明下上面的图的概念是不完整的,K8S这三方面的内容远不止于此,我所写的只是常用到的以及我用到的一些概念以及组件。由于网上的资料很多,所以这里我就总结一下,把一些使用感受和经验说一说,具体的概念我这里仅简单介绍下,不做详细复制和粘贴,大家感兴趣的可以去自己查,网上很多。这么做的目的就是希望能帮大家快速理解和掌握这些概念,尽快入门K8S。

存储

首先作为一个平台,存储是需要优先考虑的,而K8S也在存储层面做了很多支持,由于K8S中的基本单位是Pod,所以从这个层面来区分,K8S的存储分为Pod内部存储和外部存储。

内部存储Volume

首先内部存储主要通过配置Volume来实现。Pod需要设置卷来源(spec.volume)和挂载点(spec.containers.volumeMounts)两个信息后才可以使用相应的Volume。

Volume主要分为上面图上的五种,概念不多说了,说一下这五种的区别以及使用方式吧:

  • EmptyDir:临时空目录,创建后供pod内多container共享的一个目录。与Pod的生命周期一致,Pod创建时创建,删除时删除。所以可以存放临时数据或者中间数据,对于需要持久化保存的数据这种方式不合适。

  • Hostpath:与宿主机的一个目录映射,用来存储需要持久化保存的数据。容器迁移至其它节点数据会丢失。所以该方式仅适合单节点的K8S,可以做到数据持久化复用,仅适合单机版K8S测试与验证,不适合生产环境。

  • 云存储和网络存储:为了兼容和支持各个云厂家的各种产品而定制的,毕竟这些云厂家会是将来K8S最大的载体和用户,对于爸爸和上帝,K8S怎敢不支持。

  • ConfigMap:在某些场景下,pod需要依赖各种配置以及配置文件,这些配置不能写死在镜像中,否则会影响到镜像的扩展性。此时ConfigMap作为K8S中提供的配置管理组件登场了。对于少量配置可以通过ConfigMap映射到pod的环境变量中进行注入;而配置文件则会通过配置文件映射到pod中的volume来进行配置文件的动态下发。

  • Secret:K8S中Secrets用于存储和管理一些敏感数据,比如密码,token,密钥等敏感信息。而使用方式和ConfigMap的使用方式一致,用户就可以通过在Pod的容器里挂载Volume的方式或者环境变量的方式访问到这些Secret里保存的信息。

外部存储PersistentVolume

上面介绍了内部存储Volume,但是通过上面可以看出,Volume针对应用级别的pod比较合适,但是针对共享存储的服务尤其是数据库,并不是很合适,于是K8S提供了外部存储来解决相应场景的问题,其中的PV(PersistentVolume)以及PVC(PersistentVolumeClaim)是主要的解决方案。

  • PersistentVolume(PV):外部存储系统中的一块存储空间,由管理员创建和维护。与Volume一样,PV具有持久性,生命周期独立于Pod。

  • PersistentVolumeClaim(PVC):对PV的申请(Claim)。PVC通常由普通用户创建和维护。需要为Pod分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes会查找并提供满足条件的PV。

了解JAVA的小伙伴们可能会发现,这里面PV以及PVC的关系像极了JAVA中的Heap以及Class的关系,而PVC根据自身的信息申请到的PV实例其实就和JAVA中的对象是一样的。这样的类比有助于大家理顺这些概念之间的关系。

了解了上面的概念后,我们来看看PV的种类以及类型: 按照种类来划分,PV分为静态PV以及动态PV。

  • 静态PV:即通过手动指定的方式来进行PV的创建以及分配。优点是能够精确的控制,适用于小规模的K8S集群。缺点也是很显然,静态分配和管理的成本过高,不适合大的复杂的集群。对应的是静态PVC,PVC声明后只会匹配静态的PV,可用场景有限。

  • 动态PV:即创建完PV后,通过动态的PVC进行资源的分配以及管理,可用性比较高,适合大的K8S集群。

  • StorageClass:因为动态PVC需要匹配合适的PV,而PVC可能会有多种类型,所以动态PVC在匹配PV时需要制定StorageClass,K8S只会将StorageClass相同的PVC和PV绑定起来。如果再声明PVC时未指定storageClassName,则PVC会使用默认的storageClass。

下面再来看看上面提到PV的类型:

  • local:K8S默认的storageClass,说实话没用明白,实际场景中不管是测试还是生产,应该不会有人使用这种storageClass,所以就不多介绍了

  • NFS:即网络存储服务,即依赖外部的NFS服务提供存储能力。NFS存在Server单点故障的问题,但是搭建以及适配简单,大多数场景下用于K8S集群进行相关测试时使用。

  • CephFS:即以ceph搭建的分布式去中心化的分布式存储,适用于K8S的生产环境,稳定性以及扩展性较NFS有很大的提升。

  • 其他的云存储以及网络存储:和上面的原因一样,即是爸爸又是上帝,必须支持!

总结一下,PV和PVC为K8S提供了独立的持久化存储,为需要持久化存储的服务特别是有状态服务的实现提供了可能性。

组件

K8S的组件很多,此处仅简单介绍下常用的几种,在后续的文章中会详细介绍。

从纵向来看,K8S分为container,pod以及node三个层级。下面简单来说一下:

  • node:即K8S的单节点,既提供了pod运行的载体,又提供了存储,网络等其他一列资源。

  • pod:K8S逻辑上以及调度上的最小单位,K8S所有的业务都是围绕pod展开的,是K8S最重要的概念之一。

  • container:真正代码运行环境的提供者,封装了代码以及代码运行环境。正常情况下一个pod对应一个container,少数特殊情况会出现一个pod有多个container的情况,但是这样做会增加业务的耦合性,所以除非必须,否则不建议一个pod运行多个container的场景。

从横向来看,K8S又根据pod进行封装,提供了不同的组件用于实现不同的场景,下面来看几个典型以及常用的组件:

  • Deployment:针对应用服务而产生的概念,适用于无状态服务。如果需要对其他服务提供访问接口,则需要配合Service共同实现。外部服务通过Service访问对应的Deployment。

  • StatefulSet:和Deployment相对应,适用于有状态服务。StatefulSet一般配合PVC共同提供服务,其中PVC负责持久化存储,而StatefulSet则负责状态的创建,维护以及重启恢复等工作。

  • DaemonSet:可以保证Pod运行在Kubernetes集群里的每一个节点(Node)上且每个节点上只有一个这样的Pod实例。当有新的节点加入 Kubernetes 集群后,该 Pod 会自动地在新节点上被创建出来;而当旧节点被删除后,它上面的 Pod 也相应地会被回收掉。通过这个特点很容易看出DaemonSet适合运用在网络插件的Agent组件上、日志组件、监控组件等。

  • Job/CronJob:对于某些一次性的任务,执行完毕就退出的场景,用pod来实现显然不是很合适,于是针对一次性任务的场景K8S提供了Job的实现。而CronJob很显然就是针对定时任务提供的实现。

网络

最后说说网络通信相关的内容。网络在K8S中通过Service以及Ingress这两个概念进行实现。通过作者的理解,我把K8S网络相关的内容分为内部服务,内部到外部服务以及外部到内部服务三类进行说明:

  • 内部服务:内部服务通过Service的ClusterIP方式实现,这也是Service的默认type。在ClusterIP中,K8S会在Service创建完毕后提供一个内部IP作为ClusterIP属性,K8S内部服务可以通过ClusterIP或者ServiceName来访问该服务。

  • 外部到内部服务:外部到内部服务Service的ExternalName方式实现,即设置Service的type为ExternalName。这样做的好处就是内部服务访问外部服务的时候是通过别名来访问的,屏蔽了外部服务的真实信息,外部服务对内部服务透明,外部服务的修改基本上不会影响到内部服务的访问,做到了内部服务和外部服务解耦合。

  • 内部到外部服务:这个相比上两种情况会稍微复杂一些,实现方式有Service的NodePort、LoadBalancer方式以及Ingress一共三种方式实现。其中LoadBalancer一般需要云供应商的支持,或者一些本地资源如F5的支持,而且据说要额外收费,作者不是很了解这里不做过多介绍了。NodePort则是Service type是Nodeport的实现,NodePort通过配置nodePort属性,外部用户可以通过NodeIP:NodePort的方式单独访问每个Node上的实例。这种方式有很多缺点,直接访问节点的地址和端口需要在客户端记录很多信息,Pod发生迁移后这些信息没办法动态更新,节点的防火墙及节点所在网络区域的防火墙策略配置会比较麻烦。最后来说说Ingress,Ingress绑定唯一的IP,通过URL来判断和分发需要访问的服务。Ingress工作在HTTP层,配置与使用更加灵活。如果了解nginx的小伙伴,看到Ingress就能看到nginx的影子,通过反向代理来统一访问接口并屏蔽访问细节。

总结

上面仅仅简单介绍了下作者入门K8S的一些简单的理解并进行了总结,如果同样想入坑,可以通过上面的文章进行快速避雷以及入门操作。 但是上面仅仅是针对部分常用概念和用法进行了粗略的讲解,加上作者的理解偏差,可能会有部分不准确或者不清楚的地方,后续作者会通过系列文章进行细化。欢迎大家留言讨论共同学习。另外,如果你也想入门K8S,现在仍然不晚。欢迎关注作者,我们在K8S的路上共同前进!

另外,笔者长期关注大数据通用技术,通用原理以及NOSQL数据库的技术架构以及使用。如果大家感觉笔者写的还不错,麻烦大家多多点赞和分享转发,也许你的朋友也喜欢。

最后挂个公众号二维码,公众号的文章是最新的,CSDN的会有些滞后,想追更的朋友欢迎大家关注,谢谢大家支持。 

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐