背景
眾所周知,Flomesh 的服務網格產品?osm-edge[1]?是基于 SMI(Service Mesh Interface,服務網格接口) 標準的實現。SMI 定義了流量標識、訪問控制、遙測和管理的規范。在?上一篇?中,我們體驗過了多集群服務(Multi-Cluster Service,MCS),以及流量在多集群中的調度策略,屬于最基本最基礎的能力,這篇會帶大家體驗一下基于 SMI 實現的跨集群訪問控制。
在開始之前,先回顧一下?SMI 訪問控制的規范[2]。在 osm-edge 中的?流量策略有兩種形式[3]:寬松模式?和?流量策略模式。前者允許網格中的服務互相訪問,后者需要提供相應的流量策略才可以訪問。
SMI 訪問控制策略
在流量策略模式下,SMI 通過 CRD?TrafficTarget
?來定義基于?ServiceAccount
?的訪問控制,其中定義了流量源(sources
)、目標(destinations
)以及規則(rules
)。表達的是使用?sources
?中指定?ServiceAccount
?的應用可以訪問?destinations
?指定?ServiceAccount
?的應用,可訪問的流量由?rules
?指定。
比如下面的示例,表示的是使用?ServiceAccount
?promethues
?運行的負載,發送?GET
?請求到使用?ServiceAccount
?service-a
?運行的負載的?/metrics
?端點。HTTPRouteGroup
?定義了流量的標識:即訪問端點?/metrics
?的?GET
?請求。
kind:?HTTPRouteGroup
metadata:name:?the-routes
spec:matches:-?name:?metricspathRegex:?"/metrics"methods:-?GET
---
kind:?TrafficTarget
metadata:name:?path-specificnamespace:?default
spec:destination:kind:?ServiceAccountname:?service-anamespace:?defaultrules:-?kind:?HTTPRouteGroupname:?the-routesmatches:-?metricssources:-?kind:?ServiceAccountname:?prometheusnamespace:?default
那么在多集群中,訪問控制的表現如何呢?
FSM 的?ServiceExport
FSM 的?ServiceExport
?用于導出服務到其他集群,也就是服務注冊的過程。ServiceExport
?的字段?spec.serviceAccountName
?可以用來指定服務負載使用的?ServiceAccount
。
apiVersion:?flomesh.io/v1alpha1
kind:?ServiceExport
metadata:namespace:?httpbinname:?httpbin
spec:serviceAccountName:?"*"rules:-?portNumber:?8080path:?"/cluster-1/httpbin-mesh"pathType:?Prefix
接下來,我們在上次的環境基礎上開始演示,沒有看過上一篇的小伙伴可以參考?上一篇?來搭建環境。
部署應用

部署示例應用
在集群?cluster-1
?和?cluster-3
?的?httpbin
?命名空間(由網格管理,會注入 sidecar)下,部署?httpbin
?應用。這里我們指定?ServiceAccount
?為?httpbin
。
export?NAMESPACE=httpbin
for?CLUSTER_NAME?in?cluster-1?cluster-3
dokubectx?k3d-${CLUSTER_NAME}kubectl?create?namespace?${NAMESPACE}osm?namespace?add?${NAMESPACE}kubectl?apply?-n?${NAMESPACE}?-f?-?<<EOF
apiVersion:?v1
kind:?ServiceAccount
metadata:name:?httpbin
---??
apiVersion:?apps/v1
kind:?Deployment
metadata:name:?httpbinlabels:app:?pipy
spec:replicas:?1selector:matchLabels:app:?pipytemplate:metadata:labels:app:?pipyspec:serviceAccountName:?httpbincontainers:-?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?3kubectl?wait?--for=condition=ready?pod?-n?${NAMESPACE}?--all?--timeout=60s
done
在?cluster-2
?的命名空間?httpbin
?下 部署?httpbin
?應用,但不指定?ServiceAccount
,使用默認的?ServiceAccount
?default
。
export?NAMESPACE=httpbin
export?CLUSTER_NAME=cluster-2kubectx?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
在集群?cluster-2
?的命名空間?curl
?下部署?curl
?應用,這個命名空間是被網格管理的,注入的 sidecar 會完全流量的跨集群調度。這里指定使用?ServiceAccout
?curl
。
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:?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
導出服務
export?NAMESPACE_MESH=httpbin
for?CLUSTER_NAME?in?cluster-1?cluster-3
dokubectx?k3d-${CLUSTER_NAME}kubectl?apply?-f?-?<<EOF
apiVersion:?flomesh.io/v1alpha1
kind:?ServiceExport
metadata:namespace:?${NAMESPACE_MESH}name:?httpbin
spec:serviceAccountName:?"httpbin"rules:-?portNumber:?8080path:?"/${CLUSTER_NAME}/httpbin-mesh"pathType:?Prefix
---
apiVersion:?flomesh.io/v1alpha1
kind:?ServiceExport
metadata:namespace:?${NAMESPACE_MESH}name:?httpbin-${CLUSTER_NAME}
spec:serviceAccountName:?"httpbin"rules:-?portNumber:?8080path:?"/${CLUSTER_NAME}/httpbin-mesh-${CLUSTER_NAME}"pathType:?Prefix
EOF
sleep?1
done
測試
我們切換回集群?cluster-2
:
kubectx?k3d-cluster-2
默認路由類型是?Locality
?,我們需要創建一個?ActiveActive
?策略,來允許使用其他集群的服務實例來處理請求。
kubectl?apply?-n?httpbin?-f??-?<<EOF
apiVersion:?flomesh.io/v1alpha1
kind:?GlobalTrafficPolicy
metadata:name:?httpbin
spec:lbType:?ActiveActivetargets:-?clusterKey:?default/default/default/cluster-1-?clusterKey:?default/default/default/cluster-3
EOF
在?cluster-2
?集群的?curl
?應用中, 我們向?httpbin.httpbin
?發送請求。
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?cluster-1?and?controlled?by?mesh!
Hi,?I?am?from?cluster-2?and?controlled?by?mesh!
Hi,?I?am?from?cluster-3?and?controlled?by?mesh!
Hi,?I?am?from?cluster-1?and?controlled?by?mesh!
Hi,?I?am?from?cluster-2?and?controlled?by?mesh!
Hi,?I?am?from?cluster-3?and?controlled?by?mesh!
演示
調整流量策略模式
我們先將集群?cluster-2
?的流量策略模式調整下,這樣才能應用流量策略:
kubectx?k3d-cluster-2
export?osm_namespace=osm-system
kubectl?patch?meshconfig?osm-mesh-config?-n?"$osm_namespace"?-p?'{"spec":{"traffic":{"enablePermissiveTrafficPolicyMode":false}}}'?--type=merge
此時,再嘗試發送請求,會發現請求失敗。因為在流量策略模式下,沒有配置策略的話應用間的互訪是被禁止的。
kubectl?exec?"${curl_client}"?-n?curl?-c?curl?--?curl?-s?http://httpbin.httpbin:8080/
command?terminated?with?exit?code?52
應用訪問控制策略
文章開頭介紹 SMI 的訪問控制策略時有提到是基于?ServiceAccount
?的,這就是為什么我們部署的?httpbin
?服務在集群?cluster-1
?、cluster-3
?與集群?cluster-2
?中使用的?ServiceAccount
?不同:
? cluster-1:
httpbin
? cluster-2:
default
? clsuter-3:
httpbin
接下來,我們會為集群內和集群外的服務,分別設置不同的訪問控制策略?TrafficTarget
,通過在?TrafficTarget
?中目標負載的?ServiceAccount
?來進行區分。

