【Docker 那些事儿】Docker不香吗?为什么还需要K8s?
🌟 前言
大家好,我是Edison😎
今天是我们「云原生」系列的第二篇:「走进 k8s 的世界」;
Let’s get it!
1. 先导知识
在介绍 Kubernetes 之前,这里要给大家概括一下涉及到的其他知识
🍑 容器
先来看一张对比图
容器技术是虚拟化技术的一种,以 Docker 为例,Docker 利用 Linux 的 LXC(LinuX Containers)技术、CGroup(Controll Group)技术 和 AUFS(Advance UnionFileSystem)技术等,通过对进程和资源加以限制,进行调控,隔离出来一套供程序运行的环境。
我们把这一环境称为 “ 容器 ”,把构建该 “ 容器 ” 的 “ 只读模板 ”,称之为 “ 镜像 ”。
容器是独立的、隔离的,不同容器间不能直接通信,容器与宿主机也是隔离开来的,容器不能直接感知到宿主机的存在,同时宿主机也无法直接窥探容器内部。
虽然容器与宿主机在环境上,逻辑上是隔离的,但容器与宿主机共享内核,容器直接依赖于宿主机Linux系统的内核,这与虚拟机不同,后者是在宿主机的操作系统上,虚拟化一套硬件环境,然后在此环境上运行需要的操作系统。
容器技术常用来在宿主机上隔离出环境来部署应用(用容器化技术部署的应用称为 “容器化应用” ),而虚拟机常用来运行一个与宿主机不同的操作系统,从而运行特定的软件。
🍅 容器的特性
容器量级非常轻,无论是启动速度,资源占用情况,灵活性等均优于虚拟机。
容器的特性给开发生产提供了非常大的便利:
(1)DevOps理念,开发者可以使用同一个镜像,在开发环境、测试环境和生产环境构建相同的容器,即相同的程序运行环境,这样可以大大减少前期的环境部署时间,可以有效避免由于各个环境不一致而造成的灾难。
(2)“容器” 与 “微服务” 常是一起出现的一组名词,有了容器技术以后,可以更加方便的部署微服务,例如,可以把评论服务部署到一个容器里,把阅读的服务部署到另一个容器,这样在一个服务崩溃时不至于影响到其它服务,再者,容器启动速度快,可以在极短时间内恢复。
(3)很多时候,一些环境、工具需要复用,这时候容器是个很好的选择,我们可以把环境和工具打包成镜像,需要的时候用来构建容器使用。在Docker的镜像仓库上,也有很多官方的或第三方的镜像,这些镜像都是别人已经打包好的工具或者环境,我们只需一条命令,就可以把镜像拉取下来并构建容器启动,免去了自己动手开发部署的麻烦。
🍑 集群
计算机是独立的,但我们可以通过一系列技术、软件,把分散的算力有效的集中起来,把多台独立的计算机当做一个整体来使用,而且这些计算机实现相同的业务,这就是集群。
🍑 分布式
分布式就是把一个系统拆分开来部署到不同机器,与集群相同的是,两者都需要多台服务器,不同点是分布式并不强调实现相同的业务。
貌似网上大多数资料,对于集群和分布式的区分,都执着于两者是否实现相同的业务,即不同服务器运行同一份功能就是集群,运行不同功能就是分布式。
个人看法是,集群强调的是“集”、“统一的概念”,是物理上的、环境上的概念,只要是多台计算机搞在一起就是集群;
而分布式,更多的是描述应用系统的部署方式,把一个系统拆开部署到不同服务器,就是分布式。
🍑 微服务
有必要提一下微服务,使用 kubernetes 可以更加便捷地部署微服务应用。
微服务和分布式都强调 “拆”、“分”,但微服务描述的是应用系统的架构,即怎么样把系统拆分,拆成多 “微”,这是微服务需要考虑的;
而分布式,强调的是 “分布”,即系统的部署方式,该怎么把系统的模块分布好,从而提高容灾能力、高可用性。
当 “微服务” 应用部署到一台服务器上,它就是 “微服务应用”,当把 “微服务” 应用的模块分开来部署到不同服务器,那么它也成了“分布式应用”
2. 什么是Kubernetes
Kubernetes 这个词比较长,常简写成 k8s," 8 " 表示中间的 8 个字母。
Kubernetes(k8s) 是 Google 开源由 CNCF 基金会管理的容器集群管理系统,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能。
Kubernetes 被称为现在化的数据中心操作系统,大家都知道,操作系统是用来管理硬件资源比如 CPU、内存、磁盘、输入输出设备等资源的,并完成对这些资源的调度,而 Kubernetes 是将数据中心里的物理节点作为管理对象,并对物理节点上的资源进行调度完成编排任务。
操作系统的另一个特性就是容易扩展,比如,当 GPU 这种硬件出现后,操作系统应该很容扩展去管理这种资源,Kubernetes 作为数据中心操作系统同样也有这样的特性,它也非常容易扩展。
🍑 Kubernetes的特点
Kubernetes是一种用于在一组主机上运行和协同容器化应用程序的系统,旨在提供可预测性、可扩展性与高可用性的方法来完全管理容器化应用程序和服务的生命周期的平台。
用户可以定义应用程序的运行方式,以及与其他应用程序或外部世界交互的途径,并能实现服务的扩容和缩容,执行平滑滚动更新,以及在不同版本的应用程序之间调度流量以测试功能或回滚有问题的部署。
Kubernetes提供了接口和可组合的平台原语,使得用户能够以高度的灵活性和可靠性定义及管理应用程序。简单总结起来,它具有以下几个重要特性。
🍅 自动装箱
建构于容器之上,基于资源依赖及其他约束自动完成容器部署且不影响其可用性,并通过调度机制混合关键型应用和非关键型应用的工作负载于同一节点以提升资源利用率。
🍅 自我修复(自愈)
支持容器故障后自动重启、节点故障后重新调度容器,以及其他可用节点、健康状态检查失败后关闭容器并重新创建等自我修复机制。
🍅 水平扩展
支持通过简单明了或UI手动水平扩展,以及基于CPU等资源负载率的自动水平扩展机制。
🍅 服务发现和负载均衡
Kubernetes通过其附加组件之一的KubeDNS(或CoreDNS)为系统内置了服务发现功能,它会为每个Service配置DNS名称,并允许集群内的客户端直接使用此名称发出访问请求,而Service则通过iptables或ipvs内建了负载均衡机制。
🍅 自动发布和回滚
Kuberntes支持“灰度”更新应用程序或其配置信息,它会监控更新过程中应用程序的健康状态,以确保它不会同一时刻杀掉所有实例,而此过程中一旦有故障发生,就会立即自动执行回滚操作。
🍅 密钥和配置管理
Kubernetes的ConfigMap实现了配置数据与Docker镜像解耦,需要时,仅对配置做出变更而无需重新构建Docker镜像,这为应用开发部署带来了很大的灵活性。
此外,对于应用所依赖的一些敏感数据,如用户名和密码、令牌、密钥等信息,Kubernetes专门提供了Secret对象为其解耦,既便利了应用的快速开发和交付,又提供了一定程度上的安全保障。
🍅 存储编排
Kubernetes支持Pod对象按需自动挂载不同类型的存储系统,这包括节点本地存储、公有云服务商的云存储(如AWS和GCP等),以及网络存储系统(例如,NFS、ISCSI、GlusterFS、Ceph、Cinder和Flocker等)。
🍅 批量处理执行
除了服务型应用,kubernetes还支持批处理作业及CI(持续集成),如果需要,一样可以实现容器故障后恢复。
🍑 Kubernetes的部署方式
传统部署、虚拟化部署、容器部署
3. Kubernetes基本概念和术语
🍑 Master
Master是集群的网关和中枢,负责诸如为用户和客户端暴露API、跟踪其他服务器的健康状态、以最优调度工作负载,以及编排其他组件之间的通信等任务;
它是用户或客户端与集群之间的核心联络点,并负责Kubernetes系统的大多数集中式管控逻辑。
🍑 Node
Node 是 Kubernetes 集群的工作节点,负责接收来自Master的工作指令病根据指令相应地创建或销毁Pod对象,以及调整网络规则以合理地路由和转发流量等。
Node 节点可以在运行期间动态增加到 Kubernetes 集群中,前提是这个节点上已经正确安装、配置和启动了上述关键进程,在默认情况下 Kubelet 会向 Master 注册自己,这也是 Kubernetes 推荐的Node管理方式。
一旦 Node 被纳入集群管理范围,kubelet 进程就会定时向 Master 节点回报自身的情报,例如操作系统、Docker版本、机器的CPU和内存情况,以及当前有哪些Pod在运行等,这样 Master 可以获知每个Node的资源使用情况,并实现高效均衡的资源调度策略。
而某个 Node 超过指定时间不上报信息时,会被 Master 判定为”失联”,Node的状态被标记为不可用(Not Ready),随后 Master 会触发”工作负载大转移”的自动流程。
🍑 Pod
Pod 是 Kubernetes 的最重要也是最基本的概念,如下图所示,是Pod的组成示意图;
我们看到每个Pod都有一个特殊的被称为 “根容器” 的Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。
🤔思考
为什么Kubernetes会设计出一个全新的Pod概念并且Pod有这样特殊的组成结构?
⭐原因一:
在一组容器作为一个单元的情况下,我们难以对“整体”简单地进行判断及有效地进行行动。
比如,一个容器死亡了,此时算是整体死亡么?是N/M的死亡率么?引入业务无关并且不易死亡的Pause容器作为Pod的根容器,以它的状态代表整个容器组的状态,就简单、巧妙地解决了这个难题。
⭐原因二:
Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂载的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享的问题。
😏继续讲解Pod
Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP地址。
Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,这通常采用虚拟二层网络技术来实现,例如Flannel、Openvswitch等,因此我们需要牢记一点:在Kubernetes里,一个Pod里的容器与另外主机上的Pod容器能够直接通信。
Pod有两种类型:普通的Pod和机静态Pod(static Pod)
静态Pod比较特殊,它并不存在Kubernetes的etcd存储里,而是存在某个具体的Node上的一个具体文件中,并且只在此Node上启动运行。
而普通的Pod一旦被创建,就会被放入到etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的Kubelet进程实例化成一组相关的Docker容器并启动起来。
在默认情况下,当Pod里的某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,则会将这个Node上的所有Pod重新调度到其他节点上。Pod、容器与Node的关系如下图所示:
🍑 Label(标签)
标签(Label)是将资源进行分类的标识符
🍅 资源标签
资源标签其实就是一个键值型(key/values)数据。
标签旨在指定对象(如Pod、Service、RC等)辨识性的属性,一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到仁义数量的资源对象上去,Label通常在资源对象定义时确定,也可以在对象创建后动态添加或删除,这些属性仅对用户存在特定的意义。
🍅 Label Selector(标签选择器)
标签选择器(Selector)全称为“Label Selector”,它是一种根据Label来过滤符合条件的资源对象的机制。
🍑 Pod控制器
尽管Pod是Kubernetes的最小调度单元,但用户通常不会直接部署及管理Pod对象,而是要借助于另一类抽象——控制器(Controller)对其进行管理。
用于工作负载的控制器是一种管理Pod生命周期的资源抽象,它们是Kubernetes上的一类对象,而非单个资源对象,包括ReplicationController、ReplicaSet、Deployment、Statefulset、Job等。
🍑 Server服务资源(Service)
Service是建立在一组Pod对象之上的资源抽象,它通过标签选择器选定一组Pod对象,并为这组Pod对象定义一个统一的固定访问入口(通常是一个IP地址),若Kubernetes集群存在DNS附件,它就会在Service创建时为其自动配置一个DNS名称以便客户端进行服务发现。
到达Service IP的请求将贝负载均衡至其后的端点——各个Pod对象之上,因此Service从本质上来讲是一个四层代理服务。另外,Service还可以将集群外部流量引入到集群中来。
🍑 存储卷(Volume)
存储卷(Volume)是独立于容器文件系统之外的存储空间,常用于扩展容器的存储空间为它提供持久存储能力。
Kubernetes集群上的存储大体可分为临时卷、本地卷和网络卷。临时卷和本地卷都位于Node本地,一旦Pod被调度至其他Node,此种类型的存储卷将无法访问到,因此临时卷和本地卷通常用于数据缓存,持久化的数据则需要放置于持久卷(persistent volume)之上。
🍑 Name和NameSpace
名称(Name) 是 Kubernetes 集群中资源对象的标识符,它们的作用域通常是名称空间(namespace),因此名称空间是名称的额外的限定机制。
在同一个名称空间中,同一类型资源对象的名称必须具有唯一性。名称空间通常用于实现租户或项目的资源隔离,从而形成逻辑分组,创建的 Pod 和 Service 等资源对象都属于名称空间级别,未指定时,它们都属于默认的名称空间 “default”。
🍑 Annotation
Annotaion(注解)是另一种附加在对象之上的键值类型的数据,但它拥有更大的数据容量。
Annotation常用于将各种非标示型元数据(metadata)附加到对象上,但它不能用于表示和选择对象,通常也不会被kubrnetes直接使用,其主要目的是方便工具或用户的阅读及查找等。
🍑 Ingress
Kubernetes将Pod对象和外部网络环境进行了隔离,Pod和Service等对象间的通信都使用其内部专用地址进行,如若需要开放某些Pod对象提供给外部用户访问,则需要为其请求流量打开一个通往Kubernetes集群内部的通道。
除了Service之外,Ingress也是这类通道的实现方式之一。
4. Kubernetes集群组件
一个典型的Kubernetes集群由多个工作节点(worker node)和一个集群控制平面(Control plane,即Master),以及一个集群状态存储系统(etcd)组成。
其中Master节点负责整个集群的管理工作,为集群提供管理接口,并监控和编排集群中的各个工作节点。
各节点负责以Pod的形式运行容器,因此,各节点需要事先配置好容器运行依赖到的所有服务和资源,如容器运行时环境等。
Kubrnetes的系统架构如下图所示:
Master节点主要由apiserver、controller-manager和scheduler三个组件,以及一个用于集群状态存储的etcd存储服务组成;而每个Node节点则主要包含kubelet、kube-proxy及容器引擎(Docker是最为常用的实现)等组件。
此外,完整的集群服务还依赖于一些附加组件,如KubeDNS等。
🍑 Master组件
图示👇
🍅 API Server
API Server负责输出RESTful风格的kubernetes API,它是发往集群的所有REST操作命令的接入点,并负责接收、校验并响应所有的REST请求,结果状态被持久存储于etcd中。
因此,API Server是整个集群的网关。
🍅 集群状态存储(Cluster State Store)
Kubernetes集群的所有状态信息都需要持久化存储系统etcd中,不过,etcd是由CoreOS基于Raft协议开发的分布式键值存储,可用于服务发现、共享配置以及一致性保障(如数据库主节点选择、分布式锁等)。
因此,etcd是独立的服务组件,并不隶属于kubernetes集群自身,etcd不仅能够提供键值数据存储,而且还为其提供了监听(watch)机制,用于监听和推送变更。
Kubernetes集群系统中,etcd中的键值发生变化时会通知到API Server,并由其通过watch API向客户端输出,基于watch机制,kubernetes集群的各组件实现了高效协同。
🍅 控制器管理器(Controller Manager)
Kubernetes中,集群级别的大多数功能都是由几个被称为控制器的进程执行实现的,这几个进程被集成于kube-controller-manager守护进程中。由控制器完成的功能主要包括生命周期功能和API业务逻辑,具体如下。
(1)生命周期功能:包括Namespace创建和生命周期、Event垃圾回收、Pod终止相关的垃圾回收、级联垃圾回收及Node垃圾回收等。
(2)API业务逻辑:例如,由ReplicaSet执行的Pod扩展等。
🍅 调度器(Scheduler)
Kubernetes是用于部署和管理大规模容器应用的平台,根据集群规模的不同,其托管运行的容器很可能会数以千计甚至更多。
API Server确认Pod对象的创建请求之后,便需要由Scheduler根据集群内各节点的可用资源状态,以及要运行的容器的资源需求作出调度决策,其工作逻辑如下图所示。另外,Kubernetes还支持用户自定义调度器。
🍑 Node组件
Node负责提供运行容器的各种依赖环境,并接受Master的管理。每个Node主要由以下几个组件构成。
🍅 Node的核心代理程序kubelet
Kubelet是运行于工作节点之上的守护进程,它从API Server接受关于Pod对象的配置信息并确保它们处于期望的状态(desired state)。
Kubelete会在API Server上注册当前工作节点,定期向Master回报节点资源使用情况,并通过cAdvisor监控容器和节点的资源占用状况。
🍅 容器运行时环境
每个Node都要提供一个容器运行时(Container Runtime)环境,它负责下载镜像并运行容器。
Kubelet并未固定链接至某容器运行时环境,而是以插件的方式载入配置的容器环境。
这种方式清晰地定义了各组件的边界。目前,kubernetes支持的容器运行环境至少包括Docker、RKT、cri-o和Fraki等。
🍅 Kube-proxy
每个工作节点都需要运行一个kube-proxy守护进程,它能够按需要为Service资源对象生成iptables或ipvs规则,从而捕获访问当前Service的ClusterIP的流量并将其转发至挣钱的后端Pod对象。
🍑 核心附件
Kubernetes集群还依赖于一组称为 “附件”(add-ons)的组件以提供完整的功能,它们通常是由第三方提供的特定应用程序,且托管运行于Kubernetes集群之上。
下面列出的几个附件各自为集群从不同角度引用了所需的核心功能。
🍅 KubeDNS
在Kubernetes集群中调度运行提供DNS服务的Pod,同一集群中的其他Pod可使用此DNS服务解决主机名。
Kubernetes 自1.11版本开始默认使用CoreDNS项目为集群提供服务注册和服务发现的动态名称解析服务,之前的版本中用到的是kube-dns项目,而SkyDNS则是更早一代的项目。
🍅 Kubernetes Dashboard
Kubernetes集群的全部功能都要基于Web的UI,来管理集群中的应用甚至是集群自身。
🍅 Heapster
容器和节点的性能监控与分析系统,它收集并解析多种指标数据,如资源利用率、生命周期事件等。新版本的Kubernetes中,其功能会逐渐由Prometheus结合其他组件所取代。
🍅 Ingress Controller
Service是一种工作于传统层的负载均衡器,而Ingress是在应用层实现的HTTP(S)负载均衡机制。
不过,Ingress资源自身并不能进行“流量穿透”,它仅是一组路由规则的集合,这些规则需要通过Ingress控制器(Ingress Controller)发挥作用。
目前,此类的可用项目有Nignx、Traefik、Envoy及HaProxy等。
最后
目前有很多和 k8s 集成部署和测试常用的基础套件👇
(1)kubernates dashboard - 官方Dashboard
(2)Rancher UI - 强大的 k8s/非k8s 集群部署工具
(3)helm - 基于包的k8s应用部署工具
(4)Nginx Ingress Controller - 支持 Ingress L7 负载均衡
(5)metrics-server - k8s 指标聚合器
(6)kube-prometheus-stack - 一站式的 k8s 集群监控系统(简称普罗米修斯)
总的来说 k8s 这一块儿需要学的东西太多了,光一个模块儿的东西想吃透的话,得需要很长时间
下一节就会带领大家如何在本地搭建一个简单的K8s集群🤗
- 点赞
- 收藏
- 关注作者
评论(0)