跨集群流量调度实现 Kubernetes 集群金丝雀升级

有了多集群服务和跨集群的流量调度之后,使用 Kubernetes 的方式会发生很大的变化。流量的管理不再限制单一集群内,而是横向跨越了多个集群。最重要的是这一切“静悄悄地”发生,对应用来说毫无感知。

就拿 Kubernetes 版本升级来说吧。记得曾经经历过集群的原地升级:团队的几个人经过多次、多个环境的演练,还要在凌晨的时候进行生产环境的升级。幸好最后是有惊无险,整个过程的体验就像是下图一样:为飞行中的飞机换引擎。

8aaa2f35120bd8473ec10e8abf733239.png
图片来自网络

解决了跨集群的流量调度之后,一切就会变得简单:只需重新建个集群,慢慢将应用迁移到新的集群,让乘客来个“空中转机”。

方案

与之前所做的示例类似,整个方案的核心仍然是跨集群的服务调用:服务可以像使用本地 Service 一样使用多集群 Service。

67c57988438e5704c04ef46f5bd49a6f.gif

Kubernetes 集群金丝雀升级

升级过程中,创建新版本的 Kubernetes 集群,其他的中间件复用现有的,这样少了数据同步等问题。剩下的便是,调整 CD的流程将服务“同时部署到新的集群”。然后再通过 全局流量策略 慢慢放少部分流量到新的集群中进行测试,边测试边调整流量。两个集群的服务也可保持一段时间观察稳定性,然后再慢慢减少原集群的实例直至所有实例下线。

接下来,我们使用进行下示例演示。

演示

环境准备

如上面的图展示的那样,我们先创建两个集群:control-plane1-23 和 1-25。集群 1-23 就是我们现有的集群,1-25 就是最新版本的集群。

集群对外访问地址api-server 对外端口LB 对外端口描述
control-planeHOST_IP(192.168.1.110)6444N/A控制平面集群
1-23HOST_IP(192.168.1.110)644581应用集群
1-25HOST_IP(192.168.1.110)644682应用集群

环境搭建

获取主机 IP 地址备用,192.168.1.110 是我本机的地址。

export HOST_IP=192.168.1.110

搭建集群

使用 k3d 来创建这 3 个 集群。

API_PORT=6444 #6445 6446
PORT=80 #81 82
for CLUSTER_NAME in control-plane 1-23 1-25
dok3d cluster create ${CLUSTER_NAME} \--image docker.io/rancher/k3s:v1.23.8-k3s2 \--api-port "${HOST_IP}:${API_PORT}" \--port "${API_PORT}:6443@server:0" \--port "${PORT}:80@server:0" \--servers-memory 4g \--k3s-arg "--disable=traefik@server:0" \--timeout 120s \--wait((API_PORT=API_PORT+1))((PORT=PORT+1))
done

安装 FSM

在 3 个集群中安装 FSM。

helm repo update
export FSM_NAMESPACE=flomesh
exportFSM_VERSION=0.2.0-alpha.9
for CLUSTER_NAME in control-plane 1-23 1-25
do kubectx k3d-${CLUSTER_NAME}sleep 1helm install --namespace ${FSM_NAMESPACE} --create-namespace --version=${FSM_VERSION} --set fsm.logLevel=5 fsm fsm/fsmsleep 1kubectl wait --for=condition=ready pod --all -n $FSM_NAMESPACE --timeout=120s
done

加入集群组

将集群 1-23 和 1-25 纳入集群 control-plane 的管理。不管是新集群还是旧集群,如果要进行跨集群的服务调用,都是要加入集群组的。

export HOST_IP=192.168.1.110
kubectx k3d-control-plane
sleep 1
PORT=81
for CLUSTER_NAME in 1-23 1-25
dokubectl apply -f - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: Cluster
metadata:name: ${CLUSTER_NAME}
spec:gatewayHost: ${HOST_IP}gatewayPort: ${PORT}kubeconfig: |+
`k3d kubeconfig get ${CLUSTER_NAME} | sed 's|^|    |g' | sed "s|0.0.0.0|$HOST_IP|g"`
EOF
((PORT=PORT+1))
done

