一、 Kubernetes基础

1. 什么是Kubernetes(k8s)?

  • k8s是Google的一个开源容器编排引擎,用于自动部署、扩展和管理容器化应用程序。Kubernetes集群可以跨本地和公共云基础设施跨越主机,使Kubernetes成为托管云本地应用程序的理想平台。

  • Kubernetes 的一般概念相当简单:

    • 从一个或多个工作节点开始运行容器工作负载。

    • 从一个或多个控制平面节点管理这些工作负载的部署。

    • 将容器包装在称为 Pod 的部署单元中。使用 Pod 为容器提供额外的元数据,并提供将多个容器分组到单个部署实体中的能力。

    • 创建特殊类型的资产。例如,服务由一组 Pod 和定义如何访问它们的策略表示。此策略允许容器连接到它们需要的服务,即使它们没有服务的特定 IP 地址。复制控制器是另一种特殊资产,它指示一次运行需要多少个 Pod 副本。您可以使用此功能自动扩展您的应用程序以适应其当前需求。

https://kubernetes.io/ #k8s官网
https://github.com/kubernetes/kubernetes/ #大量 example案例
https://www.kubernetes.org.cn/ #kubernetes中文社区
http://docs.kubernetes.org.cn/ #大量中文文档

2. 为什么要用k8s?

IT是一个由新技术驱动的行业,Docker这个容器技术当前已经被很多公司所采用,其从单机走向集群已成为必然,k8s作为当前唯一被业界广泛看好的Docker分布式系统解决方案,未来会有大量的新系统选择它。

2.1 k8s的好处

  • 跨多个主机编排容器

  • 更好地利用硬件来最大化运行您的企业应用程序所需要的资源

  • 控制和自动化应用程序部署和更新

  • 挂载并添加存储空间以运行具有有状态的应用程序

  • 声明式地管理服务,以保证已部署的服务应用程序总是以您预期的运行方式运行。

  • 使用autoplacement进行健康检查和自我修复应用程序,自动重新启动、自动重新应用和自动缩放

  • 客户在其环境中使用Kubernetes的优势在于能够在物理系统或虚拟机(VM)的集群上调度和运行容器。并且客户的系统可以随时随地整体“搬迁”到公有云上。

  • 超强的横向扩容能力。不用修改代码,一个k8s集群即可从只包含几个node的小集群平滑扩展到拥有上百个node的大规模集群,只要微服务设计的好,结合硬件或公有云资源的线性增加,系统就能承受大量用户的并发访问所带来的巨大压力。

  • k8s可以在以下环境中运行:

    • ​ 裸金属服务器
    • ​ 虚拟机
    • ​ 公有云供应商
    • ​ 私有云
    • ​ 混合云环境

3. k8s的架构

在这里插入图片描述

1. Master

  • Master节点上面主要由四个模块组成:kube-APIServer、kube-scheduler、kube-controller-manager、etcd
    • kube-APIServer负责对外提供RESTful的Kubernetes API服务,他是系统管理指令的统一入口,任何对资源进行增删改查的操作都要交给APIServer处理后再提交给etcd。如架构图所示,kubectl(k8s提供的客户端工具,该工具内部就是对Kubernetes API的调用)是直接和APIServer交互的。
    • kube-scheduler负责调度Pod到合适的Node上。如果把scheduler看成一个黑匣子,那么它输入的是Pod和由多个Node组成的列表,输出的是Pod和一个Node的绑定,即将这个Pod部署到这个Node上。k8s目前提供了调度算法,但是同样也保留了接口,用户可以根据自己的需求定义自己的调度算法。
    • kube-controller-manager负责管理资源的控制器(一般每个资源都对应一个控制器)。比如我们通过APIServer创建一个Pod,当这个Pod创建成功后,APIServer的任务就算完成了。而后面保证Pod的状态始终和我们预期的一样的重任就由kube-controller-manager去完成。
      • 这些控制器包括:
        • 节点(Node)控制器
        • 副本(Replication)控制器:负责维护系统中每个副本中的Pod
          • k8s集群中的服务扩容和系统升级,只需要为扩容的Service关联的Pod创建一个Replication Controller(简称RC),则该Service的扩容及升级都可以解决。在一个RC定义文件中包括以下3各关键信息
            • 目标Pod的定义
            • 目标Pod需要运行的副本数量(replicas)
            • 要监控的目标Pod标签
          • 在创建好RC(系统会自动创建好Pod)后,k8s会通过RC定义的Label筛选出对应的Pod实例并实时监控其状态和数量,如果实例数量少于定义的副本数量(ralicas),则会根据RC中定义的Pod模板来创建一个新的Pod,然后将此Pod调度到合适的node上启动运行,直到Pod实例的数量达到预定目标。
        • 端点(endpoint)控制器:填充Endpoints对象(即连接services&Pods)
        • Service Account和Token控制器:为新的Namespace创建默认账户访问API Token
    • etcd是一个高可用的键值存储系统,k8s使用它来存储各个资源的状态,从而实现了Restful的API。

