新聞中心
Linkerd 與 Ingress-Nginx 結合使用以及對服務的訪問限制
作者:陽明 2022-09-09 20:55:38
云計算
云原生 對 Ingress 控制器進行網(wǎng)格化將允許 Linkerd 在流量進入集群時提供 L7 指標和 mTLS 等功能,Linkerd 支持與大部分 Ingress 控制器進行集成。

讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領域值得信任、有價值的長期合作伙伴,公司提供的服務項目有:國際域名空間、雅安服務器托管、營銷軟件、網(wǎng)站建設、商洛網(wǎng)站維護、網(wǎng)站推廣。
出于簡單,Linkerd 本身并沒有提供內置的 Ingress 控制器,Linkerd 旨在與現(xiàn)有的 Kubernetes Ingress 解決方案一起使用。
要結合 Linkerd 和你的 Ingress 解決方案需要兩件事:
- 配置你的 Ingress 以支持 Linkerd。
- 網(wǎng)格化你的 Ingress 控制器,以便它們安裝 Linkerd 代理。
對 Ingress 控制器進行網(wǎng)格化將允許 Linkerd 在流量進入集群時提供 L7 指標和 mTLS 等功能,Linkerd 支持與大部分 Ingress 控制器進行集成,包括:
- Ambassador
- Nginx
- Traefik
- Traefik 1.x
- Traefik 2.x
- GCE
- Gloo
- Contour
- Kong
- Haproxy
ingress-nginx
我們這里以集群中使用的 ingress-nginx 為例來說明如何將其與 Linkerd 進行集成使用。
$ kubectl get deploy -n ingress-nginx
NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx-controller 1/1 1 1 57d
ingress-nginx-defaultbackend 1/1 1 1 57d
$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-7647c44fb9-sss9m 1/1 Running 26 (59m ago) 57d
ingress-nginx-defaultbackend-84854cd6cb-rvgd2 1/1 Running 27 (59m ago) 57d
首先我們需要更新 ingress-nginx-controller 控制器,為 Pod 添加一個 linkerd.io/inject: enabled 注解,可以直接 kubectl edit 這個 Deployment,由于我們集群中的 ingress-nginx 使用的 Helm Chart 安裝的,所以可以在 values 中添加如下所示的配置:
controller:
podAnnotations:
linkerd.io/inject: enabled
# ......
然后使用該 values 重新更新即可:
# Update your helm repos with the ingress-nginx repo
$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm repo update
# Install the ingress-nginx chart
$ helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx --namespace=ingress-nginx --values=values.yaml
更新后 ingress-nginx 的控制器 Pod 就會被自動注入一個 linkerd proxy 的 sidecar 容器:
$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-f56c7f6fd-rxhrs 2/2 Running 0 4m21s
ingress-nginx-defaultbackend-84854cd6cb-rvgd2 1/1 Running 27 (62m ago) 57d
這樣 ingress 控制器也被加入到網(wǎng)格中去了,所以也具有了 Linkerd 網(wǎng)格的相關功能:
- 為 Ingress 控制器提供黃金指標(每秒請求數(shù)等)。
- Ingress 控制器 Pod 和網(wǎng)格應用 Pod 之間的流量是加密的(并相互驗證)。
- 可以看到 HTTP 流量
- 當應用程序返回錯誤(如 5xx HTTP 狀態(tài)代碼)時,這將在 Linkerd UI 中看到,不僅是應用程序,還有 nginx ingress 控制器,因為它向客戶端返回錯誤代碼。
在 Linkerd Dashboard 中也可以看到對應的指標數(shù)據(jù)了。
ingress-nginx metrics
對應在 Grafana 中也可以看到對應的圖表信息。
ingress-nginx grafana
接下來我們?yōu)?nbsp;Emojivoto 應用添加一個對應的 Ingress 資源對象來對外暴露服務。
# emojivoto-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: emojivoto-ingress
labels:
name: emojivoto-ingress
namespace: emojivoto
annotations:
# add below line of nginx is meshed
nginx.ingress.kubernetes.io/service-upstream: "true"
# nginx.ingress.kubernetes.io/affinity: "cookie"
# nginx.ingress.kubernetes.io/affinity-mode: "persistent"
spec:
ingressClassName: nginx
rules:
# update IP with your own IP used by Ingress Controller
- host: emoji.192.168.0.52.nip.io
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: web-svc-2
port:
number: 80
直接應用上面的資源對象即可:
$ kubectl apply -f emojivoto-ingress.yaml
$ kubectl get ingress -n emojivoto
NAME CLASS HOSTS ADDRESS PORTS AGE
emojivoto-ingress nginx emoji.192.168.0.52.nip.io 192.168.0.52 80 61s
其中 nip.io 是任何 IP 地址的簡單通配符 DNS,這樣我們就不用使用自定義主機名和 IP 地址映射來編輯你的 etc/hosts 文件了,nip.io 允許你通過使用以下格式將任何 IP 地址映射到一個主機名。
不帶名稱:
- 10.0.0.1.nip.io 映射到 10.0.0.1
- 192-168-1-250.nip.io 映射到 192.168.1.250
- 0a000803.nip.io 映射到 10.0.8.3
帶名稱:
- app.10.8.0.1.nip.io 映射到 10.8.0.1
- app-116-203-255-68.nip.io 映射到 116.203.255.68
- app-c0a801fc.nip.io 映射到 192.168.1.252
- customer1.app.10.0.0.1.nip.io 映射到 10.0.0.1
- customer2-app-127-0-0-1.nip.io 映射到 127.0.0.1
- customer3-app-7f000101.nip.io 映射到 127.0.1.1
nip.io 將
我們這里使用一個自定義的域名 emoji.192.168.0.52.nip.io 相當于直接映射到 192.168.0.52 這個 IP 地址上,該地址是我們 ingress-nginx 的入口地址,這樣我們不需要做任何映射即可訪問服務了。
emojivoto
另外需要注意在上面的 Ingress 中我們添加了一個 nginx.ingress.kubernetes.io/service-upstream: true 的注解,這是用來告訴 Nginx Ingress Controller 將流量路由到網(wǎng)格應用的服務,而不是直接路由到 Pod。默認情況下,Ingress 控制器只是查詢其目標服務的端點,以檢索該服務背后的 Pod 的 IP 地址。而通過向網(wǎng)格服務發(fā)送流量,Linkerd 的相關功能如負載均衡和流量拆分則會被啟用。
ingress-nginx meshed
限制對服務的訪問
Linkerd policy 資源可用于限制哪些客戶端可以訪問服務。同樣我們還是使用 Emojivoto 應用來展示如何限制對 Voting 微服務的訪問,使其只能從 Web 服務中調用。
我們首先為 Voting 服務創(chuàng)建一個 Server 資源,Server 是 Linkerd 的另外一個 CRD 自定義資源,它用于描述工作負載的特定端口。一旦 Server 資源被創(chuàng)建,只有被授權的客戶端才能訪問它。
創(chuàng)建一個如下所示的資源對象:
# voting-server.yaml
apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
name: voting-grpc
namespace: emojivoto
labels:
app: voting-svc
spec:
podSelector:
matchLabels:
app: voting-svc
port: grpc
proxyProtocol: gRPC
直接應用上面的資源對象即可:
$ kubectl apply -f voting-server.yaml
server.policy.linkerd.io/voting-grpc created
$ kubectl get server -n emojivoto
NAME PORT PROTOCOL
voting-grpc grpc gRPC
我們可以看到該 Server 使用了一個 podSelector 屬性來選擇它所描述的 Voting 服務的 Pod,它還指定了它適用的命名端口 (grpc),最后指定在此端口上提供服務的協(xié)議為 gRPC, 這可確保代理正確處理流量并允許它跳過協(xié)議檢測。
現(xiàn)在沒有客戶端被授權訪問此服務,正常會看到成功率有所下降, 因為從 Web 服務到 Voting 的請求開始被拒絕,也可以直接查看 Web 服務的 Pod 日志來驗證:
$ kubectl logs -f web-svc-2-f9d77474f-vxlrh -n emojivoto -c web-svc-2
2022/09/06 09:31:27 Error serving request [&{GET /api/vote?choice=:trophy: HTTP/1.1 1 1 map[Accept-Encoding:[gzip] L5d-Client-Id:[default.emojivoto.serviceaccount.identity.linkerd.cluster.local] L5d-Dst-Canonical:[web-apex.emojivoto.svc.cluster.local:80] User-Agent:[Go-http-client/1.1] X-B3-Sampled:[1] X-B3-Spanid:[f9e1dc6e24803ea8] X-B3-Traceid:[5ae662deee8fdbf2f3b9eaa40eb673d5]] {}0 [] false web-apex.emojivoto:80 map[choice:[:trophy:]] map[] map[] 10.244.1.87:51244 /api/vote?choice=:trophy: 0xc00045e4b0}]: rpc error: code = PermissionDenied desc = unauthorized connection on server voting-grpc
# ......
我們可以使用 linkerd viz authz 命令查看進入 Voting 服務的請求的授權狀態(tài):
$ linkerd viz authz -n emojivoto deploy/voting
SERVER AUTHZ SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
voting-grpc [UNAUTHORIZED] - 0.9rps
可以看到所有傳入的請求當前都處于未經授權狀態(tài)。
接下來我們需要為客戶端來授予訪問該 Server 的權限,這里需要使用到另外一個 CRD 對象 ServerAuthorization,創(chuàng)建該對象來授予 Web 服務訪問我們上面創(chuàng)建的 Voting Server 的權限,對應的資源清單文件如下所示:
# voting-server-auth.yaml
apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
name: voting-grpc
namespace: emojivoto
spec:
server:
name: voting-grpc # 關聯(lián) Server 對象
# The voting service only allows requests from the web service.
client:
meshTLS:
serviceAccounts:
- name: web
- name: web-2
上面對象中通過 spec.server.name 來關聯(lián)上面的 Server 對象,由于 meshTLS 使用 ServiceAccounts 作為身份基礎,因此我們的授權也將基于 ServiceAccounts,所以通過 spec.client.meshTLS.serviceAccounts 來指定允許從哪些服務來訪問 Voting 服務。
同樣直接應用該資源清單即可:
$ kubectl apply -f voting-server-auth.yaml
serverauthorization.policy.linkerd.io/voting-grpc created
$ kubectl get serverauthorization -n emojivoto
NAME SERVER
voting-grpc voting-grpc
有了這個對象后,我們現(xiàn)在可以看到所有對 Voting 服務的請求都是由 voting-grpc 這個 ServerAuthorization 授權的。請注意,由于 linkerd viz auth 命令在一個時間窗口內查詢,所以可能會看到一些未授權(UNAUTHORIZED)的請求在短時間內顯示。
$ linkerd viz authz -n emojivoto deploy/voting
SERVER AUTHZ SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
voting-grpc voting-grpc 84.48% 1.0rps 1ms 1ms 1ms
我們還可以通過創(chuàng)建一個 gRPC 客戶端 Pod 來嘗試從中訪問 Voting 服務測試來自其他 Pod 的請求是否會被拒絕:
$ kubectl run grpcurl --rm -it --image=networld/grpcurl --restart=Never --command -- ./grpcurl -plaintext voting-svc.emojivoto:8080 emojivoto.v1.VotingService/VoteDog
If you don't see a command prompt, try pressing enter.
Error attaching, falling back to logs: unable to upgrade connection: container grpcurl not found in pod grpcurl_default
Error invoking method "emojivoto.v1.VotingService/VoteDog": failed to query for service descriptor "emojivoto.v1.VotingService": rpc error: code = PermissionDenied desc =
pod "grpcurl" deleted
pod default/grpcurl terminated (Error)
由于該 client 未經授權,所以該請求將被拒絕并顯示 PermissionDenied 錯誤。
我們可以根據(jù)需要創(chuàng)建任意數(shù)量的 ServerAuthorization 資源來授權許多不同的客戶端,還可以指定是授權未經身份驗證(即 unmeshed)的客戶端、任何經過身份驗證的客戶端,還是僅授權具有特定身份的經過身份驗證的客戶端。
此外我們還可以為整個集群設置一個默認策略,該策略將應用于所有未定義 Server 資源的。Linkerd 在決定是否允許請求時會使用以下邏輯:
- 如果有一個 Server 資源并且客戶端為其匹配一個ServerAuthorization? 資源,則為ALLOW。
- 如果有一個 Server 資源,但客戶端不匹配它的任何ServerAuthorizations?,則為DENY。
- 如果端口沒有 Server 資源,則使用默認策略。
比如我們可以使用 linkerd upgrade 命令將默認策略設置為 deny:
$ linkerd upgrade --set policyController.defaultAllowPolicy=deny | kubectl apply -f -
另外我們也可以通過設置 config.linkerd.io/default-inbound-policy 注解,可以在單個工作負載或命名空間上設置默認策略。
意思就是除非通過創(chuàng)建 Server 和 ServerAuthorization 對象明確授權,否則所有請求都將被拒絕,這樣的話對于 liveness 和 readiness 探針需要明確授權,否則 Kubernetes 將無法將 Pod 識別為 live 或 ready 狀態(tài),并將重新啟動它們。我們可以創(chuàng)建如下所示的策略對象,來允許所有客戶端訪問 Linkerd admin 端口,以便 Kubernetes 可以執(zhí)行 liveness 和 readiness 檢查:
$ cat << EOF | kubectl apply -f -
---
# Server "admin": matches the admin port for every pod in this namespace
apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
namespace: emojivoto
name: admin
spec:
port: linkerd-admin
podSelector:
matchLabels: {} # every pod
proxyProtocol: HTTP/1
---
# ServerAuthorization "admin-everyone": allows unauthenticated access to the
# "admin" Server, so that Kubernetes health checks can get through.
apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
namespace: emojivoto
name: admin-everyone
spec:
server:
name: admin
client:
unauthenticated: true
如果你知道 Kubelet(執(zhí)行健康檢查)的 IP 地址或范圍, 也可以進一步將 ServerAuthorization 限制為這些 IP 地址或范圍,比如如果你知道 Kubelet 在 10.244.0.1 上運行,那么你的 ServerAuthorization 可以改為:
# ServerAuthorization "admin-kublet": allows unauthenticated access to the
# "admin" Server from the kubelet, so that Kubernetes health checks can get through.
apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
namespace: emojivoto
name: admin-kubelet
spec:
server:
name: admin
client:
networks:
- cidr: 10.244.0.1/32
unauthenticated: true
另外有一個值得注意的是在我們創(chuàng)建 Server 資源之后,但在創(chuàng)建 ServerAuthorization 之前有一段時間,所有請求都被拒絕。為了避免在實時系統(tǒng)中出現(xiàn)這種情況,我們建議你在部署服務之前創(chuàng)建 policy 資源,或者在創(chuàng)建 Server 之前創(chuàng)建 ServiceAuthorizations,以便立即授權客戶端。
關于授權策略的更多使用可以查看官方文檔 https://linkerd.io/2.11/reference/authorization-policy/ 以了解更多相關信息。
網(wǎng)頁題目:Linkerd與Ingress-Nginx結合使用以及對服務的訪問限制
文章地址:http://www.fisionsoft.com.cn/article/djpodjd.html


咨詢
建站咨詢