安装服务网格

下载 osm CLI

system=$(uname -s | tr [:upper:] [:lower:])
arch=$(dpkg --print-architecture)
release=v1.3.0-beta.1
curl -L https://github.com/flomesh-io/osm-edge/releases/download/$release/osm-edge-$release-$system-$arch.tar.gz | tar -vxzf -
./${system}-${arch}/osm version
cp ./${system}-${arch}/osm /usr/local/bin/

将服务网格 osm-edge 安装到集群 1-23 和 1-25。控制平面不处理应用流量,无需安装。

export OSM_NAMESPACE=osm-system
export OSM_MESH_NAME=osm
for CLUSTER_NAME in 1-23 1-25
dokubectx k3d-${CLUSTER_NAME}DNS_SVC_IP="$(kubectl get svc -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].spec.clusterIP}')"
osm install \--mesh-name "$OSM_MESH_NAME" \--osm-namespace "$OSM_NAMESPACE" \--set=osm.certificateProvider.kind=tresor \--set=osm.image.pullPolicy=Always \--set=osm.sidecarLogLevel=error \--set=osm.controllerLogLevel=warn \--timeout=900s \--set=osm.localDNSProxy.enable=true \--set=osm.localDNSProxy.primaryUpstreamDNSServerIPAddr="${DNS_SVC_IP}"
done

部署实例应用

在集群 1-23 的 httpbin 命名空间(由网格管理,会注入 sidecar)下,部署 httpbin 应用。这里的 httpbin 应用由 Pipy[1] 实现,会返回当前的集群名,并提示被网格管理。

NAMESPACE=httpbin
CLUSTER_NAME="1-23"kubectx k3d-${CLUSTER_NAME}
kubectl create namespace ${NAMESPACE}
osm namespace add ${NAMESPACE}
kubectl apply -n ${NAMESPACE} -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:name: httpbinlabels:app: pipy
spec:replicas: 1selector:matchLabels:app: pipytemplate:metadata:labels:app: pipyspec:containers:- name: pipyimage: flomesh/pipy:latestports:- containerPort: 8080command:- pipy- -e- |pipy().listen(8080).serveHTTP(new Message('Hi, I am from ${CLUSTER_NAME} and controlled by mesh!\n'))
---
apiVersion: v1
kind: Service
metadata:name: httpbin
spec:ports:- port: 8080targetPort: 8080protocol: TCPselector:app: pipy
EOFsleep 3
kubectl wait --for=condition=ready pod -n ${NAMESPACE} --all --timeout=60s

在命名空间 curl 下部署 curl 应用,这个命名空间也是被网格管理的,注入的 sidecar 会完全流量的跨集群调度。

export NAMESPACE=curl
kubectx k3d-1-23
kubectl create namespace ${NAMESPACE}
osm namespace add ${NAMESPACE}
kubectl apply -n ${NAMESPACE} -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:name: curl
---
apiVersion: v1
kind: Service
metadata:name: curllabels:app: curlservice: curl
spec:ports:- name: httpport: 80selector:app: curl
---
apiVersion: apps/v1
kind: Deployment
metadata:name: curl
spec:replicas: 1selector:matchLabels:app: curltemplate:metadata:labels:app: curlspec:serviceAccountName: curlcontainers:- image: curlimages/curlimagePullPolicy: IfNotPresentname: curlcommand: ["sleep", "365d"]
EOFsleep 3
kubectl wait --for=condition=ready pod -n ${NAMESPACE} --all --timeout=60s

测试

在集群 1-23 中的 curl 向 httpbin 发送请求。

kubectx k3d-1-23
curl_client="$(kubectl get pod -n curl -l app=curl -o jsonpath='{.items[0].metadata.name}')"kubectl exec "${curl_client}" -n curl -c curl -- curl -s http://httpbin.httpbin:8080/

看到下面的输出,说明服务正常。

Hi, I am from 1-23 and controlled by mesh!

导出服务

服务的导出就是向集群组注册服务,执行下面的命令将集群 1-23 中的服务 httpbin 注册到集群组。注意,该命令是在集群 1-23 中执行的。