2.Node

  • Node节点可以是物理机,也可以是私有云火或公有云中的一个虚拟机。每个Node主要由三个模块组成:kubelet、kube-proxy、runtime
    • kubelet是Master在每个Node节点上面的agent,是Node节点上面最重要的模块,负责维护和管理该Node上面的所有容器,但是如果容器不是通过k8s创建的,它并不会管理。本质上它负责使Pod的运行状态与期望的状态一致。负责Pod对应的容器的创建、启动等任务,同时与Master节点密切合作,实现集群管理的基本功能。
      • 具体功能:
        • 安装Pod所需的volume
        • 下载Pod的secrets
        • Pod中运行的docker(或rkt)容器
        • 定期执行容器健康检查
    • kube-proxy模块实现了k8s中的服务发现和反向代理功能
      • 反向代理方面:kube-proxy支持TCP和UDP连接转发,默认基于Round Robin算法将客户端流量转发到与service对应的一组后端Pod。
      • 服务发现发现方面,kube-proxy使用etcd的watch机制,监控集群中service和endpoint对象数据的动态变化,并且维护一个service到endpoint的映射关系,从而保证了后端Pod的IP变化不会对访问者造成影响,另外kube-proxy还支持session affinity。
    • runtime指的是容器运行环境,目前k8s支持docker和rkt两种容器。
      在这里插入图片描述

4.Kubernetes对象

  • Kubernetes对象是Kubernetes系统中的持久实体。Kubernetes使用这些实体来表示集群的状态。具体来说,他们可以描述:

    • 容器化应用正在运行(以及在哪些节点上)
    • 这些应用可用的资源
    • 关于这些应用如何运行的策略,如重新策略,升级和容错
  • k8s里的所有资源对象都可以采用yaml或者JSON格式的文件来定义或描述

  • k8s对象包括:

    • Pod
    • Service
  • 要创建/删除/修改k8s对象,需要使用Kubernetes API

    • 例如,当使用kubectl命令管理工具时,CLI会为提供Kubernetes API调用。
    • 你也可以直接在自己的程序中使用Kubernetes API
  • 对象(object)规范和状态

    • 每个对象包含两个嵌套对象字段,用于管理object的配置
      • object spec
        • 描述对象所需的状态,希望object具有的特性
      • object status
        • 描述了对象的实际状态,并由k8s系统提供和更新

5. 一些核心概念

