1、k8s常用的资源类型:
Pod、Service、Namespace(注意这里的名称空间不是容器上的六种名称空间,这个是K8S的名称空间)、Volume
控制器对象:ReplicaSet、Deployment、DaemonSet、StatefulSet、Job
K8s本身是一个集群,是容器编排系统,它得核心任务是容器编排,而容器是应用程序,所以本质上来讲K8S是建构在多节点之上得抽象的隐藏底层节点之后让用户可以统一使用的一个操作接口,用户可以在这个操作接口上主要作用就是增删改查Pod,而运行pod的核心目的就是在pod上运行容器,而容器就是应用程序,加入它有服务端应用程序,比如nginx,我们把nginx跑起来以后它肯定会占用一些cpu核心,占用一些内存资源,要监听一个端口对外进行通信,那我们通过创建pod就能把容器运行起来,会出现两个问题:第一pod中的容器怎么能够把它所提供的服务被外部的客户端所访问呢?第二万一这个pod崩了怎么办?容器编排系统会有一种功能去做健康监测,一旦发现故障就能给它自动恢复回来或者自动重建,pod自身没有这个功能,而k8s自身对此功能的支持是通过所谓的pod控制器(pod controller)来实现的,最基础的pod controller我们称为Deployment,也就意味着我们以后在k8s之上创建容器时不是直接创建pod的,而是创建一个控制器Deployment对象,控制器也是一种资源类型,把这个类型实例化出来以后他是一个对象,所以我们创建一个Deployment,由Deployment指挥着k8s创建出一个或者多个pod来,到底创建多少个这个取决于用户的定义,创建pod需要借助于控制器来完成,假设用户的指令是去创建两个pod,那么控制器Deployment就会自动告诉k8s再给我创建一个pod,Deployment控制器会精确反应用户所给出的指令,这个功能就是用控制器Deployment来实现的。
如上图:如果一个pod崩掉,客户端是否还能访问?
由于IP地址为了避免冲突是动态分配的,动态分配则无法固定IP地址,如果一个pod崩掉,建立一个新的pod,这个新的pod地址与崩掉的pod的IP不一样,这样会产生一个问题,比如我们一个客户端,此前是需要访问崩掉的pod的,我们客户端访问这个pod时使用的是它此前的IP,pod崩了换了一个新的pod,IP地址发生了变化,客户端使用崩掉的pod的地址则无法找到崩掉的pod,这就违背了容器编排所具备的功能,在这种情况下pod的销毁建立操作是动态的,因此在动态场景当中我们必须以服务注册、服务发现的方式来完成动态服务的衔接,而在k8s之上,服务注册和发现是借助于DNS来完成的。但DNS结果解析的却也不是pod,因为pod和客户端之间k8s给他添加了中间层,叫service;这个pod由于地址是动态的可能会随时发生变化,为了提供一个固定接口让客户端访问,每建立一个pod,这个pod中只要提供了服务,会在客户端和pod之间加一个中间层service,需要给他的属性赋值创建service,而service在把用户的请求反代至pod上,如果有多个pod,service还能实现负载均衡,所以最后客户端访问service,由service再反代给pod,因此service可以理解成是pod的代理,service创建完以后它也有它的地址被称为service-ip,Pod的IP称为pod-ip,可见下图
service如何知道反代的Pod有哪些?
k8s给每一个资源对象都会附加一个标签,方式是键:值 ,在service上是通过键:值来关联至后端的pod的,在service上这个方式叫标签选择器,它用于过滤符合哪些条件的标签,因此一个pod崩掉新创建一个pod,IP地址会发生变化但是标签一定不会发生变换,标签一定是符合service过滤器的条件的,所以service会过滤这个pod获取地址在反代。service的地址也是动态分配的,service地址只要不删不强行修改的话地址是不会发生变化的,service简单来讲就是iptable规则
label selector:标签选择器,用于过滤哪些符合条件得标签
podip:配置到容器的虚拟网卡IP上
service ip:不会配置在任何网卡上 ,只出现在iptables规则、DNS解析记录中
node-ip:是配置到节点的IP
如何service的地址发生变化怎么办?
DNS:当用户再k8s上创建一个service时,这个service一定有个IP地址和名称,它会把service的名称和IP地址转换成A记录,动态的注册到DNS之上,客户端向DNS查询service的名称,让它解析时一定能解析成这个IP地址,如果service删除了,在重建一个,重建的service会立即几乎接近实时的反应在dns当中,所以客户端在通过DNS去解析,同样是service名称,IP地址变成了新的IP地址,只不过保存的结果是DNS记录
pod中的容器怎么能够把它所提供的服务被外部的客户端所访问呢?
客户端访问service时会先通过dns解析得到service的IP,此时客户端已service的IP通信,而serviceIP非真IP,他需要将他通过iptables规则转换为对应后端的podIP,这个时候客户端就会与pod通信
客户端是谁:
nmt:
n的client:远程客户端
t的client:nginx k8s之外的真正访问k8s的
m的client:t上的程序
如下图:如果我们把nmt运行在k8s集群上,在k8s上面,当客户端访问nginx时需要先访问nginx service,由nginx service代理至nginx,nginx要访问tomcat需要访问tomcat service,由tomcat service转发或者代理至tomcat,tomcat程序要访问mysql也是同样先访问mysql service,由mysql service在代理至mysql
什么是控制器?
我们这里反复情调控制器,大家可以想象一下运维工作平时都是干什么的,发布,变更,故障处理,发布以后我们靠控制器,部署是由控制器来做的,变更比如一个pod不够了,在加一个pod也是由控制器来完成的,故障处理,一旦pod崩了会重建,重建也是由控制器来完成,控制器其实就是把我们运维日常的发布,变更,故障处理封装成程序放在k8s上,以往由人来手动操作的统统都由控制器来完成。service是实现让她们通过内部的固定方式完成彼此间通信的一种控制层一种抽象层仅此而已。
2、Kubernetes Network
首先你们节点和节点之间通信要有节点网络会有IP地址,各个pod之间可以通过pod-IP直接通信,service网络就是service-IP所在的网络,service-IP地址不是真正配置在哪个节点上的IP地址,它们只出现于iptables规则中,无法ping通。
假设上图中的Node01的pod1是客户端,而Node02的pod2是服务端,我们该如何访问?
首先访问需要通过pod2的service的地址,由service代理到pod2的地址,pod1为了访问pod2,它先去访问service,service是另外一个网络,这个service通过调度挑出来一个Pod2,这个pod2有IP地址,会把这个IP地址返回给pod1,pod1则与pod2直接通信。注意service不是nat,只是加了一个查询的过程,你可以把service想象成就是一个查询的服务端。
3、k8s集群部署
3.1部署要点:
测试环境:
1.可以使用单Master节点,单etcd实例
2.Node主机数量按需而定
3.nfs或glusterfs等存储系统
生产环境:
1.高可用etcd集群,建立3、5或7个节点
2.高可用master:
a.kube-apiserver无状态,可多实例
- 借助于keepalived进行vip流动实现多实例冗余;
- 或在多实力前端通过HAproxy或Nginx反代,并借助于keepalived对代理服务器进行冗余;
b. kube-scheduler及kube-controller-manager各自只能有一个活动实例,但可以有多个备用;
- 各自自带leder选举的功能,并且默认处于启动状态
3.多Node主机,数量越多,冗余能力越强
4.ceph、glusterfs、iSCSI、FC SAN及各种云存储等
3.2部署工具
常用的部署环境:
- laaS公有云环境:AWS、GCE、Azure等
- laaS私有云或公有云环境:openStack和vSphere等
- Baremetal环境:物理服务器或独立的虚拟机等
常用的部署工具:
- kubeadm
- kops
- kubespray
- kontena Pharos
其它二次封装的常用发行版
- Rancher
- Tectonic
- Openshift
4、部署方式
方式一:
方式二:
两种方式一个是守护进程,一个是pod