kuberbetes在希腊语中是「舵手、领航员」的意思,据我了解k8s算是Google borg的开源版本,正是因为google 15年放出borg的论文和近两年docker的火热,k8s也成为炙手可热的项目,部分云厂商比如Google、MS Azure、AWS甚至直接提供了kubernetes解决方案。
为了更好理解kubernetes,我们先来看下没有它之前我们是如何管理集群的。
在容器化之前,业内都是采用物理或者虚机部署,需要人肉处理各种服务异常,所有变更都为人肉操作,你得自己管理一切,包括服务器宕机、扩缩容、应用发布…… 随着服务规模的增长,人工操作也变得不大现实。于是这个时期就诞生了各种集群操作工具,比如chef、puppet、Ansible……,这些工具让集群维护变得稍微简答了点,但任然有局限。
我大概知道点Ansible,个人感觉这个工具虽然好用,但基本上只适合千百台服务器规模的集群。集群到一定规模后,有资源的厂商可能会自己开发一些集群管理工具,大多数系统的模式是一个系统调用服务器上的agent做一些操作。
容器的诞生彻底改变了集群发布和运维的方式,因为每次都发布的是同一个image,image又可以直接运行在服务器上,所以不用考虑线上环境一致性的问题。
但容器的使用又带来一些新的问题,比如虽然它相对于vm更轻量,但并不是一台完整的vm,还需要很多编排系统才能高效可靠的运转,容器资源需要调度,生命周期需要系统管理…… 容器的使用解决了一些问题,但也带来跟多新的问题,这时候就诞生了类似kubernetes的资源调度和管理系统。
其实kubernetes不仅仅是减轻了线上运维的压力,也能够提升机器资源的利用率,据说borg就为Google节省了10%以上的机器资源,Google目前机器数量超百万,一台服务器几万人民币,算下光机器就节省多少钱,再算下节省多少人力。
kubernetes
应用和服务
在介绍kubernetes之前,先说下应用和服务的区别,因为kubernetes是以服务(通常是微服务)为维度管理的,了解服务的概念有助于理解后面一些该概念。
服务有两个明显的特点。
一个服务只完成很少件事。
没有用户交互接口,只能通过API调用
而一个完整的应用,有用户界面(即便只有命令行界面),也通常提供了各种复杂的功能。
Master和node
粗看,Kubernetes只有两种角色,master和node(或称minion),master负责管理所有的node,node上跑了各种各种的服务。
master
master上主要有三个模块
1. API Server 暴露出kubernetes的api,可以被用户或者其他系统操作。
2. Etcd 一个kv存储系统,kubernetes上所有信息都被存到这。我大概了解了下,etcd可以用来替代zookeeper,相较于zk有多方面的提升,具体可以参考这篇文章etcd介绍。
3. 调度和控制管理 管理调度容器,比如确保每个服务容器数量,坏点自己动替换……
node
每个node上有三个主要进程
1. kubelet node上的agent,响应master发来的命令
2. Proxy 通过ip和servername把请求转发到正确的container上
3. cAdvisor 非必须,主要是为了收集node上的信息,比如当前运行了哪些container、资源使用率……
大概架构图如下:
接下来介绍一些kubernetes的关键词及具体概念
pods
在上图中看到了每个node中有好几个pod,pod中又有一堆container,其实一个pod就是一堆类似功能的container的集合, 这些container通常共享一个ip或者同一个文件系统,但在pod里所有container系统沟通都是通过localhost做的,有点像一台物理机上多个vm直接沟通。这里有很重要一点,kubernetes是在pod级别做管理的,不是container级别。pod里有哪些container都是用户在pod模板里指定的。
为什么kubernetes要以pod为维度管理而不是container? 我的理解,一个pod是做一组动作,每个动作可能由一个进程完成,你可以把多个进程放到一个container里做,但这可能会带来一些新问题。 比如你除了关注单个进程外,你还要考虑到进程之间的相互调用,这明显维护起来比较复杂了,而且也不便于排查问题。
单个container只包含单个进程,为什么还需要有pod的概念? 如果一组连续的动作被部署到不同的container,而container又在不同的机器上,这可能意味着着你一连串的请求需要在局域网甚至城域网中游走,相较于机器内部之间调用明显耗时多了。
Volumes
volume其实是container可以看见和使用的一个虚拟文件系统,和docker的volume很类似,但有所不同。docker中volume和docker container绑定在一起共生死的,但kubernetes中volume是和pod绑定的。同一个pod中的所有container都可以共享volume,其中一个container死了,volume不会消失。 这种方式也使得pod中container文件交互变得很容易。
kubernetes有各种volume,但最常用的有下面三种
EmptyDir
这种volume在创建的时候都是初始化为空,同一个pod里的所有container都可以读和写这个volume,该种volume也会随着pod的删除而被删除。
Network File System(NFS)
网络文件系统,不随pod的删除而被删除,一般用于存储一些日志文件。
GCEPersistenDisk(PD)
云存储,想存多久存多久。可靠性肯定要比nfs高多了。
上面一些关键词都是kubernetes各个组件相关的概念,接下来介绍和pod管理调度相关的一些概念。
Labels & Annotations
Labels
这个应该算是kubernetes中比较重要的概念了,因为靠label才能找到你想要的pod。label其实是个键值对,一个label可以表示一个pod,但一个pod可以有多个副本。
Label Selectors
通过label selector你就可以按一定规则找出相关的pod,现在有两种选取规则。一直是等式规则,比如tier = frontend, 你就可以找出所有label key为tier且value为frontend的pod。
还有另外一种基于集合的选取规则 关键词 「IN」「NOT IN」,举几个例子。
environment in (production, qa) tier notin (frontend, backend) partion
第一个例子,返回所有label中key是environment并且value是production或qa的pod。第二个例子,返回所有key是tier且值不是frontend和backend的pod。最后一个例子,返回所有key是partion的pod。
Annotations
注释,label存储的是确切的信息,annotation存储非确切信息,annotation补不会被kubernetes直接使用,它只是用来注释下这个pod是干嘛的,主要还是给人看的。
Replication Controllers
如果某个服务流量过大,一个pod无法支撑所有流量,这个时候就需要一个集群共同承担流量了,集群由多个同一pod的副本组成,pod的副本被称为replicas。整个集群的管理由replication controllers来做。比如你在pod.yaml中定义了这个机器有x个pod,replication controller就会保证有正确数量的pod,某个pod死了会自动启一个。
有个需要注意的地方,replication controller死了后,它所管理的pod并不会被删除。如果你想删除pod,必须把集群的pod数设置为0。
Services
service是提供用户发现你服务的模块, 其实上面跑着上文中提到的label selector。因为某个pod并不稳定,可能随时新建随时删除,serives出现屏蔽掉了pod变动对服务调用方带来的影响。顺便说一句,service是长期存活的。
当一个请求过来的时候,他先到proxy service,proxy service通过label selector找到对应的pod,将请求转发过去。如果有多个pod提供同一种服务,proxy service会采用轮询的方式转发请求。
Health Check
要想保证你的服务可用,你得确保pod是正常运行的,不正常的pod应该被replication controller替换掉。kubernetes提供了以下几种健康检查方式。
低级别的进程检查
只关注进程在不在,进程不在一定有问题,但进程在一定就没问题吗?
自动应用级别的检查
kubernetes提供了一些简单的应用检查,来确定你的pod是否正常运行。
TCP端口检查
测试你端口的连接是否正常,是否有超时的情况
HTTP GET
pod提供一个http接口做监控检查。接口直接实现,只需要返回一些状态码来标识pod是否健康即可。
container exec
如果你的pod没有提供http服务,但可能tcp socket监控不够, 你可以配置一些周期性的container命令来检查pod是否正常。