Skip to content

Latest commit

 

History

History
3989 lines (2973 loc) · 157 KB

k8s-1-8.md

File metadata and controls

3989 lines (2973 loc) · 157 KB

1、 微服务

·单体--巨石架构

·非静态,动态服务发现(服务总线)

·服务编排系统-----(容器编排系统)

image-20191231155945320

1.1康威定律

Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations. - Melvin Conway(1967)

中文直译大概的意思就是:设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。看看下面的图片,再想想Apple的产品、微软的产品设计,就能形象生动的理解这句话。

image-20191231160014976

用通俗的说法就是:组织形式等同系统设计。

1.1.1康威定律详细介绍

Mike从他的角度归纳这篇论文中的其他一些核心观点,如下:

第一定律:Communication dictates design(组织沟通方式会通过系统设计表达出来)

第二定律:There is never enough time to do something right, but there is always enough time to do it over(时间再多一件事情也不可能做的完美,但总有时间做完一件事情)

第三定律:There is a homomorphism from the linear graph of a system to the linear graph of its design organization(线型系统和线型组织架构间有潜在的异质同态特性)     

第四定律: The structures of large systems tend to disintegrate during development, qualitatively more so than with small systems(大的系统组织总是比小系统更倾向于分解)

1.1.2康威定律如何解释微服务的合理性

了解了康威定律是什么,再来看看他如何在半个世纪前就奠定了微服务架构的理论基础。

  • · 人与人的沟通是非常复杂的,一个人的沟通精力是有限的,所以当问题太复杂需要很多人解决的时候,我们需要做拆分组织来达成对沟通效率的管理

  • · 组织内人与人的沟通方式决定了他们参与的系统设计,管理者可以通过不同的拆分方式带来不同的团队间沟通方式,从而影响系统设计

  • · 如果子系统是内聚的,和外部的沟通边界是明确的,能降低沟通成本,对应的设计也会更合理高效

  • · 复杂的系统需要通过容错弹性的方式持续优化,不要指望一个大而全的设计或架构,好的架构和设计都是慢慢迭代出来的

    带来的具体的实践建议是:

  • · 我们要用一切手段提升沟通效率,比如slack,github,wiki。能2个人讲清楚的事情,就不要拉更多人,每个人每个系统都有明确的分工,出了问题知道马上找谁,避免踢皮球的问题。

  • · 通过MVP的方式来设计系统,通过不断的迭代来验证优化,系统应该是弹性设计的。

  • · 你想要什么样的系统设计,就架构什么样的团队,能扁平化就扁平化。最好按业务来划分团队,这样能让团队自然的自治内聚,明确的业务边界会减少和外部的沟通成本,每个小团队都对自己的模块的整个生命周期负责,没有边界不清,没有无效的扯皮,inter-operate, not integrate。

  • · 做小而美的团队,人多会带来沟通的成本,让效率下降。亚马逊的Bezos有个逗趣的比喻,如果2个披萨不够一个团队吃的,那么这个团队就太大了。事实上一般一个互联网公司小产品的团队差不多就是7,8人左右(包含前后端测试交互用研等,可能身兼数职)。

    再对应下衡量微服务的标准,我们很容易会发现他们之间的密切关系:

  • · 分布式服务组成的系统

  • · 按照业务而不是技术来划分组织

  • · 做有生命的产品而不是项目

  • · Smart endpoints and dumb pipes(我的理解是强服务个体和弱通信)

  • · 自动化运维(DevOps)

  • · 容错

  • · 快速演化

1.2微服务要遵循的设计原则

1.2.1微服务应用4个设计原则

image-20191216154225332

1.AKF拆分原则

image-20191231160024972

AKF扩展立方体(参考《The Art of Scalability》),是一个叫AKF的公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统,进行无限扩展。

X 轴 :指的是水平复制,很好理解,就是讲单体系统多运行几个实例,做个集群加负载均衡的模式。

Z 轴 :是基于类似的数据分区,比如一个互联网打车应用突然崩了,用户量激增,集群模式撑不住了,那就按照用户请求的地区进行数据分区,北京、上海、四川等多建几个集群。

Y 轴 :就是我们所说的微服务的拆分模式,就是基于不同的业务拆分。

场景说明:比如打车应用,一个集群撑不住时,分了多个集群,后来用户激增还是不够用,经过分析发现是乘客和车主访问量很大,就将打车应用拆成了三个乘客服务、车主服务、支付服务。三个服务的业务特点各不相同,独立维护,各自都可以再次按需扩展。

2.前后端分离

image-20191231160032781

前后端分离原则,简单来讲就是前端和后端的代码分离也就是技术上做分离,我们推荐的模式是最好直接采用物理分离的方式部署,进一步促使进行更彻底的分离。不要继续以前的服务端模板技术,比如JSP ,把Java JS HTML CSS 都堆到一个页面里,稍复杂的页面就无法维护。这种分离模式的方式有几个好处:

前后端技术分离,可以由各自的专家来对各自的领域进行优化,这样前端的用户体验优化效果会更好。

分离模式下,前后端交互界面更加清晰,就剩下了接口和模型,后端的接口简洁明了,更容易维护。

前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支撑前端的web UI\ 移动App等访问。

3.无状态服务

image-20191231160039266

对于无状态服务,首先说一下什么是状态:如果一个数据需要被多个服务共享,才能完成一笔交易,那么这个数据被称为状态。进而依赖这个“状态”数据的服务被称为有状态服务,反之称为无状态服务。

那么这个无状态服务原则并不是说在微服务架构里就不允许存在状态,表达的真实意思是要把有状态的业务服务改变为无状态的计算类服务,那么状态数据也就相应的迁移到对应的“有状态数据服务”中。

场景说明:例如我们以前在本地内存中建立的数据缓存、Session缓存,到现在的微服务架构中就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不再需要考虑缓存数据如何同步的问题。

4.Restful通信风格

image-20191231160046278

作为一个原则来讲本来应该是个“无状态通信原则”,在这里我们直接推荐一个实践优选的Restful 通信风格 ,因为他有很多好处:

无状态协议HTTP,具备先天优势,扩展能力很强。例如需要安全加密是,有现成的成熟方案HTTPS可用。

JSON 报文序列化,轻量简单,人与机器均可读,学习成本低,搜索引擎友好。

语言无关,各大热门语言都提供成熟的Restful API框架,相对其他的一些RPC框架生态更完善。

当然在有些特殊业务场景下,也需要采用其他的RPC框架,如thrift、avro-rpc、grpc。但绝大多数情况下Restful就足够用了。

1.2.2微服务架构带来的问题

做到了前面讲的四个原则,那么就可以说是构建了一个微服务应用,感觉上也不复杂。但实际上微服务也不是个万金油,也是有利有弊的,接下来我们来看看引入微服务架构后带来的问题有哪些。

image-20191231160053140

依赖服务变更很难跟踪,其他团队的服务接口文档过期怎么办?依赖的服务没有准备好,如何验证我开发的功能。

部分模块重复构建,跨团队、跨系统、跨语言会有很多的重复建设。

微服务放大了分布式架构的系列问题,如分布式事务怎么处理?依赖服务不稳定怎么办?

运维复杂度陡增,如:部署物数量多、监控进程多导致整体运维复杂度提升。

上面这些问题我们应该都遇到过,并且也会有一些解决方案,比如提供文档管理、服务治理、服务模拟的工具和框架; 实现统一认证、统一配置、统一日志框架、分布式汇总分析; 采用全局事务方案、采用异步模拟同步;搭建持续集成平台、统一监控平台等等。

这些解决方案折腾到最后终于搞明白了,原来我们是需要一个微服务应用平台才能整体性的解决这些问题。

2、 Kubernetes 概述

Cloud native apps (云原生)程序在云上创建运行

Faas:函数即服务

2.1 有了docker,为什么要k8s?

Kubernetes一个核心的特点就是能够自主的管理容器来保证云平台中的容器按照用户的期望状态运行着(比如用户想让apache一直运行,用户不需要关心怎么去做,Kubernetes会自动去监控,然后去重启,新建,总之,让apache一直提供服务),管理员可以加载一个微型服务,让规划器来找到合适的位置,同时,Kubernetes也系统提升工具以及人性化方面,让用户能够方便的部署自己的应用(就像canary deployments)。

现在Kubernetes着重于不间断的服务状态(比如web服务器或者缓存服务器)和原生云平台应用(Nosql),在不久的将来会支持各种生产云平台中的各种服务,例如,分批,工作流,以及传统数据库。

2.2 Kubernetes是什么?

Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。

2.3为什么要用Kubernetes?

Docker通过进行可以解决了应用程序打包的根本性难题,他推动了容器技术的快速普及和生产落地;但是单一的容器是毫无意义的,docker本身仅提供托管运用的底层逻辑。要能过管理容器的编排,而k8s却可以

2.4 Kubernetes主要组件

2.1 有了docker,为什么要k8s?

Kubernetes一个核心的特点就是能够自主的管理容器来保证云平台中的容器按照用户的期望状态运行着(比如用户想让apache一直运行,用户不需要关心怎么去做,Kubernetes会自动去监控,然后去重启,新建,总之,让apache一直提供服务),管理员可以加载一个微型服务,让规划器来找到合适的位置,同时,Kubernetes也系统提升工具以及人性化方面,让用户能够方便的部署自己的应用(就像canary deployments)。

现在Kubernetes着重于不间断的服务状态(比如web服务器或者缓存服务器)和原生云平台应用(Nosql),在不久的将来会支持各种生产云平台中的各种服务,例如,分批,工作流,以及传统数据库。

2.2 Kubernetes是什么?

Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。

2.3为什么要用Kubernetes?

Docker通过进行可以解决了应用程序打包的根本性难题,他推动了容器技术的快速普及和生产落地;但是单一的容器是毫无意义的,docker本身仅提供托管运用的底层逻辑。要能过管理容器的编排,而k8s却可以

2.4 Kubernetes主要组件

image-20191216154600253

2.5介绍

2.5 Kubernetes基本概念与术语

主节点(master)---control plane


Master 组件 Master 组件提供集群的管理控制中心。 Master 组件可以在集群中任何节点上运行。但是为了简单起见,通常在一台 VM/机器 上启动所有 Master 组件,并且不会在此 VM/机器上运行用户容器。

kube-apiserver kube-apiserver 用于暴露 Kubernetes API。任何的资源请求/调用操作都是通过 kube-apiserver 提供的接口进行。

ETCD etcd 是 Kubernetes 提供默认的存储系统,保存所有集群数据,使用时需要为 etcd 数 据提高可用。

kube-controller-manager 处理集群中常规后台任务,一个资源对应一个控制器,而 ControllerManager 就是负管理这些控制器的。

kube-scheduler kube-scheduler 调度器,为 Pod 选择一个 Node。

Node 节点 --- worker


节点(Node)组件 节点组件运行在 Node,提供 Kubernetes 运行时环境,以及维护 Pod。

kubelet kubelet 是 Master 在 node 上的代理 Agent,和 docker 引擎通信

kube-proxy kube-proxy 在 node 节点上实现 Pod 网络代理,维护网络规则及四层负载均衡工作。

各个小组件名称简单介绍 后期会详细讲解:


  • Pod

K8s有很多技术概念,同时对应很多API对象,最重要的也是最基础的是微服务Pod。Pod是在K8s集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。Pod对多容器的支持是K8s最基础的设计理念。比如你运行一个操作系统发行版的软件仓库,一个Nginx容器用来发布软件,另一个容器专门用来从源仓库做同步,这两个容器的镜像不太可能是一个团队开发的,但是他们一块儿工作才能提供一个微服务;这种情况下,不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。

Pod是K8s集群中所有业务类型的基础,可以看作运行在K8s集群中的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前K8s中的业务主要可以分为长期伺服型(long-running)、批处理型(batch)、节点后台支撑型(node-daemon)和有状态应用型(stateful application);分别对应的小机器人控制器为Deployment、Job、DaemonSet和PetSet,本文后面会一一介绍。

  • 复制控制器(Replication Controller,RC)

RC是K8s集群中最早的保证Pod高可用的API对象。通过监控运行中的Pod来保证集群中运行指定数目的Pod副本。指定的数目可以是多个也可以是1个;少于指定数目,RC就会启动运行新的Pod副本;多于指定数目,RC就会杀死多余的Pod副本。即使在指定数目为1的情况下,通过RC运行Pod也比直接运行Pod更明智,因为RC也可以发挥它高可用的能力,保证永远有1个Pod在运行。RC是K8s较早期的技术概念,只适用于长期伺服型的业务类型,比如控制小机器人提供高可用的Web服务。

  • 副本集(Replica Set,RS)

RS是新一代RC,提供同样的高可用能力,区别主要在于RS后来居上,能支持更多种类的匹配模式。副本集对象一般不单独使用,而是作为Deployment的理想状态参数使用。

  • 部署(Deployment)

部署表示用户对K8s集群的一次更新操作。部署是一个比RS应用模式更广的API对象,可以是创建一个新的服务,更新一个新的服务,也可以是滚动升级一个服务。滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新RS中副本数增加到理想状态,将旧RS中的副本数减小到0的复合操作;这样一个复合操作用一个RS是不太好描述的,所以用一个更通用的Deployment来描述。以K8s的发展方向,未来对所有长期伺服型的的业务的管理,都会通过Deployment来管理。

  • 服务(Service)

RC、RS和Deployment只是保证了支撑服务的微服务Pod的数量,但是没有解决如何访问这些服务的问题。一个Pod只是一个运行服务的实例,随时可能在一个节点上停止,在另一个节点以一个新的IP启动一个新的Pod,因此不能以确定的IP和端口号提供服务。要稳定地提供服务需要服务发现和负载均衡能力。服务发现完成的工作,是针对客户端访问的服务,找到对应的的后端服务实例。在K8s集群中,客户端需要访问的服务就是Service对象。每个Service会对应一个集群内部有效的虚拟IP,集群内部通过虚拟IP访问一个服务。在K8s集群中微服务的负载均衡是由Kube-proxy实现的。Kube-proxy是K8s集群内部的负载均衡器。它是一个分布式代理服务器,在K8s的每个节点上都有一个;这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的Kube-proxy就越多,高可用节点也随之增多。与之相比,我们平时在服务器端做个反向代理做负载均衡,还要进一步解决反向代理的负载均衡和高可用问题。

  • 任务(Job)

Job是K8s用来控制批处理型任务的API对象。批处理业务与长期伺服业务的主要区别是批处理业务的运行有头有尾,而长期伺服业务在用户不停止的情况下永远运行。Job管理的Pod根据用户的设置把任务成功完成就自动退出了。成功完成的标志根据不同的spec.completions策略而不同:单Pod型任务有一个Pod成功就标志完成;定数成功型任务保证有N个任务全部成功;工作队列型任务根据应用确认的全局成功而标志成功。

  • 后台支撑服务集(DaemonSet)

长期伺服型和批处理型服务的核心在业务应用,可能有些节点运行多个同类业务的Pod,有些节点上又没有这类Pod运行;而后台支撑型服务的核心关注点在K8s集群中的节点(物理机或虚拟机),要保证每个节点上都有一个此类Pod运行。节点可能是所有集群节点也可能是通过nodeSelector选定的一些特定节点。典型的后台支撑型服务包括,存储,日志和监控等在每个节点上支持K8s集群运行的服务。

  • 有状态服务集(PetSet)

K8s在1.3版本里发布了Alpha版的PetSet功能。在云原生应用的体系里,有下面两组近义词;第一组是无状态(stateless)、牲畜(cattle)、无名(nameless)、可丢弃(disposable);第二组是有状态(stateful)、宠物(pet)、有名(having name)、不可丢弃(non-disposable)。RC和RS主要是控制提供无状态服务的,其所控制的Pod的名字是随机设置的,一个Pod出故障了就被丢弃掉,在另一个地方重启一个新的Pod,名字变了、名字和启动在哪儿都不重要,重要的只是Pod总数;而PetSet是用来控制有状态服务,PetSet中的每个Pod的名字都是事先确定的,不能更改。PetSet中Pod的名字的作用,并不是《千与千寻》的人性原因,而是关联与该Pod对应的状态。

对于RC和RS中的Pod,一般不挂载存储或者挂载共享存储,保存的是所有Pod共享的状态,Pod像牲畜一样没有分别(这似乎也确实意味着失去了人性特征);对于PetSet中的Pod,每个Pod挂载自己独立的存储,如果一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续以它的状态提供服务。

适合于PetSet的业务包括数据库服务MySQL和PostgreSQL,集群化管理服务Zookeeper、etcd等有状态服务。PetSet的另一种典型应用场景是作为一种比普通容器更稳定可靠的模拟虚拟机的机制。传统的虚拟机正是一种有状态的宠物,运维人员需要不断地维护它,容器刚开始流行时,我们用容器来模拟虚拟机使用,所有状态都保存在容器里,而这已被证明是非常不安全、不可靠的。使用PetSet,Pod仍然可以通过漂移到不同节点提供高可用,而存储也可以通过外挂的存储来提供高可靠性,PetSet做的只是将确定的Pod与确定的存储关联起来保证状态的连续性。PetSet还只在Alpha阶段,后面的设计如何演变,我们还要继续观察。

  • 集群联邦(Federation)

