一、Kubernetes和Docker 1、以多个容器运行时的节点构成的kubertnets集群: 开发者使用自己喜欢的语言编写代码,然后用Docker进行打包、测试和交付。但是最终在测试环境或生产环境中运行的过程是由Kubernetes来完成的。Docker是一种更加偏向底层的技术,它负责诸如启停容器的操作;而Kubernetes是一种更加偏向上层的技术,它注重集群范畴的管理,比如决定在哪个节点上运行容器、决定什么适合进行扩缩容或升级。Kubernetes经常被写作K8s。其中的数字8替代了K和s中的8个字母

2、Kubernetes已经成为部署和管理云原生应用的事实上的标准平台。从多种方面来看,它就类似于云上的操作系统(OS) 3、Kubernetes对云和数据中心的资源进行了类似的操作系统的管理。总体来说,云或数据中心就是一个包含计算、存储与网络的资源池。Kubernetes对它进行了抽象。这意味着我们无须明确对应用运行在哪个节点或存储卷上进行硬编程,我们甚至无须关心应用运行在哪个云上——让Kubernetes操心这事即可 二、Kubernetes两大角色 1、支撑应用运行的集群:包含若干个节点与控制平面。控制平面对外提供API,对内负责各节点的任务分配与调度,并在持久化存储中记录各节点的状态。应用服务就运行在每个节点上。 2、支持云原生微服务应用的编排器:负责将应用组织起来并保持顺畅的运行,当出现一些特定事件或者变化时也要做出响应。 三、Kubernetes上运行应用 ●选用最喜欢的语言将应用以独立的微服务方式实现。 ●将每个微服务在容器内打包。 ●将每个容器集成到Pod。 ●使用更高层面的控制面板将Pod在集群中部署,例如Deployment、DaemonSet、StatefulSet、CronJob等。 部署(Deployment)提供可扩展性和滚动更新,DaemonSet在集群的每个工作节点中都运行相应服务的实例,有状态应用部署于StatefulSet,同时那些需要不定期运行的临时任务则由定时任务(CronJob)来管理。 四、Kubernetes概述 1、主节点:Kubernetes的主节点(master)是组成集群的控制平面的系统服务的集合,一般来说,建议使用3或5个副本来完成一个主节点高可用性部署方案。

●API Server(API服务)是Kubernetes的中央车站。所有组件之间的通信,都需要通过API Server来完成,API Server对外通过HTTPS的方式提供了RESTful风格的API接口,上传YAML配置文件也是通过这种接口实现的。这些YAML文件有时也被称作manifest文件,它们描述了用户希望应用在运行时达到的期望状态(desired state)。期望状态中包含但不限于如下内容:需要使用的容器镜像、希望对外提供的端口号,以及希望运行的Pod副本数量。访问API Server的全部请求都必须经过授权与认证,一旦通过之后,YAML文件配置就会被认为是有效的,并被持久化到集群的存储中,最后部署到整个集群。 ●集群存储:在整个控制层中,只有集群存储是有状态(stateful)的部分,它持久化地存储了整个集群的配置与状态。因此,这也是集群中的重要组件之一——没有集群存储,就没有集群。通常集群存储底层会选用一种常见的分布式数据库etcd。因为这是整个集群的唯一存储源,用户需要运行3~5个etcd副本来保证存储的高可用性,并且需要有充分的手段来应对可能出现的异常情况。 ●controller管理器实现了全部的后台控制循环,完成对集群的监控并对事件作出响应。controller管理器是controller的管理者(controller of controller),负责创建controller,并监控它们的执行。一些控制循环包括:工作节点controller、终端controller,以及副本controller。对应的每个controller都在后台启动了独立的循环监听功能,负责监控API Server的变更。这样做的目的是保证集群的当前状态(current state)可以与期望状态(desired state)相匹配(接下来会用具体案例来解释与证明)。每个控制循环实现上述功能的基础逻辑大致如下。 (1)获取期望状态。 (2)观察当前状态。 (3)判断两者间的差异。 (4)变更当前状态来消除差异点。 ●调度器:调度器的职责就是通过监听API Server来启动新的工作任务,并将其分配到适合的且处于正常运行状态的节点中。为了完成这样的工作,调度器实现了复杂的逻辑,过滤掉不能运行指定任务的工作节点,并对过滤后的节点进行排序。排序系统非常复杂,在排序之后会选择分数最高的节点来运行指定的任务,如果调度器无法找到一个合适的工作节点,那么当前任务就无法被调度,并且会被标记为暂停状态。调度器并不负责执行任务,只是为当前任务选择一个合适的节点运行。 ●云controller管理器:如果用户的集群运行在诸如AWS、Azure、GCP、DO和IBM等类似的公有云平台上,则控制平面会启动一个云controller管理器(cloud controller manager)。云controller管理器负责集成底层的公有云服务,例如实例、负载均衡以及存储等。 2、工作节点:工作节点是Kubernetes集群中的工作者,工作节点主要负责3件事情:1.监听API Server分派的新任务。2.执行新分派的任务。3.向控制平面回复任务执行的结果(通过API Server)

