Dapr 集成 Flomesh 实现跨集群服务调用
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dapr 集成 Flomesh 实现跨集群服务调用相关的知识,希望对你有一定的参考价值。
背景
随着技术和架构的不断演进,有着多运行时的态势:现代应用程序的基础能力不断地以独立运行时的方式从应用程序分离出来。这其中就有分布式应用运行时和服务网格两种运行时,今天这篇文章就为大家介绍 Dapr 与 Flomesh 服务网格的集成进行跨集群的服务调用来实现“真正的”多集群互联互通。
多集群
Kubernetes 秉持着松耦合和可扩展的设计理念,带来了 Kubernetes 生态的蓬勃发展。但这些大部分先限制在单一集群内,然后由于种种原因和目的企业内部创建的集群越来越多,比如单集群故障、监管要求、异地多机房可用区容灾、出于敏捷、降本考虑的混合云、多云部署、单一集群的承载能力受限、多版本 Kubernetes 集群共存等。
Dapr
Dapr[1] 是一个分布式应用工具包,通过提供简单而稳定的 API 实现应用程序和外围功能组件的解耦合,让开发人员可以聚焦在业务功能的研发。同时与外围组件的解耦,也使得应用程序更加的便携、更加云原生,企业可以轻松低成本地将应用迁移到不同的环境中。
Dapr 工具包提供了丰富的功能,如服务调用、弹性策略、状态存储、发布/订阅、绑定、分布式锁、名称解析等,但对于高级的服务治理功能如灰度、跨集群服务调用没有支持。
Flomesh 服务网格
微服务架构兴起之后,随着规模越来越大,服务治理的难度和碎片化显著提升,服务网格的出现使得这些问题迎刃而解。服务网格是一个处理服务间通讯的专用的基础设施层,通过它可以透明地添加可观测性、流量管理和安全性等功能,而无需将其添加到你的代码中。
Flomesh 服务网格使用可编程代理 Pipy[2] 为核心提供东西、南北向的流量管理。通过基于 L7 的流量管理能力,突破计算环境间的网络隔离,建议一个虚拟的平面网络,使不同计算环境中应用可以互相通信。可以想象,Flomesh 服务网格是覆盖多集群的“大网格”。
示例介绍
服务端 NodeApp 是个 Dapr 应用, 在 Dapr hello-kubernetes 示例[3] 中的 NodeApp 基础上做了修改,返回响应时会显示当前的集群名;客户端 curl 用于向 NodeApp 发送请求,但并没有声明为 Dapr 应用。
NodeApp 中有三个 endpoint:
•
GET /ports
返回当前应用可访问的端口•
POST /neworder
创建新的订单•
GET /order
查询订单
下面的演示中会从集群的创建开始,一步步介绍环境的配置、各个组件的安装和配置、应用的部署等等。
一键安装脚本
我们也准备脚本进行一键安装和快速的体验,免除环境和组件配置的繁琐。可以 访问 GitHub 获取脚本[4] 内容。
使用该脚本之前,需要确保系统装已经安装了 Docker
和 kubectl
。脚本运行时会进行检查,并安装 k3d
、helm
、jq
、pv
等工具。
•
flomesh.sh
- 不提供任何参数,脚本会创建 4 个集群、完成环境安装配置并运行演示•
flomesh.sh -h
- 打印帮助信息•
flomesh.sh -i
- 创建 4 个集群、完成环境的安装和配置•
flomesh.sh -d
- 运行演示•
flomesh.sh -r
- 清理演示相关的资源•
flomesh.sh -u
- 删除所有集群
执行下面的命令,即可完成环境安装配置和演示的运行。
curl -sL https://raw.githubusercontent.com/addozhang/flomesh-dapr-demo/main/flomesh.sh | bash -
逐步演示
前提条件
进行演示,我们需要如下的工具:
• Docker
• Kubectl
• K3d
• Helm
• kubectx
创建多集群
获取本机 IP 地址作为集群间的通信地址。
export HOST_IP=10.0.0.13
执行下面创建 4 个集群:control-plane
、cluster-1
、cluster-2
和 cluster-3
。
API_PORT=6444 #6444 6445 6446 6447
PORT=80 #81 82 83
for CLUSTER_NAME in control-plane cluster-1 cluster-2 cluster-3
do
k3d cluster create $CLUSTER_NAME \\
--image docker.io/rancher/k3s:v1.23.8-k3s2 \\
--api-port "$HOST_IP:$API_PORT" \\
--port "$PORT:80@server:0" \\
--servers-memory 4g \\
--k3s-arg "--disable=traefik@server:0" \\
--network multi-clusters \\
--timeout 120s \\
--wait
((API_PORT=API_PORT+1))
((PORT=PORT+1))
done
安装 FSM
helm repo add fsm https://charts.flomesh.io
helm repo update
export FSM_NAMESPACE=flomesh
export FSM_VERSION=0.2.1-alpha.3
for CLUSTER_NAME in control-plane cluster-1 cluster-2 cluster-3
do
kubectx k3d-$CLUSTER_NAME
sleep 1
helm install --namespace $FSM_NAMESPACE --create-namespace --version=$FSM_VERSION --set fsm.logLevel=5 fsm fsm/fsm
sleep 1
kubectl wait --for=condition=ready pod --all -n $FSM_NAMESPACE --timeout=120s
done
将集群 cluster-1
、cluster-2
和 cluster-3
纳入集群 control-plane
的管理。
kubectx k3d-control-plane
sleep 1
PORT=81
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectl 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-edge
下载 CLI
system=$(uname -s | tr [:upper:] [:lower:])
arch=$(dpkg --print-architecture)
release=v1.3.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 安装到集群 cluster-1
、cluster-2
和 cluster-3
。控制平面不处理应用流量,无需安装。
export OSM_NAMESPACE=osm-system
export OSM_MESH_NAME=osm
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectx 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
kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 43h
放行 pod 中访问 apiserver 的流量,不经过 sidecar。
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectx k3d-$CLUSTER_NAME
kubectl patch meshconfig osm-mesh-config -n $OSM_NAMESPACE -p '"spec":"traffic":"outboundIPRangeExclusionList":["10.43.0.1/32"]' --type=merge
done
安装 Dapr
将 Dapr 安装到集群 cluster-1
、cluster-2
和 cluster-3
。
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectx k3d-$CLUSTER_NAME
dapr init --kubernetes \\
--enable-mtls=false \\
--wait
done
查看组件运行状态。
dapr status -k
NAME NAMESPACE HEALTHY STATUS REPLICAS VERSION AGE CREATED
dapr-placement-server dapr-system True Running 1 1.9.6 2m 2023-02-09 10:36.51
dapr-operator dapr-system True Running 1 1.9.6 2m 2023-02-09 10:36.51
dapr-dashboard dapr-system True Running 1 0.11.0 2m 2023-02-09 10:36.51
dapr-sentry dapr-system True Running 1 1.9.6 2m 2023-02-09 10:36.51
dapr-sidecar-injector dapr-system True Running 1 1.9.6 2m 2023-02-09 10:36.51
查看组件 Service 及端口。
kubectl get svc -n dapr-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dapr-placement-server ClusterIP None <none> 50005/TCP,8201/TCP 5h50m
dapr-sidecar-injector ClusterIP 10.43.12.213 <none> 443/TCP 5h50m
dapr-webhook ClusterIP 10.43.103.31 <none> 443/TCP 5h50m
dapr-dashboard ClusterIP 10.43.172.156 <none> 8080/TCP 5h50m
dapr-api ClusterIP 10.43.126.14 <none> 80/TCP 5h50m
dapr-sentry ClusterIP 10.43.41.10 <none> 80/TCP 5h50m
不拦截 dapr 组件和 redis 端口的流量。
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectx k3d-$CLUSTER_NAME
kubectl patch meshconfig osm-mesh-config -n $OSM_NAMESPACE -p '"spec":"traffic":"outboundPortExclusionList":[50005,8201,6379]' --type=merge
done
部署 Redis
version: '3'
services:
redis:
image: redis:latest
container_name: redis
ports:
- 6379:6379
volumes:
- ./data:/data
command: redis-server --appendonly yes --requirepass changeme
创建示例命名空间
export NAMESPACE=dapr-test
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectx k3d-$CLUSTER_NAME
kubectl create namespace $NAMESPACE
osm namespace add $NAMESPACE
done
注册 Redis State Store 组件
export NAMESPACE=dapr-test
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectx k3d-$CLUSTER_NAME
kubectl create secret generic redis -n $NAMESPACE --from-literal=redis-password=changeme
kubectl apply -n $NAMESPACE -f - <<EOF
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: 10.0.0.13:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
auth:
secretStore: kubernetes
EOF
done
部署示例应用
在集群 cluster-1
和 cluster-3
的 httpbin
命名空间(由网格管理,会注入 sidecar)下,部署 nodeapp
应用。
export NAMESPACE=dapr-test
for CLUSTER_NAME in cluster-1 cluster-2 cluster-3
do
kubectx k3d-$CLUSTER_NAME
kubectl apply -n $NAMESPACE -f - <<EOF
kind: Service
apiVersion: v1
metadata:
name: nodeapp
labels:
app: node
spec:
selector:
app: node
ports:
- protocol: TCP
port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodeapp
labels:
app: node
spec:
replicas: 1
selector:
matchLabels:
app: node
template:
metadata:
labels:
app: node
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "nodeapp"
dapr.io/app-port: "3000"
dapr.io/enable-api-logging: "true"
spec:
containers:
- name: node
image: addozhang/dapr-nodeapp
env:
- name: APP_PORT
value: "3000"
- name: CLUSTER_NAME
value: $CLUSTER_NAME
ports:
- containerPort: 3000
imagePullPolicy: Always
EOF
done
在集群 cluster-2
的命名空间 curl
下部署 curl
应用,这个命名空间是被网格管理的,注入的 sidecar 会完全流量的跨集群调度。
export NAMESPACE=curl
kubectx k3d-cluster-2
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: 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
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "curl"
dapr.io/enable-api-logging: "true"
dapr.io/log-level: "debug"
spec:
serviceAccountName: curl
containers:
- image: curlimages/curl
imagePullPolicy: IfNotPresent
name: curl
command: ["sleep", "365d"]
EOF
sleep 3
kubectl wait --for=condition=ready pod -n $NAMESPACE --all --timeout=60s
导出服务
export NAMESPACE=dapr-test
for CLUSTER_NAME in cluster-1 cluster-3
do
kubectx k3d-$CLUSTER_NAME
kubectl apply -n $NAMESPACE -f - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:
name: nodeapp
spec:
serviceAccountName: '*'
pathRewrite:
from: '^/nodeapp/?'
to: '/'
rules:
- portNumber: 3000
path: '/nodeapp'
pathType: Prefix
EOF
sleep 1
done
导出后的服务,FSM 会自动为其创建 Ingress 规则,有了规则之后就可以通过 Ingress 来访问这些服务。
for CLUSTER_NAME_INDEX in 1 3
do
CLUSTER_NAME=cluster-$CLUSTER_NAME_INDEX
((PORT=80+CLUSTER_NAME_INDEX))
kubectx k3d-$CLUSTER_NAME
echo "Getting service exported in cluster $CLUSTER_NAME"
echo '-----------------------------------'
kubectl get serviceexports.flomesh.io -A
echo '-----------------------------------'
curl -s "http://$HOST_IP:$PORT/ports"
echo '-----------------------------------'
done
测试
切换到集群 cluster-2
在 curl pod 中发起请求进行测试。
kubectx k3d-cluster-2
curl_client="$(kubectl get pod -n curl -l app=curl -o jsonpath='.items[0].metadata.name')"
发送请求访问 nodeapp 时报错,这是因为在 cluster-2
中并未部署 nodeapp 应用。默认情况下,在不指定跨集群的流量策略时,只会尝试调用本地服务,不会将流量调度到其他的集群。
kubectl exec "$curl_client" -n curl -c curl -- curl -s http://nodeapp.dapr-test:3000/ports
command terminated with exit code 7
设置流量策略
跨集群的流量策略支持三种:
•
Locality
:只使用本集群的服务,也是默认类型。这就是为什么我们不提供任何全局策略的时候,访问nodeapp
应用会失败,因为在集群cluster-2
中并没有该服务。•
FailOver
:当本集群访问失败时才会代理到其他集群,也就是常说的故障迁移,类似主备。•
ActiveActive
:正常情况下也会代理到其他集群,类似多活。
接下来我们创建并应用如下的 ActiveActive
策略,同样是在 cluster-2
集群中进行操作。
kubectl apply -n dapr-test -f - <<EOF
apiVersion: flomesh.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:
name: nodeapp
spec:
lbType: ActiveActive
targets:
- clusterKey: default/default/default/cluster-1
weight: 100
- clusterKey: default/default/default/cluster-3
weight: 100
EOF
再次尝试发送请求,可以收到成功的响应。
kubectl exec "$curl_client" -n curl -c curl -- curl -s http://nodeapp.dapr-test:3000/ports
"DAPR_HTTP_PORT":"3500","DAPR_GRPC_PORT":"50001", from cluster: cluster-3
这时请求 /neworder
尝试写入订单数据。
kubectl exec "$curl_client" -n curl -c curl -- curl -si --request POST --data '"data":"orderId":"42"' --header Content-Type:application/json --header dapr-app-id:nodeapp http://nodeapp.dapr-test:3000/neworder
created order via cluster: cluster-1
多次请求 /order
,可以发现请求被转发到了不同的集群进行处理。
kubectl exec "$curl_client" -n curl -c curl -- curl -s http://nodeapp.dapr-test:3000/order
"orderId":"42", from cluster: cluster-3
kubectl exec "$curl_client" -n curl -c curl -- curl -s http://nodeapp.dapr-test:3000/order
"orderId":"42", from cluster: cluster-1
引用链接
[1]
Dapr: https://dapr.io[2]
Pipy: https://github.com/flomesh-io/pipy[3]
Dapr hello-kubernetes 示例: https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes[4]
访问 GitHub 获取脚本: https://github.com/addozhang/flomesh-dapr-demo
以上是关于Dapr 集成 Flomesh 实现跨集群服务调用的主要内容,如果未能解决你的问题,请参考以下文章