K8s在1.3版本里发布了beta版的Federation功能。在云计算环境中,服务的作用距离范围从近到远一般可以有:同主机(Host,Node)、跨主机同可用区(Available Zone)、跨可用区同地区(Region)、跨地区同服务商(Cloud Service Provider)、跨云平台。K8s的设计定位是单一集群在同一个地域内,因为同一个地区的网络性能才能满足K8s的调度和计算存储连接要求。而联合集群服务就是为提供跨Region跨服务商K8s集群服务而设计的。

每个K8s Federation有自己的分布式存储、API Server和Controller Manager。用户可以通过Federation的API Server注册该Federation的成员K8s Cluster。当用户通过Federation的API Server创建、更改API对象时,Federation API Server会在自己所有注册的子K8s Cluster都创建一份对应的API对象。在提供业务请求服务时,K8s Federation会先在自己的各个子Cluster之间做负载均衡,而对于发送到某个具体K8s Cluster的业务请求,会依照这个K8s Cluster独立提供服务时一样的调度模式去做K8s Cluster内部的负载均衡。而Cluster之间的负载均衡是通过域名服务的负载均衡来实现的。

所有的设计都尽量不影响K8s Cluster现有的工作机制,这样对于每个子K8s集群来说,并不需要更外层的有一个K8s Federation,也就是意味着所有现有的K8s代码和机制不需要因为Federation功能有任何变化。

  • 存储卷(Volume)

K8s集群中的存储卷跟Docker的存储卷有些类似,只不过Docker的存储卷作用范围为一个容器,而K8s的存储卷的生命周期和作用范围是一个Pod。每个Pod中声明的存储卷由Pod中的所有容器共享。K8s支持非常多的存储卷类型,特别的,支持多种公有云平台的存储,包括AWS,Google和Azure云;支持多种分布式存储包括GlusterFS和Ceph;也支持较容易使用的主机本地目录hostPath和NFS。K8s还支持使用Persistent Volume Claim即PVC这种逻辑存储,使用这种存储,使得存储的使用者可以忽略后台的实际存储技术(例如AWS,Google或GlusterFS和Ceph),而将有关存储实际技术的配置交给存储管理员通过Persistent Volume来配置。

  • 持久存储卷(Persistent Volume,PV)和持久存储卷声明(Persistent Volume Claim,PVC)

PV和PVC使得K8s集群具备了存储的逻辑抽象能力,使得在配置Pod的逻辑里可以忽略对实际后台存储技术的配置,而把这项配置的工作交给PV的配置者,即集群的管理者。存储的PV和PVC的这种关系,跟计算的Node和Pod的关系是非常类似的;PV和Node是资源的提供者,根据集群的基础设施变化而变化,由K8s集群管理员配置;而PVC和Pod是资源的使用者,根据业务服务的需求变化而变化,有K8s集群的使用者即服务的管理员来配置。

  • 密钥对象(Secret)

Secret是用来保存和传递密码、密钥、认证凭证这些敏感信息的对象。使用Secret的好处是可以避免把敏感信息明文写在配置文件里。在K8s集群中配置和使用服务不可避免的要用到各种敏感信息实现登录、认证等功能,例如访问AWS存储的用户名密码。为了避免将类似的敏感信息明文写在所有需要使用的配置文件中,可以将这些信息存入一个Secret对象,而在配置文件中通过Secret对象引用这些敏感信息。这种方式的好处包括:意图明确,避免重复,减少暴漏机会。

  • 用户帐户(User Account)和服务帐户(Service Account)

顾名思义,用户帐户为人提供账户标识,而服务账户为计算机进程和K8s集群中运行的Pod提供账户标识。用户帐户和服务帐户的一个区别是作用范围;用户帐户对应的是人的身份,人的身份与服务的namespace无关,所以用户账户是跨namespace的;而服务帐户对应的是一个运行中程序的身份,与特定namespace是相关的。

  • 名字空间(Namespace)

名字空间为K8s集群提供虚拟的隔离作用,K8s集群初始有两个名字空间,分别是默认名字空间default和系统名字空间kube-system,除此以外,管理员可以可以创建新的名字空间满足需要。

  • RBAC访问授权

K8s在1.3版本中发布了alpha版的基于角色的访问控制(Role-based Access Control,RBAC)的授权模式。相对于基于属性的访问控制(Attribute-based Access Control,ABAC),RBAC主要是引入了角色(Role)和角色绑定(RoleBinding)的抽象概念。在ABAC中,K8s集群中的访问策略只能跟用户直接关联;而在RBAC中,访问策略可以跟某个角色关联,具体的用户在跟一个或多个角色相关联。显然,RBAC像其他新功能一样,每次引入新功能,都会引入新的API对象,从而引入新的概念抽象,而这一新的概念抽象一定会使集群服务管理和使用更容易扩展和重用。

3、 Kubernetes集群安装和部署服务

3.1Kubernetes配置基础环境

由于节点过多 使用基础的ansible配置(ansible不会太难 应该可以看得懂)

ansible的host列表

[k8s-master]
192.168.208.190 ansible_ssh_user=root ansible_ssh_pass='123456'
192.168.208.191 ansible_ssh_user=root ansible_ssh_pass='123456'
192.168.208.192 ansible_ssh_user=root ansible_ssh_pass='123456'

[k8s-worker]
192.168.208.201 ansible_ssh_user=root ansible_ssh_pass='123456'
192.168.208.202 ansible_ssh_user=root ansible_ssh_pass='123456'
192.168.208.203 ansible_ssh_user=root ansible_ssh_pass='123456'
192.168.208.204 ansible_ssh_user=root ansible_ssh_pass='123456'

[volume]
192.168.208.195 ansible_ssh_user=root ansible_ssh_pass='123456'

[all:children]
k8s-master
k8s-worker
volume

[k8s:children]
k8s-master
k8s-worker

虚拟机分配说明

IP地址 主机名 内存&cpu 角色
192.168.208.190 k8s-master1 1C &&2G master
192.168.208.191 k8s-master2 1C &&2G master
192.168.208.192 k8s-master3 1C &&2G master
192.168.208.201 k8s-worker1 2C &&4G worker
192.168.208.202 k8s-worker2 2C &&4G worker
192.168.208.203 k8s-worker3 2C &&4G worker
192.168.208.204 k8s-worker4 2C &&4G worker
192.168.208.195 volume 1C&&2G nfs+harbor
192.168.208.199 ansible 1C && 1G ansible控制
192.168.208.200 vip

借助NTP服务设定各节点的时间精准同步:

[root@ansible ~]# ansible all -m shell -a "systemctl start chronyd &&  systemctl enable chronyd "
[root@ansible ~]# ansible all -m shell -a "systemctl status chronyd" 
验证:
[root@ansible ~]# ansible all -m shell -a "date" 

脚本配置

#!/bin/bash
#关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
#下载基础组件
yum -y install wget vim curl mtr 
#配置阿里云epel源
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
#下载基础组件
yum install -y yum-utils device-mapper-persistent-data lvm2 lrzsz
#配置阿里云docker-ce仓库
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast 
#配置阿里k8s仓库
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

#配置主机名
cat <<EOF > /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.208.190 k8s-master1
192.168.208.191 k8s-master2
192.168.208.192 k8s-master3
192.168.208.195 volumes
192.168.208.199 ansible
192.168.208.200 k8s-vip
192.168.208.201 k8s-worker1
192.168.208.202 k8s-worker2
192.168.208.203 k8s-worker3
192.168.208.204 k8s-worker4

EOF



ansible all -m copy -a "src=/root/1.sh dest=/root"
ansible all -m shell -a "chmod +x 1.sh && ./1.sh"

关闭selinux:

[root@ansible ~]# ansible all -m shell -a "getenforce " 
192.168.208.201 | CHANGED | rc=0 >>
Permissive
192.168.208.191 | CHANGED | rc=0 >>
Permissive
192.168.208.192 | CHANGED | rc=0 >>
Permissive
192.168.208.202 | CHANGED | rc=0 >>
Permissive
192.168.208.190 | CHANGED | rc=0 >>
Permissive
192.168.208.203 | CHANGED | rc=0 >>
Permissive
192.168.208.195 | CHANGED | rc=0 >>
Permissive
192.168.208.204 | CHANGED | rc=0 >>
Permissive

禁用 Swap 设备

kubeadm 默认会预先检当前主机是否禁用了 Swap 设备,并在未用时强制止部署 过程因此,在主机内存资惊充裕的条件下,需要禁用所有的 Swap 设备

[root@ansible ~]# ansible all -m shell -a "swapoff -a && sysctl -w vm.swappiness=0" 

# 编辑 fstab 配置文件,注释掉标识为 Swap 设备的所有行
vi /etc/fstab

image-20191209161746925

2的脚本:

#!/bin/bash
#创建 /etc/sysctl.d/k8s.conf 文件
cat <<EOF > /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
#挂载br_netfilter
modprobe br_netfilter
#生效配置文件
sysctl -p /etc/sysctl.d/k8s.conf
#查看是否生成相关文件
ls /proc/sys/net/bridge
#安装依赖包以及相关工具
yum install -y epel-release yum-utils device-mapper-persistent-data lvm2 net-tools conntrack-tools wget vim  ntpdate libseccomp libtool-ltdl



----
[root@ansible ~]# ansible all -m copy -a "src=/root/2.sh dest=/root"
[root@ansible ~]# ansible all -m shell -a "ls"
[root@ansible ~]# ansible all -m shell -a "chmod +x 2.sh && ./2.sh"

设置docker 国内加速:

[root@ansible ~]# ansible all -m shell -a "curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io "
[root@ansible ~]# ansible all -m shell -a "systemctl daemon-reload  && systemctl restart docker "

[root@ansible ~]# ansible all -m shell -a "sysctl -a |grep bridge"

资源配置文件

/etc/security/limits.conf 是 Linux 资源使用配置文件,用来限制用户对系统资源的使用

   ansible all -m command -a 'echo "* soft nofile 65536" >> /etc/security/limits.conf'
   ansible all -m command -a 'echo "* hard nofile 65536" >> /etc/security/limits.conf'
   ansible all -m command -a 'echo "* soft nproc 65536"  >> /etc/security/limits.conf'
   ansible all -m command -a 'echo "* hard nproc 65536"  >> /etc/security/limits.conf'
   ansible all -m command -a 'echo "* soft  memlock  unlimited"  >> /etc/security/limits.conf'
   ansible all -m command -a 'echo "* hard memlock  unlimited"  >> /etc/security/limits.conf'

3.2安装Kubernetes的不同方式介绍

· minikube

Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用。不能用于生产环境。

官方地址:https://kubernetes.io/docs/setup/minikube/

· kubeadm

Kubeadm也是一个工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。

官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/

· 二进制包

从官方下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。

3.2.1 配置高可用k8s集群:

yum安装Keepalived

ansible k8s-master -m yum -a 'name=keepalived state=installed'

给原来的conf文件做备份: && 并写入新的文件:

cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bk

------------master1---------
cat <<EOF > /etc/keepalived/keepalived.conf
! Configuration File for keepalived

# 主要是配置故障发生时的通知对象以及机器标识。
global_defs {
   # 标识本节点的字条串,通常为 hostname,但不一定非得是 hostname。故障发生时,邮件通知会用到。
   router_id LVS_k8s
}

# 用来做健康检查的,当时检查失败时会将 vrrp_instance 的 priority 减少相应的值。
vrrp_script check_haproxy {
    script "killall -0 haproxy"   #根据进程名称检测进程是否存活
    interval 3
    weight -2
    fall 10
    rise 2
}

# rp_instance用来定义对外提供服务的 VIP 区域及其相关属性。
vrrp_instance VI_1 {
    state MASTER   #当前节点为MASTER,其他两个节点设置为BACKUP
    interface ens192 #改为自己的网卡
    virtual_router_id 51
    priority 250
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 35f18af7190d51c9f7f78f37300a0cbd
    }
    virtual_ipaddress {
        192.168.2.10   #虚拟ip,即VIP
    }
    track_script {
        check_haproxy
    }

}
EOF
----------2个master2 3-----------
cat <<EOF > /etc/keepalived/keepalived.conf
! Configuration File for keepalived

# 主要是配置故障发生时的通知对象以及机器标识。
global_defs {
   # 标识本节点的字条串,通常为 hostname,但不一定非得是 hostname。故障发生时,邮件通知会用到。
   router_id LVS_k8s
}

# 用来做健康检查的,当时检查失败时会将 vrrp_instance 的 priority 减少相应的值。
vrrp_script check_haproxy {
    script "killall -0 haproxy"   #根据进程名称检测进程是否存活
    interval 3
    weight -2
    fall 10
    rise 2
}

# rp_instance用来定义对外提供服务的 VIP 区域及其相关属性。
vrrp_instance VI_1 {
    state BACKUP   #当前节点为MASTER,其他两个节点设置为BACKUP
    interface ens192 #改为自己的网卡
    virtual_router_id 51
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 35f18af7190d51c9f7f78f37300a0cbd
    }
    virtual_ipaddress {
        192.168.2.10   #虚拟ip,即VIP
    }
    track_script {
        check_haproxy
    }

}
EOF

配置说明

  • virtual_ipaddress: vip
  • track_script: 执行上面定义好的检测的script
  • interface: 节点固有IP(非VIP)的网卡,用来发VRRP包。
  • virtual_router_id: 取值在0-255之间,用来区分多个instance的VRRP组播
  • advert_int: 发VRRP包的时间间隔,即多久进行一次master选举(可以认为是健康查检时间间隔)。
  • authentication: 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位)。
  • state: 可以是MASTER或BACKUP,不过当其他节点keepalived启动时会将priority比较大的节点选举为MASTER,因此该项其实没有实质用途。
  • priority: 用来选举master的,要成为master,那么这个选项的值最好高于其他机器50个点,该项取值范围是1-255(在此范围之外会被识别成默认值100)。
启动keepalived:
[root@ansible ~]# ansible k8s-master -m shell -a 'systemctl enable keepalived && systemctl start keepalived'
[root@ansible ~]# ansible k8s-master -m shell -a 'systemctl status keepalived'
[root@ansible ~]# ansible k8s-master -m shell -a 'ip ad'
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:74:66:84 brd ff:ff:ff:ff:ff:ff
    inet 192.168.208.190/24 brd 192.168.208.255 scope global noprefixroute ens192
       valid_lft forever preferred_lft forever
    inet 192.168.208.200/32 scope global ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::b14e:a608:ac52:7f26/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

yum安装haproxy

[root@ansible ~]# ansible k8s-master -m yum -a 'name=haproxy state=installed'
[root@ansible ~]# ansible k8s-master -m shell -a 'cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bk'
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    #    local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
#---------------------------------------------------------------------
# kubernetes apiserver frontend which proxys to the backends
#---------------------------------------------------------------------
frontend kubernetes-apiserver
    mode                 tcp
    bind                 *:16443
    option               tcplog
    default_backend      kubernetes-apiserver
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend kubernetes-apiserver
    mode        tcp
    balance     roundrobin
    server      k8s-master1   192.168.208.190:6443 check
    server      k8s-master2   192.168.208.191:6443 check
    server      k8s-master3   192.168.208.192:6443 check
#---------------------------------------------------------------------
# collection haproxy statistics message
#---------------------------------------------------------------------
listen stats
    bind                 *:1080
    stats auth           admin:awesomePassword
    stats refresh        5s
    stats realm          HAProxy\ Statistics
    stats uri            /admin?stats

haproxy配置在其他master节点上相同
启动并检测haproxy:
   ansible k8s-master -m shell -a 'systemctl enable haproxy && systemctl start haproxy '
   ansible k8s-master -m shell -a 'systemctl status haproxy'
   ansible k8s-master -m shell -a 'ss -lnt | grep -E "16443|1080"'


image-20191209172038666

所有节点安装docker

   ansible all -m shell -a "yum -y install docker-ce "
   ansible all -m shell -a "systemctl start docker && systemctl enable docker"
   ansible all -m shell -a "systemctl status"
   ansible all -m shell -a "systemctl status docker"

修改docker 的bug:
ansible all -m shell -a 'iptables -P FORWARD ACCEPT'

image-20191209172543776

Docker从1.13版本开始调整了默认的防火墙规则,禁用了iptables filter表中FOWARD链,这样会引起Kubernetes集群中跨Node的Pod无法通信。但这里通过安装docker 1806,发现默认策略又改回了ACCEPT,这个不知道是从哪个版本改回的,因为我们线上版本使用的1706还是需要手动调整这个策略的。

安装kubelet

  • 需要在每台机器上都安装以下的软件包:

    • kubeadm: 用来初始化集群的指令。
    • kubelet: 在集群中的每个节点上用来启动 pod 和 container 等。
    • kubectl: 用来与集群通信的命令行工具。
