使用 Ingres 訪問 Dapr 應用
方案
如何公開 Dapr 應用的訪問,方案有兩種:
-
像傳統用法一樣,配置應用的 Service 作爲後端,由入口控制器直接將流量轉發到應用容器,簡單說就是支持自動配置的 L7 負載均衡器。
-
不直接訪問應用容器,而是通過 Daprd 運行時來訪問。這時,我們就需要將入口控制器也聲明爲 Dapr 應用,爲其注入 Daprd 運行時容器。此時創建入口規則指向的後端,則是 Ingress 的 Dapr Service。
兩種方案各有優劣,前者架構簡單;後者雖然引入 Daprd 容器,架構複雜,消耗了更多的資源,但也因此可以使用 Dapr 的服務治理能力,如超時、重試、訪問控制等等。
接下來我們將通過示例來分別驗證兩種方案。
演示
前置條件
-
helm
-
dapr cli
export INSTALL_K3S_VERSION=v1.23.8+k3s2
curl -sfL https://get.k3s.io | sh -s - --disable traefik --write-kubeconfig-mode 644 --write-kubeconfig ~/.kube/config
安裝 Dapr
dapr init --kubernetes --wait
安裝入口控制器
這裏使用 Flomesh 的入口控制器。通過 valus.yaml
爲入口控制器添加 dapr 相關的註解。這裏需要注意由於默認情況下 Daprd 運行時監聽的端口是綁定在迴環地址上的,而 Ingress 向後端轉發請求時使用的是 Pod IP,因此需要註解 dapr.io/sidecar-listen-addresses: "[::],0.0.0.0"
讓 Daprd 運行時可以接收來自 Pod IP 的請求。
# values.yaml
fsm:
ingress:
podAnnotations:
dapr.io/sidecar-listen-addresses: "[::],0.0.0.0"
dapr.io/enabled: "true"
dapr.io/app-id: "ingress"
dapr.io/app-port: "8000"
dapr.io/enable-api-logging: "true"
dapr.io/config: "ingressconfig"
helm repo add fsm https://charts.flomesh.io
helm repo update
helm install \
--namespace flomesh \
--create-namespace \
--version=0.2.1-alpha.3 \
-f values.yaml \
fsm fsm/fsm
部署示例應用
示例應用我們使用 kennethreitz/httpbin
,爲其添加 dapr 相關的註解。
kubectl create ns httpbin
kubectl apply -n httpbin -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: httpbin
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
strategy: {}
template:
metadata:
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "httpbin"
dapr.io/app-port: "80"
dapr.io/enable-api-logging: "true"
dapr.io/config: "httpbinconfig"
labels:
app: httpbin
spec:
containers:
- image: kennethreitz/httpbin
name: httpbin
resources: {}
---
apiVersion: v1
kind: Service
metadata:
labels:
app: httpbin
name: httpbin
namespace: httpbin
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: httpbin
EOF
方案 1
參考 Flomesh Ingress 的 文檔 [1],創建入口規則使用 Service httpbin
作爲後端。
kubectl apply -n httpbin -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
annotations:
pipy.ingress.kubernetes.io/rewrite-target-from: ^/httpbin/?
pipy.ingress.kubernetes.io/rewrite-target-to: /
spec:
ingressClassName: pipy
rules:
- http:
paths:
- backend:
service:
name: httpbin
port:
number: 80
path: /httpbin
pathType: Prefix
EOF
使用主機 IP 地址和入口控制器的 80
端口來訪問 /httpbin/get
,由於上面配置了路徑重寫,最終請求 /get
將會被髮送到目標 Pod。
curl HOST_IP:80/httpbin/get
{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "keep-alive",
"Content-Length": "0",
"Host": "20.239.95.81:30508",
"User-Agent": "curl/7.86.0"
},
"origin": "10.42.0.18",
"url": "http://20.239.95.81:30508/get"
}
方案 2
方案 2 也同樣需要配置入口規則,只是這次後端服務配置的入口控制器的 Dapr Service
,通過 kubectl get svc -n flomesh
就可以找到名字帶有 -dapr
後綴的 Service
。
kubectl apply -n flomesh -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dapr
annotations:
pipy.ingress.kubernetes.io/rewrite-target-from: ^/dapr/?
pipy.ingress.kubernetes.io/rewrite-target-to: /
spec:
ingressClassName: pipy
rules:
- http:
paths:
- backend:
service:
name: ingress-dapr
port:
number: 80
path: /dapr
pathType: Prefix
EOF
仍然是訪問 httpbin
的路徑 /get
,但是訪問方式要遵循 Dapr 服務調用的 API[2]:通過請求頭指定 dapr-app-id
爲 httpbin.httpbin
。由於入口控制器和目標應用不在同一命名空間下,在應用 id 需要帶上其命名空間。
同樣是成功返回,但是可以看到最終應用收到請求頭部會多了一些信息,這些信息都是來自 Daprd 運行時,比如 Dapr-Caller-App-Id
、"Dapr-Callee-App-Id
標識表示請求的發起方和接收方;Forwarded
標識了發起請求的主機名。如果開啓了 tracing,還會有鏈路相關的信息(本示例中並未開啓)。
curl HOST_IP:80/dapr/get -H 'dapr-app-id:httpbin.httpbin'
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip",
"Connection": "keep-alive",
"Dapr-App-Id": "httpbin.httpbin",
"Dapr-Callee-App-Id": "httpbin",
"Dapr-Caller-App-Id": "ingress",
"Forwarded": "for=10.42.0.18;by=10.42.0.18;host=fsm-ingress-pipy-864d8d9c76-4kb7r",
"Host": "127.0.0.1:80",
"Proto": "HTTP/1.1",
"Protomajor": "1",
"Protominor": "1",
"Referer": "",
"Traceparent": "00-00000000000000000000000000000000-0000000000000000-00",
"User-Agent": "curl/7.86.0",
"X-Forwarded-Host": "fsm-ingress-pipy-864d8d9c76-4kb7r"
},
"origin": "10.42.0.18",
"url": "http://fsm-ingress-pipy-864d8d9c76-4kb7r/get"
}
訪問控制
文章開頭提到使用 方案 2 雖然帶來了延遲增加了複雜度,但是可以使用 Dapr 的服務治理能力。這裏以 Dapr 的訪問控制功能 [3] 爲例。
不知道大家注意到沒,在部署入口控制器和示例應用時,有個註解 dapr.io/config: xxx
。這個註解是爲應用的 Daprd 運行時指定配置,運行時啓動時會從名爲 xxx 的 Configuration
資源讀取配置。
執行下面的命令爲 httpbin
應用設置訪問控制規則:默認拒絕所有請求,只允許 flomesh
命名空間下的 id 爲 ingress
的應用通過 GET
方式訪問路徑 /get
。更多訪問控制配置,可以參考 Dapr 訪問控制官方文檔 [4]。
kubectl apply -n httpbin -f - <<EOF
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: httpbinconfig
spec:
accessControl:
defaultAction: deny
trustDomain: "public"
policies:
- appId: ingress
defaultAction: deny
trustDomain: 'public'
namespace: "flomesh"
operations:
- name: /get
httpVerb: ['GET']
action: allow
EOF
應用配置之後,需要重啓應用。
kubectl rollout restart deploy httpbin -n httpbin
等到重啓完成,再訪問 /get
路徑,正常響應。
curl HOST_IP:80/dapr/get -H 'dapr-app-id:httpbin.httpbin'
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip",
"Connection": "keep-alive",
"Dapr-App-Id": "httpbin.httpbin",
"Dapr-Callee-App-Id": "httpbin",
"Dapr-Caller-App-Id": "ingress",
"Forwarded": "for=10.42.0.40;by=10.42.0.40;host=fsm-ingress-pipy-864d8d9c76-jctcx",
"Host": "127.0.0.1:80",
"Proto": "HTTP/1.1",
"Protomajor": "1",
"Protominor": "1",
"Referer": "",
"Traceparent": "00-00000000000000000000000000000000-0000000000000000-00",
"User-Agent": "curl/7.86.0",
"X-Forwarded-Host": "fsm-ingress-pipy-864d8d9c76-jctcx"
},
"origin": "10.42.0.40",
"url": "http://fsm-ingress-pipy-864d8d9c76-jctcx/get"
}
但是,如果是訪問路徑 /headers
,會收到下面的響應:被禁止訪問 /headers
。
curl HOST_IP:80/dapr/headers -H 'dapr-app-id:httpbin.httpbin'
{
"errorCode": "ERR_DIRECT_INVOKE",
"message": "fail to invoke, id: httpbin.httpbin, err: rpc error: code = PermissionDenied desc = access control policy has denied access to appid: ingress operation: headers verb: GET"
}
總結
文中使用的兩種入口方案各有優缺點,方案 1 架構簡單,也是我們常用的方案;方案 2 中相當於將入口控制器聲明爲 Dapr 應用,實際上暴露的是 Dapr 的 API,在實現上更像是一個全局的應用運行時。
參考資料
[1]
文檔: https://fsm-docs.flomesh.io/docs/demos/ingress_basics
[2]
Dapr 服務調用的 API: https://docs.dapr.io/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services/
[3]
Dapr 的訪問控制功能: https://docs.dapr.io/operations/configuration/invoke-allowlist/
[4]
Dapr 訪問控制官方文檔: https://docs.dapr.io/operations/configuration/invoke-allowlist/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/R7gwWjsmzqVGKk0KDYDtYA