The multi-cluster Services (MCS) feature allows you to access Services across Kubernetes clusters without load balancers. Headless Services enable cross-cluster access and access to specific pods based on domain name, making them ideal for stateful workloads managed by StatefulSet, including distributed databases and message queues. This topic uses MySQL as an example to explain how to achieve cross-cluster access through a headless multi-cluster Service.
Background Information
A headless Service does not have a cluster IP address. When you create a headless Service, Kubernetes generates a DNS record that points to the IP addresses of all pods that match the label selectors of the Service, instead of generating a Service IP address.
Clients can use the domain name of a headless multi-cluster Service to access applications deployed as StatefulSets across clusters, such as distributed databases and message queues.
You can use headless multi-cluster Services to implement read/write splitting for MySQL primary and secondary clusters. This helps improve the performance, throughput, reliability, and fault tolerance of the MySQL database.
Introduction
In this example, a headless multi-cluster Service is used to access a specified pod of a MySQL database across clusters.
A Distributed Cloud Container Platform for Kubernetes (ACK One) Fleet instance is associated with two Container Service for Kubernetes (ACK) clusters: ACK Cluster 1 and ACK Cluster 2. A MySQL Service is exported from ACK Cluster 1 and imported into ACK Cluster 2.
ACK Cluster 1 serves as a Service provider. A MySQL database and a ServiceExport are created in ACK Cluster 1. The MySQL database provides external services.
ACK Cluster 2 serves as a Service consumer. A ServiceImport and a client pod are created in ACK Cluster 2.
The client pod in ACK Cluster 1 can access the MySQL database in ACK Cluster 2 by using a domain name. In addition, the client pod can specify the pod that needs to be accessed.
Prerequisites
The Fleet management feature is enabled.
Two clusters are associated with the Fleet instance (the service provider cluster and service consumer cluster).
Kubernetes versions of the associated clusters are 1.22 or later.
The kubeconfig files of the provider and consumer clusters are obtained and kubectl is used to connect to the clusters. For more information, see Get a cluster kubeconfig and connect to the cluster using kubectl.
Service provider cluster and Service consumer cluster are connected.
The two clusters reside in the same VPC.
The two clusters reside in different VPCs, and communication is enabled among VPCs by using Cloud Enterprise Network (CEN). For more information, see What is CEN? and Create a VPC connection.
Step 1: Create a MySQL database and a ServiceExport in ACK Cluster 1
Run the following command to create a namespace
provider-nsin ACK Cluster 1:kubectl create ns provider-nsCreate a MySQL database in ACK Cluster 1
Create a file named
mysql.yamland copy the following code block to the file: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 # Two replicated pods are provisioned for the MySQL database. serviceName: mysql selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: terminationGracePeriodSeconds: 10 containers: - name: mysql image: mysql:5.6 ports: - name: tcp 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-alltypeRun the following command to deploy the MySQL database:
kubectl -n provider-ns create -f mysql.yamlExpected output:
secret/mysecret created service/mysql created statefulset.apps/mysql created
Create a ServiceExport in ACK Cluster 1 and specify the name of the Service that you want to expose to external access. In this example, the mysql Service is specified.
Create a file named
serviceexport.yamland copy the following code block to the file:apiVersion: multicluster.x-k8s.io/v1alpha1 kind: ServiceExport metadata: name: mysql # Specify the name of the Service that you want to expose to external access.Run the following command to create the ServiceExport:
kubectl -n provider-ns create -f serviceexport.yamlExpected output:
serviceexport.multicluster.x-k8s.io/mysql created
Step 2: Create a namespace and a ServiceImport in ACK Cluster 2
Run the following command to create a namespace
provider-nsin ACK Cluster 2:kubectl create ns provider-nsCreate a ServiceImport in ACK Cluster 2.
Create a file named
serviceimport.yamland copy the following code block to the file:ImportantSet the
typeparameter of the ServiceImport toHeadless.apiVersion: multicluster.x-k8s.io/v1alpha1 kind: ServiceImport metadata: name: mysql # Specify the name of the Service that you want to expose to external access. spec: ports: # Specify the ports of the Service that you want to expose to external access. - name: tcp port: 3306 protocol: TCP type: HeadlessRun the following command to create the ServiceImport:
kubectl -n provider-ns create -f serviceimport.yamlExpected output:
serviceimport.multicluster.x-k8s.io/mysql created
Step 3: Access the specified MySQL pod in ACK Cluster 1 from ACK Cluster 2 by using a domain name
You can use the following domain names to access the specified MySQL pod in ACK Cluster 1 from ACK Cluster 2:
${pod name}.amcs-${service name}.${namespace}.svc.cluster.local${pod name}.${clusterid}.${service name}.${namespace}.svc.clusterset.local
Use ${pod name}.amcs-${service name}.${namespace}.svc.cluster.local
Create a client pod in ACK Cluster 2.
Create a file named
mysqlclient.yamland copy the following code block to the file:apiVersion: v1 kind: Pod metadata: name: mysql-client spec: containers: - name: mysql-client image: mysql:5.6 command: ["sh", "-c", "sleep 12000"]Run the following command to create the client pod:
kubectl create -f mysqlclient.yamlExpected output:
pod/mysql-client created
Access the specified MySQL pod in ACK Cluster 1 from ACK Cluster 2.
Run the following command to access the mysql-0 pod:
kubectl exec -it mysql-client -- mysql -h mysql-0.amcs-mysql.provider-ns.svc.cluster.local -P3306 -uroot -ppasswordRun the following command to access the mysql-1 pod:
kubectl exec -it mysql-client -- mysql -h mysql-1.amcs-mysql.provider-ns.svc.cluster.local -P3306 -uroot -ppassword
Expected output:
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.
Use ${pod name}.${clusterid}.${service name}.${namespace}.svc.clusterset.local
Create a client pod in ACK Cluster 2.
Create a file named
mysqlclient.yamland copy the following code block to the file:apiVersion: v1 kind: Pod metadata: name: mysql-client spec: containers: - name: mysql-client image: mysql:5.6 command: ["sh", "-c", "sleep 12000"]Run the following command to create the client pod:
kubectl create -f mysqlclient.yamlExpected output:
pod/mysql-client created
Install or update CoreDNS in ACK Cluster 2. The version of CoreDNS must be 1.9.3 or later. For more information, see CoreDNS and Manage components.
Modify the Corefile configurations of CoreDNS.
Run the following command to modify the ConfigMap of CoreDNS:
kubectl edit configmap coredns -n kube-systemIn the Corefile field, add
multicluster clusterset.localto enable domain name resolution for multi-cluster Services.apiVersion: v1 data: Corefile: | .:53 { errors health { lameduck 15s } ready multicluster clusterset.local # Add this configuration to enable domain name resolution for multi-cluster Services. 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
Access a specified MySQL pod in ACK Cluster 1 from ACK Cluster 2.
Run the following command to access the mysql-0 pod:
kubectl exec -it mysql-client -- mysql -h mysql-0.${clusterid}.mysql.provider-ns.svc.clusterset.local -P3306 -uroot -ppasswordRun the following command to access the mysql-1 pod:
kubectl exec -it mysql-client -- mysql -h mysql-1.${clusterid}.mysql.provider-ns.svc.clusterset.local -P3306 -uroot -ppassword
Expected output:
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.