首页 > 其他分享 >跨集群流量调度实现 Kubernetes 集群金丝雀升级

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

时间:2024-01-04 10:37:16浏览次数:28  
标签:controlled Kubernetes 23 -- 金丝雀 kubeconfig mesh 集群

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

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

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

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

方案

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

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

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

接下来,我们使用进行下示例演示如何使用 Flomesh 服务网格 实现集群的平滑升级。

演示

环境准备

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

集群

对外访问地址

api-server 对外端口

LB 对外端口

描述

control-plane

HOST_IP(192.168.1.110)

6444

N/A

控制平面集群

1-23

HOST_IP(192.168.1.110)

6445

81

应用集群

1-25

HOST_IP(192.168.1.110)

6446

82

应用集群

工具准备

  • Docker
  • K3d
  • kubectl
  • jq

环境搭建

创建一个 bridge 类型的网络 multi-clusters,所有的容器都工作在这个网络中。

docker network create multi-clusters

获取主机 IP 地址,这个地址将作为集群的访问地址。

export HOST_IP=$(if [ "$(uname)" == "Darwin" ]; then ipconfig getifaddr en0; else ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p'; fi)

搭建集群

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

API_PORT=6444 #6445 6446
PORT=80 #81 82
for CLUSTER_NAME in control-plane 1-23 1-25
do
  if [ "$CLUSTER_NAME" = "control-plane" ]; then
    IMAGE_TAG="v1.25.15-k3s2"
  elif [ "$CLUSTER_NAME" = "1-23" ]; then
    IMAGE_TAG="v1.23.8-k3s2"
  elif [ "$CLUSTER_NAME" = "1-25" ]; then
    IMAGE_TAG="v1.25.15-k3s2"
  fi
  k3d cluster create ${CLUSTER_NAME} \
    --image docker.io/rancher/k3s:${IMAGE_TAG} \
    --api-port "${HOST_IP}:${API_PORT}" \
    --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

保存集群的 kubeconfig

kubeconfig_cp=${KUBECONFIG_CP:-"/tmp/cp.kubeconfig"}
kubeconfig_123=${KUBECONFIG_C1:-"/tmp/123.kubeconfig"}
kubeconfig_125=${KUBECONFIG_C2:-"/tmp/125.kubeconfig"}

k0="kubectl --kubeconfig ${kubeconfig_cp}"
k1="kubectl --kubeconfig ${kubeconfig_123}"
k2="kubectl --kubeconfig ${kubeconfig_125}"

k3d kubeconfig get control-plane >"${kubeconfig_cp}"
k3d kubeconfig get 1-23 >"${kubeconfig_123}"
k3d kubeconfig get 1-25 >"${kubeconfig_125}"

安装 FSM

下载 FSM CLI

system=$(uname -s | tr '[:upper:]' '[:lower:]')
arch=$(uname -m | sed -E 's/x86_/amd/' | sed -E 's/aarch/arm/')
release=v1.1.4
curl -L https://github.com/flomesh-io/fsm/releases/download/$release/fsm-$release-$system-$arch.tar.gz | tar -vxzf -
./$system-$arch/fsm version
sudo cp ./$system-$arch/fsm /usr/local/bin/fsm

在 3 个集群中安装 FSM。

export FSM_NAMESPACE=fsm-system
export FSM_MESH_NAME=fsm
for CONFIG in kubeconfig_cp kubeconfig_123 kubeconfig_125
do 
	DNS_SVC_IP="$(kubectl --kubeconfig ${!CONFIG} get svc -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].spec.clusterIP}')"
	KUBECONFIG=${!CONFIG} fsm install \
      --mesh-name "$FSM_MESH_NAME" \
      --fsm-namespace "$FSM_NAMESPACE" \
      --set=fsm.fsmIngress.enabled=true \
      --set=fsm.localDNSProxy.enable=true \
      --set=fsm.localDNSProxy.primaryUpstreamDNSServerIPAddr="${DNS_SVC_IP}" \
      --timeout=900s
    sleep 2
    kubectl --kubeconfig ${!CONFIG} wait --for=condition=ready pod --all -n $FSM_NAMESPACE --timeout=120s
done

加入集群组

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

在集群 control-plane 为两个集群创建 CR Cluster,同时提供入口的 IP 地址 gatewayHost 和端口 gatewayPort,以及服务网格所在的命名空间 fsmNamespace。最终要的还有集群的 kubeconfig,用于访问集群。

PORT=81
for CLUSTER_NAME in 1-23 1-25
do
    kubectl --kubeconfig ${kubeconfig_cp} apply -f - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: Cluster
metadata:
  name: ${CLUSTER_NAME}
spec:
  gatewayHost: ${HOST_IP}
  gatewayPort: ${PORT}
  fsmNamespace: ${FSM_NAMESPACE}
  kubeconfig: |+
$(k3d kubeconfig get ${CLUSTER_NAME} | sed 's|^|    |g' | sed "s|0.0.0.0|$HOST_IP|g")
EOF
    ((PORT = PORT + 1))
done

查看集群组的情况:

$k0 get cluster
NAME   REGION    ZONE      GROUP     GATEWAY HOST   GATEWAY PORT   MANAGED   MANAGED AGE   AGE
1-23   default   default   default   10.0.2.4       81             True      10s           11s
1-25   default   default   default   10.0.2.4       82             True      9s            11s

部署实例应用

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

NAMESPACE=httpbin
CLUSTER_NAME="1-23"
kubectl --kubeconfig ${kubeconfig_123} create namespace ${NAMESPACE}
KUBECONFIG=${kubeconfig_123} fsm namespace add ${NAMESPACE}
kubectl --kubeconfig ${kubeconfig_123} apply -n ${NAMESPACE} -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  labels:
    app: pipy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
  template:
    metadata:
      labels:
        app: pipy
    spec:
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - containerPort: 8080
          command:
            - 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: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
EOF

sleep 3
kubectl --kubeconfig ${kubeconfig_123} wait --for=condition=ready pod -n ${NAMESPACE} --all --timeout=60s

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

export NAMESPACE=curl
kubectl --kubeconfig ${kubeconfig_123} create namespace ${NAMESPACE}
KUBECONFIG=${kubeconfig_123} fsm namespace add ${NAMESPACE}
kubectl --kubeconfig ${kubeconfig_123} apply -n ${NAMESPACE} -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: curl
---
apiVersion: v1
kind: Service
metadata:
  name: curl
  labels:
    app: curl
    service: curl
spec:
  ports:
    - name: http
      port: 80
  selector:
    app: curl
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: curl
  template:
    metadata:
      labels:
        app: curl
    spec:
      serviceAccountName: curl
      containers:
      - image: curlimages/curl
        imagePullPolicy: IfNotPresent
        name: curl
        command: ["sleep", "365d"]
EOF

sleep 3
kubectl --kubeconfig ${kubeconfig_123} wait --for=condition=ready pod -n ${NAMESPACE} --all --timeout=60s

测试

在集群 1-23 中的 curlhttpbin 发送请求。

curl_client="$(kubectl --kubeconfig ${kubeconfig_123} get pod -n curl -l app=curl -o jsonpath='{.items[0].metadata.name}')"

kubectl --kubeconfig ${kubeconfig_123} 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
kubectl --kubeconfig ${kubeconfig_123} apply -f - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:
  namespace: ${NAMESPACE_MESH}
  name: httpbin
spec:
  serviceAccountName: "*"
  rules:
    - portNumber: 8080
      path: "/httpbin"
      pathType: Prefix
EOF
sleep 1

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

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

升级迁移

新集群中部署应用

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

NAMESPACE=httpbin
CLUSTER_NAME="1-25"

kubectl --kubeconfig ${kubeconfig_125} create namespace ${NAMESPACE}
KUBECONFIG=${kubeconfig_125} fsm namespace add ${NAMESPACE}
kubectl --kubeconfig ${kubeconfig_125} apply -n ${NAMESPACE} -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  labels:
    app: pipy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
  template:
    metadata:
      labels:
        app: pipy
    spec:
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - containerPort: 8080
          command:
            - 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: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin-${CLUSTER_NAME}
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
EOF

sleep 3
kubectl --kubeconfig ${kubeconfig_125} wait --for=condition=ready pod -n ${NAMESPACE} --all --timeout=60s

导出服务

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

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

发现多集群服务

回到集群 1-23,查看 ServiceImports httpbin,可以看到已经发现了集群 1-25 注册的服务。其中 82 就是新集群访问入口的端口。

kubectl --kubeconfig ${kubeconfig_123} get serviceimports httpbin -n httpbin -o jsonpath='{.spec}' | jq
{
  "ports": [
    {
      "endpoints": [
        {
          "clusterKey": "default/default/default/1-25",
          "target": {
            "host": "10.0.2.4",
            "ip": "10.0.2.4",
            "path": "/httpbin",
            "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 将其设置为 50,表示将 50/150 的流量导入集群 1-25 中,记住本集群的权重总是 100

kubectl --kubeconfig ${kubeconfig_123} apply -n httpbin -f  - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:
  name: httpbin
spec:
  lbType: ActiveActive
  targets:
    - clusterKey: default/default/default/1-25
      weight: 50
EOF

这次我们请求 20 次。

curl_client="$(kubectl  --kubeconfig ${kubeconfig_123} get pod -n curl -l app=curl -o jsonpath='{.items[0].metadata.name}')"
for i in {1..20}; do kubectl --kubeconfig ${kubeconfig_123} exec "${curl_client}" -n curl -c curl -- curl -s http://httpbin.httpbin:8080/ ; done

在结果中可以看到有 1/3 的流量进入到了新集群。

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-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-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-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-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-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-25 and controlled by mesh!

接下来,下线旧集群中的服务实例。

kubectl --kubeconfig ${kubeconfig_123} delete deploy,svc httpbin -n httpbin

再次请求,所有的流量都会进入新的集群。

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

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

总结

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

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

标签:controlled,Kubernetes,23,--,金丝雀,kubeconfig,mesh,集群
From: https://blog.51cto.com/u_16455808/9096513

相关文章

  • VMware Tanzu Community Edition (TCE) 0.9 - 适合所有人的 Tanzu Kubernetes
    作者:gc,主页:www.sysin.org2021.10.04,VMware宣布了一个非常令人兴奋的新项目,称为TanzuCommunityEdition。以下TanzuCommunityEdition介绍翻译自VMware相关博客。什么是Tanzu社区版,为什么要关心?今天,最终用户(管理员、架构师、开发人员、平台运营商等)很难获得VMware的Tan......
  • VMware Tanzu Kubernetes Grid Integrated Edition (TKGI) 1.12 下载
    作者:gc,主页:www.sysin.orgVMwareTanzuKubernetesGridIntegratedEdition(TKGI)使运营商能够使用BOSH和OpsManager配置、运营和管理企业级Kubernetes集群。VMwareTanzuKubernetesGridIntegratedEdition(以前称为VMwareEnterprisePKS)是基于Kubernetes的容器解决......
  • redis集群搭建
    redis集群需要至少3个muster节点,当前搭建使用3个muster节点和3个slave节点,工6个redis节点三台虚拟机,分别是101、102、103第一步下载redis,这一步不在描述,我使用之前下载好的第二步在101虚拟机的/usr/local下创建redis-cluster文件夹,然后在redis-cluster下创建8001、8004文件夹......
  • 数据从A集群,使用logstash迁移到B集群,如何保持_Id一致
    有时候,我们在跨集群数据同步的时候,需要保持_id一致。这里给出一个案例。这里直接给出一个配置文件input{elasticsearch{hosts=>"es.production.mysite.org"index=>"mydata-2018.09.*"query=>'{"query":{"query_string&qu......
  • 非Kubernetes工作负载(如虚拟机或裸机服务器)加入网格(续)
    摘要:workloadgroup类似于deployment;workloadentry类似于pod;存活探针不是服务网格的关注点;workloadgroup必须配置应用程序的就绪探针关键点:在vm上输入所有节点的路由routeadd-net172.25.244.192/26gw 192.168.31.211......;将东西向网关的主机名硬编码到vm的hosts文件中;istio-......
  • Kubernetes与Docker"分手"之后如何设计DevOps流水线
    一、前言总所周知,从Kubernetes1.24版本开始已经弃用Docker这个陪伴它风声水起的"初恋女友",届时在Kubernetes社区掀起了异常"轩然大波",影响甚至波及到社区之外的,也导致了Kubernetes不得不写好几篇博客来反复解释这么做的原因,虽然是老生常谈的问题了,如今距离1.24版本正式发布已过去......
  • kubernetes 集群 oom 导致集群无法访问
    现象执行kubectlgetnode无法获取集群状态。日志截图:查看message日志,发现报错存在OOM,并与应用测试的容器相关,截图如下:分析首先,定位最初的oom发生的时间点,是2023年12月15日,如图按照正常逻辑来讲,应用实例做了limit限制,如果应用超出内存限制,应该被杀掉并且进行重新调度。进一步......
  • 使用容器快速在阿里云 ECS 多节点上搭建 Citus 12.1 集群
    阿里云ECS机器节点这里我们使用两台同一区域的ECS机器。机器配置:2核2G。(ps:阿里云99元一年的活动)一台安装coordinator(协调器),这里内网IP为172.18.60.11一台安装worker,这里内网IP为172.18.60.12操作系统两台机器分别安装了厂商的AlibabaCloudLinux3系统......
  • 一篇文章彻底搞懂TiDB集群各种容量计算方式
    背景TiDB集群的监控面板里面有两个非常重要、且非常常用的指标,相信用了TiDB的都见过:Storagecapacity:集群的总容量Currentstoragesize:集群当前已经使用的空间大小当你准备了一堆服务器,经过各种思考设计部署了一个TiDB集群,有没有想过这两个指标和服务器磁盘之间到底是啥关......
  • 一个 39.3T 的集群从TiDB v3.1.0迁移升级到 TiDB v7.1.2 的实践
    作者:xingzhenxiang集群目前情况数据39.3Ttidb版本数据导出方式选择1、BR这个版本刚开始支持,不知道有什么未知bug,暂时没有选择2、逻辑导出,首先考虑同版本发行对应的mydumper,出现tidbserver内存耗尽,放弃3、最后选择dumplingv7.1.2,看文档说事兼容以前版本导出命......