分布式云
目前多集群管理已经是一个趋势,很多企业已经将业务部署在多个云上即分布式云。那么它有什么好处呢?
- 成本优化:如果企业没有上云的话,基础设施资源一般是按照季度或者年度来规划,如果业务发展速度没有达到,那么资源就会浪费。上云之后,可以将一部分业务部署在本地的数据中心,一部分业务转移到公有云,这块的预算可以少一点,这样等到业务爆发也来得及去扩展。
- 更好的弹性和灵活性:比如12306,平时购票人不多,过节时购票的并发请求非常高,可以预先配置好服务器规格,根据弹性来灵活扩展,而不是一次购买大量的服务器来支持过节时的高并发。
- 避免厂商锁定:云有多家提供商,这样可选择性就很大,不用只依赖一家。
- 第一时间获取云上的新功能:本地部署了集群,k8s版本升级很不方便。而云上可以直接选择最新版本进行部署。
- 容灾:一般是两第三中心,部署多个集群。
- 数据保护及风险管理:可以将不重要的业务迁移到公有云,生产系统部署在本地的数据中心,保护数据安全。
- 提升响应速度:集群部署在不同地域,这样不同地域的访问速度就会大大增快。
分布式云的挑战
- Kubernetes 单集群承载能力有限:k8s最多支持5000个节点。
- 异构的基础设施:操作系统,内核,硬件可能都不一样。有了k8s之后异构的多集群管理才变得可能,抽象出计算资源,通过不同的超卖比来实现不同性能机器的管理。
- 存量资源接入:现有的资源如何接入。
- 配置变更及下发:升级时先升级第一个集群,再升级第三个集群,每个集群内部有自己的rolling update Strategy,这样就需要定义集群维度的升级策略。
- 跨地域、跨机房应用部署及管理:应用在部署时需要考虑故障域。
- 容灾与隔离性,异地多活
- 弹性调度及自动伸缩
- 监控告警
如何应对挑战
通过 Kubernetes 屏蔽底层基础设施,提供统一的接入层。
统一的管控面
多云架构
- 多集群不等于多云
- 多集群管控
单集群跨地域管理
将北京,上海,深圳中的节点加入到一个集群中,通过topologyKey的annotation来管理不同地域的pod,再通过podAffinity或者podAntiAffinity来定义pod只能部署在单一地域。
service通过topologyKey来控制服务的优先级。下面就是先访问本zone再访问本region,如果没有就直接失败。或者加一个“*”,这样即使前面都没有匹配,也会访问其他地域的服务。这样就实现了就近访问。
apiVersion: V1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulinglgnoredDuringExecution:
- labelSelector:
matchExpressions:
key: region
operator: In
values:
- beiing
topologyKey: topology.kubernetes.io/zone
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
protocol:TCP
port: 80
targetPort: 9376
topologykeys:
- "topology.kubernetes.io/zone"
- "topology.kubernetes.io/region"
集群联邦
什么是集群联邦
集群联邦(Federation)是将多个Kubernetes 集群注册到统一控制平面,为用户提供统—API入口的多集群解决方案。
集群联邦设计的核心是提供在全局层面对应用的描述能力,并将联邦对象实例化为 Kubernetes 对象,分发到联邦下辖的各个成员集群中。
为什么需要集群联邦
- 单一集群的管理规模有上限
- 数据库存储
etcd 作为 Kubernetes 集群的后端存储数据库,对空间大小的要求比较苛刻,这限制了集群能存储的对象数量和大小。 - 内存占用
- 为提高系统效率,Kubernetes 的API Server 作为 API 网关,会对该集群的所有对象做缓存。集群越大,缓存需要的内存空间就越大。
- 其他 Kubernetes 控制器也需要对货听的对象构建客户端缓存,这些都需要占用系统内存。这些内存需求都要求对系统的规模有所限制。
- 控制器复杂度
Kubernetes 的一个业务流程是由多个对象和控制器联动完成的,即使控制器遵循了设计原则,随着对象数量的增长,控制器的处理耗时也会越来越长。 - 单个计算节点资源上限
- 单个计算节点的资源,不仅仅是 CPU、内存等可量化资源。
- 还有端口、进程数量等不可量化资源。比如 Linux 支持的 TCP 端口上限是 65535,去除常用端口和程序源端口后,留给 Service nodePort 的端口数量是有限的,这限制了集群支持的 Service 的数量。
- 故障域控制
集群规模越大,控制平面组件出现故障时的影响范围就越大。为了更好地控制故障域,需要将大规模的数据中心切分成多个规模相对较小的集群,每个集群控制在一定规模。 - 应用高可用部署
生产应用通常需要多数据中心部署来保障跨地域高可用,以确保当其中一个数据中心出现故障,或者集群做技术迭代更新时,其他数据中心可以继续提供服务。 - 混合云
私有云加公有云的混合云模式逐渐成为企业的主流架构。
- 数据库存储
集群联邦的职责
- 跨集群同步资源
联邦可以将资源同步到多个集群并协调资源的分配。例如,联邦可以保证一个应用的 Deployment 被部署到多个集群中,同时能够满足全局的调度策略。 - 跨集群服务发现
联邦汇总各个集群的服务和 Ingress,并暴露到全局 DNS服务中。 - 高可用
联邦可以动态地调整每个集群的应用实例,且隐藏了具体的集群信息。 - 避免厂商锁定
每个集群都是部署在真实的硬件或云供应商提供的硬件(或虚拟硬件)之上的,若要更换供应商,只需在新供应商提供的硬件上部署新的集群,并加入联邦。联邦可以几乎透明地将应用从原集群迁移到新集群而无须对应用做更改。
基于集群联邦的高可用应用部署
应用分别部署在私有云和公有云中,假如每个集群部署3个pod,再通过ingress接入网关把服务暴露出去,上层再加一层slb,再设置dns解析到这3个slb的ip。
客户访问服务时,先解析dns,dns再通过轮询分别指向3个地域,一个地域出现故障,另一个地域仍然正常工作。
集群联邦架构
集群管理+联邦对象管理。
- etcd 作为分布式存储后端存储所有对象;
- API Server 作为 API 网关,接收所有来自用户及控制平面组件的请求;
- 不同的控制器对联邦层面的对象进行管理、协调等;
- 调度控制器在联邦层面对应用进行调度、分配。
- 集群联邦支持灵活的对象扩展,允许将基本Kubernetes 对象扩展为集群联邦对象,并通过统一的联邦控制器推送和收集状态。
Federated Type:- Template:集群同步对象的具体参数
- Placement:这个对象应该往哪个集群同步
可以通过cluster或者clusterSeletor 选择对应标签(label)的集群。两者同时存在时,明确定义的集群名单优先级高。 - Overrides:同步时修改模版进行本地化
不支持 List(Array),比如无法修改image。因为数组是通过下标来标识等,如果用户删除了某个集群,后面的下标都跟着变动了。
集群联邦管理的对象
成员集群是联邦的基本管理单元,所有待管理集群均须注册到集群联邦。
集群联邦 V2 提供了统一的工具集(Kubefedctl),允许用户对单个对象动态地创建联邦对象。
动态对象的生成基于 CRD。
集群注册中心
- 集群注册中心(ClusterRegistry)提供了所有联邦下辖的集群清单,以及每个集群的认证信息、状态信息等。
- 集群联邦本身不提供算力,它只承担多集群的协调工作,所有被管理的集群都应注册到集群联邦中。
- 集群联邦使用了单独的 KubeFedCluster 对象(同样适用 CRD 来定义)来管理集群注册信息:
- 在该对象的定义中,不仅包含集群的注册信息,还包含集群的认证信息的引用,以明确每个集群使用的认证信息;
- 该对象还包含各个集群的健康状态、域名等;
- 当控制器行为出现异常时,直接通过集群状态信息即可获知控制器异常的原因。
实例
官网地址:https://github.com/kubernetes-sigs/kubefed
- 安装go,如果已经安装请忽略。
yum -y install go
- 设置go环境
go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.cn,direct go env
- 下载federation代码
git clone https://github.com/kubernetes-sigs/kubefed.git
- 使用kind生成集群,kind需要提前安装
kind create cluster
- 进入kubefed目录,安装Federation控制平面
make deploy.kind
这里会报错:
go: github.com/evanphx/json-patch@v4.12.0+incompatible: Get "https://proxy.golang.org/github.com/evanphx/json-patch/@v/v4.12.0+incompatible.mod": dial tcp 172.217.160.113:443: i/o timeout
报错原因是去proxy.golang.org拉取json-patch失败,因为不可描述的原因。查看go env正常,gobin的pkg/mod目录中也有json-patch@v4.12.0+incompatible。
- 查看报错信息,是在docker里面拉取的mod,修改Makefile
vim Makefile # 在docker启动命令中,添加goproxy $(DOCKER_BUILD) env GOPROXY="https://goproxy.cn,direct" GOARCH=$(word 2,$(subst -, ,$(2))) GOOS=$(word 1,$(subst -, ,$(2))) $(GO_BUILDCMD) -o $(1)-$(2) cmd/$(3)/main.go $(DOCKER_BUILD) env GOPROXY="https://goproxy.cn,direct" GOARCH=$(word 2,$(subst -, ,$(2))) GOOS=$(word 1,$(subst -, ,$(2))) go test -c $(LDFLAG_OPTIONS) -o $(1)-$(2) ./test/$(3)
- 再次安装,报错在bin目录中缺少etcd和’kube-apiserver,需要先执行脚本。kubefedctl-0.9.2-linux-amd64.tgz这个是我手动下载的,实际不需要。
- 执行脚本
sh ../scripts/download-binaries.sh
查看下载脚本,判断是下载kubebuilder压缩包出错。
https://github.com/kubernetes-sigs/kubebuilder/releases/
进入bin目录手动下载,再次执行脚本wget https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz wget https://github.91chi.fun//https://github.com//kubernetes-sigs/kubebuilder/releases/download/v3.4.1/kubebuilder_linux_amd64 wget https://github.91chi.fun//https://github.com//golangci/golangci-lint/releases/download/v1.46.2/golangci-lint-1.46.2-linux-amd64.tar.gz tar xvf 这三个tar.gz cp 二进制文件到bin目录 mv kubebuilder_linux_amd64 kubebuilder sh ../scripts/download-binaries.sh
- 我这里多次执行部署脚本都报错了,这是由于api-versions中没有core.kubefed.io/v1beta1
需要手动apply这个目录。k apply -f /root/kubefed/config/crds k api-versions
重新部署仍然报错。。。 - 使用helm安装(qaq)
helm repo add kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts helm repo update helm repo list helm search repo # 如果报错无法下载可以用这个链接下载到本地 wget https://github.91chi.fun//https://github.com//kubernetes-sigs/kubefed/releases/download/v0.9.2/kubefed-0.9.2.tgz tar xvf kubefed-0.9.2.tgz cd kubefed/ helm install kubefed . -n kube-federation-system helm list -n kube-federation-system kc
终于安装成功了555.。。。 - 查看kubeconfig
kind get kubeconfig
添加自身集群到kubefedcluster
kubefedctl join wghdr --cluster-context kind-kind --host-cluster-context kind-kind --v=2 kubectl -n kube-federation-system get kubefedcluster -oyaml
查看kubefedcluster集群组件kubectl get all -n kube-federation-system
- 将namespace设置为联邦对象
k create ns federate-me kubefedctl federate ns federate-me
- 创建联邦deployment
apiVersion: types.kubefed.io/v1beta1 kind: FederatedDeployment metadata: name: test-deployment spec: template: metadata: name: mynginx spec: replicas: 3 selector: matchLabels: run: mynginx template: metadata: labels: run: mynginx spec: containers: - image: nginx:latest imagePullPolicy: IfNotPresent name: nginx placement: # 可以添加多个集群 clusters: - name: wghdr k apply -f federatedeployment.yaml -n federate-me k get po,deploy -n federate-me
这里是先创建了联邦deployment,联邦控制器检测到联邦deployment后,看placement配置,下发到目标集群wghdr,生成deployment。单集群效果不明显,如果是很多个集群,就不用来回切context,而是在placement下添加多个集群就可以了。 - 添加ReplicaSchedulingPreference对象,让副本在调度的时候有选择性。
apiVersion: scheduling.kubefed.io/v1alpha1 kind: ReplicaSchedulingPreference metadata: name: test-deployment spec: targetKind: FederatedDeployment totalReplicas: 3 clusters: wghdr: minReplicas: 1 maxReplicas: 1 weight: 1 k apply -f federatedeployment-rsp.yaml -n federate-me k get po -n federate-me k get fdeploy -n federate-me -o yaml
可以看到pod数量变为了1,fdeploy中添加了overrides配置,修改了集群wghdr的/spec/replicas数量。这样即使集群模版副本数量为3,member集群也可以自定义副本数量。 - 删除rsp,pod数量仍然为1,overrides参数也没有消失。
集群类型
- Host:用于提供 KubeFed AP1 与控制平面的集群,本质上就是 Federation 控制面。
- Member:通过 KubeFed API 注册的集群,并提供相关身份凭证来让 KubeFed Controller 能够存取集群。
Host 集群也可以作为 Member 被加入。
注册集群
通过kubefedctl join/unjoin 来注册/离开集群。
kubefedcluster中会包括apiEndpoint,caBundle,secret(集群联邦需要的认证信息),status。
Federation 支持的核心对象
- core.kubefed.k8s.io
集群组态、联邦资源组态、KubeFed Controller 配置等。 - types.kubefed.k8s.io
联邦Kubernetes API资源。ns,deploy,cm,secret等。 - scheduling.kubefed.k8s.o
副本编排策略。 - multiclusterdns.kubefed.k8s.io
跨集群服务发现设定。k get crd | grep kubefed
Type Configuration
定义了哪些 Kubernetes API 资源要被用于联邦管理。
若想新增 Federated API 的话,可通过 kubefedctl enable res指令来创建。
比如说想将 ConfigMap 资源通过联邦机制建立在不同集群上时,就必须先在 Federation Host 集群中,通过 CRD 建立新资源 FederatedConfigMap,接着再建立名称为configmaps 的 Type configuration (FederatedTypeConfig)资源,然后描述ConfigMap 要被 FederatedConfigMap 所管理,
这样 KubeFed Controllers 才能知道如何建立 Federated 资源。