[root@ansible ~]# ansible k8s -m shell -a 'yum install -y kubelet-1.13.4-0'
[root@ansible ~]# ansible k8s -m shell -a 'systemctl enable kubelet && systemctl start kubelet'

检查状态

检查状态,发现是failed状态,正常,kubelet会10秒重启一次,等初始化master节点后即可正常

[root@ansible ~]# ansible k8s -m shell -a 'systemctl status kubelet'

image-20191209174106057

安装kubeadm

yum list kubeadm --showduplicates | sort -r
[root@ansible ~]# ansible k8s -m shell -a 'yum install -y kubeadm-1.13.4-0'
安装 kubeadm 时候会默认安装 kubectl ,所以不需要单独安装kubectl

重启服务器

为了防止发生某些未知错误,这里我们重启下服务器,方便进行后续操作

reboot

初始化第一个kubernetes master节点:

因为做的是高可用 所以绑定的是vip的在的master 以及vip 的域名

[root@k8s-master1 ~]# cat kubeadm-config.yaml 
apiServer:
  certSANs:
    - k8s-master1
    - k8s-master2
    - k8s-master3
    - k8s-vip
    - 192.168.208.190
    - 192.168.208.193
    - 192.168.208.192
    - 192.168.208.200
    - 127.0.0.1
  extraArgs:
    authorization-mode: Node,RBAC
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta1
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: "k8s-vip:16443"
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.13.4
networking:
  dnsDomain: cluster.local
  podSubnet: 10.20.0.0/16
  serviceSubnet: 10.10.0.0/16
scheduler: {}

以下两个地方设置:- certSANs: 虚拟ip地址(为了安全起见,把所有集群地址都加上) - controlPlaneEndpoint: 虚拟IP:监控端口号

配置说明:

  • imageRepository: registry.aliyuncs.com/google_containers (使用阿里云镜像仓库)
  • podSubnet: 10.20.0.0/16 (pod地址池)
  • serviceSubnet: 10.10.0.0/16

初始化第一个master节点:

kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=all --dry-run

--dry-run 干跑 不是真实的运行

Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join master.k8s.io:16443 --token dm3cw1.kw4hq84ie1376hji --discovery-token-ca-cert-hash sha256:f079b624773145ba714b56e177f52143f90f75a1dcebabda6538a49e224d4009

配置环境变量

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

查看组件状态

kubectl get cs
NAME                 STATUS    MESSAGE              ERROR
controller-manager   Healthy   ok
scheduler            Healthy   ok
etcd-0               Healthy   {"health": "true"}

kubectl get pods --namespace=kube-system

image-20191210114507675

可以看到coredns没有启动,这是由于还没有配置网络插件,接下来配置下后再重新查看启动状态

跳3.6

加入集群复制秘钥到各个节点

在master01 服务器上执行下面命令,将kubernetes相关文件复制到 master02、master03

如果其他节点为初始化第一个master节点,则将该节点的配置文件复制到其余两个主节点,例如master03为第一个master节点,则将它的k8s配置复制到master02和master01。

  • 复制文件到 master02
ssh root@k8s-master2 mkdir -p /etc/kubernetes/pki/etcd
scp /etc/kubernetes/admin.conf root@k8s-master2:/etc/kubernetes
scp /etc/kubernetes/pki/{ca.*,sa.*,front-proxy-ca.*} root@k8s-master2:/etc/kubernetes/pki
scp /etc/kubernetes/pki/etcd/ca.* root@k8s-master2:/etc/kubernetes/pki/etcd
  • 复制文件到 master03
ssh root@k8s-master3 mkdir -p /etc/kubernetes/pki/etcd
scp /etc/kubernetes/admin.conf root@k8s-master3:/etc/kubernetes
scp /etc/kubernetes/pki/{ca.*,sa.*,front-proxy-ca.*} root@k8s-master3:/etc/kubernetes/pki
scp /etc/kubernetes/pki/etcd/ca.* root@k8s-master3:/etc/kubernetes/pki/etcd

master02 和 master03 服务器上都执行加入集群操作

kubeadm join master.k8s.io:16443 --token dm3cw1.kw4hq84ie1376hji --discovery-token-ca-cert-hash sha256:f079b624773145ba714b56e177f52143f90f75a1dcebabda6538a49e224d4009 --experimental-control-plane

如果加入失败想重新尝试,请输入 kubeadm reset 命令清除之前的设置,重新执行从“复制秘钥”和“加入集群”这两步

显示安装过程:

This node has joined the cluster and a new control plane instance was created:

* Certificate signing request was sent to apiserver and approval was received.
* The Kubelet was informed of the new secure connection details.
* Master label and taint were applied to the new node.
* The Kubernetes control plane instances scaled up.
* A new etcd member was added to the local/stacked etcd cluster.

To start administering your cluster from this node, you need to run the following as a regular user:

	mkdir -p $HOME/.kube
	sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
	sudo chown $(id -u):$(id -g) $HOME/.kube/config

Run 'kubectl get nodes' to see this node join the cluster.
  • 配置kubectl环境变量
	mkdir -p $HOME/.kube
	sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
	sudo chown $(id -u):$(id -g) $HOME/.kube/config

node节点加入集群

除了让master节点加入集群组成高可用外,slave节点也要加入集群中。

这里将k8s-node-01、k8s-node-02加入集群,进行工作

输入初始化k8s master时候提示的加入命令,如下:

kubeadm join master.k8s.io:16443 --token dm3cw1.kw4hq84ie1376hji --discovery-token

查看各个节点加入集群情况

[root@k8s-master1 ~]# kubectl get nodes -o wide
NAME          STATUS   ROLES    AGE   VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION          CONTAINER-RUNTIME
k8s-master1   Ready    master   50m   v1.13.4   192.168.208.190   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://18.6.1
k8s-master2   Ready    master   43m   v1.13.4   192.168.208.193   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://18.6.1
k8s-master3   Ready    master   41m   v1.13.4   192.168.208.192   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://18.6.1
k8s-worker1   Ready    <none>   38m   v1.13.4   192.168.208.201   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://19.3.5
k8s-worker2   Ready    <none>   38m   v1.13.4   192.168.208.202   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://19.3.5
k8s-worker3   Ready    <none>   38m   v1.13.4   192.168.208.203   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://19.3.5
k8s-worker4   Ready    <none>   38m   v1.13.4   192.168.208.204   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64   docker://19.3.5


3.4使用二进制方式安装kubernetes实战

虚拟机分配说明

IP地址 主机名 内存&cpu 角色
192.168.208.191 k8s-master1 2C&&2G master
192.168.208.192 k8s-master2 2C&&2G master
192.168.208.193 k8s-master3 2C&&2G master
192.168.208.201 k8s-worker1 2C &&4G worker
192.168.208.202 k8s-worker2 2C &&4G worker
192.168.208.203 k8s-worker3 2C &&4G worker
192.168.208.204 k8s-worker4 2C &&4G worker
192.168.208.195 volume 1C&&2G nfs+harbor
192.168.208.199 ansible 1C && 1G ansible控制
192.168.208.200 vip
  • os centos7.6

  • kubernetes 1.16.2

  • etcd 3.4.3

  • docker 18.06

  • calico 3.10.1-2

  • coredns

    配置策略

    kube-apiserver:

    • 使用节点本地 nginx 4 层透明代理实现高可用;
    • 关闭非安全端口 8080 和匿名访问;
    • 在安全端口 6443 接收 https 请求;
    • 严格的认证和授权策略 (x509、token、RBAC);
    • 开启 bootstrap token 认证,支持 kubelet TLS bootstrapping;
    • 使用 https 访问 kubelet、etcd,加密通信;

    kube-controller-manager:

    • 3 节点高可用;
    • 关闭非安全端口 10252,在安全端口 10257 接收 https 请求;
    • 使用 kubeconfig 访问 apiserver 的安全端口;
    • 自动 approve kubelet 证书签名请求 (CSR),证书过期后自动轮转;
    • 各 controller 使用自己的 ServiceAccount 访问 apiserver;

    kube-scheduler:

    • 3 节点高可用;
    • 关闭非安全端口 10251,在安全端口 10259 接收 https 请求;
    • 使用 kubeconfig 访问 apiserver 的安全端口;

    kubelet:

    • 使用 kubeadm 动态创建 bootstrap token,而不是在 apiserver 中静态配置;
    • 使用 TLS bootstrap 机制自动生成 client 和 server 证书,过期后自动轮转;
    • 在 KubeletConfiguration 类型的 JSON 文件配置主要参数;
    • 关闭只读端口 10255,在安全端口 10250 接收 https 请求,对请求进行认证和授权,拒绝匿名访问和非授权访问;
    • 使用 kubeconfig 访问 apiserver 的安全端口;

    kube-proxy:

    • 使用 kubeconfig 访问 apiserver 的安全端口;
    • 在 KubeProxyConfiguration 类型的 JSON 文件配置主要参数;
    • 使用 ipvs 代理模式;

    集群插件:

    • DNS:使用功能、性能更好的 coredns;
    • Dashboard:支持登录认证;
    • Metric:metrics-server,使用 https 访问 kubelet 安全端口;
    • Log:Elasticsearch、Fluend、Kibana;
    • Registry 镜像库:docker-registry、harbor;
# 查看主机名
$ hostname

# 修改主机名
$ hostnamectl set-hostname <your_hostname>

# 配置host,使主节点之间可以通过hostname互相访问
$ vi /etc/hosts
# <node-ip> <node-hostname>
# 更新yum
$ yum update

# 安装依赖包
$ yum install -y conntrack ipvsadm ipset jq sysstat curl iptables libseccomp wget

## 时间同步
$ systemctl start chronyd && systemctl enable chronyd && systemctl status chronyd
# 制作配置文件
$ cat > /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-arptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
EOF

# 生效文件
$ sysctl -p /etc/sysctl.d/kubernetes.conf

#加载内核模块
modprobe ip_vs_rr
modprobe br_netfilter

# 添加 yum 源
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -P /etc/yum.repos.d/

# 清理原有版本
yum remove -y docker* container-selinux

# 安装docker
yum list docker-ce.x86_64  --showduplicates |sort -r
yum install docker-ce-18.06.1.ce -y

# 开机启动
systemctl enable docker

# 配置加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://hdi5v8p1.mirror.aliyuncs.com"]
}
EOF

# 启动docker服务
service docker restart

配置免密登录

为了方便文件的copy我们选择一个中转节点(随便一个节点,可以是集群中的也可以是非集群中的),配置好跟其他所有节点的免密登录,我们这里使用 k8s-m01。

# 看看是否已经存在rsa公钥
$ cat ~/.ssh/id_rsa.pub

# 如果不存在就创建一个新的
$ ssh-keygen -t rsa

# 免密钥认证
$ ssh-copy-id root@<your-server-ip>

官方下载地址(在CHANGELOG链接里面): https://github.com/kubernetes/kubernetes/releases

我们选择的版本是 1.16.2