export NAMESPACE_MESH=httpbin
CLUSTER_NAME="1-23"
kubectx k3d-${CLUSTER_NAME}
kubectl apply -f - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:namespace: ${NAMESPACE_MESH}name: httpbin
spec:serviceAccountName: "*"rules:- portNumber: 8080path: "/${CLUSTER_NAME}/httpbin-mesh"pathType: Prefix
EOF
sleep 1

此时,我们的系统如下图所示。

4181e4bdc31d82bddf4fad601946fcf3.jpeg
集群升级.002

升级迁移

新集群中部署应用

有了新版本的集群之后,我们慢慢向新集群迁移服务。在集群 1-25 中部署 httpbin 服务。

NAMESPACE=httpbin
CLUSTER_NAME="1-25"kubectx k3d-${CLUSTER_NAME}
kubectl create namespace ${NAMESPACE}
osm namespace add ${NAMESPACE}
kubectl apply -n ${NAMESPACE} -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:name: httpbinlabels:app: pipy
spec:replicas: 1selector:matchLabels:app: pipytemplate:metadata:labels:app: pipyspec:containers:- name: pipyimage: flomesh/pipy:latestports:- containerPort: 8080command:- pipy- -e- |pipy().listen(8080).serveHTTP(new Message('Hi, I am from ${CLUSTER_NAME} and controlled by mesh!\n'))
---
apiVersion: v1
kind: Service
metadata:name: httpbin
spec:ports:- port: 8080targetPort: 8080protocol: TCPselector:app: pipy
---
apiVersion: v1
kind: Service
metadata:name: httpbin-${CLUSTER_NAME}
spec:ports:- port: 8080targetPort: 8080protocol: TCPselector:app: pipy
EOFsleep 3
kubectl wait --for=condition=ready pod -n ${NAMESPACE} --all --timeout=60s

导出服务

向集群组注册集群 1-25 的服务 httpbin

export NAMESPACE_MESH=httpbin
CLUSTER_NAME="1-25"
kubectx k3d-${CLUSTER_NAME}
kubectl apply -f - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:namespace: ${NAMESPACE_MESH}name: httpbin
spec:serviceAccountName: "*"rules:- portNumber: 8080path: "/${CLUSTER_NAME}/httpbin-mesh"pathType: Prefix
EOF
sleep 1

回到集群 1-23,查看 ServiceImports httpbin,可以看到已经发现了集群 1-25 注册的服务。

kubectl get serviceimports httpbin -n httpbin -o jsonpath='{.spec}' | jq
{"ports": [{"endpoints": [{"clusterKey": "default/default/default/1-25","target": {"host": "192.168.1.110","ip": "192.168.1.110","path": "/1-25/httpbin-mesh","port": 82}}],"port": 8080,"protocol": "TCP"}],"serviceAccountName": "*","type": "ClusterSetIP"
}

但此时在 curl发送请求,并不会收到集群 1-25 中的响应。还记得 上篇 中提到过,默认的全局流量策略是 Locality,因此集群外的节点并不会参与请求的处理。

Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!

我们创建一个 ActiveActive 的全局流量策略。注意,这里设置 targets 的时候我们加上了代表权重的字段 weight 将其设置为 10,表示将 1/11 的流量导入集群 1-25 中,记住本集群的权重总是 100

kubectx k3d-1-23
kubectl apply -n httpbin -f  - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:name: httpbin
spec:lbType: ActiveActivetargets:- clusterKey: default/default/default/1-25weight: 10
EOF

这次我们请求 20 次,结果也正如我们所期望的,只有 1-2 次请求进入集群 1-25

for i in {1..20}; do kubectl exec "${curl_client}" -n curl -c curl -- curl -s http://httpbin.httpbin:8080/ ; done
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!

我们将集群 1-25 的权重设置为 900,因此会有 90% 的流量进入集群 1-25

kubectx k3d-1-23
kubectl apply -n httpbin -f  - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:name: httpbin
spec:lbType: ActiveActivetargets:- clusterKey: default/default/default/1-25weight: 900
EOF

