Kubernetes介绍
Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展。它与Swarm是类似的,并且是竞争产品。Swarm是Docker公司开发内置的,K8s是一个专门的社区,在2017年的时候,Docker公司宣布支持K8s,因为K8s的社区等都比较活跃及完善,所以这场竞争中,是K8s胜利了。
使用Kubernetes可以:
- 自动化容器的部署和复制
- 随时扩展或收缩容器规模
- 将容器组织成组,并且提供容器间的负载均衡
- 很容易地升级应用程序容器的新版本
- 提供容器弹性,如果容器失效就替换它,等等…
Kubernetes解决的问题:
- 调度 - 容器应该在哪个机器上运行
- 生命周期和健康状况 - 容器在无错的条件下运行
- 服务发现 - 容器在哪,怎样与它通信
- 监控 - 容器是否运行正常
- 认证 - 谁能访问容器
- 容器聚合 - 如何将多个容器合并成一个工程
Kubernetes架构及组件
Kubernetes属于主从分布式架构,主要由Master Node和Worker Node组成,以及包括客户端命令行工具kubectl和其它附加项(Add on)。
Master Node
作为控制节点,对集群进行调度管理(它类似于Swarm的Manager节点),它是K8s集群的大脑。Master Node由API Server、Scheduler、Cluster State Store和Controller-Manger Server所组成。
API Server
API Server是暴露给外接访问的,我们可以通过UI或者CLI通过API Server去跟集群进行交互。
API Server主要用来处理REST的操作,确保它们生效,并执行相关业务逻辑,以及更新etcd(或者其他存储)中的相关对象。API Server是所有REST命令的入口,它的相关结果状态将被保存在etcd(或其他存储)中。
另外,API Server也作为集群的网关。默认情况,客户端通过API Server对集群进行访问,客户端需要通过认证,并使用API Server作为访问Node和Pod(以及service)的堡垒和代理/通道。
Scheduler
Scheduler是一个调度模块,比如我们通过API Server创建一个应用,这个应用有两个容器,那么这两个容器到底要部署在哪个节点上,这就是通过Scheduler模块来进行一些算法来确认的。
scheduler组件为容器自动选择运行的主机。依据请求资源的可用性,服务请求的质量等约束条件,scheduler监控未绑定的pod,并将其绑定至特定的node节点。Kubernetes也支持用户自己提供的调度器,Scheduler负责根据调度策略自动将Pod部署到合适Node中,调度策略分为预选策略和优选策略,Pod的整个调度过程分为两步:
- 预选Node:遍历集群中所有的Node,按照具体的预选策略筛选出符合要求的Node列表。如没有Node符合预选策略规则,该Pod就会被挂起,直到集群中出现符合要求的Node。
- 优选Node:预选Node列表的基础上,按照优选策略为待选的Node进行打分和排序,从中获取最优Node。
Controller-Manager Server
控制管理服务器,主要是控制容器的负载均衡,或者对容器的横向扩展,比如增加节点等。
它用于执行大部分的集群层次的功能,它既执行生命周期功能(例如:命名空间创建和生命周期、事件垃圾收集、已终止垃圾收集、级联删除垃圾收集、node垃圾收集),也执行API业务逻辑(例如:pod的弹性扩容)。控制管理提供自愈能力、扩容、应用生命周期管理、服务发现、路由、服务绑定和提供。Kubernetes默认提供Replication Controller、Node Controller、Namespace Controller、Service Controller、Endpoints Controller、Persistent Controller、DaemonSet Controller等控制器。
etcd(Cluster state store)
集群状态存储,Kubernetes默认使用etcd作为集群整体存储,当然也可以使用其它的技术。etcd是一个简单的、分布式的、一致的key-value存储,主要被用来共享配置和服务发现。etcd提供了一个CRUD操作的REST API,以及提供了作为注册的接口,以监控指定的Node。集群的所有状态都存储在etcd实例中,并具有监控的能力,因此当etcd中的信息发生变化时,就能够快速的通知集群中相关的组件。
Worker Node
作为真正的工作节点,运行业务应用的容器;Worker Node包含kubelet、kube proxy和Fluented、Container Runtime。
Pod
在Kubernets中,Pod作为基本的执行单元,在Kubernetes中,最小的管理元素不是一个个独立的容器,而是Pod,Pod是最小的,管理,创建,计划的最小单元。Pod指的是具有相同的Name Space(这里的Name Space包含了所有的,最重要的是Network Name Space)的一些Container的组合,容器可能有多个,如果是多个,它们之间共享一个Network Name Space所以它可以拥有多个容器和存储数据卷,能够方便在每个容器中打包一个单一的应用,从而解耦了应用构建时和部署时的所关心的事项,已经能够方便在物理机/虚拟机之间进行迁移。
Kubelet
Kubelet是Kubernetes中最主要的控制器,它是Pod和Node API的主要实现者,Kubelet负责驱动容器执行层。在Kubernetes中,应用容器彼此是隔离的,并且与运行其的主机也是隔离的,这是对应用进行独立解耦管理的关键点。
API准入控制可以拒绝或者Pod,或者为Pod添加额外的调度约束,但是Kubelet才是Pod是否能够运行在特定Node上的最终裁决者,而不是scheduler或者DaemonSet。kubelet默认情况使用cAdvisor进行资源监控。负责管理Pod、容器、镜像、数据卷等,实现集群(Manager)对节点的管理,并将容器的运行状态汇报给Kubernetes API Server。
kube proxy
它是跟网络有关的,(总结就是例如一个service有多个容器,我们对这个service的所有容器提供一个公共的IP,并且实现负载均衡),基于一种公共访问策略(例如:负载均衡),服务提供了一种访问一群pod的途径。此方式通过创建一个虚拟的IP来实现,客户端能够访问此IP,并能够将服务透明的代理至Pod。每一个Node都会运行一个kube-proxy,kube proxy通过iptables规则引导访问至服务IP,并将重定向至正确的后端应用,通过这种方式kube-proxy提供了一个高可用的负载均衡解决方案。服务发现主要通过DNS实现。
在Kubernetes中,kube proxy负责为Pod创建代理服务;引到访问至服务;并实现服务到Pod的路由和转发,以及通过应用的负载均衡。
Container Runtime
每一个Node都会运行一个Container Runtime,其负责下载镜像和运行容器。这里容器我们一般选择Docker,当然也可以选择其他产品。
Fluented
主要是用于日志的采集、存储、查询等。
Add-on
Add-on是对Kubernetes核心功能的扩展,例如增加网络和网络策略等能力,在Kunbernetes中可以以附加项的方式扩展Kubernetes的功能,目前主要有网络、服务发现和可视化这三大类的附加项。
kubectl
kubectl是Kubernetes集群的命令行工具,通过kubectl能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。它用于通过命令行与API Server进行交互,而对Kubernetes进行操作,实现在集群中进行各种资源的增删改查等操作。命令的语法如下所示:kubectl [command] [TYPE] [NAME] [flags]
Kubernates安装
Kubernates-the-hard-way:最基础的方式,一步一步的安装各种组件,然后安装完成K8s集群,困难度很高
minikube:是一个工具,它能快速在我们本地创建一个只有一个节点的K8s集群
kuberadm:是一个工具,它能快速在我们本地搭建一个有多个节点的K8s集群
kops:快速的在云上创建K8s集群,比如AWS等,操作比较简单
Tectonic:企业版的一个工具,节点数量比较少,免费,大于十个节点是收费的
Play Way Kubernates:在云上快速搭建一个K8s集群,但是它有时间限制,四个小时后会自动销毁
具体的搭建方法可以Google或者Baidu
我们这里使用minikube的方式来创建。
安装完成我们就可以通过一些基础命令开查看K8s集群的状态了,例如:
kubectl config view:查看当前config的基本情况,包括Api的IP地址和端口,以及认证信息,context的名字等
kubectl config get-contexts:查看当前的context
kubectl cluster-info:查看当前K8s集群的基本情况,节点信息,类似于swarm中的 docker node 命令
使用minikube创建的k8s集群我们可以通过 minikube ssh 命令进入到虚拟机中,在这里面我们可以做具体的操作,比如直接操作docker等
Pod详解及基本操作命令
K8s我们不直接对container进行操作,pod是我们的基本操作单元。之前我们说过,一个Pod中的容器是共享一个Namespace的,他们之间是可以直接通信的。
基础操作
创建Pod,K8s中我们创建Pod需要通过一个yml文件来创建,这个yml文件有点类似于我们之前学习docker-compose和swarm的stack的文件,以下是一个示例文件:
1 | # api的版本 |
kubectl create -f [yml文件的路径名称]: 创建Pod
kubectl delete -f [yml文件的路径名称]: 删除已经创建的Pod
kubectl get pods:查看当前集群中所有的Pod及状态信息等
kubectl get pods -o wide:查看当前集群中所有的Pod及状态信息,包含的信息更全面一些,包含了容器的IP信息和运行的节点等
kubectl delete pods [Pod名称]:删除指定的Pod
kubectl describe [Pod名称]:查看Pod的详细信息,包含名称,节点信息,Namespace,所有的Container的详细信息,我们的Pod中的具体容器信息也能显示出来,这里我们就能够查到容器的Iamge、IP、端口、容器ID、状态等信息
kubectl exec -it [Pod名称] -c [Pod中Container名称] /bin/bash:进入Pod中的具体某一个容器,如果我们这里不使用 -c 参数,默认是进入第一个容器中
kubectl port-forward [Pod名称] [本地端口:Pod端口]:端口映射,类似于将容器的端口映射到宿主机上,此命令如果停止我们就无法访问
kubectl get nodes: 查询K8s集群中所有的节点信息
ReplicationController
Replication Controller简称RC,RC是Kubernetes系统中的核心概念之一,简单来说,RC可以保证在任意时间运行Pod的副本数量,能够保证Pod总是可用的。如果实际Pod数量比指定的多那就结束掉多余的,如果实际数量比指定的少就新启动一些Pod,当Pod失败、被删除或者挂掉后,RC都会去自动创建新的Pod来保证副本数量,所以即使只有一个Pod,我们也应该使用RC来管理我们的Pod。可以说,通过ReplicationController,Kubernetes实现了集群的高可用性。
- 核心命令:
kubectl create -f [rc的yml路径名称]:根据yml文件创建ReplicationController应用
kubectl get rc:查看我们K8s集群所有的rc的简单信息
kubectl get rc -o wide:查看我们K8s集群所有的rc的详细一些信息
kubectl scala rc [rc名称] –replicas=[要扩展后或回收后的Pod总数量]:扩展或者回收rc应用的pod
kubectl delete -f [rc的yml路径名称]:根据yml文件删除ReplicationController应用
ReplicationController和Pod一样,都是Kubernetes中的对象,因此创建方式类似。通过yaml或json描述文件来定义一个ReplicationController对象。一个最简单的ReplicationController的定义如下 rc-nginx.yml文件:
1 | apiVersion: v1 |
基于此文件,我们就可以通过命令:
1 | # 1.通过rc-nginx.yml来创建我们的应用 |
ReplicaSet
在新版本的 Kubernetes 中建议使用 ReplicaSet(简称为RS )来取代 ReplicationController。ReplicaSet 跟 ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector(ReplicationController 仅支持等式)
- 核心命令(与ReplicationController的核心命令大概相同):
kubectl create -f [rs的yml路径名称]:根据yml文件创建ReplicaSet应用
kubectl get rs:查看我们K8s集群所有的rs的简单信息
kubectl get rs -o wide:查看我们K8s集群所有的rs的详细一些信息
kubectl scale rs [rs名称] –replicas=[要扩展后或回收后的Pod总数量]:扩展或者回收rs应用的pod
kubectl delete -f [rs的yml路径名称]:根据yml文件删除ReplicaSet应用
下面是rs文件示例,rs-nginx.yml:
1 | apiVersion: apps/v1 |
具体的操作我们发现与RC是没有什么区别的,我们可以通过上面的示例,替换一下命令来测试一下,如下:
1 | jjw@jjw-PC:~$ kubectl create -f rs-nginx.yml |
Deployment
Deployment为Pod和Replica Set提供声明式更新。(个人理解最大的作用就是更新我们的应用用的,它用来替换我们上面学习的三种创建Pod的方式,它底层使用的还是ReplicaSet,类似与对ReplicaSet又做了一层高级的封装)
你只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和ReplicaSet 的实际状态改变到您的目标状态。您可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。
注意:不能手动管理由 Deployment 创建的 Replica Set,否则就篡越了 Deployment controller 的职责!
- 核心命令(与ReplicaSet的核心命令大概相同):
kubectl create -f [deployment的yml路径名称]:根据yml文件创建deployment应用
kubectl get deployment:查看我们K8s集群所有的deployment:的简单信息
kubectl get deployment -o wide:查看我们K8s集群所有的deployment的详细一些信息
kubectl set image deployment [deployment名称] [要升级的image名称]=[升级的image版本]:通过命令行直接指定升级的image来升级我们的deployment pod应用
kubectl rollout history deployment [deployment名称]:查看我们的deployment的历史版本,这里默认只有当前和上一个两个版本
kubectl rollout undo deployment [deployment名称]:回滚deployment应用的版本至上一个版本
kubectl delete -f [deployment的yml路径名称]:根据yml文件删除Deployment应用
下面我们通过一个示例来讲解:
首先定义deployment的yml文件,文件内容如下(deployment-nginx.yml)
1 | # 定义的版本,因为它底层使用的是Replica Set |
下面演示具体的操作:
1 | # 通过此yml文件创建deployment |
上述升级方式并不是滚动升级的,即不是优雅升级,期间会有一段时间服务处于宕机状态,实现滚动升级,我们只需要重新定义depolyment.yml文件,升级后的depolyment.yml文件中添加如下内容:
1 | # 定义的版本,因为它底层使用的是Replica Set |
具体添加内容解释如下:
minReadySeconds:
Kubernetes在等待设置的时间后才进行升级
如果没有设置该值,Kubernetes会假设该容器启动起来后就提供服务了
如果没有设置该值,在某些极端情况下可能会造成服务不正常运行
maxSurge:
升级过程中最多可以比原先设置多出的POD数量
例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD。
maxUnavaible:
升级过程中最多有多少个POD处于无法提供服务的状态
当maxSurge不为0时,该值也不能为0
例如:maxUnavaible=1,则表示Kubernetes整个升级过程中最多会有1个POD处于无法服务的状态。
然后执行命令:
kubectl apply -f [新的depolyment的yml文件]
这样就实现了滚动升级
升级可以暂停和继续,使用如下命令:
kubectl rollout pause deployment <deployment名称>:暂停升级
kubectl rollout resume deployment <deployment名称>:继续升级
最后更新: 2020年07月10日 20:50