The multi-cluster Services (MCS) feature allows you to access Services across Kubernetes clusters without the need to create load balancers. A headless multi-cluster Service provides a domain name that you can use to access the specified backend pods of the Service across clusters. Headless multi-cluster Services are suitable for accessing applications deployed as StatefulSets across clusters, such as distributed databases and message queues. This topic describes how to use a headless multi-cluster Service to access a MySQL database across clusters.
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. For more information, see Enable multi-cluster management.
Two clusters (the service provider cluster and service consumer cluster) are associated with the Fleet instance. For more information, see Associate clusters with a Fleet instance.
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 Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
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 in ACK Cluster 1. In this example, the
provider-ns
namespace is created.kubectl create ns provider-ns
Create a MySQL database in ACK Cluster 1
Create a file named
mysql.yaml
and 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: 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
Run the following command to deploy the MySQL database:
kubectl -n provider-ns create -f mysql.yaml
Expected 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.yaml
and 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.yaml
Expected 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 in ACK Cluster 2. In this example, the
provider-ns
namespace is created.kubectl create ns provider-ns
Create a ServiceImport in ACK Cluster 2.
Create a file named
serviceimport.yaml
and copy the following code block to the file:ImportantSet the
type
parameter 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: Headless
Run the following command to create the ServiceImport:
kubectl -n provider-ns create -f serviceimport.yaml
Expected 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.yaml
and 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.yaml
Expected 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 -ppassword
Run 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.yaml
and 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.yaml
Expected 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-system
In the Corefile field, add
multicluster clusterset.local
to 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 -ppassword
Run 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.