通過多集群服務,您可以無需創建負載均衡,即可實現Kubernetes服務的跨集群訪問。其中,Headless類型服務不僅支持跨集群服務訪問,還可以根據域名選擇服務中的指定Pod實例進行訪問,一般用于有狀態服務(StatefulSets)的應用訪問,例如分布式數據庫、消息隊列等。本文以MySQL服務為例,為您介紹如何通過Headless類型的多集群Service,實現跨集服務的訪問。
背景信息
Headless類型的服務在Kubernetes中是一種特殊的服務(Service)配置,其主要特點是沒有分配ClusterIP。Kubernetes的DNS系統會為服務生成一條特殊的DNS記錄,該記錄直接指向所有匹配該服務 Selector的Pod的IP地址列表,而不是一個統一的Service IP。
客戶端可通過域名跨集群訪問服務中的指定實例,常用于有狀態服務(StatefulSets)的應用訪問,例如分布式數據庫、消息隊列等。
對于MySQL服務來說,可以使用該能力可以實現MySQL主從集群的讀寫分離,以提升性能和吞吐量,并提升系統的可靠性和容錯性。
方案介紹
本文以有狀態服務MySQL為例,介紹如何通過Headless類型服務實現跨集群訪問MySQL服務中指定的Pod實例。
ACK One多集群艦隊Fleet實例管理關聯集群(ACK Cluster 1、ACK Cluster 2)服務的開放與注入。
ACK Cluster 1作為服務提供者集群,在ACK Cluster 1上創建MySQL服務和ServiceExport,將MySQL服務設置為允許集群外訪問。
ACK Cluster 2作為服務消費者集群,在ACK Cluster 2上創建ServiceImport對象和Client Pod以做驗證。
在ACK Cluster 2中,Client Pod可通過域名訪問ACK Cluster 1中的MySQL服務,并支持指定具體需要訪問哪一個Pod實例。
前提條件
已開啟艦隊管理功能。具體操作,請參見開啟艦隊管理功能。
艦隊的Fleet實例已添加2個關聯集群(服務提供者集群、服務消費者集群)。具體操作,請參見添加關聯集群。
確保關聯集群的版本為1.22及以上版本。
獲取服務提供者集群和服務消費者集群的Kubeconfig,并通過kubectl連接集群。具體操作,請參見獲取集群KubeConfig并通過kubectl工具連接集群。
確保服務提供者集群和服務消費者集群的網絡已連通。
步驟一:在服務提供者集群Cluster 1上創建MySQL服務和ServiceExport
執行如下命令,在ACK Cluster 1中創建命名空間。本示例的命名空間為
provider-ns
。kubectl create ns provider-ns
在ACK Cluster 1中創建MySQL服務。
使用如下內容創建一個
mysql.yaml
文件。apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: ROOT_PASSWORD: cGFzc3dvcmQ= --- apiVersion: v1 kind: Service metadata: name: mysql labels: app: mysql spec: clusterIP: None selector: app: mysql ports: - name: tcp protocol: TCP port: 3306 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: replicas: 2 # 本示例為部署2個Pod副本 serviceName: mysql selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: terminationGracePeriodSeconds: 10 containers: - name: mysql image: mysql:5.6 ports: - name: tpc protocol: TCP containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: key: ROOT_PASSWORD name: mysecret volumeMounts: - name: data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: data spec: storageClassName: standard accessModes: - ReadWriteOnce resources: requests: storage: 50Gi storageClassName: alicloud-disk-topology-alltype
執行如下命令創建MySQL服務。
kubectl -n provider-ns create -f mysql.yaml
預期輸出如下:
secret/mysecret created service/mysql created statefulset.apps/mysql created
在ACK Cluster 1中創建ServiceExport資源,指定需要開放多集群訪問的Kubernetes服務。本示例為mysql服務。
使用如下內容創建一個
serviceexport.yaml
文件。apiVersion: multicluster.x-k8s.io/v1alpha1 kind: ServiceExport metadata: name: mysql # 名稱與待開放的Kubernetes服務名稱相同。
執行如下命令創建ServiceExport。
kubectl -n provider-ns create -f serviceexport.yaml
預期輸出如下:
serviceexport.multicluster.x-k8s.io/mysql created
步驟二:在服務消費者集群Cluster 2上創建Namespace和ServiceImport
執行如下命令在ACK Cluster 2創建服務提供者命名空間。本示例的命名空間為
provider-ns
。kubectl create ns provider-ns
在ACK Cluster 2中創建ServiceImport。
使用如下內容創建一個
serviceimport.yaml
文件。重要ServiceImport的類型,即
type
必須設置為Headless
。apiVersion: multicluster.x-k8s.io/v1alpha1 kind: ServiceImport metadata: name: mysql # 名稱與待開放的Kubernetes服務名稱相同。 spec: ports: # 與待開放的Kubernetes服務ports相同。 - name: tcp port: 3306 protocol: TCP type: Headless
執行如下命令創建ServiceImport服務。
kubectl -n provider-ns create -f serviceimport.yaml
預期輸出如下:
serviceimport.multicluster.x-k8s.io/mysql created
步驟三:在服務消費者集群中通過域名訪問服務提供者中的指定MySQL實例
在服務消費者集群ACK Cluster 2中,通過以下兩種域名均可訪問服務提供者集群ACK Cluster 1中MySQL服務的指定實例。
${pod name}.amcs-${service name}.${namespace}.svc.cluster.local
${pod name}.${clusterid}.${service name}.${namespace}.svc.clusterset.local
通過${pod name}.amcs-${service name}.${namespace}.svc.cluster.local
域名訪問
在ACK Cluster 2中創建Client Pod。
使用以下內容創建一個
mysqlclient.yaml
文件。apiVersion: v1 kind: Pod metadata: name: mysql-client spec: containers: - name: mysql-client image: mysql:5.6 command: ["sh", "-c", "sleep 12000"]
執行如下命令創建Client Pod。
kubectl create -f mysqlclient.yaml
預期輸出如下:
pod/mysql-client created
在ACK Cluster 2中訪問ACK Cluster 1中的指定MySQL實例。
執行如下命令訪問指定的mysql-0實例
kubectl exec -it mysql-client -- mysql -h mysql-0.amcs-mysql.provider-ns.svc.cluster.local -P3306 -uroot -ppassword
執行如下命令訪問指定的mysql-1實例
kubectl exec -it mysql-client -- mysql -h mysql-1.amcs-mysql.provider-ns.svc.cluster.local -P3306 -uroot -ppassword
預期輸出如下:
Warning: Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.6.51 MySQL Community Server (GPL) Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
通過${pod name}.${clusterid}.${service name}.${namespace}.svc.clusterset.local
域名訪問
在ACK Cluster 2中創建Client Pod。
使用以下內容創建一個
mysqlclient.yaml
文件。apiVersion: v1 kind: Pod metadata: name: mysql-client spec: containers: - name: mysql-client image: mysql:5.6 command: ["sh", "-c", "sleep 12000"]
執行如下命令創建Client Pod。
kubectl create -f mysqlclient.yaml
預期輸出如下:
pod/mysql-client created
在服務消費者集群Cluster 2中安裝或升級CoreDNS,版本要求1.9.3及以上。具體操作,請參見CoreDNS和管理組件。
修改CoreDNS組件的配置Corefile。
執行如下命令,修改CoreDNS組件的ConfigMap文件。
kubectl edit configmap coredns -n kube-system
在Corefile文件中新增一行配置項
multicluster clusterset.local
,支持多集群服務域名解析。apiVersion: v1 data: Corefile: | .:53 { errors health { lameduck 15s } ready multicluster clusterset.local #增加配置項,支持多集群服務域名解析。 kubernetes cluster.local in-addr.arpa ip6.arpa { pods verified ttl 30 fallthrough in-addr.arpa ip6.arpa } ... } kind: ConfigMap metadata: name: coredns namespace: kube-system
在ACK Cluster 2中訪問ACK Cluster 1中的指定MySQL實例。
執行如下命令訪問指定的mysql-0實例
kubectl exec -it mysql-client -- mysql -h mysql-0.${clusterid}.mysql.provider-ns.svc.clusterset.local -P3306 -uroot -ppassword
執行如下命令訪問指定的mysql-1實例
kubectl exec -it mysql-client -- mysql -h mysql-1.${clusterid}.mysql.provider-ns.svc.clusterset.local -P3306 -uroot -ppassword
預期輸出如下:
Warning: Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.6.51 MySQL Community Server (GPL) Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.