5.1 Pod

  • Pod运行在Node中,通常一个节点上运行几百个Pod;Pod是Kubernetes创建或部署的最小/最简单的基本单位,一个Pod代表集群上正在运行的一个进程。
    在这里插入图片描述

  • 用户可以通过kubernetes的Pod API生产一个Pod,让k8s对这Pod进行调度,也就是把它放在某一个k8s管理的节点上运行起来。一个Pod简单来说是对一组容器的抽象,他里面会包含一个或多个容器。一个Pod封装一个应用容器(也可以有多个容器),存储资源、一个独立的网络IP以及管理控制容器运行方式的策略选项。Pod代表部署的一个单位:Kubernetes中单个应用的实例,它可能由单个容器或多个容器共享组成的资源。

  • 每个Pod里运行这一个特殊的被称之为Pause的容器,Pause容器对应的镜像属于k8s平台的一部分。其他容器称之为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷。下图展示Pod组成与容器的关系。
    在这里插入图片描述

  • 注意:并不是每个Pod和它里面运行的容器都能被“映射”到一个Service上,只有那些提供服务(无论对内或对外)的一组Pod才会被“映射”成一个服务。

  • 在k8s里,一个Pod里的容器与另外主机上的Pod容器能够直接通信。

  • 根据状态分,Pod有两种类型

    • 普通的Pod

      • 一旦创建就会被放入到etcd中存储,随后会被k8s Master调度到某个具体的Node上进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器启动起来。
    • 静态Pod(Static Pod)

      • 存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动运行。
  • 默认情况下,当Pod里的某个容器停止时,k8s会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,则会将这个Node上的所有Pod重新调度到其他节点上。Pod、容器与Node的关系如图
    在这里插入图片描述

  • 根据运行的容器数量分类,k8s的Pod分为两种:

    • Pod中运行一个容器
    • Pod中运行多个容器,这些容器之间能够共享资源,可以形成一个单一的内部service单位 - 一个容器共享文件。
  • 如果需要水平扩展应用(比如运行多个实例),应该使用多个Pods,每个实例一个Pod

  • Pods如何管理多个容器

    • Pods的设计可用于支持多进程的协同工作(作为容器),形成一个cohesive的Service单位。Pod中的容器在集群中Node上被自动分配,容器之间可以共享资源、网络和相互依赖关系,并同时被调度使用。
    • Pods提供两种共享资源:网络和存储
      • 网络:每个Pod被分配一个独立的IP地址,Pod中的每个容器共享网络命名空间,包括IP和端口。Pod内的容器可以使用localhost相互通信。当Pod中的容器与Pod 外部通信时,他们必须协调如何使用共享网络资源(如端口)
      • 存储:Pod可以指定一组共享存储volumes。Pod中的所有容器都可以访问共享volumes,允许这些容器共享数据。volumes 还用于Pod中的数据持久化,以防其中一个容器需要重新启动而丢失数据。
  • 使用Pod:不会单独使用Pod,Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例。

    • controller可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力。
      • 例如,如果一个Node故障,Controller就能自动将该节点上的Pod调度到其他健康的Node上。
      • 包含一个或多个Pod的controller实列:
        • Deployment
        • StatefulSet
        • DaemonSet
      • 通常,controller会用你提供的Pod template来创建相应的Pod
  • Pod模板

    • Deployment
    • Replication Controller
    • Replicaset
    • Daemonset
    • Statefulset

5.2 Replica Set

  • Replica Set目的是为了定义一个期望的场景,比如定义某种Pod的副本数量在任意时刻都处于 Replica Set期望的值,假设 Replica Set定义Pod的副本数目为: replicas=2,当该 Replica Set提交给 Master后, Master会定期巡检该Pod在集群中的数目,如果发现该Pod挂掉了ー个, Master就会芸试依据 Replica Set设置的Pod模版创建Pod,以维持Pod的数量与 Replica Set预期的Pod数量相同。

  • 很少单独使用Replica Set,它主要被Deployment这个更高层的资源对象所使用,从而形成一套Pod创建、删除、更新的编排机制。

  • 通过 Replica Set,k8s集群实现了用户应用的高可用性,而且大大减少了运维工作量。因此生产环境一般用Deployment?或者 Replica Set去控制Pod的生命周期和期望信,而不是直接单独创建Pod。

  • Replica Set与 Deployment这两个重要资源对象逐步替换了之前的RC的作用

