1. 介绍
Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展。
Kubernetes组件组成:
1 Kubectl
客户端命令行工具,将接受的命令格式化后发送给kube-apiserver,作为整个系统的操作入口。
2 kube-apiserver
作为整个系统的控制入口,以REST API服务提供接口,提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制。
3 kube-controller-manager
用来执行整个系统中的后台任务,包括节点状态状况、Pod个数、Pods和Service的关联等。负责维护集群的状态,比如故障检测、自动扩展、滚动更新等。
4 kube-scheduler
负责节点资源管理,接受来自kube-apiserver创建Pods任务,并分配到某个节点。
5 etcd
etcd 集群的主数据库,保存了整个集群的状态,负责节点间的服务发现和配置共享。
6 kube-proxy
运行在每个计算节点上,负责Pod网络代理。定时从etcd获取到service信息来做相应的策略。负责为Service提供cluster内部的服务发现和负载均衡。
7 kubelet
运行在每个计算节点上,作为agent,接受分配该节点的Pods任务及管理容器,周期性获取容器状态,反馈给kube-apiserver。负责维护容器的生命周期,负责管理pods和它们上面的容器,images镜像、volumes、etc。同时也负责Volume(CVI)和网络(CNI)的管理。
8 DNS
一个可选的DNS服务,用于为每个Service对象创建DNS记录,这样所有的Pod就可以通过DNS访问服务了。
2 相关概念
2.1 Pod
Pod是在K8s集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务.比如你运行一个操作系统发行版的软件仓库,一个Nginx容器用来发布软件,另一个容器专门用来从源仓库做同步,这两个容器的镜像不太可能是一个团队开发的,但是他们一块儿工作才能提供一个微服务;这种情况下,不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务
2.2副本复制器(RC)
通过监控运行中的Pod来保证集群中运行指定数目的Pod副本。少于指定数目,RC就会启动运行新的Pod副本;多于指定数目,RC就会杀死多余的Pod副本
2.3副本集(Replica Set,RS)
RS是新一代RC,提供同样的高可用能力,区别主要在于RS后来居上,能支持更多种类的匹配模式。副本集对象一般不单独使用,而是作为Deployment的理想状态参数使用
2.4部署(Deployment)
部署是一个比RS应用模式更广的API对象,支持动态扩展。可以创建一个新的服务,更新一个新的服务,也可以是滚动升级一个服务。滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新RS中副本数增加到理想状态,将旧RS中的副本数减小到0的复合操作【逐步升级新得副本,剔除旧的副本】;
总结:RC、RS和Deployment只是保证了支撑服务的微服务Pod的数量
2.5服务(Service)
RC、RS和Deployment只是保证了支撑服务的微服务Pod的数量,但是没有解决如何访问这些服务的问题。一个Pod只是一个运行服务的实例,随时可能在一个节点上停止,在另一个节点以一个新的IP启动一个新的Pod,因此不能以确定的IP和端口号提供服务。要稳定地提供服务需要服务发现和负载均衡能力。服务发现完成的工作,是针对客户端访问的服务,找到对应的的后端服务实例。在K8s集群中,客户端需要访问的服务就是Service对象。
每个Service会对应一个集群内部有效的虚拟IP,集群内部通过虚拟IP访问一个服务。在K8s集群中微服务的负载均衡是由Kube-proxy实现的。Kube-proxy是K8s集群内部的负载均衡器。它是一个分布式代理服务器,在K8s的每个节点上都有一个;这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的Kube-proxy就越多,高可用节点也随之增多。与之相比,我们平时在服务器端做个反向代理做负载均衡,还要进一步解决反向代理的负载均衡和高可用问题。
3 PodIP、ClusterIP和外部IP
3.1 Pod IP
Kubernetes的最小部署单元是Pod。利用Flannel作为不同HOST之间容器互通技术时,由Flannel和etcd维护了一张节点间的路由表。Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。
每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause:0.8.0的容器,容器内部与外部的通信经由此容器代理,该容器的IP也可以称为Pod IP。
Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但Service Cluster IP就不一样了,没有网络设备为这个地址负责。它是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。
就拿上面我们提到的图像处理程序为例。当我们的Service被创建时,Kubernetes给它分配一个地址10.0.0.1。这个地址从我们启动API的service-cluster-ip-range参数(旧版本为portal_net参数)指定的地址池中分配,比如–service-cluster-ip-range=10.0.0.0/16。假设这个Service的端口是1234。集群内的所有kube-proxy都会注意到这个Service。当proxy发现一个新的service后,它会在本地节点打开一个任意端口,建相应的iptables规则,重定向服务的IP和port到这个新建的端口,开始接受到达这个服务的连接。
当一个客户端访问这个service时,这些iptable规则就开始起作用,客户端的流量被重定向到kube-proxy为这个service打开的端口上,kube-proxy随机选择一个后端pod来服务客户。这个流程如下图所示:
根据Kubernetes的网络模型,使用Service Cluster IP和Port访问Service的客户端可以坐落在任意代理节点上。外部要访问Service,我们就需要给Service外部访问IP。
Service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个Service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。
外部访问者是访问集群代理节点的访问者。为这些访问者提供服务,我们可以在定义Service时指定其spec.publicIPs,一般情况下publicIP 是代理节点的物理IP地址。和先前的Cluster IP range上分配到的虚拟的IP一样,kube-proxy同样会为这些publicIP提供Iptables 重定向规则,把流量转发到后端的Pod上。有了publicIP,我们就可以使用load balancer等常用的互联网技术来组织外部对服务的访问了。
spec.publicIPs在新的版本中标记为过时了,代替它的是spec.type=NodePort,这个类型的service,系统会给它在集群的各个代理节点上分配一个节点级别的端口,能访问到代理节点的客户端都能访问这个端口,从而访问到服务。
3.4 Endpoint地址保持
Pod的endpointd地址会随着pod的销毁和重新创建而发生改变,因为新的pod的ip地址和旧的pod的地址不同,service一旦创建,kubernetes会自动为它分配一个可用cluster ip,而且在service的整个生命周期内,它的cluster ip不会发生改变。解决endpoint地址不发生改变的方法:只需要service的name与service的cluster ip地址做一个dns域名映射就可以解决。
3.5 namespace(命名空间)
Namespace(命名空间)是kubernetes系统中的一个重要概念,namespace在很多情况下用于实现多租户的资源隔离。Namespace通过将集群内部的资源对象“分配”到不同的namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。如果不特别指明namespace,用户创建的pod、rc、service都将被系统创建到这个默认名为default的namespace中。当我们给每个租户创建一个namespace来实现多租户的资源隔离,还能结合kubernetes的资源配额管理,限定不同租户能占用的资源,例如cpu使用量,内存使用量等。
3.6 mysql-rc.yaml详解
apiVersion: V1
king: ReplicationController ---副本控制器rc
metadata:
name: mysql --- rc的名称,全局唯一
spec:
replics :1 --- pod副本期待数量
selector:
app: mysql --- 符合目标的pod拥有此标签
template: ---根据此模板创建pod的副本(实例)
metadata:
labels:
app: mysql --pod副本拥有的标签,对应rc的selector
spec:
containers: -- pod内容器的定义部分
name: mysql -- 容器的名称
image: mysql -- 容器对应的docker image
ports:
- containerPort: 3306 -- 容器暴露的端口号
env: -- 注入到容器内的环境变量
- name: MYSQL_ROOT_PASSWORD
Value: “123456”
Kind属性:用来表示此资源对象的类型,比如这里是replication,表示这是一个rc,Spec一节中是rc的相关属性定义,比如spec.selector是rc的pod标签(label)选择器,即监控和管理拥有这些标签的pod实例,确保当前集群上始终有且仅有replicas哥pod实例在运行,这里我们设置replicas=1表示只能运行一个mysql pod实例。
3.7 mysql-svc.yaml
apiVersion: v1
kind: Service --表明是kubernetes service
metadata:
name: mysql -- service的全局唯一名称
spec:
ports:
- port: 3306 --service提供服务的端口号
selector:
app: mysql -- services对应的pod拥有这里定义的标签
metadata.name是service的服务名(servicename)
port属性定义了service的端口
spec.selector确定了哪些pod副本(实例)对应到本地服务
3.8 myweb-rc.yaml
king: ReplicationController
metadata:
name: myweb
spec:
replicas: 5
selector:
app: myweb
template:
metadata:
labels:
app:myweb
spec:
containers:
- name: myweb
image:kubeguide/tomcat-app:v1
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
value: ‘mysql’
- name: MYSQL_SERVICE_PORT
Value: ‘3306’
该配置文件中的rc对应的tomcat容器里引用了MYSQL_SERVICE_HOST=mysql这个环境变量,而mysql是我们之前定义的mysql服务的服务名
3.9 myweb-svc.yaml
apiVersion: V1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
app: myweb
该配置文件中的type=nodeport和nodeport=30001这两个属性表示,表明此service开启了nodeport方式的外网访问模式