1.3 Kubernetes——云计算的新标杆
1.3.1 Kubernetes 的横空出世
Docker 的“燎原”之火烧遍了整个IT 界,但是当Docker 容器的规模达到一定程度时,需要使用编排技术将这些容器管理起来。有了编排技术,才能够保证Docker 容器稳定运行,方便Docker 容器的维护管理、故障排查和恢复、负载均衡和升级管理等,Google开发的Kubernetes 在众多编排工具中脱颖而出,其热度甚至超过Docker 的原生编排工具Swarm,成为云计算的新标杆。接下来,我们来了解一下Kubernetes。
Kubernetes,简称K8s(用8 代替8 个字符“ubernete”),它是一个开源的、基于Docker的开源容器集群管理系统,用于管理云平台上多个主机中的容器化的应用,Kubernetes 的目标是使容器化的应用简单且高效。Kubernetes 提供了一种机制,可以帮助用户快速、方便地部署、规划、更新和维护应用。Kubernetes 可以使用公有云、私有云和混合云技术,已经成为云计算领域的标杆技术。那么Kubernetes 是如何诞生的呢?
早在2003 年,Google 内部为了管理大规模集群,组成了一个只有几个人的小团队,研发了一个叫作Borg 的系统,这个系统就是Kubernetes 的前身;在2014 年,Google 推出Kubernetes(作为Borg 的开源版本),之后Kubernetes 受到了众多云计算厂商的追捧,代码活跃度非常高。目前不仅主流的公有云平台支持Kubernetes,而且很多企业将私有云、混合云平台也基于Kubernetes 进行部署了。
1.3.2 Kubernetes 的基本概念和架构
Kubernetes 可以构建一个容器的调度服务,用户可以通过Kubernetes 管理云端的容器和集群,避免了一些复杂的设置和配置工作。在Kubernetes 中,系统会自动选取合适的工作节点来执行具体的容器和集群调度处理工作。Kubernetes 的核心概念是Container Pod,一个Pod 由一组工作于同一物理工作节点的容器组成,这些容器组拥有相同的网络命名空间、IP 及存储配额,可以根据实际情况对每个Pod 进行端口映射。
Kubernetes 集群由众多节点组成,这些节点可以是物理服务器,也可以是虚拟机。Kubernetes 节点架构如图1-5 所示。根据图1-5 可知,Kubernetes 集群由Kubernetes Master节点和多个工作节点组成,远程镜像仓库为整个Kubernetes 集群提供镜像下载、上传服务,Kubernetes 向用户提供了功能非常强大的CLI 接口,同时提供了UI 用户接口,方便用户访问和管理Kubernetes 集群。
图1-5 Kubernetes 节点架构
除了Kubernetes 节点架构外,我们需要重点介绍一下Kubernetes 组件架构,如图1-6所示。根据图1-6 可知,Kubernetes 由Kubernetes Master 和Node 组成,Kubernetes Master中包含Scheduler、Controller、etcd 等,下面详细介绍这些组件的作用。
图1-6 Kubernetes 组件架构
1.Kubernetes Master
每个Kubernetes 集群都有一个Master 节点,Kubernetes 集群的大部分管理行为都需要在这个节点上完成,并且Master 节点拥有一系列组件,如Kubernetes API Server、Scheduler、Controller 和etcd 等。Kubernetes Master 是Kubernetes 集群的主控组件,也是核心组件。一个Kubernetes 集群中只有一个Kubernetes Master,如果Kubernetes Master出现了问题,会对这个Kubernetes 集群造成灾难性的损失,因此Kubernetes Master 的可靠性非常重要。业界为了保证Kubernetes Master 的可靠性提供了很多种方案,如HA 主备机制、Balancer 机制等。
2.Scheduler
Scheduler 主要用于实现Kubernetes 集群的作业调度功能,接收从Controller Manager发送的创建Pod(Pod 的概念见下文)的请求,并且根据当前集群的使用情况,找到合适的资源(Node)并创建Pod。
3.Controller
Controller 的首要职责是保证Kubernetes 集群各资源的使用状态与用户定义(YAML文件)保持一致,并且随时修正错误。其实Controller 是一个比较笼统的概念,除了各种控制器的集中管理控制中心Controller Manager,还包含很多种控制器,这些控制器的功能如下。
1)Replication Controller,简称RC,用于实现管理Pod 副本的功能,主要有以下3个功能。
① 根据RC 中定义的副本数量N,确保Kubernetes 集群中有且只有N 个Pod实例。
② 动态调整集群中Pod 的数量,进行扩容或缩容,称为弹性伸缩。
③ 用户根据RC 中定义的Pod 模板实现滚动升级。如果在RC 中定义spec.replicas = 0,那么Kubernetes 集群中的相关Pod 会被删除。
2)Node Controller,用于实时地动态获取工作节点的相关信息,管理和监控Kubernetes集群中的各个工作节点。
3)ResourceQuota Controller,用于管理资源配置,可以保证Kubernetes 集群使用的资源不超过占用的系统物理资源,可以提高Kubernetes 集群的可靠性,还可以抽象出三个级别进行资源限制,分别是容器、Pod、Namespace(Kubernetes 进行多租户资源隔离的主要手段)。
4)Namespace Controller,用于管理Namespace 的生命周期,当用户删除Namespace时,Namespace 会被设置为Terminating 状态,与此同时,Namespace Controller 会保证该Namespace 中的所有资源被安全删除。
5)Service Controller,用于监听Service,如果Service 发生变化,则Service Controller会相应地创建、删除或修改Service 对应的实例。
除了以上Controller,还有Token Controller、ServiceAccount Controller、EndPointController,用户也可以开发自己的Controller,这里不再一一赘述。
4.etcd
etcd 存储了 Kubernetes 集群的所有网络配置和对象状态的信息,如Node、Service、Pod、Namespace 等。
5.API Server
前面提到,etcd 存储了Kubernetes 集群所有对象状态的信息,但是用户是怎么管理这些信息的呢?API Server 是用户和节点之间管理资源对象的唯一入口,所有组件都必须通过API Server 来管理资源对象。
6.Node
Node,即前面经常提到的工作节点,它可以是物理机,也可以是虚拟机。Node 是Kubernetes 集群中的重要节点组成部分,其中每个节点都包含Kubelet、Kube-proxy 和Pod等组件。
7.Kubelet
每个节点中都有Kubelet 组件。Kubelet 的默认监听端口号为10250,它接收并执行Master 发来的指令,负责该节点中Pod 的增、删、改、查功能,还负责将该节点的状态信息实时上报给API Server。
8.Kube-proxy
同Kubelet 一样,每个节点中都有Kube-proxy 组件,它通过API Server 监听Service和Endpoint 的状态变化情况,并且通过Iptables 动态实现负载均衡。Kube-proxy 可以直接运行于物理机上,也可以是一个静态Pod 或DaemonSet。
Kube-proxy 支持多种实现方式。
· Userspace:该负载均衡方案比较早,它的实现方法是通过Iptables 将负载均衡转发到Pod 实例中。
· Iptables:目前的主流方案,该方案完全通过Iptables 动态实现负载均衡。
· Ipvs:为了解决Iptables 的性能问题,提出了Ipvs 解决方案,该方案预先在每个节点上加载内核模块,采用增量式更新,从而解决延时问题。
9.Pod
Pod 是一组紧密联系的Docker 容器的集合,是Kubernetes 调度的基本单位,也是Kubernetes 与Docker 原生编排工具Swarm 最大的不同之处。Pod 的设计理念是支持多个容器一起共享网络和文件系统,可以将进程间的通信和文件共享组合起来,从而高效完成某一个服务。
1.3.3 Kubernetes 集群的部署
Kubernetes 提供了多种方法供用户部署Kubernetes 集群。初学者可以使用Kubernetes开源社区的新成员——Minikube,它是一个快速部署单节点Kubernetes 集群的工具,特别适合个人学习、测试和开发,而且它的开源代码在社区活跃度非常高。
Kubernetes 开源社区推出了一个非常好用的工具——kind。kind 工具可以帮助用户非常快速、方便地部署Kubernetes 集群,步骤非常简单,只需下载kind 工具并执行一条命令(前提是用户安装并启动了Docker)。使用kind 工具部署Kubernetes 集群的具体步骤如下。
(1)下载kind 工具。在MAC 或Linux 操作系统中,下载kind 工具的方法如下:
在Windows 操作系统中,下载kind 工具的方法如下:
(2)使用kind 命令启动Kubernetes 集群。在下载kind 工具后,运行如下kind 命令即可启动Kubernetes 集群。
使用kind 命令删除Kubernetes 集群也非常简单,命令如下:
(3)安装kubectl 工具。kubectl 工具的安装方法与kind 工具的安装方法相同,只需下载并解压缩。
此外,可以根据Kubernetes 官方文档安装原生Kubernetes。如果运行Kubeflow,那么笔者建议使用原生Kubernetes 或OpenShift 等云平台。在安装完成之后,可以运行kubectl version 命令查看Kubernetes 集群的版本,如下所示,Kubernetes 集群版本号是1.13。
还可以运行kubectl cluster-info 命令查看更详细的版本信息,从而得知Kubernetes Master 的IP 地址。
前面介绍了节点分为Master 和Node,可以运行kubectl get nodes 命令查看该Kubernetes 集群的节点信息,如下所示。根据下面的节点信息可知,目前该Kubernetes 集群有3 个节点,1 个是Master 节点,2 个是Node 节点。
1.3.4 Kubernetes 的“Hello World”应用
在安装好Kubernetes 集群后,下面我们在这个Kubernetes 集群中运行一个端到端的“Hello World”应用,以便更深入地理解Kubernetes。
1.部署Kubernetes 应用
运行kubectl run my-app --image=nginx --port=80 命令创建一个my-app 应用,以部署一个Nginx 服务器为例,该服务器使用的镜像为Nginx(此镜像公开存储于Docker Hub中),使用的端口号为80。在创建完成后,运行kubectl get deployment my-app 命令查询这个应用是否部署成功。
在Deployment 状态正常后,运行kubectl get pod 命令可以查看当前Pod 的运行状况。
也可以运行kubectl describe pod my-app-57dd8b7bb9-5pfsl 命令查看当前Pod 的详细信息。
2.发布服务
应用了Nginx 服务器的my-app 应用已经运行起来了,但是用户应该怎样访问这个Nginx 服务器呢?这时就要用到服务发布了。
首先创建一个Service,用于转发my-app 应用的80 端口。运行kubectl expose deployment/my-app --type="NodePort" --port=80 命令,这条命令的意思是创建my-app 的一个Service,并且使用NodePort 的方式对外暴露my-app 的Deployment 的80 端口,然后运行kubectl get service my-app 命令查看这个Service,运行结果如下所示。
从运行结果来看,my-app 应用的Service 将Pod 中的80 端口发布出来并转发到了Master 主机的31743 端口。根据Master 主机的IP 和31743 端口,可以访问这个Nginx服务器,如下所示,访问成功。
3.弹性伸缩
前面我们成功发布并访问了这个Nginx 服务器,但是根据需求,我们需要将Nginx服务器横向扩展,应该怎么办呢?这对Kubernetes 来说非常简单,运行kubectl scale deployment/my-app --replicas=3 命令即可。运行以下命令查看Pod 的运行情况。
可以看到,此时已经有3 个Nginx 服务器共同提供服务了,当然也可以减小--replicas 的值实现缩容。
4.更新应用
在现实项目中,我们经常有版本升级、应用更新等需求。那么这些需求如何在Kubernetes 中实现呢?
我们仍然以该Nginx 服务器为例进行说明。首先查看当前Nginx 服务器的版本信息,如下所示,我们看到目前版本是Nginx 1.17.5.
如果发现Nginx 1.17.5 有兼容性问题,那么需要将版本回退,退到Nginx 1.13.9。在Kubernetes 中,运行kubectl set image deployment/my-app my-app=nginx:1.13.9 命令即可实现。
再次查看Nginx 服务器的版本信息,发现版本已经回退成功了。
5.删除应用
运行kubectl delete deployment my-app 命令即可删除my-app 应用,运行结果如下:
在删除my-app 应用之后,相应的Pod 也消失了。但是,在前面的步骤中,我们为了发布服务还曾手动创建了一个Service,也需要一并删除。
至此,my-app 应用就彻底被删除了。