在这里插入图片描述

5.3 Service

  • Service是分布式集群架构的核心,k8s的 Service就是我们平时所提及的微服务架构中的"微服务”,本文上面提及的Pod、 Replica Set等都是为 Service服务的资源,如下图表示Service、Pod、 Replica Set的关系:
    在这里插入图片描述

  • 一个Service对象拥有如下关键特征:

    • 一个唯一指定的名字(比如mysql-server)
    • 一个虚拟IP(cluster IP、service IP或VIP)和端口号
      • 在Service的整个生命周期内,它的Cluster IP不会发生改变
    • 能够提供某种远程服务能力
    • 被映射到了这种服务能力的一组容器应用上。
  • Service的服务进程目前都基于socket通信方式对外提供服务,比如Redis、Memcache、MySQL、Web Server,或者是实现了某个具体业务的一个特定的TCP Server进程。

  • Service定义了一个服务的访问入口地址,前端的应用通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与后端Pod副本集群之间则是通过Label Selector来实现1对接的,而RC的作用实际上是保证Service的服务能力和服务质量始终处于预期的标准。

  • 一个Service通常由多个相关的服务进程来提供服务,每个服务进程都有独立的Endpoint(IP+Port)访问点,但k8s能够让我们通过Service(虚拟Cluster IP+Service Port)连接到指定的Service上。

  • Service与Pod的关联关系:

    • Pod中运行的容器就是为Service提供服务的进程,首先给Pod贴上一个标签(Label),给运行MySQL的Pod贴上name=mysql标签,给运行PHP的Pod贴上name=php标签,然后给对应的Service定义标签选择器(Label Selector),比如MySQL的Service的标签选择器的选择条件为name=mysql,意味该Service要作用于所有包含name=mysql标签的Pod上。
  • 用户是如何访问一个集群的服务的呢?

    • 一般的做法是部署一个负载均衡器(软件或硬件),为这组Pod开启一个对外的服务端口如8000端口,将这些Pod的Endponit列表加入8000端口的转发列表中,客户端就可以通过负载均衡器的对外IP地址+服务端口来访问此服务,而客户端最后会被转发到哪个Pod,则由负载均衡器的算法决定。
  • 很多服务都存在多端口的问题,通常一个端口提供业务服务,另外一个端口提供管理服务,比如Mycat、Codis等常见中间件。Service支持多个Endpoint,在存在多个Endpoint的情况下,要求每个Endpoint定义一个名字来区分,例如

在这里插入图片描述

  • 为什么要给每个端口命名呢?

    • 涉及k8s的服务发现机制(1.4.5小节)

5.4 Deployment

  • Deployment,为Pod和 Replica Set提供声明式更新,Dployment在内部使用了Replica Set来实现目的。

  • 你只需要在 Deployments中描述你想要的目标状态是什么, Deployment controller就会帮你将Pod和 Replica Set的实际状态改变到你的目标状态。你可以定义一个全新的 Deployment,也可以创建一个新的替换旧的Deployment.

  • 典型使用场景

    • 使用 Deployment来创建 Replicaset. Replicaset,在后台创建Pod。检查启动状态,看它是成功还是失败。

    • 然后,通过更新 Deployment的 Podtemplatespec字段来声明Pod的新状态。这会创建一个新的Replicaset, Deployment会按照控制的速率将Pod从日的 Replicaset移动到新的Replicasete中,如果当前状态不稳定,回滚到之前的 Deployment revision。每次回滚都会更新 Deployment的 Revision.

    • 扩容 Deployment以满足更高的负载

    • 暂停 Deployments来应用 Pod Templatespecl的多个修复,然后恢复上线。

    • 根据 Deployment的状态判断上线是否hang住了。

    • 清除旧的不必要的ReplicaSet
      在这里插入图片描述