分发文件
etcd  etcdctl  kubeadm  kube-apiserver  kube-controller-manager  kubectl  kube-scheduler给各个master
kubelet  kube-proxy 给各个worker
# 把文件copy到每个节点上(注意替换自己的文件目录)
$ scp master/* <user>@<master-ip>:/usr/local/bin/
$ scp worker/* <user>@<worker-ip>:/usr/local/bin/

# 给文件添加可执行权限
$ chmod +x /usr/local/bin/*

上一步我们下载了kubernetes各个组件的二进制文件,这些可执行文件的运行也是需要添加很多参数的,包括有的还会依赖一些配置文件。现在我们就把运行它们需要的参数和配置文件都准备好。我这准备了一个项目,专门为大家按照自己的环境生成配置的。它只是帮助大家尽量的减少了机械化的重复工作。它并不会帮你设置系统环境,不会给你安装软件。总之就是会减少你的部署工作量,但不会耽误你对整个系统的认识和把控。

$ cd ~
$ git clone https://github.com/wangzan18/kubernetes-ha-binary.git

# 看看git内容
$ ls -l kubernetes-ha-binary
addons/
configs/
pki/
services/
init.sh
global-configs.properties

addons :kubernetes的插件目录,包括calico、coredns、dashboard等。

configs:这个目录比较 - 凌乱,包含了部署集群过程中用到的杂七杂八的配置文件、脚本文件等。

pki:各个组件的认证授权相关证书配置。

services:所有的kubernetes服务(service)配置文件。

global-configs.properties:全局配置,包含各种易变的配置内容。

init.sh:初始化脚本,配置好global-config之后,会自动生成所有配置文件。

这里会根据大家各自的环境生成kubernetes部署过程需要的配置文件。 在每个节点上都生成一遍,把所有配置都生成好,后面会根据节点类型去使用相关的配置。

# cd到之前下载的git代码目录
$ cd kubernetes-ha-binary

# 编辑属性配置(根据文件注释中的说明填写好每个key-value)
$ vim global-config.properties

# 生成配置文件,确保执行过程没有异常信息
$ ./init.sh

# 查看生成的配置文件,确保脚本执行成功
$ find target/ -type f

CA证书(任意节点)安装cfssl

cfssl是非常好用的CA工具,我们用它来生成证书和秘钥文件 安装过程比较简单,如下:

# 下载
$ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl
$ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssljson

# 修改为可执行权限
$ chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson

# 验证
$ cfssl version
Version: 1.2.0
Revision: dev
Runtime: go1.6

查看证书配置文件,CA 配置文件用于配置根证书的使用场景 (profile) 和具体参数 (usage,过期时间、服务端认证、客户端认证、加密等),后续在签名其它证书时需要指定特定场景。

$ cd target/pki/
$ cat ca-config.json
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }
}
  • signing:表示该证书可用于签名其它证书,生成的 ca.pem 证书中 CA=TRUE
  • server auth:表示 client 可以用该该证书对 server 提供的证书进行验证;
  • client auth:表示 server 可以用该该证书对 client 提供的证书进行验证;
查看证书签名请求文件。
$ cat ca-csr.json 
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "seven"
    }
  ]
}
  • CN:Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name),浏览器使用该字段验证网站是否合法;
  • O:Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group)
  • kube-apiserver 将提取的 User、Group 作为 RBAC 授权的用户标识;

根证书是集群所有节点共享的,只需要创建一个 CA 证书,后续创建的所有证书都由它签名。

# 生成证书和私钥
$ cd target/pki
$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca

# 生成完成后会有以下文件(我们最终想要的就是ca-key.pem和ca.pem,一个秘钥,一个证书)
$ ls
ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem

# 创建目录
$ ssh <user>@<node-ip> "mkdir -p /etc/kubernetes/pki/"

# 分发到每个matser主节点
$ scp ca*.pem <user>@<master-ip>:/etc/kubernetes/pki/

部署etcd集群(master节点)下载etcd,并传到各master节点

$ wget https://github.com/etcd-io/etcd/releases/download/v3.4.3/etcd-v3.4.3-linux-amd64.tar.gz
$ tar xf etcd-v3.4.3-linux-amd64.tar.gz
$ scp etcd-v3.4.3-linux-amd64/etcd* <user>@<master-ip>:/usr/local/bin/

查看证书请求文件。

$ cd target/pki/etcd
$ cat etcd-csr.json
{
  "CN": "etcd",
  "hosts": [
    "127.0.0.1",
    "192.168.208.191",
    "192.168.208.192",
    "192.168.208.193"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "seven"
    }
  ]
}
  • hosts 字段指定授权使用该证书的 etcd 节点 IP 或域名列表,需要将 etcd 集群的三个节点 IP 都列在其中;
# 生成证书、私钥
$ cfssl gencert -ca=../ca.pem \
    -ca-key=../ca-key.pem \
    -config=../ca-config.json \
    -profile=kubernetes etcd-csr.json | cfssljson -bare etcd

# 分发到每个etcd节点(master节点)
$ scp etcd*.pem <user>@<master-ip>:/etc/kubernetes/pki/

创建service文件

# scp配置文件到每个master节点
$ scp target/<node-ip>/services/etcd.service <node-ip>:/etc/systemd/system/

# 创建数据和工作目录
$ ssh <user>@<node-ip> "mkdir -p /var/lib/etcd"

etcd 进程首次启动时会等待其它节点的 etcd 加入集群,命令 systemctl start etcd 会卡住一段时间,为正常现象。

[root@k8s-master1 system]# vi etcd.service 

[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
ExecStart=/usr/local/bin/etcd \
  --data-dir=/var/lib/etcd \
  --name=k8s-master1 \
  --cert-file=/etc/kubernetes/pki/etcd.pem \
  --key-file=/etc/kubernetes/pki/etcd-key.pem \
  --trusted-ca-file=/etc/kubernetes/pki/ca.pem \
  --peer-cert-file=/etc/kubernetes/pki/etcd.pem \
  --peer-key-file=/etc/kubernetes/pki/etcd-key.pem \
  --peer-trusted-ca-file=/etc/kubernetes/pki/ca.pem \
  --peer-client-cert-auth \
  --client-cert-auth \
  --listen-peer-urls=https://192.168.208.191:2380 \
  --initial-advertise-peer-urls=https://192.168.208.191:2380 \
  --listen-client-urls=https://192.168.208.191:2379,http://127.0.0.1:2379 \
  --advertise-client-urls=https://192.168.208.191:2379 \
  --initial-cluster-token=etcd-cluster-0 \
  --initial-cluster=k8s-master1=https://192.168.208.191:2380,k8s-master2=https://192.168.208.192:2380,k8s-master3=https://192.168.208.193:2380 \
  --initial-cluster-state=new
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

#启动服务
$ systemctl daemon-reload && systemctl enable etcd && systemctl restart etcd

#查看状态
$ service etcd status

#查看启动日志
$ journalctl -f -u etcd

#查看服务监听端口
$ netstat -tlnp |grep etcd
  1. 部署api-server(master节点)

3.1 生成证书和私钥

查看证书请求文件。

查看证书请求文件。

$ cd target/pki/apiserver
$ cat kubernetes-csr.json 
{
  "CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
    "192.168.208.191",
    "192.168.208.192",
    "192.168.208.193",
    "192.168.208.200",
    "10.96.0.1",
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "seven"
    }
  ]
}

# 生成证书、私钥
$ cfssl gencert -ca=../ca.pem \
  -ca-key=../ca-key.pem \
  -config=../ca-config.json \
  -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes

# 分发到每个master节点
$ scp kubernetes*.pem <user>@<master-ip>:/etc/kubernetes/pki/

3.2 创建后续访问 metrics-server 使用的证书

创建证书签名请求:

$ cd target/pki/metrics-server
$ cat > proxy-client-csr.json <<EOF
{
  "CN": "aggregator",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "seven"
    }
  ]
}
EOF
  • CN 名称需要位于 kube-apiserver 的 --requestheader-allowed-names 参数中,否则后续访问 metrics 时会提示权限不足。

生成证书和私钥:

$ cfssl gencert -ca=../ca.pem \
  -ca-key=../ca-key.pem  \
  -config=../ca-config.json  \
  -profile=kubernetes proxy-client-csr.json | cfssljson -bare proxy-client

# 分发到每个master节点
$ scp proxy-client*.pem <user>@<master-ip>:/etc/kubernetes/pki/

3.3 创建service文件

# scp配置文件到每个master节点
$ scp target/<node-ip>/services/kube-apiserver.service <user>@<node-ip>:/etc/systemd/system/

# 创建日志目录
$ ssh <user>@<node-ip> "mkdir -p /var/log/kubernetes"

# 复制配置文件
$ scp target/configs/encryption-config.yaml <user>@<master-ip>:/etc/kubernetes/
$ scp target/configs/audit-policy.yaml <user>@<master-ip>:/etc/kubernetes/

3.3 启动服务

[root@k8s-master1 system]# cat kube-apiserver.service 
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
ExecStart=/usr/local/bin/kube-apiserver \
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
  --anonymous-auth=false \
  --advertise-address=192.168.208.191 \
  --bind-address=0.0.0.0 \
  --insecure-port=0 \
  --authorization-mode=Node,RBAC \
  --runtime-config=api/all \
  --enable-bootstrap-token-auth \
  --service-cluster-ip-range=10.96.0.0/12 \
  --service-node-port-range=30000-33000 \
  --tls-cert-file=/etc/kubernetes/pki/kubernetes.pem \
  --tls-private-key-file=/etc/kubernetes/pki/kubernetes-key.pem \
  --client-ca-file=/etc/kubernetes/pki/ca.pem \
  --kubelet-client-certificate=/etc/kubernetes/pki/kubernetes.pem \
  --kubelet-client-key=/etc/kubernetes/pki/kubernetes-key.pem \
  --service-account-key-file=/etc/kubernetes/pki/ca-key.pem \
  --etcd-cafile=/etc/kubernetes/pki/ca.pem \
  --etcd-certfile=/etc/kubernetes/pki/kubernetes.pem \
  --etcd-keyfile=/etc/kubernetes/pki/kubernetes-key.pem \
  --etcd-servers=https://192.168.208.191:2379,https://192.168.208.192:2379,https://192.168.208.193:2379 \
  --enable-swagger-ui=true \
  --allow-privileged=true \
  --apiserver-count=3 \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/var/log/kube-apiserver-audit.log \
  --event-ttl=1h \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target


#启动服务
$ systemctl daemon-reload && systemctl enable kube-apiserver && systemctl restart kube-apiserver

#查看运行状态
$ service kube-apiserver status

#查看日志
$ journalctl -f -u kube-apiserver

#检查监听端口
$ netstat -ntlp|grep kube-apiserver
  1. 部署keepalived - apiserver高可用(master节点)

4.1 安装keepalived

# 在两个主节点上安装keepalived(一主一备),我这里选择 k8s-m01, k8s-m02
$ yum install -y keepalived

4.2 创建keepalived配置文件

# 创建目录
$ ssh <user>@<master-ip> "mkdir -p /etc/keepalived"
$ ssh <user>@<backup-ip> "mkdir -p /etc/keepalived"

# 分发配置文件
$ scp target/configs/keepalived-master.conf <user>@<master-ip>:/etc/keepalived/keepalived.conf
$ scp target/configs/keepalived-backup.conf <user>@<backup-ip>:/etc/keepalived/keepalived.conf

# 分发监测脚本
$ scp target/configs/check-apiserver.sh <user>@<master-ip>:/etc/keepalived/
$ scp target/configs/check-apiserver.sh <user>@<backup-ip>:/etc/keepalived/

4.3 启动keepalived

# 分别在master和backup上启动服务
$ systemctl enable keepalived && service keepalived start

# 检查状态
$ service keepalived status

# 查看日志
$ journalctl -f -u keepalived

# 访问测试
$ curl --insecure https://<master-vip>:6443/
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}
  1. 部署kubectl(任意节点),我选择 k8s-m01

kubectl 是 kubernetes 集群的命令行管理工具,它默认从 ~/.kube/config 文件读取 kube-apiserver 地址、证书、用户名等信息。

5.1 创建 admin 证书和私钥

kubectl 与 apiserver https 安全端口通信,apiserver 对提供的证书进行认证和授权。

kubectl 作为集群的管理工具,需要被授予最高权限。这里创建具有最高权限的 admin 证书。

$ cd target/pki/admin
$ cat admin-csr.json 
{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "system:masters",
      "OU": "seven"
    }
  ]
}
  • O 为 system:masters,kube-apiserver 收到该证书后将请求的 Group 设置为 system:masters;
  • 预定义的 ClusterRoleBinding cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予所有 API的权限;
  • 该证书只会被 kubectl 当做 client 证书使用,所以 hosts 字段为空;
# 创建证书、私钥
$ cfssl gencert -ca=../ca.pem \
  -ca-key=../ca-key.pem \
  -config=../ca-config.json \
  -profile=kubernetes admin-csr.json | cfssljson -bare admin

5.2 创建kubeconfig配置文件

kubeconfig 为 kubectl 的配置文件,包含访问 apiserver 的所有信息,如 apiserver 地址、CA 证书和自身使用的证书

# 设置集群参数
$ kubectl config set-cluster kubernetes \
  --certificate-authority=../ca.pem \
  --embed-certs=true \
  --server=https://<MASTER_VIP>:6443 \
  --kubeconfig=kube.config

# 设置客户端认证参数
$ kubectl config set-credentials admin \
  --client-certificate=admin.pem \
  --client-key=admin-key.pem \
  --embed-certs=true \
  --kubeconfig=kube.config

# 设置上下文参数
$ kubectl config set-context admin@kubernetes \
  --cluster=kubernetes \
  --user=admin \
  --kubeconfig=kube.config

# 设置默认上下文
$ kubectl config use-context admin@kubernetes --kubeconfig=kube.config

# 分发到目标节点
$ scp kube.config <user>@<node-ip>:~/.kube/config
  • --certificate-authority:验证 kube-apiserver 证书的根证书;
  • --client-certificate--client-key:刚生成的 admin 证书和私钥,连接 kube-apiserver 时使用;
  • --embed-certs=true:将 ca.pem 和 admin.pem 证书内容嵌入到生成的 kubectl.kubeconfig 文件中(不加时,写入的是证书文件路径,后续拷贝 kubeconfig 到其它机器时,还需要单独拷贝证书文件,不方便。);

5.3 授予 kubernetes 证书访问 kubelet API 的权限

在执行 kubectl exec、run、logs 等命令时,apiserver 会转发到 kubelet。这里定义 RBAC 规则,授权 apiserver 调用 kubelet API。

$ kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes

5.4 小测试

# 查看集群信息
$ kubectl cluster-info
$ kubectl get all -A
$ kubectl get cs
  1. 部署controller-manager(master节点)

controller-manager启动后将通过竞争选举机制产生一个 leader 节点,其它节点为阻塞状态。当 leader 节点不可用后,剩余节点将再次进行选举产生新的 leader 节点,从而保证服务的可用性。

6.1 创建证书和私钥

查看证书请求。

$ cd target/pki/controller-manager
$ cat controller-manager-csr.json 
{
    "CN": "system:kube-controller-manager",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [
      "127.0.0.1",
      "192.168.208.191",
      "192.168.208.192",
      "192.168.208.193"
    ],
    "names": [
      {
        "C": "CN",
        "ST": "BeiJing",
        "L": "BeiJing",
        "O": "system:kube-controller-manager",
        "OU": "seven"
      }
    ]
}
  • hosts 列表包含所有 kube-controller-manager 节点 IP;
  • CN 和 O 均为 system:kube-controller-manager,kubernetes 内置的 ClusterRoleBindingssystem:kube-controller-manager 赋予 kube-controller-manager 工作所需的权限。
# 生成证书、私钥
$ cfssl gencert -ca=../ca.pem \
  -ca-key=../ca-key.pem \
  -config=../ca-config.json \
  -profile=kubernetes controller-manager-csr.json | cfssljson -bare controller-manager

# 分发到每个master节点
$ scp controller-manager*.pem <user>@<node-ip>:/etc/kubernetes/pki/

6.2 创建controller-manager的kubeconfig

# 创建kubeconfig
$ kubectl config set-cluster kubernetes \
  --certificate-authority=../ca.pem \
  --embed-certs=true \
  --server=https://<MASTER_VIP>:6443 \
  --kubeconfig=controller-manager.kubeconfig

$ kubectl config set-credentials system:kube-controller-manager \
  --client-certificate=controller-manager.pem \
  --client-key=controller-manager-key.pem \
  --embed-certs=true \
  --kubeconfig=controller-manager.kubeconfig

$ kubectl config set-context system:kube-controller-manager@kubernetes \
  --cluster=kubernetes \
  --user=system:kube-controller-manager \
  --kubeconfig=controller-manager.kubeconfig

$ kubectl config use-context system:kube-controller-manager@kubernetes --kubeconfig=controller-manager.kubeconfig

# 分发controller-manager.kubeconfig
$ scp controller-manager.kubeconfig <user>@<node-ip>:/etc/kubernetes/

6.3 创建service文件

# scp配置文件到每个master节点
$ scp target/<node-ip>/services/kube-controller-manager.service <user>@<node-ip>:/etc/systemd/system/

6.4 启动服务

[root@k8s-master1 system]# cat kube-controller-manager.service 
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \
  --port=0 \
  --secure-port=10252 \
  --bind-address=127.0.0.1 \
  --kubeconfig=/etc/kubernetes/controller-manager.kubeconfig \
  --service-cluster-ip-range=10.96.0.0/12 \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file=/etc/kubernetes/pki/ca.pem \
  --cluster-signing-key-file=/etc/kubernetes/pki/ca-key.pem \
  --allocate-node-cidrs=true \
  --cluster-cidr=10.244.0.0/16 \
  --experimental-cluster-signing-duration=8760h \
  --root-ca-file=/etc/kubernetes/pki/ca.pem \
  --service-account-private-key-file=/etc/kubernetes/pki/ca-key.pem \
  --leader-elect=true \
  --feature-gates=RotateKubeletServerCertificate=true \
  --controllers=*,bootstrapsigner,tokencleaner \
  --horizontal-pod-autoscaler-use-rest-clients=true \
  --horizontal-pod-autoscaler-sync-period=10s \
  --tls-cert-file=/etc/kubernetes/pki/controller-manager.pem \
  --tls-private-key-file=/etc/kubernetes/pki/controller-manager-key.pem \
  --use-service-account-credentials=true \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

# 启动服务
$ systemctl daemon-reload && systemctl enable kube-controller-manager && systemctl restart kube-controller-manager

# 检查状态
$ service kube-controller-manager status

# 查看日志
$ journalctl -f -u kube-controller-manager

# 查看leader
$ kubectl get endpoints kube-controller-manager --namespace=kube-system -o yaml
  1. 部署scheduler(master节点)

scheduler启动后将通过竞争选举机制产生一个 leader 节点,其它节点为阻塞状态。当 leader 节点不可用后,剩余节点将再次进行选举产生新的 leader 节点,从而保证服务的可用性。

7.1 创建证书和私钥

查看证书请求文件。

$ cd target/pki/scheduler
$ cat scheduler-csr.json 
{
    "CN": "system:kube-scheduler",
    "hosts": [
      "127.0.0.1",
      "192.168.208.191",
      "192.168.208.192",
      "192.168.208.193"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
      {
        "C": "CN",
        "ST": "BeiJing",
        "L": "BeiJing",
        "O": "system:kube-scheduler",
        "OU": "seven"
      }
    ]
}
  • hosts 列表包含所有 kube-scheduler 节点 IP;
  • CN 和 O 均为 system:kube-scheduler,kubernetes 内置的 ClusterRoleBindings system:kube-scheduler 将赋予 kube-scheduler 工作所需的权限;
# 生成证书、私钥
$ cfssl gencert -ca=../ca.pem \
  -ca-key=../ca-key.pem \
  -config=../ca-config.json \
  -profile=kubernetes scheduler-csr.json | cfssljson -bare kube-scheduler

# 分发到每个master节点
$ scp kube-scheduler*.pem <user>@<node-ip>:/etc/kubernetes/pki/

7.2 创建scheduler的kubeconfig

# 创建kubeconfig
$ kubectl config set-cluster kubernetes \
  --certificate-authority=../ca.pem \
  --embed-certs=true \
  --server=https://<MASTER_VIP>:6443 \
  --kubeconfig=kube-scheduler.kubeconfig

$ kubectl config set-credentials system:kube-scheduler \
  --client-certificate=kube-scheduler.pem \
  --client-key=kube-scheduler-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-scheduler.kubeconfig

$ kubectl config set-context system:kube-scheduler@kubernetes \
  --cluster=kubernetes \
  --user=system:kube-scheduler \
  --kubeconfig=kube-scheduler.kubeconfig

$ kubectl config use-context system:kube-scheduler@kubernetes --kubeconfig=kube-scheduler.kubeconfig

# 分发kubeconfig
$ scp kube-scheduler.kubeconfig <user>@<node-ip>:/etc/kubernetes/

7.3 创建service文件

# scp配置文件到每个master节点
$ scp target/<node-ip>/services/kube-scheduler.service <user>@<node-ip>:/etc/systemd/system/
$ scp target/<node-ip>/configs/kube-scheduler.config.yaml <user>@<node-ip>:/etc/kubernetes/

7.4 启动服务

[root@k8s-master1 system]# cat kube-controller-manager.service 
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \
  --port=0 \
  --secure-port=10252 \
  --bind-address=127.0.0.1 \
  --kubeconfig=/etc/kubernetes/controller-manager.kubeconfig \
  --service-cluster-ip-range=10.96.0.0/12 \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file=/etc/kubernetes/pki/ca.pem \
  --cluster-signing-key-file=/etc/kubernetes/pki/ca-key.pem \
  --allocate-node-cidrs=true \
  --cluster-cidr=10.244.0.0/16 \
  --experimental-cluster-signing-duration=8760h \
  --root-ca-file=/etc/kubernetes/pki/ca.pem \
  --service-account-private-key-file=/etc/kubernetes/pki/ca-key.pem \
  --leader-elect=true \
  --feature-gates=RotateKubeletServerCertificate=true \
  --controllers=*,bootstrapsigner,tokencleaner \
  --horizontal-pod-autoscaler-use-rest-clients=true \
  --horizontal-pod-autoscaler-sync-period=10s \
  --tls-cert-file=/etc/kubernetes/pki/controller-manager.pem \
  --tls-private-key-file=/etc/kubernetes/pki/controller-manager-key.pem \
  --use-service-account-credentials=true \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
[root@k8s-master1 system]# cat kube-scheduler.service 
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \
  --address=127.0.0.1 \
  --kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \
  --leader-elect=true \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

# 启动服务
$ systemctl daemon-reload && systemctl enable kube-scheduler && systemctl restart kube-scheduler

# 检查状态
$ service kube-scheduler status

# 查看日志
$ journalctl -f -u kube-scheduler

# 查看leader
$ kubectl get endpoints kube-scheduler --namespace=kube-system -o yaml
  1. 部署kubelet(worker节点)

8.1 创建bootstrap配置文件

# 创建 token
$ cd target/pki/admin
$ export BOOTSTRAP_TOKEN=$(kubeadm token create \
      --description kubelet-bootstrap-token \
      --groups system:bootstrappers:worker \
      --kubeconfig kube.config)

# 设置集群参数
$ kubectl config set-cluster kubernetes \
      --certificate-authority=../ca.pem \
      --embed-certs=true \
      --server=https://<MASTER_VIP>:6443 \
      --kubeconfig=kubelet-bootstrap.kubeconfig

# 设置客户端认证参数
$ kubectl config set-credentials kubelet-bootstrap \
      --token=${BOOTSTRAP_TOKEN} \
      --kubeconfig=kubelet-bootstrap.kubeconfig

# 设置上下文参数
$ kubectl config set-context kubelet@kubernetes \
      --cluster=kubernetes \
      --user=kubelet-bootstrap \
      --kubeconfig=kubelet-bootstrap.kubeconfig

# 设置默认上下文
$ kubectl config use-context kubelet@kubernetes --kubeconfig=kubelet-bootstrap.kubeconfig

# 把生成的配置copy到每个worker节点上
$ scp kubelet-bootstrap.kubeconfig <user>@<node-ip>:/etc/kubernetes/kubelet-bootstrap.kubeconfig

# 把ca分发到每个worker节点
$ scp target/pki/ca.pem <user>@<node-ip>:/etc/kubernetes/pki/

# 查看生成的 token
$ kubeadm token list --kubeconfig ~/.kube/config
  • 向 kubeconfig 写入的是 token,bootstrap 结束后 kube-controller-manager 为 kubelet 创建 client 和 server 证书;
  • token 有效期为 1 天,超期后将不能再被用来 boostrap kubelet,且会被 kube-controller-manager 的 tokencleaner 清理;
  • kube-apiserver 接收 kubelet 的 bootstrap token 后,将请求的 user 设置为 system:bootstrap:<Token ID>,group 设置为 system:bootstrappers,后续将为这个 group 设置 ClusterRoleBinding;

8.2 kubelet配置文件

把kubelet配置文件分发到每个worker节点上

$ scp target/worker-<node-ip>/kubelet.config.json <user>@<node-ip>:/etc/kubernetes/
cat kubelet.config.json 
{
  "kind": "KubeletConfiguration",
  "apiVersion": "kubelet.config.k8s.io/v1beta1",
  "authentication": {
    "x509": {
      "clientCAFile": "/etc/kubernetes/pki/ca.pem"
    },
    "webhook": {
      "enabled": true,
      "cacheTTL": "2m0s"
    },
    "anonymous": {
      "enabled": false
    }
  },
  "authorization": {
    "mode": "Webhook",
    "webhook": {
      "cacheAuthorizedTTL": "5m0s",
      "cacheUnauthorizedTTL": "30s"
    }
  },
  "address": "xxxxxxxx",
  "staticPodPath": "",
  "port": 10250,
  "readOnlyPort": 10255,
  "cgroupDriver": "cgroupfs",
  "hairpinMode": "promiscuous-bridge",
  "serializeImagePulls": false,
  "featureGates": {
    "RotateKubeletClientCertificate": true,
    "RotateKubeletServerCertificate": true
  },
  "clusterDomain": "cluster.local.",
  "clusterDNS": ["10.96.0.2"]
}
  • authentication.anonymous.enabled:设置为 false,不允许匿名访问 10250 端口;
  • authentication.x509.clientCAFile:指定签名客户端证书的 CA 证书,开启 HTTPs 证书认证;
  • authentication.webhook.enabled=true:开启 HTTPs bearer token 认证;

同时配置了如下授权参数:

  • authroization.mode=Webhook:开启 RBAC 授权;

kubelet 收到请求后,使用 clientCAFile 对证书签名进行认证,或者查询 bearer token 是否有效。如果两者都没通过,则拒绝请求,提示 Unauthorized:

8.3 kubelet服务文件

把kubelet服务文件分发到每个worker节点上

$ scp target/worker-<node-ip>/kubelet.service <user>@<node-ip>:/etc/systemd/system/

8.4 启动服务

kublet 启动时查找配置的 --kubeletconfig 文件是否存在,如果不存在则使用 --bootstrap-kubeconfig 向 kube-apiserver 发送证书签名请求 (CSR)。 kube-apiserver 收到 CSR 请求后,对其中的 Token 进行认证(事先使用 kubeadm 创建的 token),认证通过后将请求的 user 设置为 system:bootstrap:,group 设置为 system:bootstrappers,这就是Bootstrap Token Auth。

# bootstrap附权
$ kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers

# 启动服务
$ mkdir -p /var/lib/kubelet
$ mkdir -p /var/log/kubernetes
$ systemctl daemon-reload && systemctl enable kubelet && systemctl restart kubelet

# 在master上Approve bootstrap请求
$ kubectl get csr
$ kubectl certificate approve <name> 

[root@k8s-worker4 system]# cat kubelet.service 
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/local/bin/kubelet \
  --bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \
  --cert-dir=/etc/kubernetes/pki \
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \
  --config=/etc/kubernetes/kubelet.config.json \
  --network-plugin=cni \
  --pod-infra-container-image=k8s.gcr.io/pause-amd64:3.1 \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target


# 查看服务状态
$ service kubelet status

# 查看日志
$ journalctl -f -u kubelet
  • kubelet 启动后使用 --bootstrap-kubeconfig 向 kube-apiserver 发送 CSR 请求,当这个 CSR 被 approve 后,kube-controller-manager 为 kubelet 创建 TLS 客户端证书、私钥和 --kubeletconfig 文件。
  • 注意:kube-controller-manager 需要配置 --cluster-signing-cert-file 和 --cluster-signing-key-file 参数,才会为 TLS Bootstrap 创建证书和私钥。
  1. 部署kube-proxy(worker节点)

9.1 创建证书和私钥

查看证书请求文件。

$ cd target/pki/proxy
cat kube-proxy-csr.json 
{
  "CN": "system:kube-proxy",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "seven"
    }
  ]
}
  • CN:指定该证书的 User 为 system:kube-proxy
  • 预定义的 RoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限;
  • 该证书只会被 kube-proxy 当做 client 证书使用,所以 hosts 字段为空;
$ cfssl gencert -ca=../ca.pem \
  -ca-key=../ca-key.pem \
  -config=../ca-config.json \
  -profile=kubernetes  kube-proxy-csr.json | cfssljson -bare kube-proxy

9.2 创建和分发 kubeconfig 文件

# 创建kube-proxy.kubeconfig
$ kubectl config set-cluster kubernetes \
  --certificate-authority=../ca.pem \
  --embed-certs=true \
  --server=https://<master-vip>:6443 \
  --kubeconfig=kube-proxy.kubeconfig

$ kubectl config set-credentials kube-proxy \
  --client-certificate=kube-proxy.pem \
  --client-key=kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig

$ kubectl config set-context kube-proxy@kubernetes \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig

$ kubectl config use-context kube-proxy@kubernetes --kubeconfig=kube-proxy.kubeconfig

# 分发kube-proxy.kubeconfig 到 node 节点
$ scp kube-proxy.kubeconfig <user>@<node-ip>:/etc/kubernetes/

9.3 分发kube-proxy.config

$ scp target/worker-<node-ip>/kube-proxy.config.yaml <user>@<node-ip>:/etc/kubernetes/

9.4 分发kube-proxy服务文件

$ scp target/services/kube-proxy.service <user>@<node-ip>:/etc/systemd/system/

9.5 启动服务

[root@k8s-worker4 system]# cat kubelet.service 
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/local/bin/kubelet \
  --bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \
  --cert-dir=/etc/kubernetes/pki \
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \
  --config=/etc/kubernetes/kubelet.config.json \
  --network-plugin=cni \
  --pod-infra-container-image=k8s.gcr.io/pause-amd64:3.1 \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
[root@k8s-worker4 system]# cat kube-proxy.service 
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart=/usr/local/bin/kube-proxy \
  --config=/etc/kubernetes/kube-proxy.config.yaml \
  --alsologtostderr=true \
  --logtostderr=false \
  --log-dir=/var/log/kubernetes \
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

# 创建依赖目录
$ mkdir -p /var/lib/kube-proxy

# 启动服务
$ systemctl daemon-reload && systemctl enable kube-proxy && systemctl restart kube-proxy

# 查看状态
$ service kube-proxy status

# 查看日志
$ journalctl -f -u kube-proxy

目前是 iptables 模式,使用 ipvs 模式可以修改文件 kube-proxy.config.yaml 我这里遇到的一个问题是 iptables 版本过低,如果遇到,可以编译安装使用新版本。

  1. 部署CNI插件 - calico

我们使用calico官方的安装方式来部署。

# 创建目录(在配置了kubectl的节点上执行)
$ mkdir -p /etc/kubernetes/addons

# 上传calico配置到配置好kubectl的节点(一个节点即可)
$ scp target/addons/calico.yaml <user>@<node-ip>:/etc/kubernetes/addons/

# 部署calico
$ kubectl apply -f /etc/kubernetes/addons/calico.yaml

# 查看状态
$ kubectl get pods -n kube-system

https://docs.projectcalico.org/v3.10/getting-started/kubernetes/

  1. 部署DNS插件 - coredns
# 上传配置文件
$ scp target/addons/coredns.yaml <user>@<node-ip>:/etc/kubernetes/addons/

# 部署coredns
$ kubectl apply -f /etc/kubernetes/addons/coredns.yaml

https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base

四、集群可用性测试

  1. 创建nginx ds
 # 写入配置
$ cat > nginx-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: nginx-ds
  labels:
    app: nginx-ds
spec:
  type: NodePort
  selector:
    app: nginx-ds
  ports:
  - name: http
    port: 80
    targetPort: 80
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ds
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
spec:
  template:
    metadata:
      labels:
        app: nginx-ds
    spec:
      containers:
      - name: my-nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
  selector:
    matchLabels:
      app: nginx-ds
EOF

# 创建ds
$ kubectl apply -f nginx-ds.yml
  1. 检查各种ip连通性
# 检查各 Node 上的 Pod IP 连通性(主节点没有calico所以不能访问podip)
$ kubectl get pods -o wide

# 在每个worker节点上ping pod ip
$ ping <pod-ip>

# 检查service可达性
$ kubectl get svc

# 在每个worker节点上访问服务(主节点没有proxy所以不能访问service-ip)
$ curl <service-ip>:<port>

# 在每个节点检查node-port可用性
$ curl <node-ip>:<port>
  1. 检查dns可用性
# 创建一个nginx pod
$ cat > pod-nginx.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.7.9
    ports:
    - containerPort: 80
EOF

# 创建pod
$ kubectl apply -f pod-nginx.yaml

# 进入pod,查看dns
$ kubectl exec nginx -it -- /bin/bash

# 查看dns配置
root@nginx:/# cat /etc/resolv.conf

# 查看名字是否可以正确解析
root@nginx:/# ping nginx-ds
root@nginx:/# ping kubernetes

五. 部署dashboard

跳3.6.1

  1. 访问dashboard

为了集群安全,从 1.7 开始,dashboard 只允许通过 https访问,我们使用nodeport的方式暴露服务,可以使用 https://NodeIP:NodePort 地址访问。

关于自定义证书

默认dashboard的证书是自动生成的,肯定是非安全的证书,如果大家有域名和对应的安全证书可以自己替换掉。使用安全的域名方式访问dashboard。 在dashboard-all.yaml中增加dashboard启动参数,可以指定证书文件,其中证书文件是通过secret注进来的。

--tls-cert-file=dashboard.cer --tls-key-file=dashboard.key

  1. 登录dashboard

Dashboard 默认只支持 token 认证,所以如果使用 KubeConfig 文件,需要在该文件中指定 token,我们这里使用token的方式登录

# 创建service account
$ kubectl create sa dashboard-admin -n kube-system

# 创建角色绑定关系
$ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin

# 查看dashboard-admin的secret名字
$ ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}')

# 打印secret的token
$ kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}'

部署 metrics-server

metrics-server 通过 kube-apiserver 发现所有节点,然后调用 kubelet APIs(通过 https 接口)获得各节点(Node)和 Pod 的 CPU、Memory 等资源使用情况。

从 Kubernetes 1.12 开始,kubernetes 的安装脚本移除了 Heapster,从 1.13 开始完全移除了对 Heapster 的支持,Heapster 不再被维护。

  1. 安装 metrics-server
$ cd target/addons
$ git clone https://github.com/kubernetes-incubator/metrics-server.git
$ cd metrics-server/deploy/1.8+/

修改metrics-server-deployment.yaml文件,把 metrics-server 修改为如下命令行参数:

      containers:
      - name: metrics-server
        image: wangzan18/metrics-server-amd64:v0.3.6
        args:
          - --cert-dir=/tmp
          - --secure-port=4443
          - --metric-resolution=30s
          - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
  • --metric-resolution=30s:从 kubelet 采集数据的周期;
  • --kubelet-preferred-address-types:优先使用 InternalIP 来访问 kubelet,这样可以避免节点名称没有 DNS 解析记录时,通过节点名称调用节点 kubelet API 失败的情况(未配置时默认的情况);
  1. 部署
$ cd target/addons/metrics-server/deploy/1.8+/
$ kubectl apply -f .

3.5通过Kubernetes部署应用服务

3.6 常用的插件部署:flannel、dashboard

3.6.1 配置flannel的插件

cat > kube-flannel.yaml << EOF
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
rules:
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes/status
    verbs:
      - patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: flannel
  namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
  labels:
    tier: node
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.20.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-amd64
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      hostNetwork: true
      nodeSelector:
        beta.kubernetes.io/arch: amd64
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni
        image: registry.cn-shenzhen.aliyuncs.com/cp_m/flannel:v0.10.0-amd64
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: registry.cn-shenzhen.aliyuncs.com/cp_m/flannel:v0.10.0-amd64
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: true
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg
EOF

“Network”: “10.20.0.0/16”要和kubeadm-config.yaml配置文件中podSubnet: 10.20.0.0/16相同 可以自己定义 但是必须要一致

创建flanner相关role和pod

kubectl apply -f kube-flannel.yaml

等待一会时间,再次查看各个pods的状态

kubectl get pods --namespace=kube-system

3.6.2 配置dashboard

这个在一个服务器上部署,其他服务器会复制这个部署的pod,所以这里在master01服务器上部署 dashboard

# ------------------- Dashboard Secret ------------------- #
apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-certs
  namespace: kube-system
type: Opaque

---
# ------------------- Dashboard Service Account ------------------- #

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system

---
# ------------------- Dashboard Role & Role Binding ------------------- #

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: kubernetes-dashboard-minimal
  namespace: kube-system
rules:
  # Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret.
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["create"]
  # Allow Dashboard to create 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["create"]
  # Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"]
  verbs: ["get", "update", "delete"]
  # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["kubernetes-dashboard-settings"]
  verbs: ["get", "update"]
  # Allow Dashboard to get metrics from heapster.
- apiGroups: [""]
  resources: ["services"]
  resourceNames: ["heapster"]
  verbs: ["proxy"]
- apiGroups: [""]
  resources: ["services/proxy"]
  resourceNames: ["heapster", "http:heapster:", "https:heapster:"]
  verbs: ["get"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: kubernetes-dashboard-minimal
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kubernetes-dashboard-minimal
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system

---

# ------------------- Dashboard Deployment ------------------- #
# 1.修改了镜像仓库位置,编辑成自己的镜像仓库
# 2.变更了镜像拉去策略imagePullPolicy: IfNotPresent
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: kubernetes-dashboard
  template:
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
    spec:
      containers:
      - name: kubernetes-dashboard
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/kubernetes-dashboard-amd64:v1.10.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8443
          protocol: TCP
        args:
          - --auto-generate-certificates
          # Uncomment the following line to manually specify Kubernetes API server Host
          # If not specified, Dashboard will attempt to auto discover the API server and connect
          # to it. Uncomment only if the default does not work.
          # - --apiserver-host=http://my-address:port
        volumeMounts:
        - name: kubernetes-dashboard-certs
          mountPath: /certs
          # Create on-disk volume to store exec logs
        - mountPath: /tmp
          name: tmp-volume
        livenessProbe:
          httpGet:
            scheme: HTTPS
            path: /
            port: 8443
          initialDelaySeconds: 30
          timeoutSeconds: 30
      volumes:
      - name: kubernetes-dashboard-certs
        secret:
          secretName: kubernetes-dashboard-certs
      - name: tmp-volume
        emptyDir: {}
      serviceAccountName: kubernetes-dashboard
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
---
# ------------------- Dashboard Service ------------------- #
# 增加了nodePort,使得能够访问,改变默认的type类型ClusterIP,变为NodePort
# 如果不配置的话默认只能集群内访问
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30001
  selector:
    k8s-app: kubernetes-dashboard
    
    
 -----
 kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: admin
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: admin
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin
  namespace: kube-system
  labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile

运行进入就好

3.6.1 配置dashboard部署

官方文档:https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/

仪表板是基于Web的Kubernetes用户界面。您可以使用仪表板将容器化的应用程序部署到Kubernetes集群,对容器化的应用程序进行故障排除以及管理集群资源。您可以使用Dashboard来概述集群上运行的应用程序,以及创建或修改单个Kubernetes资源(例如Deployments,Jobs,DaemonSets等)。例如,您可以使用部署向导来扩展部署,启动滚动更新,重新启动Pod或部署新应用程序。

仪表板还提供有关集群中Kubernetes资源状态以及可能发生的任何错误的信息。

(注意 不同版本的k8s 请在GitHub上对应版本不同版本之间兼容性不同)

[root@k8s-master1 ~]# kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml
namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created

kubectl get pods -nkubernetes-dashboard -o wide
NAME                                         READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
dashboard-metrics-scraper-566cddb686-kbk7t   1/1     Running   0          87s   10.244.2.3   k8s-node2   <none>           <none>
kubernetes-dashboard-7b5bf5d559-jz8vp        1/1     Running   0          94s   10.244.1.3   k8s-node1   <none>           <none>




[root@k8s-master1 ~]# kubectl proxy
Starting to serve on 127.0.0.1:8001

如果本地有图像界面(linux)上 可以访问:

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/.

若没有的话 请暴露端口 NodePort:在集群外部访问

没设置之前为:
[root@k8s-master1 yaml]# kubectl get svc -n kubernetes-dashboard -o wide
NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE     SELECTOR
dashboard-metrics-scraper   ClusterIP   10.96.166.124   <none>        8000/TCP   9m13s   k8s-app=dashboard-metrics-scraper
kubernetes-dashboard        ClusterIP   10.104.156.18   <none>        443/TCP    9m22s   k8s-app=kubernetes-dashboard
设定之后:
[root@k8s-master1 yaml]# kubectl patch svc kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}' -n kubernetes-dashboard
service/kubernetes-dashboard patched
(使用打补丁的方式)
[root@k8s-master1 yaml]# kubectl get svc -n kubernetes-dashboard -o wide
NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE   SELECTOR
dashboard-metrics-scraper   ClusterIP   10.96.166.124   <none>        8000/TCP        11m   k8s-app=dashboard-metrics-scraper
kubernetes-dashboard        NodePort    10.104.156.18   <none>        443:30457/TCP   11m   k8s-app=kubernetes-dashboard


查看你的tokens:

[root@k8s-master1 pki]# kubectl get secret -n kubernetes-dashboard
NAME                               TYPE                                  DATA   AGE
default-token-5phn6                kubernetes.io/service-account-token   3      32m
gomo-dashboard-admin-token-dscjb   kubernetes.io/service-account-token   3      13m
gomo-dashboard-cert                Opaque                                2      22m
kubernetes-dashboard-certs         Opaque                                0      32m
kubernetes-dashboard-csrf          Opaque                                1      32m
kubernetes-dashboard-key-holder    Opaque                                2      32m
kubernetes-dashboard-token-m72lj   kubernetes.io/service-account-token   3      32m
[root@k8s-master1 pki]# kubectl describe secret kubernetes-dashboard-token-m72lj -n kubernetes-dashboard
Name:         kubernetes-dashboard-token-m72lj
Namespace:    kubernetes-dashboard
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: kubernetes-dashboard
              kubernetes.io/service-account.uid: c93fb35c-abb8-4935-a981-e89f08b0e2f7

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  20 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6ImVrdFBjUkFQS0lpSU9hNUhUWUJzeGtNbEhVRk5Udkw5LVJCVE1MQmRTM0EifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC10b2tlbi1tNzJsaiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImM5M2ZiMzVjLWFiYjgtNDkzNS1hOTgxLWU4OWYwOGIwZTJmNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDprdWJlcm5ldGVzLWRhc2hib2FyZCJ9.FvKgO-kh0a7b9G56pF4fF3Cbg6x0j4F2XeBtoIqQ78I4j8lwQ41C3E4Z8WqM6ze3GW9QwC18dSAc4LVUKv7ROWnkIE8J73CTp-OrHs42I-Q-whD7CNeD9I-OKgfoyyrNZZ9eWmNQywrmz6mxiBVHG6BNw4ZxOnt03xCdEaZMcON4L3OS_Wfd1vt9U_0_VtxAeYkUB0aENwdPSwydCnJ3m3zMesG3KJVLK4KkcpFqMzhvYVYCFa_dR94Cmd5_97sBppAsjJ87L7-wM0t9sDSlImkeGhQ45M_U2k5BYE4s5xXhov4owugNHCPShEFO0ePo3Tb_KN3KdUyMHx4tnt8ZlA

image-20191213141959470

4、 Kubernetes 架构

4.1 Kubernetes设计理念

分层架构

Kubernetes设计理念和功能其实就是一个类似Linux的分层架构,如下图所示

图片 - 分层架构示意图

img

核心层:Kubernetes最核心的功能,对外提供API构建高层的应用,对内提供插件式应用执行环境

应用层:部署(无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS解析等)

管理层:系统度量(如基础设施、容器和网络的度量),自动化(如自动扩展、动态Provision等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy等)

接口层:kubectl命令行工具、客户端SDK以及集群联邦

生态系统:在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴

Kubernetes外部:日志、监控、配置管理、CI、CD、Workflow、FaaS、OTS应用、ChatOps等

Kubernetes内部:CRI、CNI、CVI、镜像仓库、Cloud Provider、集群自身的配置和管理等

4.2 ETCD解析

开放接口:

Kubernetes作为云原生应用的的基础调度平台,相当于云原生的操作系统,为了便于系统的扩展,Kubernetes中开放的以下接口,可以分别对接不同的后端,来实现自己的业务逻辑:(4.3 4.4 4.5)

4.2.1ETCD概念

ETCD是一种高可用的键值对类型的数据库,提供可靠的分布式的状态存储,可以配置多节点群集,群集之间做数据同步来保证数据可靠性,当一台因为故障挂点,会从剩余的节点通过选举算法选举出一个几点来代替故障节点,从而实现高可用性。(因此在生产环境中 1个master配置一个1etcd,同时master 数量为奇数 一般为3台+)

4.2.2****ETCD与Kubernetes的关系****

ETCD为Kubernetes提供了可靠的数据存储机制,和基于watch机制的订阅发布机制,实现了核心数据的存储,和核心的基于watch-list的informer机制,当ETCD数据变化通过watch机制触发相应的核心操作,如pod创建,deployment构建等 。

在分布式系统中,最为适用的组件间通信的方式是消息发布和订阅机制。当应用在启动的时候主动从ETCD中拉取一次完整的列表信息,并在ETCD节点上注册一个watcher,以后每次列表中的数据有变化,ETCD都会实时通知订阅者,订阅者就可以获取最新的数据并且利用这些数据和行为(增删改)作为参数执行相应的预定义方法。Kubernetes核心的基于watch-list的informer机制就是基于ETCD的订阅机制实现的。

4.2.3ETCD的主要功能

基本的key-value存储

监听机制

key的过期及续约机制,用于监控和服务发现

原子CAS和CAD,用于分布式锁和leader选举

参考链接:https://www.cnblogs.com/wlbl/p/10694261.html

4.3 CRI

我们都知道Kubernetes不会直接和容器打交道,Kubernetes的使用者能接触到的概念只有pod,而pod里包含了多个容器。当我们在Kubernetes里用kubectl执行各种命令时,Kubernetes工作节点如何悄悄地为我们生成底层的容器呢?

这一切是通过Kubernetes工作节点里所谓“容器运行时”的软件在起作用。大家最熟悉的容器运行时软件当然是Docker,然而Docker只是Kubernetes支持的容器运行时技术的一种。

为了让Kubernetes不和某种特定的容器运行时技术绑死,而是能无需重新编译源代码就能够支持多种容器运行时技术的替换,和我们面向对象设计中引入接口作为抽象层一样,在Kubernetes和容器运行时之间我们引入了一个抽象层,即容器运行时接口。

在CRI还没有问世的Kubernetes早期版本里,比如1.3版本里,添加了对另一个容器运行时技术rkt的支持,即rktnetes项目。这个项目虽然让Kubernetes增加了除Docker之外的另一种容器运行时的支持,然而这种增强的实现方式是通过直接修改kubelet实现源代码进行的,需要贡献者非常熟悉kubelet内部原理,开发门槛较高。

为了实现一个真正支持可插拔替换的容器运行时的机制,Kubernetes引入了CRI的概念。

有了CRI后,kubelet不再直接和容器运行时交互,而是通过CRI这个中间层。

image-20191216155748037

4.4 CNI

一直以来,kubernetes 并没有专门的网络模块负责网络配置,它需要用户在主机上已经配置好网络。

kubernetes 对网络的要求是:

容器之间(包括同一台主机上的容器,和不同主机的容器)可以互相通信

容器和集群中所有的节点也能直接通信

kubernetes 网络的发展方向是希望通过插件的方式来集成不同的网络方案, CNI 就是这一努力的结果。CNI只专注解决容器网络连接和容器销毁时的资源释放,提供一套框架,所以CNI可以支持大量不同的网络模式,并且容易实现。

Flannel

链接:https://github.com/coreos/flannel

由CoreOS开发的项目Flannel,可能是最直接和最受欢迎的CNI插件。它是容器编排系统中最成熟的网络结构示例之一,旨在实现更好的容器间和主机间网络。随着CNI概念的兴起,Flannel CNI插件算是早期的入门。

与其他方案相比,Flannel相对容易安装和配置。它被打包为单个二进制文件flanneld,许多常见的Kubernetes集群部署工具和许多Kubernetes发行版都可以默认安装Flannel。Flannel可以使用Kubernetes集群的现有etcd集群来使用API存储其状态信息,因此不需要专用的数据存储。

Flannel配置第3层IPv4 overlay网络。它会创建一个大型内部网络,跨越集群中每个节点。在此overlay网络中,每个节点都有一个子网,用于在内部分配IP地址。在配置pod时,每个节点上的Docker桥接口都会为每个新容器分配一个地址。同一主机中的Pod可以使用Docker桥接进行通信,而不同主机上的pod会使用flanneld将其流量封装在UDP数据包中,以便路由到适当的目标。

Flannel有几种不同类型的后端可用于封装和路由。默认和推荐的方法是使用VXLAN,因为VXLAN性能更良好并且需要的手动干预更少。

总的来说,Flannel是大多数用户的不错选择。从管理角度来看,它提供了一个简单的网络模型,用户只需要一些基础知识,就可以设置适合大多数用例的环境。一般来说,在初期使用Flannel是一个稳妥安全的选择,直到你开始需要一些它无法提供的东西。

Calico

链接:https://github.com/projectcalico/cni-plugin

Calico是Kubernetes生态系统中另一种流行的网络选择。虽然Flannel被公认为是最简单的选择,但Calico以其性能、灵活性而闻名。Calico的功能更为全面,不仅提供主机和pod之间的网络连接,还涉及网络安全和管理。Calico CNI插件在CNI框架内封装了Calico的功能。

在满足系统要求的新配置的Kubernetes集群上,用户可以通过应用单个manifest文件快速部署Calico。如果您对Calico的可选网络策略功能感兴趣,可以向集群应用其他manifest,来启用这些功能。

尽管部署Calico所需的操作看起来相当简单,但它创建的网络环境同时具有简单和复杂的属性。与Flannel不同,Calico不使用overlay网络。相反,Calico配置第3层网络,该网络使用BGP路由协议在主机之间路由数据包。这意味着在主机之间移动时,不需要将数据包包装在额外的封装层中。BGP路由机制可以本地引导数据包,而无需额外在流量层中打包流量。

除了性能优势之外,在出现网络问题时,用户还可以用更常规的方法进行故障排除。虽然使用VXLAN等技术进行封装也是一个不错的解决方案,但该过程处理数据包的方式同场难以追踪。使用Calico,标准调试工具可以访问与简单环境中相同的信息,从而使更多开发人员和管理员更容易理解行为。

除了网络连接外,Calico还以其先进的网络功能而闻名。 网络策略是其最受追捧的功能之一。此外,Calico还可以与服务网格Istio集成,以便在服务网格层和网络基础架构层中解释和实施集群内工作负载的策略。这意味着用户可以配置强大的规则,描述pod应如何发送和接受流量,提高安全性并控制网络环境。

如果对你的环境而言,支持网络策略是非常重要的一点,而且你对其他性能和功能也有需求,那么Calico会是一个理想的选择。此外,如果您现在或未来有可能希望得到技术支持,那么Calico是提供商业支持的。一般来说,当您希望能够长期控制网络,而不是仅仅配置一次并忘记它时,Calico是一个很好的选择。

Canal

链接:https://github.com/projectcalico/canal

Canal也是一个有趣的选择,原因有很多。

首先,Canal 是一个项目的名称,它试图将Flannel提供的网络层与Calico的网络策略功能集成在一起。然而,当贡献者完成细节工作时却发现,很明显,如果Flannel和Calico这两个项目的标准化和灵活性都已各自确保了话,那集成也就没那么大必要了。结果,这个官方项目变得有些“烂尾”了,不过却实现了将两种技术部署在一起的预期能力。出于这个原因,即使这个项目不复存在,业界还是会习惯性地将Flannel和Calico的组成称为“Canal”。

由于Canal是Flannel和Calico的组合,因此它的优点也在于这两种技术的交叉。网络层用的是Flannel提供的简单overlay,可以在许多不同的部署环境中运行且无需额外的配置。在网络策略方面,Calico强大的网络规则评估,为基础网络提供了更多补充,从而提供了更多的安全性和控制。

确保集群满足必要的系统要求(https://docs.projectcalico.org/v3.6/getting-started/kubernetes/requirements)后,用户需要应用两个manifest才能部署Canal,这使得其配置比单独的任何一个项目都困难。如果企业的IT团队计划改变他们的网络方案,且希望在实施改变之前能先对网络策略进行一些实验并获取一些经验,那么Canal是一个不错的选择。

一般来说,如果你喜欢Flannel提供的网络模型,但发现Calico的一些功能很诱人,那么不妨尝试一下Canal。从安全角度来看,定义网络策略规则的能力是一个巨大的优势,并且在许多方面是Calico的杀手级功能。能够将该技术应用到熟悉的网络层,意味着您可以获得更强大的环境,且可以省掉大部分的过渡过程。

Weave

链接:https://www.weave.works/oss/net/

Weave是由Weaveworks提供的一种Kubernetes CNI网络选项,它提供的模式和我们目前为止讨论的所有网络方案都不同。Weave在集群中的每个节点之间创建网状overlay网络,参与者之间可以灵活路由。这一特性再结合其他一些独特的功能,在某些可能导致问题的情况下,Weave可以智能地路由。

为了创建网络,Weave依赖于网络中每台主机上安装的路由组件。然后,这些路由器交换拓扑信息,以维护可用网络环境的最新视图。当需要将流量发送到位于不同节点上的pod时,Weave路由组件会自动决定是通过“快速数据路径”发送,还是回退到“sleeve”分组转发的方法。

快速数据路径依靠内核的本机Open vSwitch数据路径模块,将数据包转发到适当的pod,而无需多次移入和移出用户空间。Weave路由器会更新Open vSwitch配置,以确保内核层具有有关如何路由传入数据包的准确信息。相反,当网络拓扑不适合快速数据路径路由时,sleeve模式可用作备份。它是一种较慢的封装模式,在快速数据路径缺少必要的路由信息或连接的情况下,它可以来路由数据包。当流量通过路由器时,它们会了解哪些对等体与哪些MAC地址相关联,从而允许它们以更少的跳数、更智能地路由后续流量。当网络更改导致可用路由改变时,这一相同的机制可以帮助每个节点进行自行更正。

与Calico一样,Weave也为Kubernetes集群提供网络策略功能。设置Weave时,网络策略会自动安装和配置,因此除了添加网络规则之外,用户无需进行其他配置。一个其他网络方案都没有、Weave独有的功能,是对整个网络的简单加密。虽然这会增加相当多的网络开销,但Weave可以使用NaCl加密(http://nacl.cr.yp.to)来为sleeve流量自动加密所有路由流量,而对于快速数据路径流量,因为它需要加密内核中的VXLAN流量,Weave会使用IPsec ESP来加密快速数据路径流量。

对于那些寻求功能丰富的网络、同时希望不要增加大量复杂性或管理难度的人来说,Weave是一个很好的选择。它设置起来相对容易,提供了许多内置和自动配置的功能,并且可以在其他解决方案可能出现故障的场景下提供智能路由。网状拓扑结构确实会限制可以合理容纳的网络的大小,不过对于大多数用户来说,这也不是一个大问题。此外,Weave也提供收费的技术支持,可以为企业用户提供故障排除等等技术服务。

*结 语*

Kubernetes采用的CNI标准,让Kubernetes生态系统中的网络解决方案百花齐放。更多样的选择,意味着大多数用户将能够找到适合其当前需求和部署环境的CNI插件,同时还可以在环境发生变化时也能找到新的解决方案。

不同企业之间的运营要求差异很大,因此拥有一系列具有不同复杂程度和功能丰富性的成熟解决方案,大大有助于Kubernetes在满足不同用户独特需求的前提下,仍然能够提供一致的用户体验。

4.5 CSI

详细讲解:https://www.codercto.com/a/59711.html

以上三种资源相当于一个分布式操作系统的最基础的几种资源类型,而Kuberentes是将他们粘合在一起的纽带。

img

5、 Kubernetes API

5.1了解 Kubernetes 的 API

对于云计算系统,系统API实际上处于系统设计的统领地位,正如本文前面所说,K8s集群系统每支持一项新功能,引入一项新技术,一定会新引入对应的API对象,支持对该功能的管理操作,理解掌握的API,就好比抓住了K8s系统的牛鼻子。K8s系统API的设计有以下几条原则:

1. *所有API应该是声明式的*。正如前文所说,声明式的操作,相对于命令式操作,对于重复操作的效果是稳定的,这对于容易出现数据丢失或重复的分布式环境来说是很重要的。另外,声明式操作更容易被用户使用,可以使系统向用户隐藏实现的细节,隐藏实现的细节的同时,也就保留了系统未来持续优化的可能性。此外,声明式的API,同时隐含了所有的API对象都是名词性质的,例如Service、Volume这些API都是名词,这些名词描述了用户所期望得到的一个目标分布式对象。

2. *API对象是彼此互补而且可组合的*。这里面实际是鼓励API对象尽量实现面向对象设计时的要求,即“高内聚,松耦合”,对业务相关的概念有一个合适的分解,提高分解出来的对象的可重用性。事实上,K8s这种分布式系统管理平台,也是一种业务系统,只不过它的业务就是调度和管理容器服务。

3. *高层API以操作意图为基础设计*。如何能够设计好API,跟如何能用面向对象的方法设计好应用系统有相通的地方,高层设计一定是从业务出发,而不是过早的从技术实现出发。因此,针对K8s的高层API设计,一定是以K8s的业务为基础出发,也就是以系统调度管理容器的操作意图为基础设计。

4. *低层API根据高层API的控制需要设计*。设计实现低层API的目的,是为了被高层API使用,考虑减少冗余、提高重用性的目的,低层API的设计也要以需求为基础,要尽量抵抗受技术实现影响的诱惑。

  1. 尽量避免简单封装 ,不要有在外部API无法显式知道的内部隐藏的机制。简单的封装,实际没有提供新的功能,反而增加了对所封装API的依赖性。内部隐藏的机制也是非常不利于系统维护的设计方式,例如PetSet和ReplicaSet,本来就是两种Pod集合,那么K8s就用不同API对象来定义它们,而不会说只用同一个ReplicaSet,内部通过特殊的算法再来区分这个ReplicaSet是有状态的还是无状态。

6. *API操作复杂度与对象数量成正比*。这一条主要是从系统性能角度考虑,要保证整个系统随着系统规模的扩大,性能不会迅速变慢到无法使用,那么最低的限定就是API的操作复杂度不能超过O(N),N是对象的数量,否则系统就不具备水平伸缩性了。

7. *API对象状态不能依赖于网络连接状态*。由于众所周知,在分布式环境下,网络连接断开是经常发生的事情,因此要保证API对象状态能应对网络的不稳定,API对象的状态就不能依赖于网络连接状态。

8. *尽量避免让操作机制依赖于全局状态*,因为在分布式系统中要保证全局状态的同步是非常困难的。

5.2kubectl工具的使用

5.2.1 kubectl 常用命令及使用技巧

Basic Commands (Beginner):
  create         Create a resource from a file or from stdin.
  expose         Take a replication controller, service, deployment or pod and expose it as a new
Kubernetes Service
  run            Run a particular image on the cluster
  set            Set specific features on objects

Basic Commands (Intermediate):
  explain        Documentation of resources
  get            Display one or many resources
  edit           Edit a resource on the server
  delete         Delete resources by filenames, stdin, resources and names, or by resources and
label selector

Deploy Commands:
  rollout        Manage the rollout of a resource
  scale          Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job
  autoscale      Auto-scale a Deployment, ReplicaSet, or ReplicationController

Cluster Management Commands:
  certificate    Modify certificate resources.
  cluster-info   Display cluster info
  top            Display Resource (CPU/Memory/Storage) usage.
  cordon         Mark node as unschedulable
  uncordon       Mark node as schedulable
  drain          Drain node in preparation for maintenance
  taint          Update the taints on one or more nodes

Troubleshooting and Debugging Commands:
  describe       Show details of a specific resource or group of resources
  logs           Print the logs for a container in a pod
  attach         Attach to a running container
  exec           Execute a command in a container
  port-forward   Forward one or more local ports to a pod
  proxy          Run a proxy to the Kubernetes API server
  cp             Copy files and directories to and from containers.
  auth           Inspect authorization

Advanced Commands:
  diff           Diff live version against would-be applied version
  apply          Apply a configuration to a resource by filename or stdin
  patch          Update field(s) of a resource using strategic merge patch
  replace        Replace a resource by filename or stdin
  wait           Experimental: Wait for a specific condition on one or many resources.
  convert        Convert config files between different API versions
  kustomize      Build a kustomization target from a directory or a remote url.

Settings Commands:
  label          Update the labels on a resource
  annotate       Update the annotations on a resource
  completion     Output shell completion code for the specified shell (bash or zsh)

Other Commands:
  api-resources  Print the supported API resources on the server
  api-versions   Print the supported API versions on the server, in the form of "group/version"
  config         Modify kubeconfig files
  plugin         Provides utilities for interacting with plugins.
  version        Print the client and server version information

Usage:
  kubectl [flags] [options]



主要常用命令:
获取pods 的大致信息
[root@k8s-master3 ~]# kubectl get pods 
NAME                                       READY   STATUS    RESTARTS   AGE
gomoci-jenkins-558b487c79-j8mkq            1/1     Running   7          5d22h
kissing-stingray-tomcat-6cf9d966bf-srmlm   1/1     Running   8          12d


获取pods的详细信息
[root@k8s-master3 ~]# kubectl get pods -o wide
NAME                                       READY   STATUS    RESTARTS   AGE     IP           NODE          NOMINATED NODE   READINESS GATES
gomoci-jenkins-558b487c79-j8mkq            1/1     Running   7          5d22h   10.20.4.65   k8s-worker2   <none>           <none>
kissing-stingray-tomcat-6cf9d966bf-srmlm   1/1     Running   8          12d     10.20.5.53   k8s-worker3   <none>           <none>


获取的pods的动态信息:
[root@k8s-master3 ~]# kubectl get pods -w
NAME                                       READY   STATUS    RESTARTS   AGE
gomoci-jenkins-558b487c79-j8mkq            1/1     Running   7          5d22h
kissing-stingray-tomcat-6cf9d966bf-srmlm   1/1     Running   8          12d

Ctrl+C 可以退出

查看 pods 的具体信息:
[root@k8s-master3 ~]# kubectl describe pods kissing-stingray-tomcat-6cf9d966bf-srmlm

查看pod的日志
[root@k8s-master3 ~]# kubectl logs kissing-stingray-tomcat-6cf9d966bf-srmlm


删除pods
[root@k8s-master3 ~]# kubectl delete pods kissing-stingray-tomcat-6cf9d966bf-srmlm

将pods换成各种资源 如node svc pv pvc ns ......都是一样的

Kubectl run :

Examples:
  # Start a single instance of nginx.
  kubectl run nginx --image=nginx
  
  # Start a single instance of hazelcast and let the container expose port 5701 .
  kubectl run hazelcast --image=hazelcast --port=5701
  
  # Start a single instance of hazelcast and set environment variables "DNS_DOMAIN=cluster" and
"POD_NAMESPACE=default" in the container.
  kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"
  
  # Start a single instance of hazelcast and set labels "app=hazelcast" and "env=prod" in the
container.
  kubectl run hazelcast --image=hazelcast --labels="app=hazelcast,env=prod"
  
  # Start a replicated instance of nginx.
  kubectl run nginx --image=nginx --replicas=5
  
  # Dry run. Print the corresponding API objects without creating them.
  kubectl run nginx --image=nginx --dry-run
  
  # Start a single instance of nginx, but overload the spec of the deployment with a partial set of
values parsed from JSON.
  kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
  
  # Start a pod of busybox and keep it in the foreground, don't restart it if it exits.
  kubectl run -i -t busybox --image=busybox --restart=Never
  
  # Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for
that command.
  kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>
  
  # Start the nginx container using a different command and custom arguments.
  kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
  
  # Start the perl container to compute π to 2000 places and print it out.
  kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'print bpi(2000)'
  
  # Start the cron job to compute π to 2000 places and print it out every 5 minutes.
  kubectl run pi --schedule="0/5 * * * ?" --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle

5.2.2 kubectl 工具管理应用程序

查看pod的详细信息(将pod的换成各种类型的资源 都可以)
[root@k8s-master3 ~]# kubectl describe pod gomoci-jenkins-558b487c79-j8mkq

查看pod 的标签(将pod的换成各种类型的资源 都可以)
[root@k8s-master3 ~]# kubectl get pods --show-labels

查看pod的的具体信息(将pod的换成各种类型的资源 都可以)
[root@k8s-master3 ~]# kubectl get pods -o wide

// 查看Events事件
kubectl describe pod名称  

// 通过deploy查看事件
kubectl describe deploy/nginx 

//查看发布具体信息
kubectl describe svc name名称

//查看日志
kubectl logs  pod名称

//进入容器排查
kubectl exec -it pod名称 bash


更新镜像升级
//把当前nginx:1.10版本更新至1.11
[root@master ~]# kubectl set image deployments/nginx nginx=nginx:1.11

or

kubectl edit deploy/nginx  编辑里面的镜像版本号保存退出
查看发布状态
// 布署资源的状态
kubectl rollout status deploy/nginx

// 发布的历史版本
kubectl rollout history deploy/nginx



回滚
复制代码
//回退到上一个退版
kubectl rollout undo deploy/nginx   默认回滚到上一个版本

//查看状态
kubectl  rollout status deploy/nginx

//回到指定版本
kubectl rollout undo deploy/nginx --to-revision=4
pod副本扩容

// 把当前的pod扩容到5个
kubectl scale deploy/nginx --replicas=5

缩减也是上述命令
删除
复制代码
// 删除pod
kubectl delete deployment.extensions/nginx

//删除service
kubectl delete service/nginx-service

//查看
kubectl get all
kubectl get deploy

5.2.3 kubectl 工具远程连接K8S集群

https://blog.csdn.net/sinat_35930259/article/details/79994078

5.3Kubernetes中API之外的其他资源

详情请看2.5篇章

6、资源编排(YAML)

Apiserver仅接收json格式的资源定义;

Yaml 格式提供配置了清单,apiserver可自动将其转为json格式,然后提交。

查看当前k8s版本所支持的api(V1.16)
[root@k8s-master3 ~]# kubectl api-versions
admissionregistration.k8s.io/v1
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1
authentication.k8s.io/v1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1
authorization.k8s.io/v1beta1
autoscaling/v1
autoscaling/v2beta1
autoscaling/v2beta2
batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
coordination.k8s.io/v1
coordination.k8s.io/v1beta1
events.k8s.io/v1beta1
extensions/v1beta1
networking.k8s.io/v1
networking.k8s.io/v1beta1
node.k8s.io/v1beta1
policy/v1beta1
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1
scheduling.k8s.io/v1
scheduling.k8s.io/v1beta1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1

6.1 yaml文件格式说明

apiVsrsion: group/version    
 Kind: 资源类型
 Metada:元数据
Name: 实例名称唯一
Namespace : 属于哪个名称空间
Labels:  标签键值
Annotations: 注解
Spec: 期望状态
Status:当前状态

PS: kubectl explain XXX来查看各种注释含义及用法

其他的用法在后面慢慢展示

7、 集群资源管理

7.1Node节点管理

node是kubernetes集群中的工作节点,可以是虚拟机也可以是物理机。node节点上运行一些服务用来运行pod以及与master通信等。一个node上的服务包括docker运行时环境、kubelet、kube-proxy以及其它一些可选的add-ons。

  • Node的扩缩容:

在实际生产系统中经常遇到服务器容量不足的情况,这时候就需要购买新的服务器,对应用系统进行水平扩展以实现扩容。 在k8s中,对一个新的node的加入非常简单,只需要在node节点上安装docker、kubelet和kube-proxy服务,然后将kubelet和kube-proxy的启动参数中的master url指定为当前kubernetes集群master的地址,然后启动服务即可。基于kubelet的自动注册机制,新的node会自动加入现有的kubernetes集群中(请看kubernetes安装章节加载node)

  • 删除node节点

kubectl delete node k8s-node1

  • Node的隔离与恢复

1通过yaml 文件来实现:
Cat unschedule_node.yml:
apiVersion: v1
kind: Node
metadata:
  name: k8s-node1
  labels:
    namne: k8s-node1
spec:
  unschedulable: true
kubectl replace -f unschedule_node.yml

通过命令行来实现:(patch 打补丁)
kubectl patch node k8s-node1 -p '{"spec":"{"unschedulable":"true"}"}'
恢复

无论上面哪一种方法,其实都是将unsechdulable的值改为true,实现 了隔离,同理,恢复时,只需要将unschedulable的值改为false即可。

当然这里还有另一种更简单的方式:
kubectl cordon k8s-node1    #将k8s-node1节点设置为不可调度模式
kubectl drain k8s-node1     #将当前运行在k8s-node1节点上的容器驱离
kubectl uncordon k8s-node1  #执行完维护后,将节点重新加入调度

7.2Namespace介绍和管理

  • 什么是名称空间?

您可以将名称空间看作Kubernetes集群中的虚拟集群。在一个Kubernetes集群中可以有多个名称空间,并且它们在逻辑上彼此隔离。它们可以在组织、安全性甚至性能方面帮助您和您的团队!

  • "默认"命名空间概念

在大多数Kubernetes发行版中,集群都有一个名为“default”的名称空间。实际上,Kubernetes附带了三个名称空间:default、kube-system(用于Kubernetes组件)和kube-public(用于公共资源)。kube-public目前并不常用,通常最好不要使用kube-system,尤其是在谷歌Kubernetes引擎这样的托管系统中。这使得默认名称空间成为创建服务和应用程序的地方。这个名称空间没有什么特别之处,除了Kubernetes工具是开箱即用来使用这个名称空间的,您不能删除它。虽然它对于入门和小型生产系统非常有用,但我建议不要在大型生产系统中使用它。这是因为团队很容易在没有意识到的情况下意外地覆盖或中断另一个服务。相反,创建多个名称空间并使用它们将服务划分为可管理的块。

  • 创建名称空间
命令行的方式:
[root@k8s-master3 yaml]# kubectl create ns gomo
namespace/gomo created


Yml文件的方式:
cat test.yaml:
apiVersion: v1
kind: Namespace
metadata:
  name: gomo
  labels:
    name: gomo
kubectl apply -f test.yaml

查看namespace命令

[root@k8s-master3 yaml]# kubectl get ns
NAME                   STATUS   AGE
default                Active   15d
efk                    Active   13d
gitlab                 Active   2d21h
gomo                   Active   2m47s
kube-node-lease        Active   15d
kube-public            Active   15d
kube-system            Active   15d
kubernetes-dashboard   Active   15d

7.3Label介绍

Label 的作用:

Label是Kubernetes系统中的一个核心概念。*Label以key/value键值对的形式附加到任何对象上,如Pod,Service,Node,RC(ReplicationController)/RS(ReplicaSet)等*。Label可以在创建对象时就附加到对象上,也可以在对象创建后通过API进行额外添加或修改。

apiVersion: v1
kind: ReplicationController
metadata:
  name: gomo-rd
spec:
  replicas: 3
  selector:
    app: gomo
  template:
    metadata:
      labels:
        app: gomo
    spec:
      containers:
      - name: redis
        image: redis
        ports:
        - containerPort: 80

关于Label的用法重点在于这两步:

  • 通过template.metadata.labels字段为即将新建的Pod附加Label。在上面的例子中,新建了一个名称为gomo-rd的Pod,它拥有一个键值对为app:gomo的Label。
  • 通过spec.selector字段来指定这个RC管理哪些Pod。在上面的例子中,新建的RC会管理所有拥有app:gomoLabel的Pod。这样的spec.selector在Kubernetes中被称作Label Selector。
#-L 显示全部的值 包括key
[root@k8s-master2 ~]# kubectl get pods -L app  
NAME                          READY   STATUS    RESTARTS   AGE     APP
nginx                         1/1     Running   2          21h     
nginx-ds-4gb2k                1/1     Running   2          21h     nginx-ds
nginx-ds-5bmrq                1/1     Running   2          21h     nginx-ds
nginx-ds-sxz49                1/1     Running   2          21h     nginx-ds
nginx-ds-tzz7d                1/1     Running   2          21h     nginx-ds
wbs-deploy-5f95795668-g2qk4   1/1     Running   0          3h23m   gomo-wbs
wbs-deploy-5f95795668-lp74k   1/1     Running   0          3h23m   gomo-wbs
wbs-deploy-5f95795668-p485p   1/1     Running   0          3h23m   gomo-wbs
wbs-deploy-5f95795668-xxcwk   1/1     Running   0          3h23m   gomo-wbs
#-l 筛选符合规格的label
[root@k8s-master2 ~]# kubectl get pods -l app
NAME                          READY   STATUS    RESTARTS   AGE
nginx-ds-4gb2k                1/1     Running   2          21h
nginx-ds-5bmrq                1/1     Running   2          21h
nginx-ds-sxz49                1/1     Running   2          21h
nginx-ds-tzz7d                1/1     Running   2          21h
wbs-deploy-5f95795668-g2qk4   1/1     Running   0          3h23m
wbs-deploy-5f95795668-lp74k   1/1     Running   0          3h23m
wbs-deploy-5f95795668-p485p   1/1     Running   0          3h23m
wbs-deploy-5f95795668-xxcwk   1/1     Running   0          3h23m
#具体查看值
[root@k8s-master2 ~]# kubectl get pods -l app --show-labels
NAME                          READY   STATUS    RESTARTS   AGE     LABELS
nginx-ds-4gb2k                1/1     Running   2          21h     app=nginx-ds,controller-revision-hash=5c55d4f86d,pod-template-generation=1
nginx-ds-5bmrq                1/1     Running   2          21h     app=nginx-ds,controller-revision-hash=5c55d4f86d,pod-template-generation=1
nginx-ds-sxz49                1/1     Running   2          21h     app=nginx-ds,controller-revision-hash=5c55d4f86d,pod-template-generation=1
nginx-ds-tzz7d                1/1     Running   2          21h     app=nginx-ds,controller-revision-hash=5c55d4f86d,pod-template-generation=1
wbs-deploy-5f95795668-g2qk4   1/1     Running   0          3h24m   app=gomo-wbs,pod-template-hash=5f95795668
wbs-deploy-5f95795668-lp74k   1/1     Running   0          3h24m   app=gomo-wbs,pod-template-hash=5f95795668
wbs-deploy-5f95795668-p485p   1/1     Running   0          3h24m   app=gomo-wbs,pod-template-hash=5f95795668
wbs-deploy-5f95795668-xxcwk   1/1     Running   0          3h24m   app=gomo-wbs,pod-template-hash=5f95795668


# 给pod 打标签:
[root@k8s-master2 ~]# kubectl label pods nginx-ds-4gb2k abc=123 
pod/nginx-ds-4gb2k labeled
添加--overwrite 表示强制覆盖原来的标签

7.3.1常见的Label

一般来说,我们会给一个Pod(或其他对象)定义多个Label,以便于配置,部署等管理工作。例如:部署不同版本的应用到不同的环境中;或者监控和分析应用(日志记录,监控,报警等)。*通过多个Label的设置,我们就可以多维度的Pod或其他对象进行精细化管理*。一些常用的Label示例如下:

relase: stable
release: canary
environment: dev
environemnt: qa
environment: production
tier: frontend
tier: backend
tier: middleware

7.3.2 Label Selector

带有Label的对象创建好之后,我们就可以通过Label Selector来引用这些对象。 通常我们通过描述文件中的****spec.selector****字段来指定Label,从而Kubernetes寻找到所有包含你指定Label的对象,进行管理。 Kubernetes目前支持两种类型的Label Selector:

· 基于等式的Selector(Equality-based) =,==,!=

· 基于集合的Selector(Set-based)

​ key in (value1,value2)

​ key notin (value1,value2)

​ key 存在

​ !key 不存在

RC只支持基于等式的Selector,而RS两种Selector都支持。

许多资源支持内嵌字段定义其使用的标签选择器:

matchLabels:直接给定键值

matchExpressions:基于给定的表达式来定义使用标签选择器,{key:"KEY", operator:"OPERATOR",

values:[VAL1,VAL2,...]}

操作符:

In, NotIn:values字段的值必须为非空列表;

Exists, NotExists:values字段的值必须为空列表;

7.4Annotation 介绍

Annotation,顾名思义,就是注解。Annotation可以将Kubernetes资源对象关联到任意的非标识性元数据。使用客户端(如工具和库)可以检索到这些元数据。

Annotation与Label类似,也使用key/value键值对的形式进行定义。不同的是Label具有严格的命名规则,****它定义的是Kubernetes对象的元数据(Metadata),****并且用于Label Selector。而Annotation则是用户任意定义的“附加”信息,以便于外部工具进行查找,很多时候,Kubernetes的模块自身会通过Annotation的方式标记资源对象的特殊信息。

通常来说,用Annotation来记录的信息如下。

  • build信息、release信息、Docker镜像信息等,例如时间戳、release id号、PR号、镜像hash值、docker registry地址等。
  • 日志库、监控库、分析库等资源库的地址信息。
  • 程序调试工具信息,例如工具、版本号等。
  • 团队等联系信息,例如电话号码、负责人名称、网址等

7.5Label和Annotation区别和使用

Annotation不能用于挑选资源对象,仅用于为对象提供元数据

Label和Annotation都可以将元数据关联到Kubernetes资源对象。Label主要用于选择对象,可以挑选出满足特定条件的对象。相比之下,annotation 不能用于标识及选择对象。annotation中的元数据可多可少,可以是结构化的或非结构化的,也可以包含label中不允许出现的字符。

7.6Taint和Tolerationa (污点和容忍)

参考文档:https://www.cnblogs.com/weavepub/p/10968667.html

NoSchedule:仅影响调度过程,对现存的Pod对象不产生影响;但容忍的pod同时也能够被分配到集群中的其它节点
NoExecute:既影响调度过程,也影响现在的Pod对象;不容忍的Pod对象将被驱逐
PreferNoSchedule:NoSchedule的柔性版本,最好别调度过来,实在没地方运行调过来也行

Taint(污点)和 Toleration(容忍)可以作用于 node 和 pod 上,其目的是优化 pod 在集群间的调度,这跟节点亲和性类似,只不过它们作用的方式相反,具有 taint 的 node 和 pod 是互斥关系,而具有节点亲和性关系的 node 和 pod 是相吸的。另外还有可以给 node 节点设置 label,通过给 pod 设置 nodeSelector 将 pod 调度到具有匹配标签的节点上。

Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有相应 taint 的节点上。

设置taint
[root@k8s-master3 yaml]# kubectl taint nodes k8s-worker1 key1=value1:NoSchedule
删除taint
[root@k8s-master3 yaml]# kubectl taint nodes k8s-worker1 key1:NoSchedule-
node/k8s-worker1 untainted


为 pod 设置 toleration
只要在 pod 的 spec 中设置 tolerations 字段即可,可以有多个 key,如下所示:
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
- key: "node.alpha.kubernetes.io/unreachable"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 6000

value 的值可以为 NoSchedule、PreferNoSchedule 或 NoExecute。

tolerationSeconds 是当 pod 需要被驱逐时,可以继续在 node 上运行的时间。

7.7垃圾收集

垃圾收集

Kubernetes 垃圾收集器的角色是删除指定的对象,这些对象曾经有但以后不再拥有 Owner 了。

注意:垃圾收集是 beta 特性,在 Kubernetes 1.4 及以上版本默认启用。

Owner 和 Dependent

一些 Kubernetes 对象是其它一些的 Owner。例如,一个 ReplicaSet 是一组 Pod 的 Owner。具有 Owner 的对象被称为是 Owner 的 Dependent。每个 Dependent 对象具有一个指向其所属对象的 metadata.ownerReferences 字段。

有时,Kubernetes 会自动设置 ownerReference 的值。例如,当创建一个 ReplicaSet 时,Kubernetes 自动设置 ReplicaSet 中每个 Pod 的 ownerReference 字段值。在 1.6 版本,Kubernetes 会自动为一些对象设置 ownerReference 的值,这些对象是由 ReplicationController、ReplicaSet、StatefulSet、DaemonSet 和 Deployment 所创建或管理。

也可以通过手动设置 ownerReference 的值,来指定 Owner 和 Dependent 之间的关系。

这有一个配置文件,表示一个具有 2个 Pod 的 ReplicaSet:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: gomo-repset
spec:
  replicas: 2
  selector:
    matchLabels:
      pod-is-for: garbage-collection-gomo
  template:
    metadata:
      labels:
        pod-is-for: garbage-collection-gomo
    spec:
      containers:
      - name: wbs
        image: 192.168.208.195/library/wbs:latest
 -----
输出显示了 Pod 的 Owner 是名为 gomo-repset 的 ReplicaSet:
[root@k8s-master3 yaml]# kubectl get pods gomo-repset-t9pg9 -o yaml
apiVersion: v1
kind: Pod
metadata:
...
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: gomo-repset
    uid: da476438-1212-442b-b117-d6635964dde1
...

控制垃圾收集器删除 Dependent

当删除对象时,可以指定是否该对象的 Dependent 也自动删除掉。自动删除 Dependent 也称为 级联删除。Kubernetes 中有两种 级联删除 的模式:background 模式和 foreground 模式。

8、 Kubernetes Pod

8.1Pod是什么?

Pod是可以创建和管理Kubernetes计算的最小可部署单元。一个Pod代表着集群中运行的一个进程。

Pod就像是豌豆荚一样,它由一个或者多个容器组成(例如Docker容器),它们共享容器存储、网络和容器运行配置项。Pod中的容器总是被同时调度,有共同的运行环境。你可以把单个Pod想象成是运行独立应用的“逻辑主机”——其中运行着一个或者多个紧密耦合的应用容器——在有容器之前,这些应用都是运行在几个相同的物理机或者虚拟机上。

尽管kubernetes支持多种容器运行时,但是Docker依然是最常用的运行时环境,我们可以使用Docker的术语和规则来定义Pod。

Pod中共享的环境包括Linux的namespace,cgroup和其他可能的隔绝环境,这一点跟Docker容器一致。在Pod的环境中,每个容器中可能还有更小的子隔离环境。

Pod中的容器共享IP地址和端口号,它们之间可以通过localhost互相发现。它们之间可以通过进程间通信,例如SystemV信号或者POSIX共享内存。不同Pod之间的容器具有不同的IP地址,不能直接通过IPC通信。

Pod中的容器也有访问共享volume的权限,这些volume会被定义成pod的一部分并挂载到应用容器的文件系统中。

就像每个应用容器,pod被认为是临时实体。在Pod的生命周期中,pod被创建后,被分配一个唯一的ID(UID),调度到节点上,并一致维持期望的状态直到被终结(根据重启策略)或者被删除。如果node死掉了,分配到了这个node上的pod,在经过一个超时时间后会被重新调度到其他node节点上。一个给定的pod(如UID定义的)不会被“重新调度”到新的节点上,而是被一个同样的pod取代,如果期望的话甚至可以是相同的名字,但是会有一个新的UID(查看replication controller获取详情)

  • 单容器Pod,最常见的应用方式。

  • 多容器Pod,对于多容器Pod,Kubernetes会保证所有的容器都在同一台物理主机或虚拟主机中运行。多容器Pod是相对高阶的使用方式,除非应用耦合特别严重,一般不推荐使用这种方式。一个Pod内的容器共享IP地址和端口范围,容器之间可以通过 localhost 互相访问。

8.2Pod介绍与原理讲解

  1. Pause 容器

在接触Kubernetes的初期,便知道集群搭建需要下载一个gcr.io/google_containers/pause-amd64:3.0镜像,然后每次启动一个容器,都会伴随一个pause容器的启动。

kubernetes中的pause容器主要为每个业务容器提供以下功能:

  • 在pod中担任Linux命名空间共享的基础;

  • 启用pid命名空间,开启init进程。

8.3Pod创建与删除

Pods的创建:

[root@k8s-master3 ~]# kubectl run gomo-nginx --image=192.168.208.195/library/nginx:v1 --port=80 --replicas=1
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
[root@k8s-master3 ~]# kubectl get pods 
NAME                                       READY   STATUS    RESTARTS   AGE
gomo-nginx-584975ffcb-cfzs2                1/1     Running   0          7s
gomoci-jenkins-558b487c79-j8mkq            1/1     Running   7          5d23h
kissing-stingray-tomcat-6cf9d966bf-srmlm   1/1     Running   8          12d
[root@k8s-master3 ~]# kubectl get deploy
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
gomo-nginx                1/1     1            1           24s
gomoci-jenkins            1/1     1            1           5d23h
kissing-stingray-tomcat   1/1     1            1           12d

所对应的就是delete pod 但是如果有deployment (pods的控制副本在的话 pod 还是会起来的后面在将详细的讲述deployment)

8.4Pod生命周期管理

像单独的容器应用一样,Pod并不是持久运行的。Pod创建后,Kubernetes为其分配一个UID,并且通过Controller调度到Node中运行,然后Pod一直保持运行状态直到运行正常结束或者被删除。在Node发生故障时,Controller负责将其调度到其他的Node中。Kubernetes为Pod定义了几种状态,分别如下:

  • Pending,Pod已创建,正在等待容器创建。经常是正在下载镜像,因为这一步骤最耗费时间。

  • Running,Pod已经绑定到某个Node并且正在运行。或者可能正在进行意外中断后的重启。

  • Succeeded,表示Pod中的容器已经正常结束并且不需要重启。

  • Failed,表示Pod中的容器遇到了错误而终止。

  • Unknown,因为网络或其他原因,无法获取Pod的状态。

img

在pod生命周期中可以做的一些事情。主容器启动前可以完成初始化容器,初始化容器可以有多个,他们是串行执行的,执行完成后就推出了,在主程序刚刚启动的时候可以指定一个post start 主程序启动开始后执行一些操作,在主程序结束前可以指定一个 pre stop 表示主程序结束前执行的一些操作。在程序启动后可以做两类检测 liveness probe 和 readness probe。如下图:

img

8.5PodHook 讲解

实际上 Kubernetes 为我们的容器提供了生命周期钩子的,就是我们说的Pod Hook,Pod Hook 是由 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。我们可以同时为 Pod 中的所有容器都配置 hook。

Kubernetes 为我们提供了两种钩子函数:

PostStart:这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOINT之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起, 容器将不能达到running状态。

PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的, 所以它必须在删除容器的调用发出之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态。

如果PostStart或者PreStop钩子失败, 它会杀死容器。所以我们应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的, 比如在停止容器之前预先保存状态。

另外我们有两种方式来实现上面的钩子函数:

  • Exec - 用于执行一段特定的命令,不过要注意的是该命令消耗的资源会被计入容器。

  • HTTP - 对容器上的特定的端点执行HTTP请求。

8.6Pod的重启策略

Pod的重启策略(RestartPolicy)应用与Pod内所有容器,并且仅在Pod

所处的Node上由kubelet进行判断和重启操作。当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作。

Pod的重启策略包括:Always、OnFailure和Never,默认值为Always。

Always:当容器失效时,由kubelet自动重启该容器。

OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。

Never:不论容器运行状态如何,kubelet都不会重启该容器。

Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下:

RC和DaemonSet:必须设置为Always,需要保证该容器持续运行。

Job和CronJob:OnFailure或Never,确保容器执行完成后不再重启。

kubelet:在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查。

8.7Pod健康检查(探针)

Kubernetes利用Handler功能,可以对容器的状况进行探测,有以下三种形式。

  • ExecAction:在容器中执行特定的命令。如果命令以状态代码0退出,则认为诊断成功

  • TCPSocketAction:检查容器端口是否可以连接。对指定端口上的Container的IP地址执行TCP检查如果端口打开,则诊断被认为是成功的

  • HTTPGetAction:检查HTTP请求状态是否正常。对指定端口和路径上的Container的IP地址执行HTTP Get请求。如果响应的状态代码大于或等于200且小于400,则认为诊断成功。

每个探针都有三个结果之一:

  • 成功:Container通过了诊断。

  • 失败:容器未通过诊断。

  • 未知:诊断失败,因此不应采取任何措施。

8.7.1livenessProbe

存活状态检测 主进程是否处在存活状态

   livenessProbe:
      exec: 
        command: [xxxxxxx]
      httpGet:
        ports: http
        path: /index.html
      initialDelaySeconds: 1  (第一次的探测时间是什么时候开始)
      periodSeconds: 3

8.7.2readinessProbe

就绪状态检测

 readinessProbe:
      exec: 
        command: [xxxxxxx]
      httpGet:
        ports: http
        path: /index.html
      initialDelaySeconds: 1  (第一次的探测时间是什么时候开始)
      periodSeconds: 3