1.计算资源管理
2.网络资源管理
3.存储资源管理
4.镜像资源管理
计算资源在云平台上指:应用程序运行所需要的资源,包括cpu+memory。
多租户=》资源共享+资源隔离
k8s体系中,对计算资源的管理可以在如下三个级别进行:
同时根据应用计算资源的需求和限制,提供不同级别的服务质量(QoS)管理。
大型企业中,将企业各个数据中心的服务器全部纳入一个k8s集群中进行管理是不切实际的,主要要考虑到如下问题:
基于以上原因,通常需要部署多个k8s集群,来共同完成应用的发布和运行。
在容器云平台上,对资源的管理首先是将多个k8s集群纳入管理,以便能够对所有资源进行统一分配和管理。
将多个k8s集群纳入统一管理方案:
- 通过对接每个k8s集群的master,来完成集群内的资源管理和应用部署管理
实现:容器云平台需要通过k8s master提供的restful api去控制整个集群,包括对各种资源的CURD操作;还需完成应用的多集群部署管理、跨集群水平扩展、集群的服务发现和自动灾难切换等多集群管理;并设置相应的网络策略,以保护各集群的master不被攻击。- 使用统一的Federation控制平面(k8s的一个子项目)来对多个k8s集群进行他同意管理
实现:https://jimmysong.io/kubernetes-handbook/practice/federation.html
Federation的设计目标是对多个k8s集群进行统一管理,将用户的应用部署到不同地域的DC或是云环境中,通过动态优化部署来节约运营成本。
federation架构中,引入一个位于所有k8s集群之上的Federation控制平面,屏蔽了后端的各k8s子集群,向客户提供了一个统一的管理入口。
Federation控制平面封装了多个k8s集群的master角色,提供了一个统一的master,包括Federation API Server、Federation Controller Manager,用户可以像操作单个集群一样操作Federation;还统一管理了全部k8s集群的DNS、ConfigMap,并将数据保存在集中的etcd数据库中。
问题:
- 为确保所有集群的运行状态符合预期,Federation控制平面会持续监控所有集群,导致网络开销和成本增加
- Federation控制平面是“中心化”的总控节点,一旦出现问题,就可能会影响到所有集群。
- Federation出现较晚,不是很成熟,目前k8s中的资源对象只有一部分在Federation中是可用的。
在容器云平台纳管所有k8s集群之后,平台管理员就可以进行资源分配的工作,为多个租户提供应用部署运行环境了。
在一个k8s集群中,提供计算资源的的实体被称为Node,即工作节点。
Node可为物理机服务器,也可为虚拟机服务器。
每个Node都提供了计算(cpu+memory)+网络+存储三大资源,应用系统则是这些资源的使用者。
为了支持多租户模型,k8s使用namespace机制将一个集群划分为多个虚拟分区,进而实现资源隔离。类似互联网的域名,ns的名称可以看做是一级域名,在ns中部署的服务名则可看做是二级域名。
如:
ns的“分区”是逻辑上的,ns并不与特定的物理资源进行绑定。
多个ns下的应用可以共享相同的Node资源,将“小而轻”的容器应用以更加合理的方式在物理资源中进行调度。
对于某些独享资源的用户,则需为其划分固定的Node范围。
k8s使用【标签label+标签选择器label selector】来实现所有资源对象的角色划分及选择。
通过给Node设置特定的Label,就可以标注该Node属于哪个租户。
在总体资源不够充分的情况下,也可将一个Node设置多个Label,让多个租户共享。
在共享资源的环境下,管理员需要为租户设置更精细的资源配额和资源限制的管理。
各租户在自己的资源分区上部署应用时,将只能使用被分配到的总资源数量。
容器云平台应该将持续监控和统计各租户对资源的使用情况,为未来是否应该为租户增加资源或是减少资源提供依据。
在k8s集群中,为了完成【资源的配额管理+资源限制管理】,可从ns、pod、container三个级别进行管理。
type=container
=>kind: LimitRanger(ns)
defaultRequest
】,表示容器希望被分配到的可完全保证的资源量,Requests的值会被提供给k8s调度器scheduler,以便于优化基于资源请求的容器调度。default
】,Limits是容器能用的资源上限,这个上限的值会影响在节点上发生资源竞争是的解决策略。max+min+maxLimitReauestRatio
type=pod
=>kind: LimitRanger(ns)
max+min+maxLimitReauestRatio
kind: ResourceQuota
compute-resources.yaml
中设置了ns为default的所有容器的cpu request综合不超过1,上限为2等。apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: default
spec:
hard:
requests.cpu: "1"
requests.memory: 1GB
limits.cpu: "2"
limits.memory: 2GB
pods: "4'
configmaps: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
在一个定义了ResourceQuota的k8s集群中部署了许多符合资源条件的容器应用之后,系统会自动统计出已经使用的资源数量。
kubectl describe quota compute-resources
对于租户来说,只要服务的名称保持唯一,不同的服务可以使用相同的端口号。
但是,对于需要对外提供服务的service来说,需要映射服务端口号到Node上(NodePort模式)。
容器云平台应该对映射到Node上的服务端口号提供统一管理,以保证各服务的NodePort端口号不会冲突,同时要确保与Node上其它应用监听的端口号不会产生冲突。
在容器云平台上,对端口号port的管理至少应该包含以下功能:
网络资源作为容器云平台的基础设施,需要为多租户的微服务之间的互联互通提供保障。
在基于k8s的容器云平台上,对于网络资源的需求通常包含依稀阿济格方面:
主流的开源网络方案解决。
k8s网络设计的一个基本原则:每个pod都拥有一个独立的ip地址,而且假定所有的pod都在一个可以直接连通的、扁平的网络空间中,不管他们是否运行在同一个Node(宿主机)中,都可以直接通过对方的ip进行访问。
即:k8s的要求是各Node之间的容器网络能够互通,但k8s本身不提供跨主机的容器网络解决方案。
公有环境(aws、azure、gce、阿里云)通常都提供了容器网络解决方案,但在私有云环境下,任然需要容器云平台为不同的用户提供容器网络解决方案。
Overlay网络解决方案
目前,为容器设置overlay网络是最主流的跨主机容器网络解决方案。
overlay网络是指在不改变现有网络配置的前提下,通过某种额外的网络协议,将原ip报文封装起来,形成一个逻辑上的新网络。
overlay网络为容器云平台提供了灵活的配置方案,能够应对更多的业务需求。
CNI插件解决方案
CNI:Container Network Interface,容器网络接口。
在k8s上建议通过CNI插件的方式部署容器网络。
CNI是CNCF基金会下的一个项目,由一组用于配置容器的网络接口的规范和库组成,现已被k8s、rkt、Apache Mesos、Cloud Foundry和Kurma等项目采纳。
CNI定义的是容器运行环境与网络插件之间的接口规范,仅关心容器创建时的网络配置和容器销毁时网络资源的释放,目的是提供一个普适的容器网络解决方案。
通过一个JSON Schema定义CNI插件提供的输入和输出参数。
一个容器可以通过绑定多个CNI插件加入多个网络中。
目前,Flannel、Contiv Networking、Project Calico、Weave、SR-IOV等开源项目均为k8s CNI提供了具体的插件实现方案。
在CNI模型中只涉及两个概念:容器和网络。
对容器网络的设置和操作都通过插件进行具体的实现,CNI插件包括两种类型:
k8s从1.3版本开始引入了Network Policy机制,主要用于对容器间的网络通信进行限制和准入控制,作用于ns之间和服务之间。
在k8s中使用==NetworkPolicy资源对象(自己编写yaml网络策略定义配置文件)设置网络策略,但仅定义一个网络策略是无法完成实际的网络隔离的,还需要一个策略控制器(由三方网络组件提供)==来实现。
策略控制器由第三方网络组建提供,目前calico、romana、weave等开源项目均支持k8s网络策略的具体实现。
网络策略包括默认策略和自定义策略,以完成粗粒度和细粒度的策略设置。
通过默认策略和自定义策略的组合设置,就能实现在网络层面上对租户之间和服务之间进行禁止访问或允许访问的策略限制,能够起到类似于在防火墙上设置黑白名单的效果。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/6
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
在k8s集群内部,容器默认以srv的形式提供服务,由kube-proxy实现srv到容器的负载均衡功能。
service的概念仅作用于k8s集群内部,集群外的客户端应用默认无法知道service名称的意义,也无法直接使用这些服务。
对于需要为k8s集群外的客户端提供服务的service,可以通过Ingress将服务暴露出去,并且如果该集群(网站)拥有真实域名,则还能将service直接与域名进行对接。
在k8s中可以通过对Ingress资源对象的配置,将不同URL的访问请求转发到后端不同的service上。
k8s将【一个Ingress资源对象的定义 + 一个具体的Ingress Controller】相结合来实现7层负载均衡器。
Ingress Controller在转发客户端请求到后端服务时,将跳过kube-proxy提供的4层LB的功能,直接转发到service的后端pod(endpoints),以提高网络转发效率。
一.常用的Ingress策略:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: myweb
servicePort: 8080
apiVersions: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: mywebsite.com
http:
paths:
- path: /web
backend:
serviceName: web-service
servicePort: 80
- path: /api
backend:
serviceName: api-service
servicePort: 8081
apiVersions: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: foo.com
http:
paths:
- backend:
serviceName: foo-srv
servicePort: 80
- host: bar.com
http:
paths:
- backend:
serviceName: bar-srv
servicePort: 80
/demo
的访问请求转发到webapp:8080/demo
服务上的Ingress策略配置如下:apiVersions: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- http:
paths:
- path: /demo
backend:
serviceName: webapp
servicePort: 8080
注意:在使用无域名的Ingress转发规则是,将默认使用HTTPS安全协议进行转发。
如需使用费安全的HTTP,则需调整Ingress Controller的配置,通常在一个安全的网络环境下进行配置。
二.常用的Ingress Controller
目前针对k8s Ingress提供具体Controller的开源工具包括Nginx、HAProxy和Traefik。
Nginx
Nginx是一款流行的反向代理服务器软件,同时也是一个全栈的web服务器,可以提供web服务器、http代理服务器、邮件代理服务器和负载均衡器功能。
目前k8s社区主要维护基于Nginx的Ingess Controller(https://github.com/kubernetes/ingress-nginx),其主要机制是:通过监听用户设置的Ingress策略,自动完成Nginx相关upstream配置的生成和在线更新。
Nginx特点如下:
-工作在网络7层
-模块化,有丰富的第三方功能模块支持
-支持更强大的正则配置规则
-配置文件热更新
-除了作为LB,还可作为静态web服务器、缓存服务器。
HAProxy
HAProxy为另一款流行的开源代理服务器软件,使用C语言编写而成,提供高可用性、负载均衡、4层和7层代理服务器功能。
目前面向k8s的HAProxy Ingress Controller在github上维护:https://github.com/jcmoraisjr/haproxy-ingress
Traefik
Traefix(https://traefik.io)是近两年出现的面向微服务架构的前端负载均衡器,它 能够实现自动感知k8s集群中service后端容器的变化,自动动态刷新配置文件,以快速实现服务发现。
Nginx、HAProxy和Traefik都能够用于k8s的Ingress Controller,总结对比如下:
Nginx | HAProxy | Traefik | |
---|---|---|---|
性能 | 转发效率高 | HTTP转发效率最高 | 吞吐率约为Nginx的85% |
配置难易度 | 简单,支持强大的正则匹配规则 | 简单 | 简单,与微服务架构对接最好 |
负载均衡机制 | 一般 | 会话保持和健康检查机制全面 | 会话保持和健康检查机制全面 |
社区活跃度 | 活跃 | 一般 | 一般 |
功能使用面 | 代理服务器、web服务器、邮件服务器、LB等 | 代理服务器、LB | proxy、LB |
在k8s集群推荐使用service name作为目的服务的访问地址,这就需要在一个集群范围内的DNS服务来完成从服务名到ClusterIP的解析工作。
一 集群内的DNS服务
在k8s集群内,DNS作为特殊的系统级服务,首先需要在Service ClusterIP地址范围内指定一个固定的IP地址;然后需要在每台Node的kubelet启动参数上指定--cluster-dns=
。
在经过这样的设置后,kubelet会在每个pod内部为其设置DNS服务器的配置,容器内的/etc/resolv.conf
配置文件内容如下:
search default.svc.cluster.local svc.cluster.local svc.cluster.local cluster.local
nameserver 169.169.0.100
options ndots:5
这就为容器环境设置了集群范围内的DNS服务器169.169.0.100,由其完成服务名与服务ClusterIP的解析。
接下来,需要部署这个集群内的DNS服务,DNS服务作为k8s的addon组件发布,经历了从skyDNS到kubeDNS再到coreDNS的演进历程。
二 自定义DNS服务器和上游DNS服务器
k8s集群内部的DNS服务主要用于解析集群内各个service的服务名,并且这个DNS服务的地址在整个集群中需要固定下来,不能与物理网络的真是DNS服务器互相干扰。
同时,很多企业在实际生产环境中都有自己的私有域名区域,例如,可能希望在集群内解析其内部的".corp"域名。
从k8s v1.6版本开始,就可以在k8s集群内配置私有DNS区域(通常被称为存根域Stub Domain),并在k8s集群外配置上游域名服务。
k8s默认的域名解析流程
k8s目前在pod定义中支持两个DNS策略:Default
和ClusterFirst
,dnsPolicy默认为ClusterFirst。
如果将dnsPolicy设置为ClusterFirst,则DNS查询会被发送到集群DNS服务(由skyDNS、kubeDNS或CoreDNS提供具体实现)。
集群DNS服务负责以集群域名为包含域名后缀的服务名,进行从服务名到ClusterIP地址的解析。
客户端对其它域名的查询则会被转发给节点上定义的上游域名服务器。
自定义DNS服务器地址
k8s从1.6版本开始,便可使用ConfigMap
指定 【自定义的存根域(私有DNS域):stubDomains
】 和 【上游DNS Server:upstreamNameservers
】。
通过域名访问集群外的服务—自定义DNS记录
在企业DC环境下,尝尝还需将某些主机的IP地址设置为某个内部域名,以支持客户端应用仅需配置域名就能访问k8s集群外的服务。
kubeDNS和CoreDNS均支持用户自定义的DNS记录。
以CoreDNS为例,可以配置一个新的custom-hosts文件,在其中定义域名(myweb.com)与IP地址的记录。
myweb.com IN SOA sns.dns.icann.org noc.dns.icann.org
myweb.com IN NS a.iana-servers.net
myweb.com IN NS b.iana-servers.net
srv1.myweb.com IN A 192.168.18.4
然后通过CoreDNS的配置文件Corefile指定对该自定义域名文件的引用。
{
...
file/etc/coredns/custom-hosts
...
}
通过上述配置即可实现在pod内对域名srv1.myweb.com的访问了。
通过k8s中service的DNS解析机制、k8s外DNS服务器的设置和自定义DNS记录等机制,可以实现对k8s集群内各容器应用所需的DNS服务进行完整管理,以及与物理网络环境的DNS服务进行对接。
在基于k8s的容器云平台上,对存储资源的使用需求包含以下几个方面:
k8s的volume对象即为针对上述问题的解决方案。
volume类型:
emptyDir
:随着pod的销毁而销毁ConfigMap
:将保存在ConfigMap资源对象中的配置文件信息挂载到容器内的某个目录下。Secret
:将保存在Secret资源对象中的密码秘钥等信息挂载到容器内的某个文件中。downwardAPI
:将downwardAPI的数据已环境变量或文件的形式注入到容器中。gitRepo
:将某Git代码库挂载到容器内的某个目录下。hostPath
:将宿主机的目录或文件挂载到容器内进行使用。local
:k8s从v1.9版本引入,将本地存储以PV的形式提供给容器使用,并能够实现存储空间的管理。PV(persistent volume)
:将共享存储定义为持久存储卷,可以被多个容器应用共享使用。PVC(persistent volume claim)
:用户对存储资源的一次申请,PVC申请的对象是PV,一旦申请成功,应用就能够像使用本地目录一样使用共享存储。共享存储主要用于多个应用都能够使用的存储资源,例如:NFS存储、光纤存储、GlusterFS共享文件系统等。
在k8s系统中通过使用PV/StorageClass和PVC来完成定义,并通过volumeMount挂载到容器的目录或文件进行使用。
PV:对存储资源的抽象
PVC:声明对存储资源的需求
k8s的共享存储供应模式包括静态模式和动态模式,资源供应的结果就是创建好的PV。
container: mountVolume ->挂载pod的volume进容器内使用
pod: volume ->引用PVC
PVC:绑定PV
PV:对应后端物理存储(静态模式下需手工创建PV)
StorageClass
的设置对后端存储进行动态描述,标记为某种“类型Class”。此时要求PVC对存储的类型进行声明,系统将自动完成PV的创建及与PVC的绑定。PVC可以声明Class为""
,说明该PVC进制使用动态模式。container: mountVolume ->挂载pod的volume进容器内使用
pod: volume ->引用PVC
PVC:选择StorageClass
StorageClass:描述后端存储(动态资源供应下,通过StorageClass和PVC完成资源的动态绑定,系统自动生成PV)
对于不同的类型的共享存储,有的需要以静态模式进行管理(如NFS),有的可以以动态模式
进行管理(如GlusterFS)。
k8s支持的共享存储类型:
Ceph RBD
(Rados Block Device):Ceph文件系统和RBD快存储Cinder
:OpenStack Cinder块存储GlusterFS
:开源分布式文件系统vSphere
:VMware的VMDK存储卷Quobyte
:统一文件存储、块存储和对象存储的数据中心文件系统Portworx
:容器定义存储是共享存储解决方案ScaleIO
:Dell EMC提供的一种软件定义存储解决方案StorageOS
:一个提供统一的存储层视图的容器解决方案。gcePersistentDisk
:GCE公有云提供的PersistentDiskAWSElasticBlockStore
:AWS公有云提供的ElasticBlockStoreAzureFile
:Azure公有云提供的FileAzureDisk
:Azure公有云提供的DiskCSI是k8s v1.9版本开始引入的,旨在在容器和共享存储之间建立一套标准的存储访问接口。
在CSI之前,在k8s集群内提供共享存储服务是通过一种被称为“in-tree”的方式实现,该方式要求存储供应商的代码逻辑集成在k8s代码中运行,与k8s为紧耦合关系。
v1.2版本开始开发了FlexVolume模式,通过调用外部存货从供应商提供的可执行程序完成对共享存储的设置,但是依赖外部可执行程序的模式任然有两个复杂的问题需要解决:
CSI规范用于将存储供应商的代码与k8s的代码完全解耦,存储插件的代码由供应商自行维护。
其中,k8s提供以下sidecar辅助容器:
存储供应商可以使用这些组件作为Sidecar配置在存储加减容器旁共同工作,让CSI驱动无须感知他们的存在。
CSI驱动的代码则被完全交给第三方存储供应商自行维护。
对于CSI模式提供的存储资源的使用,同样遵循k8s的PV和PVC模型,也可通过静态资源供应(PVC+PV)或动态资源供应(PVC+StorageClass)对存储资源进行管理。
静态资源管理(PVC+PV):
apiVersion: v1
kind: PersistentVolume
metadata:
name: data-nfsplugin
labels:
name: data-nfsplugin
annotations:
csi.volume.kubernetes.io/volume-attributes: '{"server": "192.168.18.6", "share": "/nfs"}'
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 100MB
csi:
driver: csi-nfsplugin
volumeHandle: data-id
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-nfsplugin
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100MB
selector:
matchExpressions:
- key: name
operator: In
values: ["data-nfsplugin"]
动态资源管理(PVC+StorageClass):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-rbd
provisioners: csi-rbdplugin
parameters:
monitors: 192.168.18.200:6789
pool: kubernetes
csiProvisionerSecretName: csi-ceph-secret
csiProvisionerSecretNamespace: default
reclaimPolicy: Delete
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: csi-rbd
容器应用需根据应用系统的特点,综合考虑容器应用对存储类型、存储性能及数据高可用性等方面的要求,选择最适合存储资源类型。
常见的存储资源应用场景包括如下三类:
容器云平台除了应该提供计算、网络、存储资源的管理功能,还应该提供容器镜像的管理功能。
镜像作为容器应用的基石,需要在镜像库中同一管理,包括对镜像声明周期的管理、对镜像看多租户权限的管理、对镜像库远程复制的管理和对镜像库操作审计的管理。
应用的容器镜像作为应用程序部署包,应具备完善的生命周期管理。
在容器云平台上,通常基于持续集成工作流,由DevOps工具链完成镜像的自动化构建过程,并且记录每次构建的镜像的版本信息。
为了让多租户都能够对各自的应用镜像进行管理,镜像库需要为不同的租户设置不同的镜像访问权限,包括基于角色的权限控制。
对镜像库多租户的权限管理应包括如下功能:
在多DC或跨地域多站点的环境下,为了提高多地区镜像的下载效率,至少需要两级镜像库的设置:总镜像库和子镜像库。
镜像的远程复制能以准实时的方式进行同步,即当在总镜像库中上传了新的镜像或更新了已有镜像时,能够自动触发远程复制操作。
在镜像库中对镜像的操作CRUD等,应当保留操作记录,用于审计管理。
常见开源容器镜像库:
docker run -d --name registry -p 5000:5000 -v /storage/registry:/tmp/registry registry:2
特性对比:
以上开源容器镜像库都支持TLS和RESTful API。