5.5 Label

  • 一个Label是一个key=value地键值对,其中key与value由用户自己指定资源对象与Label的关系是:n:n,Label通常在资源对象定义时确定,也可以在对象创建后动态添加或删除。

  • 给某个资源对象定义一个Label,随后通过Label Selector(标签选择器)查询和筛选某些Label的资源对象。

    • Label Selector类似于SQL的where查询条件

      • 基于等式的表达式(Equality-based)

        name=redis-slave:匹配所有具有标签name=redis-slave的资源对象。
        env!=production:匹配所有不具有标签env=production的资源对象,比如env=test就是满足此条件的标签之一。
        
      • 基于集合的表达式(Set-based)

        name in( redis-master,redis-slave):匹配所有具有标签name=redis-master或者name=redis-slave的资源对象。
        name not in(php-frontend):匹配所有不具有标签name=php-frontend的资源对象。
        
    • Label Selector的重要使用场景:

      • kube- controller进程通过资源对象RC上定义的 Label Selector来筛选要监控的Pod副本的数量,从而实现Pod副本的数量始终符合预期设定的全自动控制流程。
      • kube-proxy进程通过 Service的 Label Selector来选择对应的Pod,自动建立起每个 Service到对应Pod的请求转发路由表,从而实现 Service的智能负载均衡机制。
      • 通过对某些Node定义特定的 Label,并且在Pod定义文件中使用 NodeSelector这种标签调度策略,kube- scheduler进程可以实现Pod“定向调度”的特性。
  • 总结:使用 Label可以给对象创建多组标签, Label和 Label Selector共同构成了 Kubernetes系统中最核心的应用模型,使得被管理对象能够被精细地分组管理,同时实现了整个集群的高用性。

5.6 Replication Controller (RC)

  • RC是定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包括如下几个部分:

    • Pod期待的副本数(replicas)
    • 用于筛选目标Pod的Label Selector
    • 当Pod的副本数量小于预期数量的时候,用于创建新Pod的Pod模板(template)
  • 删除RC并不会影响通过该RC已创建好的Pod。为了删除所有Pod,可以设置replicas的值为0,然后更新该RC。

    • stop和delete命令一次性删除RC和RC控制的全部Pod
  • 通过RC,K8S可以实现系统的平滑升级,称为“滚动升级”

5.7 Volume(存储卷)

  • Volume是Pod中能够被多个容器访问的共享目录。
  • Volume与Pod的生命周期相同,与容器的生命周期不相关。
  • k8s支持多种类型的Volume,例如GLUSTERfs、Ceph等分布式文件系统。
  • Volume的使用:
    • 先在Pod上声明一个Volume,然后在该容器里引用该Volume并Mount到容器的某个目录上。
apiVersion: apps/v1
kind: Deployment
metadata:
 name: frontend
spec:
 replicas: 1
 selector:
  matchLabels:
   tier: frontend
  matchExpressions:
   - {key: tier, operator: In, values: [frontend]}
 template:
  metadata:
   labels:
    app: app-demo
    tier: frontend
  spec:
   volume: ###
    - name: datavol  ###
      emptyDir: {} ###
   containers:
   - name: tomcat-demo
     image: tomcat
     volumeMounts:  ### 
      - mountPath: /mydata-data   ###
        name: datavol  ###
     imagePullPolicy: IfNotPresent
     ports:
     - containerPort: 8080

k8s提供了很多的Volume类型

1. emptyDir
  • 在Pod分配到Node时创建的,它的初始化内容为空,并且无须指定宿主机上对应的目录文件,因为这是Kubernetes自动分配的一个目录,当Pod从Node上移除时,emptyDir中的数据也会被永久删除。emptyDir的一些用途如下:
    • 临时空间,例如用于某些应用程序运行时所需要的临时目录,且无须永久保留。
    • 长时间任务的中间过程CheckPoint的临时保存目录。
    • 一个容器需要从另一个容器中获取数据的目录。