工作节点三个主要功能: Kubelet是每个工作节点上的核心部分,是Kubernetes中重要的代理端,并且在集群中的每个工作节点上都有部署。实际上,通常工作节点与Kubelet这两个术语基本上是等价的。Kubelet的一个重要职责就是负责监听API Server新分配的任务。每当其监听到一个任务时,Kubelet就会负责执行该任务,并维护与 控制平面之间的一个通信频道,准备将执行结果反馈回去。如果Kuberlet无法运行指定任务,就会将这个信息反馈给控制平面,并由控制平面决定接下来要采取什么措施。例如,如果Kubelet无法执行一个任务,则其并不会负责寻找另外一个可执行任务的工作节点。Kubelet仅仅是将这个消息上报给控制平面,由控制平面决定接下来该如何做。 容器运行时:Kubelet需要一个容器运行时(container runtime)来执行依赖容器才能执行的任务,例如拉取镜像并启动或停止容器。在早期的版本中,Kubernetes原生支持了少量容器运行时,例如Docker。而在最近的版本中,Kubernetes将其迁移到了一个叫作容器运行时接口(CRI)的模块当中。从整体上来看,CRI屏蔽了Kubernetes内部运行机制,并向第三方容器运行时提供了文档化接口来接入,Kubernetes目前支持丰富的容器运行时。一个非常著名的例子就是cri-containerd。 kube-proxy运行在集群中的每个工作节点,负责本地集群网络。例如,kube-proxy保证了每个工作节点都可以获取到唯一的IP地址,并且实现了本地IPTABLE以及IPVS来保障Pod间的网络路由与负载均衡。 3、Kubernetes DNS:除种类丰富的控制平面与工作节点组件外,每个Kubernetes集群都有自己内部的DNS服务,这对于集群操作也是非常重要的。集群DNS服务有一个静态IP地址,并且这个IP地址集群总每个Pod上都是硬编码的,这意味着每个容器以及Pod都能找到DNS服务。每个新服务都会自动注册到集群DNS服务上,这样所有集群中的组件都能根据名称找到相应的服务。一些其他的组件也会注册到集群DNS服务,例如Statefulset以及由Statefulset管理的独立Pod。 4、Kubernetes的应用打包 一个应用想要在Kubernetes上运行,需要完成如下几步。 1)将应用按容器方式进行打包:用户需要选择某种语言来编写一个应用程序,完成之后需要将应用构建到容器镜像当中并存放于某个私有仓库(Registry)。此时,已经完成了应用服务的容器化(containerized)。 2)将应用封装到Pod中:Pod就是一层简单的封装,允许容器在Kubernetes集群上运行。在用户定义好Pod之后,就可以随时将其部署到集群上运行了。 3)通过声明式manifest文件部署:在Kubernetes集群中可以运行一个Pod单例,但是通常情况下不建议这么做。推荐的方式是通过更上层的controller来完成。最常见的controller就是Deployment,它提供了可扩容、自愈与滚动升级等特性。读者只需要通过一个YAML文件就可以指定Deployment的配置信息,包括需要使用哪个镜像以及需要部署多少副本。