執行下面的命令,創建流量策略?curl-to-httpbin
,允許?curl
?訪問命名空間?httpbin
?下使用?ServiceAccount
?default
?的負載。
kubectl?apply?-n?httpbin?-f?-?<<EOF
apiVersion:?specs.smi-spec.io/v1alpha4
kind:?HTTPRouteGroup
metadata:name:?httpbin-route
spec:matches:-?name:?allpathRegex:?"/"methods:-?GET
---
kind:?TrafficTarget
apiVersion:?access.smi-spec.io/v1alpha3
metadata:name:?curl-to-httpbin
spec:destination:kind:?ServiceAccountname:?defaultnamespace:?httpbinrules:-?kind:?HTTPRouteGroupname:?httpbin-routematches:-?allsources:-?kind:?ServiceAccountname:?curlnamespace:?curl
EOF
多次發送請求嘗試,集群?cluster-2
?的服務都會做出響應,而集群?cluster-1
?和?cluster-3
?不會參與服務。
Hi,?I?am?from?cluster-2?and?controlled?by?mesh!
Hi,?I?am?from?cluster-2?and?controlled?by?mesh!
Hi,?I?am?from?cluster-2?and?controlled?by?mesh!
執行下面命令檢查?ServiceImports
,可以看到?cluster-1
?和?cluster-3
?導出的服務使用的是?ServiceAccount
?httpbin
。
kubectl?get?serviceimports?httpbin?-n?httpbin?-o?jsonpath='{.spec}'?|?jq{"ports":?[{"endpoints":?[{"clusterKey":?"default/default/default/cluster-1","target":?{"host":?"192.168.1.110","ip":?"192.168.1.110","path":?"/cluster-1/httpbin-mesh","port":?81}},{"clusterKey":?"default/default/default/cluster-3","target":?{"host":?"192.168.1.110","ip":?"192.168.1.110","path":?"/cluster-3/httpbin-mesh","port":?83}}],"port":?8080,"protocol":?"TCP"}],"serviceAccountName":?"httpbin","type":?"ClusterSetIP"
}
因此,我們創建另一個?TrafficTarget
?curl-to-ext-httpbin
,允許?curl
?訪問使用?ServiceAccount
?httpbin
?的負載。
kubectl?apply?-n?httpbin?-f?-?<<EOF
kind:?TrafficTarget
apiVersion:?access.smi-spec.io/v1alpha3
metadata:name:?curl-to-ext-httpbin
spec:destination:kind:?ServiceAccountname:?httpbinnamespace:?httpbinrules:-?kind:?HTTPRouteGroupname:?httpbin-routematches:-?allsources:-?kind:?ServiceAccountname:?curlnamespace:?curl
EOF
應用策略后,再測試一下,所有請求都成功。
Hi,?I?am?from?cluster-2?and?controlled?by?mesh!
Hi,?I?am?from?cluster-1?and?controlled?by?mesh!
Hi,?I?am?from?cluster-3?and?controlled?by?mesh!
總結
MCS(Multi-cluster Service)API 的實現目標是能夠像 Service 一樣,使用其他集群的服務。雖然在 Kubernetes 本身實現還有漫長的路要走,但作為 SMI 標準實現的服務網格來說,可以將其視作 Service 一樣來進行操作。
就如本篇的訪問控制一樣,SMI 的流量拆分一樣也可以支持多集群的服務。預告一下,下一篇就為大家介紹多集群服務的流量拆分。
引用鏈接
[1]
?osm-edge:?https://github.com/flomesh-io/osm-edge[2]
?SMI 訪問控制的規范:?https://github.com/servicemeshinterface/smi-spec/blob/main/apis/traffic-access/v1alpha3/traffic-access.md[3]
?流量策略有兩種形式:?https://osm-edge-docs.flomesh.io/docs/getting_started/traffic_policies/