然后请求 10 次,会看到 9 次的请求都进入到集群 1-25,也就是 90% 的流量分流到了其他集群。

for i in {1..10}; do kubectl exec "${curl_client}" -n curl -c curl -- curl -s http://httpbin.httpbin:8080/ ; done
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-23 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!
Hi, I am from 1-25 and controlled by mesh!

接着就是停止集群 1-23 中的实例,使所有流量都分流到外集群。

kubectl scale deploy httpbin -n httpbin --replicas 0

最后的工作就是慢慢得将 curl 服务也迁移到新的集群中,进而是所有的服务都迁移完成之后,下线旧的集群。

总结

自维护的 Kubernetes 集群升级不是一件容易的事情,原地升级风险高,尤其是升级控制面。不管是蓝绿还是金丝雀升级,都面临着流量跨集群的问题:流量除了从入口进入还会有其他的途径,比如消息系统,定时任务等等。

解决了流量的跨集群调度问题后,这些问题都迎刃而解。剩下的问题就是如何让迁移做到自动化、可控的迁移了。

引用链接

[1] Pipy: https://flomesh.io/pipy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280495.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

usr/bin/expect方式免密码登录和发送文件脚本

2019独角兽企业重金招聘Python工程师标准>>> ssh 登录 #!/usr/bin/expect set timeout 20 if { [llength $argv] < 3} { puts "Usage:" puts "remote_host password cmd" exit 1 } set remote_host [lindex $argv 0] set passwor…

8-[多线程] 进程池线程池

1、为甚需要进程池&#xff0c;线程池 介绍官网&#xff1a;https://docs.python.org/dev/library/concurrent.futures.htmlconcurrent.futures模块提供了高度封装的异步调用接口 ThreadPoolExecutor&#xff1a;线程池&#xff0c;提供异步调用 ProcessPoolExecutor: 进程池&a…

香港连续25年被评为全球最自由经济体

中新社香港1月25日电 美国智库传统基金会25日在华盛顿发表2019年《经济自由度指数》报告&#xff0c;香港今年再次成为唯一一个总分超过90分的经济体&#xff0c;已连续25年被评价为全球最自由经济体。 报告显示&#xff0c;香港今年的总分为90.2分&#xff08;100分为满分&…

mac 下安装jenkins

2019独角兽企业重金招聘Python工程师标准>>> 平台搭建 Jenkins安装和启动 官网&#xff1a;https://jenkins.io/index.html 下载&#xff1a;http://mirrors.jenkins-ci.org/war/latest/jenkins.war 安装&#xff1a; 依赖于Java环境&#xff0c;首先安装和配置Java…

safari 获取视频流_如何在Safari中将RSS feed和社交媒体合并为一个流

safari 获取视频流Safari allows you to subscribe to RSS feeds and add your social media accounts so you can view them right in the browser, in one universal feed, without the need of any add-on applications or extensions. Safari允许您订阅RSS feed并添加您的社…

编译安装Centos7.2+Apache2.4.25+PHP7.2.10+Mysql5.6.16

一、编译部署Apache2.4.251、环境准备#设置或停止防火墙&#xff1a; [rootlocalhost ~]# systemctl stop firewalld.service [rootlocalhost ~]# systemctl disable firewalld.service#关闭selinux&#xff1a; 临时关闭&#xff1a; [rootlocalhost ~]# setenforce 0永久关闭…

国际知名计算机视觉和机器学习软件开源平台OpenCV正式支持龙架构

前言介绍近期&#xff0c;OpenCV开源社区正式合入了对龙架构&#xff08;LoongArch™&#xff09;支持的代码&#xff0c;基于龙架构自主指令系统&#xff0c;优化后的OpenCV性能显著提升。OpenCV是一款跨平台的计算机视觉和机器学习软件平台&#xff0c;在计算机视觉领域广泛使…

优化器--牛顿法总结

---这里记录下一些关于牛顿法来作为优化器的个人笔记 &#xff1a;&#xff09; 关于牛顿法&#xff0c;先不说其中的概念&#xff0c;来简单看一个例子&#xff1f; 不用计算器&#xff0c;如何手动开一个值的平方根&#xff0c;比如计算{sqrt(a) | a4 } &#xff1f; 不用程序…

