1) Overview
Ở đây mình xin trình bày về route trong mô hình mutil Cluster istio Primary Remote.
Nếu bạn thắc mắc mô hình cài sau thì mình có hướng dẫn chi tiết rồi nhé:
Chúng ta cần tool của istio ở link này ha: Prepare essential tool.
istioctl --context <cluster-config> pc l <pod-name>.<namespace> --port <filter-port>
Mình muốn coi là con istiod nó có route như thế nào:
./istioctl --context k0s-cluster2 pc l istio-eastwestgateway-869c45b46d-c6ztl.istio-system
2) Discovery
2.1) Remote cluster
Trên remote cluster (k0s-cluster2) mình cài 1 keydb theo helm
https://enapter.github.io/charts/
Giờ mình show route của 1 workload nằm trong cluster 2 xem có j thú vị.
Bạn để ý mỗi route thì đều có 1 route tcp và 1 route http
và ở bài về test các feature mình có nhắc vụ bạn nên gắn refix name cho port trong service để istio detect đây traffic tcp hày http he. Đây link đây 1.4 Test với Service GRPC (update thu 30 Sep 2021)
Giờ mình show route của con istio-ingressgateway có biết route này ko nhé:
./istioctl --context k0s-cluster2 pc l istio-eastwestgateway-865f9bb7cb-hw2fp.istio-system | grep keydb
Khi mình grep keydb
Suy ra khi 1 service được tạo ra thì istio sẽ discover and announce cho tất cả các istio-proxy he.
2.2) Primary cluster
Uhm keydb ở remote cluster thì nằm ở namespace default.
Vậy giờ mình thử show trên cluster primary -> 1 vài workload ở namespace default, xem có workload có route của keydb trên cluster 2 không nhé.
Mình cũng chứng mình cho bạn thấy là mình tạo service nào liên quan đến keydb trên cluster 1
3) The dangerous problem.
3.1) Service headless
Có vấn đề khá là nguy hiểm. các bạn thấy đó là trên cluster primary ko hề có svc của keydb nhưng các workload được inject istio vần có route của keydb he.
Giờ giờ bạn tạo svc gần như svc bên cluster remote rồi apply cho cluster primary thì sẽ như thế nào
Mình hơi hười nên mình sẽ lấy service headless của cluster remote ra thì nghiệm he.
Mình có serivce headless bên cluster 2 ntn:
apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"keydb-cluster2","app.kubernetes.io/managed-by":"Helm","app.kubernetes.io/name":"keydb","app.kubernetes.io/version":"6.2.0","helm.sh/chart":"keydb-0.27.1"},"name":"keydb-cluster2-headless","namespace":"default"},"spec":{"clusterIP":"None","ports":[{"name":"server","port":6379,"protocol":"TCP","targetPort":"keydb"}],"selector":{"app.kubernetes.io/instance":"keydb-cluster2","app.kubernetes.io/name":"keydb"},"type":"ClusterIP"}}
creationTimestamp: "2021-11-20T17:36:24Z"
labels:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: keydb
app.kubernetes.io/version: 6.2.0
helm.sh/chart: keydb-0.27.1
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.: {}
f:kubectl.kubernetes.io/last-applied-configuration: {}
f:labels:
.: {}
f:app.kubernetes.io/instance: {}
f:app.kubernetes.io/managed-by: {}
f:app.kubernetes.io/name: {}
f:app.kubernetes.io/version: {}
f:helm.sh/chart: {}
f:spec:
f:clusterIP: {}
f:ports:
.: {}
k:{"port":6379,"protocol":"TCP"}:
.: {}
f:name: {}
f:port: {}
f:protocol: {}
f:targetPort: {}
f:selector:
.: {}
f:app.kubernetes.io/instance: {}
f:app.kubernetes.io/name: {}
f:sessionAffinity: {}
f:type: {}
manager: argocd-application-controller
operation: Update
time: "2021-11-20T17:36:24Z"
name: keydb-cluster2-headless
namespace: default
resourceVersion: "1029960"
uid: fd05f53f-43c5-460f-a81a-409f689a4b56
spec:
clusterIP: None
clusterIPs:
- None
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: server
port: 6379
protocol: TCP
targetPort: keydb
selector:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/name: keydb
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
Rồi bỏ đi các phần thừa và được file manifest svc như sau:
Nhìn file bên dưới khi tạo nó sẽ ra type: ClusterIP
apiVersion: v1
kind: Service
metadata:
name: keydb-cluster2-headless
labels:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: keydb
app.kubernetes.io/version: 6.2.0
helm.sh/chart: keydb-0.27.1
namespace: default
spec:
selector:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/name: keydb
ports:
- name: server
port: 6379
protocol: TCP
targetPort: keydb
sessionAffinity: None
type: ClusterIP
Giờ mình apply file trên vào primary cluster.
Giờ chạy về remote cluster show route phát
./istioctl --context k0s-cluster2 pc l sleep-66f47b6f5d-ztnzz.sample --port 6379
Đây chúng ta thấy điều khá mỏi
0.0.0.0 bạn có thể hiểu là nó như là default route vậy đó.
Nó sảy ra vấn đề:
workload muốn kết nối với redis với ip là x.x.x.x:6379 hay là redis.hihi:6379
Và workload đó đã inject istio thì khi nó nhìn route trên nó sẽ vẫn truyền về cho Cluster: outbound|6379||keydb-cluster2-headless.default.svc.cluster.local
Nên là khi đó bạn check ping pong redis vẫn thấy có tín hiệu nhưng đó ko phải là con redis của bạn
Vậy alo nếu service headless thì sao.
apiVersion: v1
kind: Service
metadata:
name: keydb-cluster2-headless
labels:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: keydb
app.kubernetes.io/version: 6.2.0
helm.sh/chart: keydb-0.27.1
namespace: default
spec:
clusterIP: None
selector:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/name: keydb
ports:
- name: server
port: 6379
protocol: TCP
targetPort: keydb
sessionAffinity: None
type: ClusterIP
Nói chung là test thì có nhiều case lắm.
nếu có thời gian mình sẽ test thêm.
3.2) Service ClusterIP
Nay đang tiện thì lab luôn.
Mình có 1 service với type là clusterip đang ở cluster remote.
./istioctl --context k0s-cluster2 pc l sleep-66f47b6f5d-ztnzz.sample --port 6379 | grep keydb-cluster2.default
10.36.38.164 6379 Trans: raw_buffer; App: HTTP Route: keydb-cluster2.default.svc.cluster.local:6379
10.36.38.164 6379 ALL Cluster: outbound|6379||keydb-cluster2.default.svc.cluster.local
Bạn có thể thấy IP đúng như service.
apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"keydb-cluster2","app.kubernetes.io/managed-by":"Helm","app.kubernetes.io/name":"keydb","app.kubernetes.io/version":"6.2.0","helm.sh/chart":"keydb-0.27.1"},"name":"keydb-cluster2","namespace":"default"},"spec":{"ports":[{"name":"server","port":6379,"protocol":"TCP","targetPort":"keydb"},{"name":"redis-exporter","port":9121,"protocol":"TCP","targetPort":"redis-exporter"}],"selector":{"app.kubernetes.io/instance":"keydb-cluster2","app.kubernetes.io/name":"keydb"},"sessionAffinity":"ClientIP","type":"ClusterIP"}}
creationTimestamp: "2021-11-20T17:36:24Z"
labels:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: keydb
app.kubernetes.io/version: 6.2.0
helm.sh/chart: keydb-0.27.1
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.: {}
f:kubectl.kubernetes.io/last-applied-configuration: {}
f:labels:
.: {}
f:app.kubernetes.io/instance: {}
f:app.kubernetes.io/managed-by: {}
f:app.kubernetes.io/name: {}
f:app.kubernetes.io/version: {}
f:helm.sh/chart: {}
f:spec:
f:ports:
.: {}
k:{"port":6379,"protocol":"TCP"}:
.: {}
f:name: {}
f:port: {}
f:protocol: {}
f:targetPort: {}
k:{"port":9121,"protocol":"TCP"}:
.: {}
f:name: {}
f:port: {}
f:protocol: {}
f:targetPort: {}
f:selector:
.: {}
f:app.kubernetes.io/instance: {}
f:app.kubernetes.io/name: {}
f:sessionAffinity: {}
f:sessionAffinityConfig:
.: {}
f:clientIP:
.: {}
f:timeoutSeconds: {}
f:type: {}
manager: argocd-application-controller
operation: Update
time: "2021-11-20T17:36:24Z"
name: keydb-cluster2
namespace: default
resourceVersion: "1029962"
uid: eceaddd1-787a-4361-a00b-08598bd6ac45
spec:
clusterIP: 10.36.38.164
clusterIPs:
- 10.36.38.164
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: server
port: 6379
protocol: TCP
targetPort: keydb
- name: redis-exporter
port: 9121
protocol: TCP
targetPort: redis-exporter
selector:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/name: keydb
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
type: ClusterIP
status:
loadBalancer: {}
giờ mình thu gọn manifest lại như sau:
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: keydb
app.kubernetes.io/version: 6.2.0
helm.sh/chart: keydb-0.27.1
name: keydb-cluster2
namespace: default
spec:
ports:
- name: server
port: 6379
protocol: TCP
targetPort: keydb
- name: redis-exporter
port: 9121
protocol: TCP
targetPort: redis-exporter
selector:
app.kubernetes.io/instance: keydb-cluster2
app.kubernetes.io/name: keydb
sessionAffinity: ClientIP
type: ClusterIP
Khi chưa apply thì mình sẽ check route bên primary cluster thử nhé
./istioctl --context local pc l busybox-deployment-5f5bc59d9f-tzz2z.default --port 6379 | grep keydb-cluster2.default
10.36.38.164 6379 Trans: raw_buffer; App: HTTP Route: keydb-cluster2.default.svc.cluster.local:6379
10.36.38.164 6379 ALL Cluster: outbound|6379||keydb-cluster2.default.svc.cluster.local
CHúng ta thấy là workload đã injected istio bên primary cluster, vẫn biết chính sác route bên remote cluster
Và mình apply bên cluster primary.
Giờ mình kiểm tra route
./istioctl --context local pc l busybox-deployment-5f5bc59d9f-tzz2z.default --port 6379 | grep keydb-cluster2.default
10.98.166.59 6379 Trans: raw_buffer; App: HTTP Route: keydb-cluster2.default.svc.cluster.local:6379
10.98.166.59 6379 ALL Cluster: outbound|6379||keydb-cluster2.default.svc.cluster.local
OK giờ route đã có sự thay đổi và thông tin ko còn là ở cluster remote nữa.
giờ nó lấy thông tin service keydb-cluster2.default trên primary cluster
End) Materials reference
https://istio.io/latest/docs/ops/diagnostic-tools/proxy-cmd/