5、声明式模型与期望状态 在Kubernetes中,声明式模型的工作方式如下所述。 1)在manifest文件中声明一个应用(微服务)期望达到的状态:manifest文件是按照简版YAML格式进行编写的,用户通过manifest文件来告知Kubernetes集群自己希望应用运行的样子。这就是所谓的期望状态。其中包括:需要使用哪个镜像、有多少副本需要运行、哪个网络端口需要监听,以及如何执行更新。 2)将manifest文件发送到API Server:最常见的方式是通过kubectl命令行工具来完成这个操作。kubectl会将manifest文件通过HTTP POST请求发送到控制平面,通常HTTP服务使用的端口是443。 3)Kubernetes将manifest存储到集群存储,并作为应用的期望状态:在请求经过认证以及授权后,Kubernetes会检查manifest文件,确定需要将该文件发送到哪个控制器(例如Deployment controller),并将其保存到集群存储当中,作为整个集群的期望状态(desired state)中的一部分。 4)Kubernetes在集群中实现上述期望状态。在上述工作都完成之后,就要在集群中执行相应的调度工作了。调度工作包括拉取镜像、启动容器、构建网络以及启动应用进程。 5)Kubernetes启动监控循环,保证应用的当前状态(current state)不会与期望状态出现差异。Kubernetes通过后台的reconciliation(调谐)循环来持续监控集群状态。如果集群当前状态(current state)与期望状态(desired state)存在差异,则Kubernetes会执行必要的任务来解决对应的差异点 6、POD 在VMware的世界中,调度的原子单位是虚拟机(VM);在Docker的世界中,调度的原子单位是容器;而在Kubernetes的世界中,调度的原子单位是Pod,kubernetes的确支持运行容器化应用。但是,用户无法直接在Kubernetes集群中运行一个容器,容器必须并且总是需要在Pod中才能运行。

Pod与容器:a group of whales(一群鲸鱼)称作a Pod of whales,Pod就是来源于此。因为Docker的Logo是鲸鱼,所以在Kubernetes中会将包含了一组容器的事物称作Pod。

Pod就是为用户在宿主机操作系统中划出有限的一部分特定区域,构建一个网络栈,创建一组内核命名空间,并且在其中运行一个或者多个容器,这就是Pod。如果在Pod中运行多个容器,那么多个容器间是共享相同的Pod环境的。共享环境中包括了IPC命名空间,共享的内存,共享的磁盘、网络以及其他资源等。如果在同一个Pod中运行的两个容器之间需要通信(在Pod内部的容器间),那么就可以使用Pod提供的localhost接口来完成。 调度单元:Kubernetes中最小的调度单元也是Pod。如果读者需要扩容或缩容自己的应用,可以通过添加或删除Pod来实现。千万不要选择通过向一个已经存在的Pod中增加更多的容器这种方式来完成扩容。多容器Pod仅适用于那种两个的确是不同容器但又需要共享资源的场景。 Pod的部署是一个原子操作。这意味着,只有当Pod中的所有容器都启动成功且处于运行状态时,Pod提供的服务才会被认为是可用的。对于部分启动的Pod,绝对不会响应服务请求。整个Pod要么全部启动成功,并加入服务;要么被认为启动失败。一个Pod只会被唯一的工作节点调度。这一点对于多容器Pod来说也是一样的,一个多容器Pod中的全部容器都会运行在相同的工作节点上。Pod的生命周期是有限的。Pod会被创建并运行,并且最终被销毁。如果Pod出现预期外的销毁,用户无须将其重新启动。因为Kubernetes会启动一个新的Pod来取代有问题的Pod。尽管新启动的Pod看起来跟原来的Pod完全一样,本质上却并不是同一个。这是一个有全新的ID与IP地址的Pod。 7、Deployment 用户通过更上层的控制器来完成Pod部署。上层的控制器包括Deployment、DaemonSet以及StatefulSet。Deployment是对Pod的更高一层的封装,除Pod之外,还提供了如扩缩容管理、不停机更新以及版本控制等其他特性。除此之外,Deployment、DaemonSet以及StatefulSet还实现了自己的controller与监控循环,可以持续监控集群状态,并确保当前状态与期望状态相符。 8、服务与稳定的网络 通过Deployment或者DaemonSet对Pod进行管理,出现故障的Pod会自动被替换。但是替换后的新Pod会拥有完全不同的IP地址。这种情况也会在水平扩/缩容时发生,扩容时会创建拥有新IP地址的Pod,缩容时会移除掉现有的Pod。这些都会引起IP地址变化(IP churn)。Service为一组Pod提供了可靠且稳定的网络。

