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

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:國際域名空間、雅安服務(wù)器托管、營銷軟件、網(wǎng)站建設(shè)、商洛網(wǎng)站維護(hù)、網(wǎng)站推廣。
出于簡單,Linkerd 本身并沒有提供內(nèi)置的 Ingress 控制器,Linkerd 旨在與現(xiàn)有的 Kubernetes Ingress 解決方案一起使用。
要結(jié)合 Linkerd 和你的 Ingress 解決方案需要兩件事:
- 配置你的 Ingress 以支持 Linkerd。
- 網(wǎng)格化你的 Ingress 控制器,以便它們安裝 Linkerd 代理。
對 Ingress 控制器進(jìn)行網(wǎng)格化將允許 Linkerd 在流量進(jìn)入集群時(shí)提供 L7 指標(biāo)和 mTLS 等功能,Linkerd 支持與大部分 Ingress 控制器進(jìn)行集成,包括:
- Ambassador
- Nginx
- Traefik
- Traefik 1.x
- Traefik 2.x
- GCE
- Gloo
- Contour
- Kong
- Haproxy
ingress-nginx
我們這里以集群中使用的 ingress-nginx 為例來說明如何將其與 Linkerd 進(jìn)行集成使用。
$ 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 添加一個(gè) linkerd.io/inject: enabled 注解,可以直接 kubectl edit 這個(gè) 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 就會(huì)被自動(dòng)注入一個(gè) 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)格的相關(guān)功能:
- 為 Ingress 控制器提供黃金指標(biāo)(每秒請求數(shù)等)。
- Ingress 控制器 Pod 和網(wǎng)格應(yīng)用 Pod 之間的流量是加密的(并相互驗(yàn)證)。
- 可以看到 HTTP 流量
- 當(dāng)應(yīng)用程序返回錯(cuò)誤(如 5xx HTTP 狀態(tài)代碼)時(shí),這將在 Linkerd UI 中看到,不僅是應(yīng)用程序,還有 nginx ingress 控制器,因?yàn)樗蚩蛻舳朔祷劐e(cuò)誤代碼。
在 Linkerd Dashboard 中也可以看到對應(yīng)的指標(biāo)數(shù)據(jù)了。
ingress-nginx metrics
對應(yīng)在 Grafana 中也可以看到對應(yīng)的圖表信息。
ingress-nginx grafana
接下來我們?yōu)?nbsp;Emojivoto 應(yīng)用添加一個(gè)對應(yīng)的 Ingress 資源對象來對外暴露服務(wù)。
# 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
直接應(yīng)用上面的資源對象即可:
$ 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,這樣我們就不用使用自定義主機(jī)名和 IP 地址映射來編輯你的 etc/hosts 文件了,nip.io 允許你通過使用以下格式將任何 IP 地址映射到一個(gè)主機(jī)名。
不帶名稱:
- 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 將
我們這里使用一個(gè)自定義的域名 emoji.192.168.0.52.nip.io 相當(dāng)于直接映射到 192.168.0.52 這個(gè) IP 地址上,該地址是我們 ingress-nginx 的入口地址,這樣我們不需要做任何映射即可訪問服務(wù)了。
emojivoto
另外需要注意在上面的 Ingress 中我們添加了一個(gè) nginx.ingress.kubernetes.io/service-upstream: true 的注解,這是用來告訴 Nginx Ingress Controller 將流量路由到網(wǎng)格應(yīng)用的服務(wù),而不是直接路由到 Pod。默認(rèn)情況下,Ingress 控制器只是查詢其目標(biāo)服務(wù)的端點(diǎn),以檢索該服務(wù)背后的 Pod 的 IP 地址。而通過向網(wǎng)格服務(wù)發(fā)送流量,Linkerd 的相關(guān)功能如負(fù)載均衡和流量拆分則會(huì)被啟用。
ingress-nginx meshed
限制對服務(wù)的訪問
Linkerd policy 資源可用于限制哪些客戶端可以訪問服務(wù)。同樣我們還是使用 Emojivoto 應(yīng)用來展示如何限制對 Voting 微服務(wù)的訪問,使其只能從 Web 服務(wù)中調(diào)用。
我們首先為 Voting 服務(wù)創(chuàng)建一個(gè) Server 資源,Server 是 Linkerd 的另外一個(gè) CRD 自定義資源,它用于描述工作負(fù)載的特定端口。一旦 Server 資源被創(chuàng)建,只有被授權(quán)的客戶端才能訪問它。
創(chuàng)建一個(gè)如下所示的資源對象:
# 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
直接應(yīng)用上面的資源對象即可:
$ 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 使用了一個(gè) podSelector 屬性來選擇它所描述的 Voting 服務(wù)的 Pod,它還指定了它適用的命名端口 (grpc),最后指定在此端口上提供服務(wù)的協(xié)議為 gRPC, 這可確保代理正確處理流量并允許它跳過協(xié)議檢測。
現(xiàn)在沒有客戶端被授權(quán)訪問此服務(wù),正常會(huì)看到成功率有所下降, 因?yàn)閺?Web 服務(wù)到 Voting 的請求開始被拒絕,也可以直接查看 Web 服務(wù)的 Pod 日志來驗(yàn)證:
$ 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 命令查看進(jìn)入 Voting 服務(wù)的請求的授權(quán)狀態(tài):
$ linkerd viz authz -n emojivoto deploy/voting
SERVER AUTHZ SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
voting-grpc [UNAUTHORIZED] - 0.9rps
可以看到所有傳入的請求當(dāng)前都處于未經(jīng)授權(quán)狀態(tài)。
接下來我們需要為客戶端來授予訪問該 Server 的權(quán)限,這里需要使用到另外一個(gè) CRD 對象 ServerAuthorization,創(chuàng)建該對象來授予 Web 服務(wù)訪問我們上面創(chuàng)建的 Voting Server 的權(quán)限,對應(yīng)的資源清單文件如下所示:
# voting-server-auth.yaml
apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
name: voting-grpc
namespace: emojivoto
spec:
server:
name: voting-grpc # 關(guān)聯(lián) Server 對象
# The voting service only allows requests from the web service.
client:
meshTLS:
serviceAccounts:
- name: web
- name: web-2
上面對象中通過 spec.server.name 來關(guān)聯(lián)上面的 Server 對象,由于 meshTLS 使用 ServiceAccounts 作為身份基礎(chǔ),因此我們的授權(quán)也將基于 ServiceAccounts,所以通過 spec.client.meshTLS.serviceAccounts 來指定允許從哪些服務(wù)來訪問 Voting 服務(wù)。
同樣直接應(yīng)用該資源清單即可:
$ 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
有了這個(gè)對象后,我們現(xiàn)在可以看到所有對 Voting 服務(wù)的請求都是由 voting-grpc 這個(gè) ServerAuthorization 授權(quán)的。請注意,由于 linkerd viz auth 命令在一個(gè)時(shí)間窗口內(nèi)查詢,所以可能會(huì)看到一些未授權(quán)(UNAUTHORIZED)的請求在短時(shí)間內(nèi)顯示。
$ 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)建一個(gè) gRPC 客戶端 Pod 來嘗試從中訪問 Voting 服務(wù)測試來自其他 Pod 的請求是否會(huì)被拒絕:
$ 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 未經(jīng)授權(quán),所以該請求將被拒絕并顯示 PermissionDenied 錯(cuò)誤。
我們可以根據(jù)需要?jiǎng)?chuàng)建任意數(shù)量的 ServerAuthorization 資源來授權(quán)許多不同的客戶端,還可以指定是授權(quán)未經(jīng)身份驗(yàn)證(即 unmeshed)的客戶端、任何經(jīng)過身份驗(yàn)證的客戶端,還是僅授權(quán)具有特定身份的經(jīng)過身份驗(yàn)證的客戶端。
此外我們還可以為整個(gè)集群設(shè)置一個(gè)默認(rèn)策略,該策略將應(yīng)用于所有未定義 Server 資源的。Linkerd 在決定是否允許請求時(shí)會(huì)使用以下邏輯:
- 如果有一個(gè) Server 資源并且客戶端為其匹配一個(gè)ServerAuthorization? 資源,則為ALLOW。
- 如果有一個(gè) Server 資源,但客戶端不匹配它的任何ServerAuthorizations?,則為DENY。
- 如果端口沒有 Server 資源,則使用默認(rèn)策略。
比如我們可以使用 linkerd upgrade 命令將默認(rèn)策略設(shè)置為 deny:
$ linkerd upgrade --set policyController.defaultAllowPolicy=deny | kubectl apply -f -
另外我們也可以通過設(shè)置 config.linkerd.io/default-inbound-policy 注解,可以在單個(gè)工作負(fù)載或命名空間上設(shè)置默認(rèn)策略。
意思就是除非通過創(chuàng)建 Server 和 ServerAuthorization 對象明確授權(quán),否則所有請求都將被拒絕,這樣的話對于 liveness 和 readiness 探針需要明確授權(quán),否則 Kubernetes 將無法將 Pod 識別為 live 或 ready 狀態(tài),并將重新啟動(dòng)它們。我們可以創(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 地址或范圍, 也可以進(jìn)一步將 ServerAuthorization 限制為這些 IP 地址或范圍,比如如果你知道 Kubelet 在 10.244.0.1 上運(yùn)行,那么你的 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
另外有一個(gè)值得注意的是在我們創(chuàng)建 Server 資源之后,但在創(chuàng)建 ServerAuthorization 之前有一段時(shí)間,所有請求都被拒絕。為了避免在實(shí)時(shí)系統(tǒng)中出現(xiàn)這種情況,我們建議你在部署服務(wù)之前創(chuàng)建 policy 資源,或者在創(chuàng)建 Server 之前創(chuàng)建 ServiceAuthorizations,以便立即授權(quán)客戶端。
關(guān)于授權(quán)策略的更多使用可以查看官方文檔 https://linkerd.io/2.11/reference/authorization-policy/ 以了解更多相關(guān)信息。
文章題目:Linkerd與Ingress-Nginx結(jié)合使用以及對服務(wù)的訪問限制
分享URL:http://www.dlmjj.cn/article/djpodjd.html


咨詢
建站咨詢
