目录
前言:
Devops:
DevOps(Development和Operations的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。
它是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。透过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。
它的出现是由于软件行业日益清晰地认识到:为了按时交付软件产品和服务,开发和运营工作必须紧密合作。
1、Kubernetes介绍
kubernetes翻译成舵手
kubernetes受Borg系统的影响。k8s用go语言把Borg重写一遍变成了k8s。
kubernetes的代码托管在github上
而在2017年大量的云厂商对k8s的原生支持。
k8s的特性:自动装箱,自我修复,水平扩展,服务发现和负载均衡,自动发布和回滚,密钥和配置管理,存储编排,批量处理执行。
2、k8s的架构
架构图
架构是master/node的主从架构
master:API Server ,Scheduler,Controller-Manager (这三个是组件,也是守护进程)
node:kubelet,docker,kube-proxy
- API Server:负责接收请求,解析请求,处理请求。
- Scheduler:调度器,调度容器创建的请求,负责去观测每一个node之上总共可用的CPU,RAM和存储资源并根据用户所请求创建容器的资源量(因为在k8s上我们可以设定容器的资源上限和资源下限我们成为资源请求量),调度器就是根据容器的最低需求,来进行评估,哪一个节点最合适。因此k8s设定了一个两级调度的方式来完成调度,第一步先做预选(先评估一下到底有多少个是符合这个容器运行需求的节点,比如有三个)。第二步要做优选,从这三者中在选择一个最佳适配,到底哪个是最佳取决于调度算法当中的优选算法来决定的。
- kubelet:集群代理,用于能够与master通信的,接收master和调度过来的各种任务由他来执行的我们称为集群代理,是保证容器始终处于健康运行状态的软件。简单来讲API Server把任务编排以后由Scheduler来调度,Scheduler的调度结果由kubelet来执行。比如启动pod、在本地上管理pod健康、创建存储卷等等都由kubelet来执行,但是kubelet本身并不能运行容器,他最多就能接收任务,并在本机上试图启动容器,运行容器就需要容器引擎来运行,最流行的引擎就是docke,是用于pod中的容器的而创建的。
- 控制器:是用来不断的监听他所管理的每一个容器是否是健康的,一旦发现不健康,控制器就负责向MasterServer发请求再调度重新启动一个。k8s支持很多类型的控制器,控制容器自身健康的只是一种,他还有其他的控制器。我们以后就不能在k8s上称呼容器了,因为k8s最小运行地单元是pod。
- Controller-Manager:控制器管理器,负责监控每一个控制器是健康的,他本身是高可用的,是冗余的。假如Master是三个节点,那么Master每一个上面都有一个控制器管理器,大家都在的时候这三个控制器管理器只有一个正常工作,他是主节点,其他都是做冗余的。
- pod:是k8s的最小运行地单元。其可以理解为容器的外壳,给容器做了一层抽象的封装,pod是k8s系统之上最小的调度的逻辑单元,他的内部主要是用来放容器的,pod有一个工作特点:一个pod内可以包含多个容器,多个容器共享同一个底层的网络命名空间Net(网络设备、网络栈、端口等),UTS(主机名和域名)和IPC(信号量、消息队列和共享内存)三个网络名称空间,另外三个互相隔离User、MNT、PID是互相隔离的。所以说pod对外更像是一个模拟虚拟机,而且同一个pod下的容器还共享存储卷,存储卷就不在属于容器而属于pod。各个node主要是运行pod的,一般说一个pod只放一个容器,除非容器之间有非常紧密的关系需要放在同一个pod中,通常我们他们中的一个容器为主容器,其他的容器是辅助这个主容器中的应用程序完成更多功能来实现的。其他的辅助容器也成为 边车。我们为pod打上标签,用标签来识别pod,能让控制器或者是人能够基于标签的值来识别出pod的,比如我们创建了4个nginx pod,我们可以给每一个pod上加上一个标签叫app这个叫key,他的值都等于nginx,当我们想挑出来这些pod的时候就找key是app的并且值是nginx的就ok了。标签不是pod独有的,因为k8s是restfull风格的api,几乎所有被操纵的目标都是对象,几乎所有的对象都可以拥有标签,可以用标签选择器操作。
- Label select:标签选择器,根据标签来过滤符合条件的资源对象的机制,把感兴趣的pod挑出来的组件。
- kube-proxy:管理service,随时与Api Server进行通信。关于这个的详解请点击kubernetes 简介:kube-proxy 和 service
- etcd:是一个开源的、分布式的键值对数据存储系统,提供共享配置、服务的注册和发现。etcd与zookeeper相比算是轻量级系统,两者的一致性协议也一样,etcd的raft协议比zookeeper的paxos简单;他要是宕机了整个集群也就宕机了,所以要高可用,一个端口用于集群内通信,一个端口用于向客户端提供服务
- CNI:容器网络接口,是k8s的外部接入的网络服务解决方案,能遵循CNI开发的这个服务那么就能作为k8s的网络解决方案来使用,事实上这些解决方式可以以附件的方式托管在集群之上。常见的有 flannel:简单,支持网络配置,是叠加网络实现。calico:复杂,即支持网络配置又支持网络策略,是三层隧道实现。canel:用flannel提供网络,用calico提供网络策略来搭配使用。除了上述三个还有很多,这里不说了。
Pod分为两类(我自己给分的类):
- 自主式pod:自我管理的。没法实现全局进行调度。
- 控制器管理的pod:(我们建议使用这种)正是由于控制器的设计,pod才被成为有生命周期的对象。
Pod的常用控制器:
- ReplicationController:副本控制器,多退少补。
- ReplicaSet:副本集控制器,他不直接使用他有个声明式更新的控制器Deployment来管理。
- Deployment:(我们用的最多)只能负责管理那些无状态的应用,还支持二级控制器叫HPA(HorizontalPodAutoscaler:水平pod自动伸缩控制器)
- StatefulSet:有状态副本集,负责管理那些有状态的应用
- DaemonSet:我们需要在每一个node上运行一个副本而不是随意运行还需要DaemonSet
- job:要运行作业
- Ctonjob:周期性任务化作业
- HorizontalPodAutoscaler:可自动进行扩展
Service:
因为pod经常变,所以我们不能通过访问pod的ip地址和端口来访问pod,那么我们怎么访问呢?就通过接入层的一个叫service的东西,他是关联pod的,当他所管理的pod挂掉了,他会自动去找一个新的pod并自动关联上service。
那么service是怎么管理pod的呢?pod的ip地址经常变,主机名也经常变,但是pod上有固定的元数据叫标签label,只要创建了pod的label是统一的,都能被service识别,因为service是靠标签选择器来关联pod对象的。所以只要pod存在,只要属于这个标签选择器,那么就会立即被service挑选住,并作为service的后端组件。而后这个service把这个pod关联进来后在动态探测这个pod的ip地址是什么,端口是什么,并作为自己调度的后端可用服务器主机对象。因此客户端的请求到达service,并由service代理至客户端pod来实现。因此客户端始终看见的都是service的地址。而在k8s之上,service不是应用程序,也不是一个实体组件,他只不过是一个iptables的DNAT规则(目标地址转换)。因为是个规则,所以service的地址是没有配置在任何一个网卡上的,是不存在的,他仅仅出现在规则中,所以ping不通的,但是却可以请求做服务端。能ping通是因为有一个TCP/IP协议栈有支持这个ip地址,所以他能在协议栈上进行响应。
service作为k8s的对象来讲,有service的名称,而service名称就相当于这个服务的名称,而名称可以被解析,可以直接把service名称解析为service的ip,名称解析靠DNS,所以我们装完k8s集群以后,第一件事就需要在k8s集群之上部署一个DNS Pod,已确保各service域名能被解析,像这样的pod是k8s自身就需要用到的,所以我们把它成为基础性的系统架构的pod对象,而且他们也被成为集群的附件AddOns。
集群的附件AddOns:
插件是什么:插件是本身作为程序的一部分而存在
附件是什么:有它,功能更丰富,没它也行。它本身不作为程序的一部分而存在。只是另外一个应用程序。但是他俩可以很好地结合起来提供一种工作。
- DNS:而且k8s的DNS会动态创建、动态改变、动态删除。比如我们把service的名称一改,他会自动触发DNS中的解析记录名称并修改。DNS也是一个pod,也需要service来访问管理,也需要高可用防止宕机。
k8s集群的三种网络:
节点网络、集群网络(service网络)、pod网络
各pod运行在一个网络中,而service是另外一个网络。service的地址和pod的地址是不同网段的。pod地址是配置在pod内部的网络名称空间之上,是可以ping通的,相当于一个正常的主机地址。但是service的地址是虚拟的、是假的。它只存在iptables或ipvs规则当中。
所已由外部访问时,先到达节点网络,由节点网络代为代理至集群网络,再由集群网络代为代理至pod网络。
k8s集群的三种通信:
同一Pod内的多个容器之间通信:lo(localhost)本地通信
各pod之间的通信:用到叠加网络,这里先认识一下,部署完的效果能看到。
Pod与service之间的通信:
3、k8s的安装部署
k8s的两种常见部署方案
- 传统的部署方式:让k8s自己的相关组件统统运行为系统级的守护进程,这包括master节点上的四个组件,以及每个node节点上的三个组件,都运行为系统级守护进程,但是这种安装方式每一组都需要我们手动解决,包括做证书等等,而安装过程也需要我们手动解决,编辑配置文件也需要手动解决,他的配置过程繁琐而复杂,一般第一次部署需要一天左右的时间能调通。
- kubeadm:这个工具是k8s官方的集群部署管理工具,几个命令就能完成安装,但是他把所有组件能运行为容器的全部运行为容器,只有kubelet是需要单独装在主机上的,其他统统运行为容器。这些容器的所有的镜像都托管在gcr的仓库当中,gcr的仓库出于某种不可描述的原因(国内访问不了) ,是不能直接访问的。 实现一种自我管理的方式把k8s自己也部署为pod,至少核心组件部署为pod,包括master和各node所在内的所有节点,我们还需要手动安装和部署,但是只需要部署kubelet和docker就行了。因为docker是运行容器的引擎,kubelet是负责能运行pod化容器的核心组件。那么每一个节点都装上kubelet和docker,也就意味着,运行容器及运行pod的基础环境我们已经准备好了。在此基础之上我们能够实现把master的相关四个组件统统运行为pod,就是直接托管在k8s之上,而后把每个node节点上的余下的组件叫kube-proxy也运行为pod,那整个集群就跑起来了。要注意以上说的这些pod都是静态pod(static pod,不受k8s的管理,只不过运行为pod的形式而已)而不是我们之前讲过的能够接受k8s自身管理的pod。我们的flannel也是需要托管的,每一个节点包括master和各node节点还需要部署flannel,以支撑他们部署的pod资源彼此之间能够互相通信的。但是这个flannel的的确确是托管在k8s集群之上的附件,他不像前面那几个都是静态的pod,都是动态的由k8s自身管理的pod。
总结一下使用kubeadm安装k8s:
- 在master、nodes节点安装kubelet,kubeadm,docker
- 在master节点上去运行 kubeadm init去初始化集群
- 各nodes节点上分别执行kubeadm join加入到集群中
- 官方的安装文档在https://github.com/kubernetes/kubeadm/blob/master/docs/design/design_v1.10.md
假设我们部署的网络如下图所示:
3、k8s的安装部署
3.1、传统的部署方式:(本文不使用这种,往下看)
作为系统级守护进程的方式
进入k8s官网:点我去官网
点击进入releases,我们去下载把master和node分开组织的包,按下图红框所示,.tar.gz的包是k8s的所有组件的包,我们不建议用这个。
可以看到上图,分开的server端的包和客户端的包,而且是针对不同平台的。
无论master还是node用的都是server端的东西就是Server Binaries下的包。
上述这种都是属于安装的第一种运行为系统级守护进程的方式。挑战度非常大!这里我们就提一嘴
3.2、使用kubeadm方式安装k8s(推荐)
进入阿里云镜像库点我进入
记得要关闭防火墙和ipv6
3.2.1配置yum仓库
下图均为在master上的操作
- 先配置docker的仓库
不用进行修改了
- 再配置kubernetes的仓库
写入下图的内容
其中的baseurl的值是下图所示
其中的gpgkey的值是下图所示
然后运行yum repolist命令,可以看到下图docker和k8s的有程序包可以用。没问题
然后通过scp发送给node1和node2节点
3.2.2 安装并启动相关组件
- 在master节点进行安装docker、kubelet、kubeadm、kubectl :
kubectl 是apiServer的命令行客户端
出现下图表示安装完成
- 启动docker的服务:
因为docker会自动到docker仓库去下载所依赖到的每一个镜像文件,这些镜像文件国内无法访问。所以我们先通过下面的方式把相关镜像文件加载完成并导入进来使用。例如加载进来后我们可以docker save保存下来,或者推送到本地的仓库中。kubeadm新版本是支持直接使用本地当中已有的镜像文件或者使用本地私有仓库作为下载路径的。
加入下图所示内容,用来定义环境变量。
当我们要访问HTTPS服务的时候,通过这么一个所谓的代理去访问并加载相关的镜像文件。等加载完了,我们再把它注释掉,然后再使用我们国内的加速方式来访问其他镜像。下图的地址是可以帮我们辗转访问到相应的镜像。
可以看到下图所示信息
因为docker会生成大量的IP6或者IP的规则,有可能对iptables内部的nf-call需要打开内生的桥接功能,所以如下图所示先查看
要确保两个值都是1,就说明随后我们在docker上去用是没有问题的。
- 启动kubelet服务:
我们之前准备好了yum仓库和程序包都安装好了。因此我们直接去启动kubelet就可以了。
但是在启动之前先查看都安装生成了哪些文件
清单目录/etc/bubernetes/manifests
配置文件/etc/sysconfig/kubelet
/etc/systemd/system/kubelet.service
主程序/usr/bin/kubelet
通过上图我们发现,配置文件的参数是空的,也就意味着我们使用默认配置它就有可能正常工作了。
启动服务:
查看相关状态:
下面我们查看日志信息:
这就意味着我们不需要启动k8s,现在关闭k8s
现在我们要把它设置为开机自启,但是现在不能是启动状态,因为我们的各种配置还没有触发完成,触发完成后才能启动。
但是开机自启要打开的,要不然里面还会警告的。包括docker也一样。
- kubeadm的 init
先查看kubeadm init 的命令参数
指明参数并执行init命令:
可以看到报错,我们忽略不了Swap,所以我们需要做两个设定,第一,去编辑下列文件
在当中加个忽略swap选项,只在命令行中加是不够的。
然后在init命令中加入忽略swap错误的信息
出现下图及下下图显示的镜像则表示成功
发现监听了6443端口。
--token是个令牌,其实是个域共享秘钥。我这个集群不是谁都能加入进来的,需要拿着我事先给你的密码才行,这个令牌是动态生成的。所以建议复制保存下载,免得以后找不到了。
--discovery-token-ca-cert-hash 表示做发现时,相关文件的或者是私钥的哈希码。如果我们的server发现证书的哈希码不是这个哈希码,我们是拒绝加入集群的。也避免自己的节点误入别的狼群中去。
他去下载镜像到本地了,速度取决于网络,现在等着他就行了,过了一会发现如下就是成功了。
pause用来做:我们之前讲docker时候说过,以后我们可以做一个容器,这个容器不用启动,随后其他容器启动后可以加入复制这个基础容器的网络和存储卷等等,我们把它称为基础架构容器。每一个pod的内部,之所以叫pod,而且pod能启动起来,里边还有主容器,还有其他容器能够协同,就是因为他底层有个基础架构容器,而pause,就是用来为构建基础架构容器而创建的。说明它就是为了能够分配一个网络名称空间、ip地址、主机名然后能够有存储卷,为一个pod提供底层基础结构的。他不需要启动和运行。
继续执行下面命令:
上图的复制文件命令的意思是:这个命令复制了admin.conf就是kubeadm帮我们自动初始化好的一个被kubectl可以拿来作为配置文件指定连接着k8s的apiServer并完成认证的配置文件,这里包含了认证信息(就是认证证书,客户端证书)等相关信息的非常非常重要的一些配置。因为他的生成是比较复杂的,他的格式也比较复杂。后面我们还会讲这个格式。现在我们会简单使用就可以了。
上面报错,提示我们使用kubectl get -h,我们执行这个命令可以查看到get相关的帮助
- 获取各组件健康状态信息
cs是组件状态信息,显示的是各组件的健康状态,之所以没显示ApiServer是因为如果它不健康,那么这里的请求发不过去的。能正常显示信息就说明本身一定是健康的。
- 获取节点信息
可以看到当前是未就绪状态。是因为还缺少一个重要的附件叫flannel,或者这样的网络组件,没有网络,那个各pod装起来是没法跑的,彼此间无法通信。部署flannel属于另外的事情,本身不属于k8s的事情了。
- 在master部署flannel
在flannel的github上可以看到如下文档
往下拉看到如下图所示,如果你的k8s是1.7+只需要执行下面命令即可,他会自动的获取在线的部署清单,基于此清单下载镜像启动并部署flannel。
这里可以看到各种各样的created,但是这是不够的,我们要使用 kubectl get pods -n kube-system命令查看,我们要看到flannel正常启动并运行的状态才算ok。
我们要使用docker image ls 要看到flannel镜像拖下来才能看见启动起来。我们只需要等待一会即可。耐心一点。
可以看到现在的状态为Ready了。
这里所显示的列表就是当前节点上运行地所有pod,而且他们属于kube-system名称空间。
如果默认不指明名称空间的话是k8s集群默认的名称空间叫default。
我们的系统级的pod都在kube-system名称空间中。
- 获取名称空间
到这里master就全部搞定了,就等着我们另外两个node节点加入进来了。
- 在node01节点进行安装docker、kubelet、kubeadm:
在master节点发送相关东西到node节点:
kubectl 是apiServer的命令行客户端,我们按不按都行,因为我们不一定会在这个主机上执行客户端程序。这里就不安装了。
然后把master的docker的配置文件发送到node节点上
因为我们就在node01安装了,所以我们先不演示node02的了。
- 在node01节点启动docker:
可以看到下图红框所示,证明docker.service配置文件生效成功了。
设置为开机自启:
加入到集群中:
在上面kubeadm的 init的时候有join的令牌,但是还不够,我们还要忽略swap错误
然后我们去master节点查看一下新加入这个node节点的情况:
然后我们需要一个简短的等待,让这个节点去下载kube-proxy镜像、flannel镜像并启动起来,他才能真正的初始化完成。
上图可以看到有两个flannel,两个proxy,查看后面的地址发现一个是master一个是node01
- 在node02节点安装:
跟node01节点安装是一样的
出现上图安装成功,下面在master发送一下配置文件到node02
启动node02的docker