Kubernetes Service提供了一个稳定的服务名称与IP地址,并且对于其下的两个Pod提供了请求级别的负载均衡机制。Service在Kubernetes API中是一个成熟且稳定的组件,就像Pod与Deployment一样。DNS名称、IP地址与端口共同组成了其前端。在其后端实现了对一组Pod间的动态负载均衡。同时,跟Pod一样,Service也实现了自我监控机制,可以自动更新,并持续提供稳定的网络终端。如果对于Pod进行数量上的增加,则在Service中同样会生效。新的Pod会被无缝添加到Service并承担请求流量。已经终止的Pod会被平滑地从当前Service中移除,并不再处理请求流量。这就是Service的职责:一个稳定的网络终端,提供了基组动态Pod集合的TCP以及UDP负载均衡能力。因为Service作用于TCP以及UDP层,所以Service层并不具备应用层的智能,即无法提供应用层的主机与路径路由能力。因此,用户需要一个入口来解析HTTP请求并提供基于主机与路径的路由能力。Service使用标签(label)与一个标签选择器(label selector)来决定应当将流量负载均衡到哪一个Pod集合。Service中维护了一个标签选择器(label selector),其中包含了一个Pod所需要处理的全部请求对应的标签。基于此,Service层才能将流量路由到对应的Pod。

Service只会将流量路由到健康的Pod,这意味着如果Pod的健康检查失败,那么Pod就不会接收到任何流量。以上就是关于Service的基础介绍。Service为不稳定的Pod集合提供了稳定的IP地址以及DNS名称。

服务发现与命名空间学习:

9、ConfigMap&secret

多数应用程序由两部分组成:应用执行程序和配置。将程序和配置打包到一个构件(容器镜像)中有多方面的不足。由于dev、test和prod环境有不同的特点,因此需要针对每个环境构建不同的镜像。因为这些差异的存在,prod的镜像无法运行在dev和test环境中。从而需要创建和维护3份应用,这会带来更多的复杂性,以及更大的出差错的风险。另外,还需要在3个不同的仓库中存储3个镜像。不仅如此,还要仔细处理各个构件仓库的权限。prod的镜像中通常包含一些敏感的线上配置信息、密码、密钥等,而这些是不应该让研发和测试工程师获取到的。还有一点,当某次升级中同时包含应用程序和配置的更新时,对其进行问题排查就更加困难。如果程序和配置紧密耦合,那么故障原因也难以区分。而且,即使是对配置的小改动(例如修改Web页面上的一个拼写错误),也需要重新打包、测试和部署包括程序和配置在内的整个应用。Kubernetes通过提供一个名为ConfigMap(CM)的对象,将配置数据从Pod中剥离出来。使用它可以动态地在Pod运行时注入数据。从而实现一次构建,多次部署。我们不应使用ConfigMap来存储诸如凭证和密码等的敏感数据。Kubernetes提供了另一种名为Secret的对象来存储敏感数据。

Logo

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

更多推荐