K8S(Kubernetes)中包含哪些核心概念及其介绍?
- 内容介绍
- 文章标签
- 相关推荐
本文共计4409个文字,预计阅读时间需要18分钟。
Kubernetes(简称k8s)是Google在2014年6月开源的容器集群管理系统,采用Go语言开发,用于管理云平台中多个主机上的容器化应用。其目标是实现应用的容器化部署。
一、kubernetes的前生今生Kubernetes(简称k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了资源调度、部署管理、服务发现、扩容缩容、监控,维护等一整套功能。努力成为跨主机集群的自动部署、扩展以及运行应用程序容器的平台。 它支持一系列容器工具, 包括Docker等。
从Borg到Kubernetes在Docker 作为高级容器引擎快速发展的同时,Google也开始将自身在容器技术及集群方面的积累贡献出来。在Google内部,容器技术已经应用了很多年,Borg系统运行管理着成千上万的容器应用,在它的支持下,无论是谷歌搜索、Gmail还是谷歌地图,可以轻而易举地从庞大的数据中心中获取技术资源来支撑服务运行。
Borg是集群的管理器,在它的系统中,运行着众多集群,而每个集群可由成千上万的服务器联接组成,Borg每时每刻都在处理来自众多应用程序所提交的成百上千的Job, 对这些Job进行接收、调度、启动、停止、重启和监控。
Borg提供了3大好处:
1)隐藏资源管理和错误处理,用户仅需要关注应用的开发。
2) 服务高可用、高可靠。
3) 可将负载运行在由成千上万的机器联合而成的集群中。
作为Google的竞争技术优势,Borg理所当然的被视为商业秘密隐藏起来,但当Tiwtter的工程师精心打造出属于自己的Borg系统(Mesos)时, Google也审时度势地推出了来源于自身技术理论的新的开源工具。
2014年6月,谷歌云计算专家埃里克·布鲁尔(Eric Brewer)在旧金山的发布会为这款新的开源工具揭牌,它的名字Kubernetes在希腊语中意思是船长或领航员,这也恰好与它在容器集群管理中的作用吻合,即作为装载了集装箱(Container)的众多货船的指挥者,负担着全局调度和运行监控的职责。
虽然Google推出Kubernetes的目的之一是推广其周边的计算引擎(Google Compute Engine)和谷歌应用引擎(Google App Engine)。但Kubernetes的出现能让更多的互联网企业可以享受到连接众多计算机成为集群资源池的好处。
Kubernetes对计算资源进行了更高层次的抽象,通过将容器进行细致的组合,将最终的应用服务交给用户。Kubernetes在模型建立之初就考虑了容器跨机连接的要求,支持多种网络解决方案,同时在Service层次构建集群范围的SDN网络。其目的是将服务发现和负载均衡放置到容器可达的范围,这种透明的方式便利了各个服务间的通信,并为微服务架构的实践提供了平台基础。而在Pod层次上,作为Kubernetes可操作的最小对象,其特征更是对微服务架构的原生支持。
Kubernetes项目来源于Borg,可以说是集结了Borg设计思想的精华,并且吸收了Borg系统中的经验和教训。
Kubernetes作为容器集群管理工具,于2015年7月22日迭代到 v 1.0并正式对外公布,这意味着这个开源容器编排系统可以正式在生产环境使用。与此同时,谷歌联合Linux基金会及其他合作伙伴共同成立了CNCF基金会( Cloud Native Computing Foundation),并将Kuberentes 作为首个编入CNCF管理体系的开源项目,助力容器技术生态的发展进步。Kubernetes项目凝结了Google过去十年间在生产环境的经验和教训,从Borg的多任务Alloc资源块到Kubernetes的多副本Pod,从Borg的Cell集群管理,到Kubernetes设计理念中的联邦集群,在Docker等高级引擎带动容器技术兴起和大众化的同时,为容器集群管理提供独了到见解和新思路。
二、kubernetes的特点-
可移植:支持公有云,私有云,混合云,多重云(multi-cloud)
-
可扩展::模块化, 插件化, 可挂载, 可组合
-
自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展,自我修复
-
服务发现和负载均衡
Kubernetes一个核心的特点就是自动化,能够自主的管理容器来保证云平台中的容器按照用户的期望状态运行着(比如用户想让apache一直运行,用户不需要关心怎么去做,Kubernetes会自动去监控,然后去重启,新建,总之,让apache一直提供服务),管理员可以加载一个微型服务,让规划器来找到合适的位置,同时,Kubernetes也系统提升工具以及人性化方面,让用户能够方便的部署自己的应用(就像canary deployments)。
现在Kubernetes着重于不间断的服务状态(比如web服务器或者缓存服务器)和原生云平台应用(Nosql),在不久的将来会支持各种生产云平台中的各种服务,例如,分批,工作流,以及传统数据库。
所有Kubernetes中的资源,比如Pod,都通过一个叫URI的东西来区分,这个URI有一个UID,URI的重要组成部分是:对象的类型(比如pod),对象的名字,对象的命名空间,对于特殊的对象类型,在同一个命名空间内,所有的名字都是不同的,在对象只提供名称,不提供命名空间的情况下,这种情况是假定是默认的命名空间。UID是时间和空间上的唯一。
三、kubernetes的相关概念使用Kubernetes,需要对pods、services、replication controller等概念了然于心。
1、PodPod是最小部署单元,一个Pod由一个或多个容器组成,Pod中容器共享存储和网络,在同一台Docker主机上运行。每个Pod都会包含一个 “根容器”,还会包含一个或者多个紧密相连的业务容器。
-
Pod运行在节点Node中;
-
Pod是对容器的封装,是k8s最小的调度单元,也是Kubernetes最重要的基本概念;
-
Pause容器简述:每个Pod都有一个特殊的被称为“根容器”的Pause容器,Pause容器对应的镜像属于Kubernetes平台的一部分。Kubernetes设计出全新Pod概念的原因如下。原因一、在一组容器作为一个单位的情况下,我们难以简单地对整组容器的状态进行判断。如果其中一个容器死亡,此时该去定义整组容器都死亡呢?还是定义N/M的死亡率呢?通过引入与业务无关并且不容易死亡的Pause容器作为Pod的根容器,以它的状态代表整组容器的状态,可以简单的解决整个问题。原因二、Pod里的多个业务容器共享Pause容器IP,共享Pause容器挂接的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。
-
Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP。Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,因此一个Pod容器与另外主机上的Pod容器能够直接通信。
pod 清单:
apiVersion: v1 # Pod版本号为v1 kind: Pod # 使用的资源类型为Pod metadata: name: string # 当前Pod的名称,名字唯一 namespace: string # Pod所属的命名空间,默认值为default labels: # 自定义标签列表 - name: string # 当前pod标签为“name=string” annotations: # 自定义注解列表 - name: string spec: # Pod中的详细定义 containers: # Pod的容器列表 - name: string # 容器名字 image: string # 容器镜像 imagePullPolicy: # 容器的镜像拉取策略 command: [string] # 容器的启动命令列表 args: [string] # 容器的启动命令参数列表 workingDir: String 容器的工作目录 volumeMounts: # 挂载到容器内部的存储卷配置 - name: String # 引用Pod定义的共享存储卷的名,需用Pod.spec.volumes[]部分定义的卷名 mountPath: String # 存储卷在容器内的绝对路径 readOnly: boolean # 设置为只读模式,默认为false volumes: # 在该Pod上定义共享存储卷列表 - name: String # 共享存储卷名称,必须字母小写 emptyDir: { } # 类型为emptyDir的存储卷,与Pod同生命周期的一个临时目录,为空值 hostPath: String # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录 path: String # Pod所在宿主机的目录,将被用于同期中Mount的目录 ports: 容器需要暴露的端口库号列表 - name: String 端口号名称 containerPort: Int 容器需要监听的端口号 hostPort: Int 可选,容器所在主机需要监听的端口号,默认与Container相同 env: # 容器运行前需设置的环境变量列表 - name: String # 环境变量名称 value: String # 环境变量的值 resources: # 资源限制和请求的设置 limits: # 资源限制的设置 cpu: String # Cpu的限制,单位为Core数,将用于docker run --cpu-shares参数,如果整数后跟m,表示占用权重,1Core=1000m memory: String # 内存限制,单位可以为Mib/Gib,将用于docker run --memory参数 requests: # 资源请求的设置 cpu: string # CPU请求,容器启动的初始可用数量 memory: string # 内存请求,容器启动的初始可用数量 livenessProbe: # 对Pod内容器健康检查设置,当探测无响应几次后将自动重启该容器,检查方法有exec、/ui 这个地址,之后会重定向到 /api/v1/proxy/namespaces/kube-system/services/kube-ui/#/dashboard/ 。
如果你发现你无法访问UI,那有可能是Kubernetes UI服务在你的集群上还没有启动。如果是这样,你可以手动开启UI服务:
kubectl create -f cluster/addons/kube-ui/kube-ui-rc.yaml –namespace=kube-system kubectl create -f cluster/addons/kube-ui/kube-ui-svc.yaml –namespace=kube-system
通常,这些应该通过 kube-addons.sh 脚本自动地被运行在主节点上。
七、Kubernetes相关经验 1、Pod的管理在Kubernetes中,所有的容器均在Pod中运行,一个Pod可以承载一个或者多个相关的容器,在后边的案例中,同一个Pod中的容器会部署在同一个物理机器上并且能够共享资源。一个Pod也可以包含O个或者多个磁盘卷组(volumes),这些卷组将会以目录的形式提供给一个容器,或者被所有Pod中的容器共享,对于用户创建的每个Pod,系统会自动选择那个健康并且有足够容量的机器,然后创建类似容器的容器,当容器创建失败的时候,容器会被node agent自动的重启,这个node agent叫kubelet,但是,如果是Pod失败或者机器,它不会自动的转移并且启动,除非用户定义了 replication controller。
用户可以自己创建并管理Pod,Kubernetes将这些操作简化为两个操作:基于相同的Pod配置文件部署多个Pod复制品;创建可替代的Pod当一个Pod挂了或者机器挂了的时候。而Kubernetes API中负责来重新启动,迁移等行为的部分叫做“replication controller”,它根据一个模板生成了一个Pod,然后系统就根据用户的需求创建了许多冗余,这些冗余的Pod组成了一个整个应用,或者服务,或者服务中的一层。一旦一个Pod被创建,系统就会不停的监控Pod的健康情况以及Pod所在主机的健康情况,如果这个Pod因为软件原因挂掉了或者所在的机器挂掉了,replication controller 会自动在一个健康的机器上创建一个一摸一样的Pod,来维持原来的Pod冗余状态不变,一个应用的多个Pod可以共享一个机器。
我们经常需要选中一组Pod,例如,我们要限制一组Pod的某些操作,或者查询某组Pod的状态,作为Kubernetes的基本机制,用户可以给Kubernetes Api中的任何对象贴上一组 key:value 的标签,然后,我们就可以通过标签来选择一组相关的Kubernetes Api 对象,然后去执行一些特定的操作,每个资源额外拥有一组(很多) keys 和 values,然后外部的工具可以使用这些keys和vlues值进行对象的检索,这些Map叫做annotations(注释)。
2、网络配置如何从Internet访问部署的应用?
部署前的服务有一个IP地址,但这个地址仅在Kubernetes集群中可用。这意味着无法通过网络访问该服务!在Google Cloud Engine上运行时,Kubernetes会自动配置一个负载均衡用以访问应用;如果不在Google Cloud Engine上运行(比如我们),那就需要做一些额外的工作来获得负载均衡了。
直接在主机端口上开放服务是一个可行的解决方案(很多人一开始的确是这么做的),但我们发现,这样的做法等于放弃了Kubernetes所提供的许多好处。如果我们依赖主机上的端口,部署多个应用时会遇到端口冲突。另外这样的做法会加大扩展集群和更换主机的难度。
我们发现,解决以上问题的更好办法,是在Kubernetes集群前配置负载均衡器,例如HAProxy或者NGINX。于是我们开始在AWS上的VPN中运行Kubernetes集群,并使用AWS ELB将外部web流量路由到内部HAProxy集群。HAProxy为每个Kubernetes服务配置了“后端”,以便将流量交换到各个pods。
在任何情况下,创建新的Kubernetes服务,我们都需要一种机制动态重新配置负载均衡器(在我们的例子中是HAProxy)。
Kubernetes社区目前正在开发一个名为ingress的功能,用来直接从Kubernetes配置外部负载均衡器。
3、配置负载均衡首先,我们需要一个地方存储负载均衡器配置。负载均衡器配置可以存储在任何地方,不过因为我们已经有etcd可用,就把这些配置放在了etcd里。我们使用一个名为“confd”的工具观察etcd中的配置变动,并用模板生成了一个新的HAProxy配置文件。当一个新的服务添加到Kubernetes,我们向etcd中添加一个新的配置,一个新的HAProxy配置文件也就此产生。
4、资源限制使用Kubernetes时,搞清楚资源限制很重要。你可以在每个pod上配置资源请求和CPU/内存限制,也可以控制资源保证和bursting limits。
这些设置对于高效运行多个容器极为重要,防止容器因分配内存不足而意外停止。
建议尽早设置和测试资源限制。没有限制时,看起来运行良好,不代表把重要负载放到容器中不会出现问题。
当我们快要搭建好Kubernetes时,我们意识到监控和日志在这个新的动态环境中非常重要。当我们面对大规模服务和节点时,进入服务器查看日志文件是不现实的,建一个中心化的日志和监控系统需要尽快提上议程。
6、日志有很多用于日志记录的开源工具,我们使用的是Graylog和Apache Kafka(从容器收集摘录日志的消息传递系统)。容器将日志发送给Kafka,Kafka交给Graylog进行索引。我们让应用组件将日志打给Kafka,方便将日志流式化,成为易于索引的格式。也有一些工具可以从容器外收集日志,然后发送给日志系统。
7、监控Kubernetes具备超强的故障恢复机制,Kubernetes会重启意外停止的pod。我们曾遇到过因内存泄露,导致容器在一天内宕机多次的情况,然而令人惊讶的是,甚至我们自己都没有察觉到。
Kubernetes在这一点上做得非常好,不过一旦问题出现,即使被及时处理了,我们还是想要知道。因此我们使用了一个自定义的运行状况检查仪表盘来监控Kubernetes节点和pod,以及包括数据存储在内的一些服务。可以说在监控方面,Kubernetes API再次证明了其价值所在。
检测负载、吞吐量、应用错误等状态也是同样重要的,有很多开源软件可以满足这一需求。我们的应用组件将指标发布到InfluxDB,并用Heapster去收集Kubernetes的指标。我们还通过Grafana(一款开源仪表盘工具)使存储在InfluxDB中的指标可视化。有很多InfluxDB/Grafana堆栈的替代方案,无论你才用哪一种,对于运行情况的跟踪和监控都是非常有价值的。
8、数据存储和Kubernetes很多Kubernetes新用户都有一个问题:我该如何使用Kubernetes处理数据?
运行数据存储时(如MangoDB或MySQL),我们很可能会有持久化数据储存的需求。不过容器一但重启,所有数据都会丢失,这对于无状态组件没什么影响,但对持久化数据储存显然行不通。好在,Kubernetes具有Volume机制。
Volume可以通过多种方式备份,包括主机文件系统、EBS(AWS的Elastic Block Store)和nfs等。当我们研究持久数据问题是,这是一个很好的方案,但不是我们运行数据存储的答案。
9、副本问题在大多数部署中,数据存储也是有副本的。Mongo通常在副本集中运行,而MySQL可以在主/副模式下运行。我们都知道数据储存集群中的每个节点应该备份在不同的volume中,写入相同volume会导致数据损坏。另外,大多数数据存储需要明确配置才能使集群启动并运行,自动发现和配置节点并不常见。同时,运行着数据存储的机器通常会针对某项工作负载进行调整,例如更高的IOPS。扩展(添加/删除节点)对于数据存储来说,也是一个昂贵的操作,这些都和Kubernetes部署的动态本质不相符。
决定不在生产环境数据存储上使用Kubernetes,以我们的情况,在Kubernetes内运行数据存储没有想象中那么完美,设置起来也比其他Kubernetes部署复杂得多。
于是我们决定不在生产环境数据存储上使用Kubernetes,而是选择在不同的机器上手动启动这些集群,我们在Kubernetes内部运行的应用正常连接到数据存储集群。
所以说,没必要运行Kubernetes的一切,按自身情况与其他工具配合使用,会有意想不到的效果,比如我们的数据存储和HAProxy服务器。
10、未来看看我们现在的部署,可以负责任的说,Kubernetes的表现绝对是梦幻级的,而Kubernetes API更是自动化部署流程的利器。由于不需要处理VM,我们现在的部署相比之前更快、更可靠。更简单的容器测试和交付,也让我们在构建和部署可靠性上得到了巨大提升。
这种新的部署方式迅速高效,让我们得以跟上其他团队的节奏,这绝对是必要的。
11、成本计算任何事情都有两面性。运行Kubernetes,需要一个etcd集群以及一个Master节点,对于较小的部署来说,这一开销还是比较大的,适合通过一些云服务达成。
对于大规模部署,Kubernetes可以帮助节省大量服务器成本,etcd集群和Master节点这点开销就显得微不足道了。Kubernetes让很多容器在一个主机上运行变得非常容易,最大程度上利用了现有资源,减少了服务器数量,成本自然下降了。不过这样的集群也给运维工作提出了更高的要求,必须要的时候,我们可以选择一些云计算平台提供的云服务来轻松达成。
本文共计4409个文字,预计阅读时间需要18分钟。
Kubernetes(简称k8s)是Google在2014年6月开源的容器集群管理系统,采用Go语言开发,用于管理云平台中多个主机上的容器化应用。其目标是实现应用的容器化部署。
一、kubernetes的前生今生Kubernetes(简称k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了资源调度、部署管理、服务发现、扩容缩容、监控,维护等一整套功能。努力成为跨主机集群的自动部署、扩展以及运行应用程序容器的平台。 它支持一系列容器工具, 包括Docker等。
从Borg到Kubernetes在Docker 作为高级容器引擎快速发展的同时,Google也开始将自身在容器技术及集群方面的积累贡献出来。在Google内部,容器技术已经应用了很多年,Borg系统运行管理着成千上万的容器应用,在它的支持下,无论是谷歌搜索、Gmail还是谷歌地图,可以轻而易举地从庞大的数据中心中获取技术资源来支撑服务运行。
Borg是集群的管理器,在它的系统中,运行着众多集群,而每个集群可由成千上万的服务器联接组成,Borg每时每刻都在处理来自众多应用程序所提交的成百上千的Job, 对这些Job进行接收、调度、启动、停止、重启和监控。
Borg提供了3大好处:
1)隐藏资源管理和错误处理,用户仅需要关注应用的开发。
2) 服务高可用、高可靠。
3) 可将负载运行在由成千上万的机器联合而成的集群中。
作为Google的竞争技术优势,Borg理所当然的被视为商业秘密隐藏起来,但当Tiwtter的工程师精心打造出属于自己的Borg系统(Mesos)时, Google也审时度势地推出了来源于自身技术理论的新的开源工具。
2014年6月,谷歌云计算专家埃里克·布鲁尔(Eric Brewer)在旧金山的发布会为这款新的开源工具揭牌,它的名字Kubernetes在希腊语中意思是船长或领航员,这也恰好与它在容器集群管理中的作用吻合,即作为装载了集装箱(Container)的众多货船的指挥者,负担着全局调度和运行监控的职责。
虽然Google推出Kubernetes的目的之一是推广其周边的计算引擎(Google Compute Engine)和谷歌应用引擎(Google App Engine)。但Kubernetes的出现能让更多的互联网企业可以享受到连接众多计算机成为集群资源池的好处。
Kubernetes对计算资源进行了更高层次的抽象,通过将容器进行细致的组合,将最终的应用服务交给用户。Kubernetes在模型建立之初就考虑了容器跨机连接的要求,支持多种网络解决方案,同时在Service层次构建集群范围的SDN网络。其目的是将服务发现和负载均衡放置到容器可达的范围,这种透明的方式便利了各个服务间的通信,并为微服务架构的实践提供了平台基础。而在Pod层次上,作为Kubernetes可操作的最小对象,其特征更是对微服务架构的原生支持。
Kubernetes项目来源于Borg,可以说是集结了Borg设计思想的精华,并且吸收了Borg系统中的经验和教训。
Kubernetes作为容器集群管理工具,于2015年7月22日迭代到 v 1.0并正式对外公布,这意味着这个开源容器编排系统可以正式在生产环境使用。与此同时,谷歌联合Linux基金会及其他合作伙伴共同成立了CNCF基金会( Cloud Native Computing Foundation),并将Kuberentes 作为首个编入CNCF管理体系的开源项目,助力容器技术生态的发展进步。Kubernetes项目凝结了Google过去十年间在生产环境的经验和教训,从Borg的多任务Alloc资源块到Kubernetes的多副本Pod,从Borg的Cell集群管理,到Kubernetes设计理念中的联邦集群,在Docker等高级引擎带动容器技术兴起和大众化的同时,为容器集群管理提供独了到见解和新思路。
二、kubernetes的特点-
可移植:支持公有云,私有云,混合云,多重云(multi-cloud)
-
可扩展::模块化, 插件化, 可挂载, 可组合
-
自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展,自我修复
-
服务发现和负载均衡
Kubernetes一个核心的特点就是自动化,能够自主的管理容器来保证云平台中的容器按照用户的期望状态运行着(比如用户想让apache一直运行,用户不需要关心怎么去做,Kubernetes会自动去监控,然后去重启,新建,总之,让apache一直提供服务),管理员可以加载一个微型服务,让规划器来找到合适的位置,同时,Kubernetes也系统提升工具以及人性化方面,让用户能够方便的部署自己的应用(就像canary deployments)。
现在Kubernetes着重于不间断的服务状态(比如web服务器或者缓存服务器)和原生云平台应用(Nosql),在不久的将来会支持各种生产云平台中的各种服务,例如,分批,工作流,以及传统数据库。
所有Kubernetes中的资源,比如Pod,都通过一个叫URI的东西来区分,这个URI有一个UID,URI的重要组成部分是:对象的类型(比如pod),对象的名字,对象的命名空间,对于特殊的对象类型,在同一个命名空间内,所有的名字都是不同的,在对象只提供名称,不提供命名空间的情况下,这种情况是假定是默认的命名空间。UID是时间和空间上的唯一。
三、kubernetes的相关概念使用Kubernetes,需要对pods、services、replication controller等概念了然于心。
1、PodPod是最小部署单元,一个Pod由一个或多个容器组成,Pod中容器共享存储和网络,在同一台Docker主机上运行。每个Pod都会包含一个 “根容器”,还会包含一个或者多个紧密相连的业务容器。
-
Pod运行在节点Node中;
-
Pod是对容器的封装,是k8s最小的调度单元,也是Kubernetes最重要的基本概念;
-
Pause容器简述:每个Pod都有一个特殊的被称为“根容器”的Pause容器,Pause容器对应的镜像属于Kubernetes平台的一部分。Kubernetes设计出全新Pod概念的原因如下。原因一、在一组容器作为一个单位的情况下,我们难以简单地对整组容器的状态进行判断。如果其中一个容器死亡,此时该去定义整组容器都死亡呢?还是定义N/M的死亡率呢?通过引入与业务无关并且不容易死亡的Pause容器作为Pod的根容器,以它的状态代表整组容器的状态,可以简单的解决整个问题。原因二、Pod里的多个业务容器共享Pause容器IP,共享Pause容器挂接的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。
-
Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP。Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,因此一个Pod容器与另外主机上的Pod容器能够直接通信。
pod 清单:
apiVersion: v1 # Pod版本号为v1 kind: Pod # 使用的资源类型为Pod metadata: name: string # 当前Pod的名称,名字唯一 namespace: string # Pod所属的命名空间,默认值为default labels: # 自定义标签列表 - name: string # 当前pod标签为“name=string” annotations: # 自定义注解列表 - name: string spec: # Pod中的详细定义 containers: # Pod的容器列表 - name: string # 容器名字 image: string # 容器镜像 imagePullPolicy: # 容器的镜像拉取策略 command: [string] # 容器的启动命令列表 args: [string] # 容器的启动命令参数列表 workingDir: String 容器的工作目录 volumeMounts: # 挂载到容器内部的存储卷配置 - name: String # 引用Pod定义的共享存储卷的名,需用Pod.spec.volumes[]部分定义的卷名 mountPath: String # 存储卷在容器内的绝对路径 readOnly: boolean # 设置为只读模式,默认为false volumes: # 在该Pod上定义共享存储卷列表 - name: String # 共享存储卷名称,必须字母小写 emptyDir: { } # 类型为emptyDir的存储卷,与Pod同生命周期的一个临时目录,为空值 hostPath: String # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录 path: String # Pod所在宿主机的目录,将被用于同期中Mount的目录 ports: 容器需要暴露的端口库号列表 - name: String 端口号名称 containerPort: Int 容器需要监听的端口号 hostPort: Int 可选,容器所在主机需要监听的端口号,默认与Container相同 env: # 容器运行前需设置的环境变量列表 - name: String # 环境变量名称 value: String # 环境变量的值 resources: # 资源限制和请求的设置 limits: # 资源限制的设置 cpu: String # Cpu的限制,单位为Core数,将用于docker run --cpu-shares参数,如果整数后跟m,表示占用权重,1Core=1000m memory: String # 内存限制,单位可以为Mib/Gib,将用于docker run --memory参数 requests: # 资源请求的设置 cpu: string # CPU请求,容器启动的初始可用数量 memory: string # 内存请求,容器启动的初始可用数量 livenessProbe: # 对Pod内容器健康检查设置,当探测无响应几次后将自动重启该容器,检查方法有exec、/ui 这个地址,之后会重定向到 /api/v1/proxy/namespaces/kube-system/services/kube-ui/#/dashboard/ 。
如果你发现你无法访问UI,那有可能是Kubernetes UI服务在你的集群上还没有启动。如果是这样,你可以手动开启UI服务:
kubectl create -f cluster/addons/kube-ui/kube-ui-rc.yaml –namespace=kube-system kubectl create -f cluster/addons/kube-ui/kube-ui-svc.yaml –namespace=kube-system
通常,这些应该通过 kube-addons.sh 脚本自动地被运行在主节点上。
七、Kubernetes相关经验 1、Pod的管理在Kubernetes中,所有的容器均在Pod中运行,一个Pod可以承载一个或者多个相关的容器,在后边的案例中,同一个Pod中的容器会部署在同一个物理机器上并且能够共享资源。一个Pod也可以包含O个或者多个磁盘卷组(volumes),这些卷组将会以目录的形式提供给一个容器,或者被所有Pod中的容器共享,对于用户创建的每个Pod,系统会自动选择那个健康并且有足够容量的机器,然后创建类似容器的容器,当容器创建失败的时候,容器会被node agent自动的重启,这个node agent叫kubelet,但是,如果是Pod失败或者机器,它不会自动的转移并且启动,除非用户定义了 replication controller。
用户可以自己创建并管理Pod,Kubernetes将这些操作简化为两个操作:基于相同的Pod配置文件部署多个Pod复制品;创建可替代的Pod当一个Pod挂了或者机器挂了的时候。而Kubernetes API中负责来重新启动,迁移等行为的部分叫做“replication controller”,它根据一个模板生成了一个Pod,然后系统就根据用户的需求创建了许多冗余,这些冗余的Pod组成了一个整个应用,或者服务,或者服务中的一层。一旦一个Pod被创建,系统就会不停的监控Pod的健康情况以及Pod所在主机的健康情况,如果这个Pod因为软件原因挂掉了或者所在的机器挂掉了,replication controller 会自动在一个健康的机器上创建一个一摸一样的Pod,来维持原来的Pod冗余状态不变,一个应用的多个Pod可以共享一个机器。
我们经常需要选中一组Pod,例如,我们要限制一组Pod的某些操作,或者查询某组Pod的状态,作为Kubernetes的基本机制,用户可以给Kubernetes Api中的任何对象贴上一组 key:value 的标签,然后,我们就可以通过标签来选择一组相关的Kubernetes Api 对象,然后去执行一些特定的操作,每个资源额外拥有一组(很多) keys 和 values,然后外部的工具可以使用这些keys和vlues值进行对象的检索,这些Map叫做annotations(注释)。
2、网络配置如何从Internet访问部署的应用?
部署前的服务有一个IP地址,但这个地址仅在Kubernetes集群中可用。这意味着无法通过网络访问该服务!在Google Cloud Engine上运行时,Kubernetes会自动配置一个负载均衡用以访问应用;如果不在Google Cloud Engine上运行(比如我们),那就需要做一些额外的工作来获得负载均衡了。
直接在主机端口上开放服务是一个可行的解决方案(很多人一开始的确是这么做的),但我们发现,这样的做法等于放弃了Kubernetes所提供的许多好处。如果我们依赖主机上的端口,部署多个应用时会遇到端口冲突。另外这样的做法会加大扩展集群和更换主机的难度。
我们发现,解决以上问题的更好办法,是在Kubernetes集群前配置负载均衡器,例如HAProxy或者NGINX。于是我们开始在AWS上的VPN中运行Kubernetes集群,并使用AWS ELB将外部web流量路由到内部HAProxy集群。HAProxy为每个Kubernetes服务配置了“后端”,以便将流量交换到各个pods。
在任何情况下,创建新的Kubernetes服务,我们都需要一种机制动态重新配置负载均衡器(在我们的例子中是HAProxy)。
Kubernetes社区目前正在开发一个名为ingress的功能,用来直接从Kubernetes配置外部负载均衡器。
3、配置负载均衡首先,我们需要一个地方存储负载均衡器配置。负载均衡器配置可以存储在任何地方,不过因为我们已经有etcd可用,就把这些配置放在了etcd里。我们使用一个名为“confd”的工具观察etcd中的配置变动,并用模板生成了一个新的HAProxy配置文件。当一个新的服务添加到Kubernetes,我们向etcd中添加一个新的配置,一个新的HAProxy配置文件也就此产生。
4、资源限制使用Kubernetes时,搞清楚资源限制很重要。你可以在每个pod上配置资源请求和CPU/内存限制,也可以控制资源保证和bursting limits。
这些设置对于高效运行多个容器极为重要,防止容器因分配内存不足而意外停止。
建议尽早设置和测试资源限制。没有限制时,看起来运行良好,不代表把重要负载放到容器中不会出现问题。
当我们快要搭建好Kubernetes时,我们意识到监控和日志在这个新的动态环境中非常重要。当我们面对大规模服务和节点时,进入服务器查看日志文件是不现实的,建一个中心化的日志和监控系统需要尽快提上议程。
6、日志有很多用于日志记录的开源工具,我们使用的是Graylog和Apache Kafka(从容器收集摘录日志的消息传递系统)。容器将日志发送给Kafka,Kafka交给Graylog进行索引。我们让应用组件将日志打给Kafka,方便将日志流式化,成为易于索引的格式。也有一些工具可以从容器外收集日志,然后发送给日志系统。
7、监控Kubernetes具备超强的故障恢复机制,Kubernetes会重启意外停止的pod。我们曾遇到过因内存泄露,导致容器在一天内宕机多次的情况,然而令人惊讶的是,甚至我们自己都没有察觉到。
Kubernetes在这一点上做得非常好,不过一旦问题出现,即使被及时处理了,我们还是想要知道。因此我们使用了一个自定义的运行状况检查仪表盘来监控Kubernetes节点和pod,以及包括数据存储在内的一些服务。可以说在监控方面,Kubernetes API再次证明了其价值所在。
检测负载、吞吐量、应用错误等状态也是同样重要的,有很多开源软件可以满足这一需求。我们的应用组件将指标发布到InfluxDB,并用Heapster去收集Kubernetes的指标。我们还通过Grafana(一款开源仪表盘工具)使存储在InfluxDB中的指标可视化。有很多InfluxDB/Grafana堆栈的替代方案,无论你才用哪一种,对于运行情况的跟踪和监控都是非常有价值的。
8、数据存储和Kubernetes很多Kubernetes新用户都有一个问题:我该如何使用Kubernetes处理数据?
运行数据存储时(如MangoDB或MySQL),我们很可能会有持久化数据储存的需求。不过容器一但重启,所有数据都会丢失,这对于无状态组件没什么影响,但对持久化数据储存显然行不通。好在,Kubernetes具有Volume机制。
Volume可以通过多种方式备份,包括主机文件系统、EBS(AWS的Elastic Block Store)和nfs等。当我们研究持久数据问题是,这是一个很好的方案,但不是我们运行数据存储的答案。
9、副本问题在大多数部署中,数据存储也是有副本的。Mongo通常在副本集中运行,而MySQL可以在主/副模式下运行。我们都知道数据储存集群中的每个节点应该备份在不同的volume中,写入相同volume会导致数据损坏。另外,大多数数据存储需要明确配置才能使集群启动并运行,自动发现和配置节点并不常见。同时,运行着数据存储的机器通常会针对某项工作负载进行调整,例如更高的IOPS。扩展(添加/删除节点)对于数据存储来说,也是一个昂贵的操作,这些都和Kubernetes部署的动态本质不相符。
决定不在生产环境数据存储上使用Kubernetes,以我们的情况,在Kubernetes内运行数据存储没有想象中那么完美,设置起来也比其他Kubernetes部署复杂得多。
于是我们决定不在生产环境数据存储上使用Kubernetes,而是选择在不同的机器上手动启动这些集群,我们在Kubernetes内部运行的应用正常连接到数据存储集群。
所以说,没必要运行Kubernetes的一切,按自身情况与其他工具配合使用,会有意想不到的效果,比如我们的数据存储和HAProxy服务器。
10、未来看看我们现在的部署,可以负责任的说,Kubernetes的表现绝对是梦幻级的,而Kubernetes API更是自动化部署流程的利器。由于不需要处理VM,我们现在的部署相比之前更快、更可靠。更简单的容器测试和交付,也让我们在构建和部署可靠性上得到了巨大提升。
这种新的部署方式迅速高效,让我们得以跟上其他团队的节奏,这绝对是必要的。
11、成本计算任何事情都有两面性。运行Kubernetes,需要一个etcd集群以及一个Master节点,对于较小的部署来说,这一开销还是比较大的,适合通过一些云服务达成。
对于大规模部署,Kubernetes可以帮助节省大量服务器成本,etcd集群和Master节点这点开销就显得微不足道了。Kubernetes让很多容器在一个主机上运行变得非常容易,最大程度上利用了现有资源,减少了服务器数量,成本自然下降了。不过这样的集群也给运维工作提出了更高的要求,必须要的时候,我们可以选择一些云计算平台提供的云服务来轻松达成。