2. hostPath
  • 为Pod上挂载宿主机上的文件或目录,它通常可以用于以下几个方面。
    • 容器应用程序生成的日志文件需要永久保存时,可以使用宿主机的高速文件系统进行存储
    • 需要访问宿主机上Docker引擎内部数据结构的容器应用时,可以通过定义hostPath为宿主机/var/lib/docker目录,使用容器内部应用可以直接访问Docker的文件系统。
  • 使用时需要注意:
    • 不同Node上具有相同配置的Pod可能会因为宿主机上的目录和文件不同而导致对Volume上目录和文件的访问结果不一致。
3. gcePersistentDisk
  • 使用谷歌公有云提供的永久磁盘存放Volume的数据
  • 需要创建一个永久磁盘(PD),才能使用gcePersistentDisk。
  • 使用 gcePersistent Disk有以下一些限制条件。
    • Node(运行 kubelet I的节点)需要是GCE虚拟机。
    • 这些虚拟机需要与PD存在于相同的GCE项目和Zone中。
4. awsElasticBlockStore
  • 亚马逊公有云提供的EBS Volume存储数据,需要创建一个EBS Volume才能使用awsElasticBlockStore。
  • 使用 awsElasticBlockStore的一些限制条件如下。
    • Node(运行 kubelet I的节点)需要是 AWS E2实例。
    • 这些 AWS EC2实例需要与 EBS volume存在于相同的 region和 availability-zone中。
    • EBS只支持单个EC2实例 mountー个 volume.
5. NFS
  • 网络文件系统提供的共享目录存储数据,需要在系统中部署一个NFS Server。
6.其他类型
  • iscsi
  • flocker
  • glusterfs
  • rbd
  • gitRepo
  • secret

5.8 Persistent Volume

  • Persistent Volume(简称PV),可以理解成网络存储中的一块存储。
    • 只能是网络存储,不属于任何Node,但可以在每个Node上访问。
    • 独立于Pod之外定义。
    • 类型:GCE Persistent Disks、NFS、RBD、 ISCSI、AWS Elastic Block Store、 Glusterfs等。
  • PV的accessModes属性的类型
    • ReadWriteNnce:读写权限、并且只能被单个Node挂载。
    • ReadOnlyMany:只读权限、允许被多个Node挂载。
    • ReadWriteMany:读写权限、允许被多个Node挂载。
  • 如果某个Pod想申请某种条件的PV,则首先需要定义一个PersistentVolumeClaim(PVC)对象。
  • PV是有状态的对象,它的状态如下
    • Available:空闲状态。
    • Bound:已经绑定到某个PVC上。
    • Released:对应的PVC已经删除,但资源还没有被集群收回。
    • Failed:PV自动回收失败。

5.9 Namespace

  • 用于实现多租户的资源隔离。
  • 通过将集群内部的资源对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
  • k8s集群在启动后,会创建一个名为“default”的Namespace,通过kubectl可以查看到
[root@master ~]# kubectl get namespaces
NAME                   STATUS   AGE
default                Active   6d21h
  • 如果没有特别指明Namespace,则用户创建的Pod、RC、Service都将被系统创建到default的Namespace中。

5.10 Annotation(注解)

  • key/value键值对形式进行定义,定义的是k8s对象的元数据(Metadata),并且用于Label Selector。
  • 用户任意定义的“附加”信息,以便于外部工具进行查找,很多时候k8s的模块自身会通过Annotation的方式标记资源对象的一些特殊信息。
  • 通常来说,用Annotation来记录的信息如下
    • build信息、 release信息、 Docker镜像信息等,例如时间戳、 release id号、PR号、镜像hash值、 docker registry地址等
    • 日志库、监控库、分析库等资源库的地址信息。
    • 程序调试工具信息,例如工具名称、版本号等。
    • 团队的联系信息,例如电话号码、负责人名称、网址等。
Logo

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

更多推荐