在命令提示符输出c语言代码_您可以在Windows命令提示符中更改输出缓冲区的大小吗?...

在命令提示符输出c语言代码If you are someone who loves using the Windows Command Prompt, you may have found yourself curious as to why the screen output buffer has such a ‘large’ default size. Can you change it to a smaller (or even larger) size? Today’…

django23:BS4/kindeditor上传图片

BS4 Beautiful Soup&#xff0c;Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。 安装 pip3 install beautifulsoup4 使用 from bs4 import BeautifulSoup#html_doc为网页内容 soup Be…

mac 防止 下载 睡眠_如何暂时防止Mac进入睡眠状态

mac 防止 下载 睡眠Let’s say you start a big download, then go to bed. When you wake up, you realize your Mac went to sleep before finishing its job. Isn’t there some way to stop this? 假设您开始进行大量下载&#xff0c;然后上床睡觉。 当您醒来时&#xff0…

mac共享单个磁盘_如何与您的所有设备共享酒店的单个Wi-Fi连接

mac共享单个磁盘Many hotels still limit you to one or two Wi-Fi devices per room–a frustrating limitation, especially when traveling with someone else. Connection restrictions can apply anywhere you have to log into a Wi-Fi network via a portal instead of …

Python FastApi:快速建立docker容器/挂载共享文件夹/导入导出

一、目的 a.快速把原有fastapi代码部署到docker&#xff0c;让docker在server运行。 b.不涉及docker深入设置。 c.使用python第三方lib少或简单。 二、步骤 ps:请提前安装docker 1.新建Dockerfile&#xff0c;放入到项目根目录 a.Dockerfile没有后缀. b.准备好requireme…

PHP-FPM 与 Nginx 的通信机制总结

PHP-FPM 介绍 CGI 协议与 FastCGI 协议 每种动态语言&#xff08; PHP,Python 等&#xff09;的代码文件需要通过对应的解析器才能被服务器识别&#xff0c;而 CGI 协议就是用来使解释器与服务器可以互相通信。PHP 文件在服务器上的解析需要用到 PHP 解释器&#xff0c;再加上对…

Android——监听事件总结

各种监听事件 1.按钮 Button&#xff08;1&#xff09;点击监听btn_1.setOnClickListener(new View.OnClickListener() { &#xff08;2&#xff09;长按监听btn_1.setOnLongClickListener(new View.OnLongClickListener() { 2.单选框 RadioGroupradio_gp.setOnCheckedChangeLi…

ChatGPT 大智近妖,从宇宙人生到手搓光刻机,从哄女朋友到写年终总结我们聊得非常开心,反而让人越来越忧心...

都说 ChatGPT 要干掉程序员&#xff0c;清理搜索引擎&#xff0c;取代Stack Overflow&#xff0c;还能消灭人类&#xff0c;这些有些言过其实了。ChatGPT 的定位是一个人工智能助理&#xff0c;它说&#xff0c;它的主要目的是通过回答用户的问题&#xff0c;为用户提供帮助。在…

如何在Windows Defender中安排扫描

Windows Defender automatically performs background scans during your PC’s idle moments, but doesn’t include an easy way to schedule a full scan. There is a way to do it, though. Windows Defender在PC空闲时自动执行后台扫描&#xff0c;但是没有包括安排完整扫…

复习深入笔记02:魔法方法/cookie,session,token/异常

魔法方法 对象生成 1.先调用__new__方法&#xff0c;生成空对象。控制对象生成。 2.当执行“对象类名&#xff08;namelqz&#xff09;”&#xff0c;触发类的__init__()

比特熊故事汇独家 | .NET 感恩专场

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;15分钟)大家好&#xff01;我是爱吃、爱玩、更爱学习技术&#xff0c;IT界新晋小红人&#xff0c;开发者的好朋友——比特熊&#xff01;比特熊&#xff1a;本期故事汇是.NET专场&#xff0c;今天一次性邀请到DOTNET领…