6

I want to deploy MySQL-router in Kubernetes working as a service.

My plan..

  • Deploy MySQL-router inside k8 and expose MySQL-router as a service using LoadBalancer (MetalLB)
  • Applications running inside k8 sees mysql-router service as its database.
  • MySQL-router sends application data to outside InnoDB cluster.

I tried to deploy using:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-router
  namespace: mysql-router
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: mysql-router
  template:
    metadata:
      labels:
        app: mysql-router
        version: v1
    spec:
      containers:
      - name: mysql-router
        image: mysql/mysql-router
        env:
        - name: MYSQL_HOST
          value: "192.168.123.130"
        - name: MYSQL_PORT
          value: "3306"
        - name: MYSQL_USER
          value: "root"
        - name: MYSQL_PASSWORD
          value: "root@123"
        imagePullPolicy: Always
        ports:
        - containerPort: 6446

192.168.123.130 is MySQL cluster Master IP.

apiVersion: v1
kind: Service
metadata:
  name: mysql-router-service
  namespace: mysql-router
  labels:
    app: mysql-router
spec:
  selector:
    app: mysql-router
  ports:
  - protocol: TCP
    port: 6446
  type: LoadBalancer
  loadBalancerIP: 192.168.123.123

When I check mysql-router container logs, I see something like this:

Waiting for mysql server 192.168.123.130 (0/12)
Waiting for mysql server 192.168.123.130 (1/12)
Waiting for mysql server 192.168.123.130 (2/12)
....

After setting my external MySQL cluster info in deployment, I get following errors:

Successfully contacted mysql server at 192.168.123.130. Checking for cluster state. Can not connect to database. Exiting.

I can not deploy mysql-router without specifying MYSQL_HOST. What am I missing here?

My ideal deployment

Deployment

Sachith Muhandiram
  • 2,819
  • 10
  • 45
  • 94
  • 1
    please share yamls for mysql also , make sure your myql is running on 192.168.123.123 at the specified port 3306 – Tarun Khosla Jul 29 '20 at 09:26
  • @tarunkhosla MySQL is running outside K8. Its a separate MySQL cluster. I want , applications to see MySQL-router IP address and router does routing to real MySQL cluster. – Sachith Muhandiram Jul 29 '20 at 09:46
  • 1
    what is the IP of mysql then ? , give that as MYSQL_HOST – Tarun Khosla Jul 29 '20 at 09:49
  • 1
    Also mysql router doesn't seem to run on 3306 , it runs on 6446 or 6447 unless you changed something. – Tarun Khosla Jul 29 '20 at 10:02
  • @tarunkhosla Thanks, but I have a MySQL cluster,so how can I specify one? – Sachith Muhandiram Jul 29 '20 at 10:07
  • 1
    As tarun mentioned, please provide your MySQL YAML. Your `MySQL-router` is on your local env. Your MySQL instance is in cloud or local? Did you configured your firewalls? – PjoterS Jul 29 '20 at 10:24
  • @PjoterS MySQL is a local cluster running. Its not docker or kubernetes service. – Sachith Muhandiram Jul 29 '20 at 10:26
  • 1
    how do you connect to your local cluster ? – Tarun Khosla Jul 29 '20 at 11:08
  • @TarunKhosla I have added a diagram, I think its healpful. – Sachith Muhandiram Jul 29 '20 at 11:13
  • 1
    The solution is to have a load balancer in front of the MySQL cluster which (as its name suggests) balances the load between the MySQL cluster nodes. The load balancer configures a virtual IP address that is shared between the cluster nodes, and all your applications use this virtual IP address to access the cluster. Use this IP as host in your YAML – Tarun Khosla Jul 29 '20 at 11:17
  • 1
    I read your question 3 times and didn't understand what is your problem. You described your setup and showed some logs. What is not working? I think you should be more specific :) – Vüsal Jul 31 '20 at 13:02
  • 1
    how do you connect to your local cluster currently , are you able to access at all ? – Tarun Khosla Jul 31 '20 at 14:13
  • @Vusal I have uploaded an image, isnt that clear? – Sachith Muhandiram Jul 31 '20 at 15:38
  • 1
    Your diagram is clear but would be good if you tell what is the IP with which that sql cluster is accessible. – Tarun Khosla Aug 01 '20 at 13:58
  • 1
    You did not specify targetPort it should be acquired dynamically then. It should be listen to in `kubectl get svc` as the second number after 3306/33333 for example and you should connect to 192.168.123.123:33333 instead of 192.168.123.123:3306. Try to telnet to that port first if its open. – Milan Baran Aug 04 '20 at 12:24
  • @MilanBaran Target port should be `3306` or `6446` as @Tarun said? – Sachith Muhandiram Aug 04 '20 at 12:47
  • From your service definition, it's set to random. Can you add output from `kubectl get service mysql-router-service -n mysql-router` or for verbosity add `-o yaml` to the end. – Milan Baran Aug 04 '20 at 13:01
  • Nevermind! I think i got it now. I try to write an answer. – Milan Baran Aug 04 '20 at 13:11

2 Answers2

5

Of course you have to provide the MySQL Host. You could doing this with k8s DNS which setup with in the services.

MySQL Router is middleware that provides transparent routing between your application and any backend MySQL Servers. It can be used for a wide variety of use cases, such as providing high availability and scalability by effectively routing database traffic to appropriate backend MySQL Servers.

Examples

For examples below i use dynamic volume provisioning for data using openebs-hostpath And using StatefulSet for the MySQL Server.

Deployment

MySQL Router :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-router
  namespace: mysql-router
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: mysql-router
  template:
    metadata:
      labels:
        app: mysql-router
        version: v1
    spec:
      containers:
      - name: mysql-router
        image: mysql/mysql-router
        env:
        - name: MYSQL_HOST
          value: "mariadb-galera.galera-cluster"
        - name: MYSQL_PORT
          value: "3306"
        - name: MYSQL_USER
          value: "root"
        - name: MYSQL_PASSWORD
          value: "root@123"
        imagePullPolicy: Always
        ports:
        - containerPort: 3306

MySQL Server

apiVersion: apps/v1
kind: StatefulSet
metadata:
  namespace: galera-cluster
  name: mariadb-galera
spec:
  podManagementPolicy: OrderedReady
  replicas: 1
  selector:
    matchLabels:
      app: mariadb-galera
  serviceName: mariadb-galera
  template:
    metadata:
      labels:
        app: mariadb-galera
    spec:
      restartPolicy: Always
      securityContext:
        fsGroup: 1001
        runAsUser: 1001
      containers:
      - command:
        - bash
        - -ec
        - |
          # Bootstrap from the indicated node
          NODE_ID="${MY_POD_NAME#"mariadb-galera-"}"
          if [[ "$NODE_ID" -eq "0" ]]; then
              export MARIADB_GALERA_CLUSTER_BOOTSTRAP=yes
              export MARIADB_GALERA_FORCE_SAFETOBOOTSTRAP=no
          fi
          exec /opt/bitnami/scripts/mariadb-galera/entrypoint.sh /opt/bitnami/scripts/mariadb-galera/run.sh
        env:
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: BITNAMI_DEBUG
          value: "false"
        - name: MARIADB_GALERA_CLUSTER_NAME
          value: galera
        - name: MARIADB_GALERA_CLUSTER_ADDRESS
          value: gcomm://mariadb-galera.galera-cluster
        - name: MARIADB_ROOT_PASSWORD
          value: root@123
        - name: MARIADB_DATABASE
          value: my_database
        - name: MARIADB_GALERA_MARIABACKUP_USER
          value: mariabackup
        - name: MARIADB_GALERA_MARIABACKUP_PASSWORD
          value: root@123
        - name: MARIADB_ENABLE_LDAP
          value: "no"
        - name: MARIADB_ENABLE_TLS
          value: "no"
        image: docker.io/bitnami/mariadb-galera:10.4.13-debian-10-r23
        imagePullPolicy: IfNotPresent
        livenessProbe:
          exec:
            command:
            - bash
            - -ec
            - |
              exec mysqladmin status -uroot -p$MARIADB_ROOT_PASSWORD
          failureThreshold: 3
          initialDelaySeconds: 120
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: mariadb-galera
        ports:
        - containerPort: 3306
          name: mysql
          protocol: TCP
        - containerPort: 4567
          name: galera
          protocol: TCP
        - containerPort: 4568
          name: ist
          protocol: TCP
        - containerPort: 4444
          name: sst
          protocol: TCP
        readinessProbe:
          exec:
            command:
            - bash
            - -ec
            - |
              exec mysqladmin status -uroot -p$MARIADB_ROOT_PASSWORD
          failureThreshold: 3
          initialDelaySeconds: 30
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        volumeMounts:
        - mountPath: /opt/bitnami/mariadb/.bootstrap
          name: previous-boot
        - mountPath: /bitnami/mariadb
          name: data
        - mountPath: /opt/bitnami/mariadb/conf
          name: mariadb-galera-config
      volumes:
      - emptyDir: {}
        name: previous-boot
      - configMap:
          defaultMode: 420
          name: my.cnf
        name: mariadb-galera-config
  volumeClaimTemplates:
  - apiVersion: v1
    metadata:
      name: data
    spec:
      storageClassName: openebs-hostpath
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 20Gi

Services

MySQL Router Service

apiVersion: v1
kind: Service
metadata:
  name: mysql-router-service
  namespace: mysql-router
  labels:
    app: mysql-router
spec:
  selector:
    app: mysql-router
  ports:
  - protocol: TCP
    port: 3306
  type: LoadBalancer
  loadBalancerIP: 192.168.123.123

MySQL Service

apiVersion: v1
kind: Service
metadata:
  namespace: galera-cluster
  name: mariadb-galera
  labels:
    app: mariadb-galera
spec:
  type: ClusterIP
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mariadb-galera
---
apiVersion: v1
kind: Service
metadata:
  namespace: galera-cluster
  name: mariadb-galera-headless
  labels:
    app: mariadb-galera
spec:
  type: ClusterIP
  ports:
  - name: galera
    port: 4567
  - name: ist
    port: 4568
  - name: sst
    port: 4444
  selector:
    app: mariadb-galera
Bayu Dwiyan Satria
  • 986
  • 12
  • 28
3

What you need its #1 communication from App1-x to Mysql router and #2 a VIP/LB from MysqlRoutere to external mysql instances.

Well start with #2 configuration of Mysql instances VIP. You will need a service without selector.

apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  ports:
  - name: mysql
    port: 3306
    protocol: TCP
    targetPort: 3306
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
  name: mysql-service
subsets:
- addresses:
  - ip: 192.168.123.130
  - ip: 192.168.123.131
  - ip: 192.168.123.132
  ports:
  - name: mysql
    port: 3306
    protocol: TCP

You don't need LoadBalancer cuz you will connect only inside cluster. So, use ClusterIp instead.

#1 Create MysqlRouter deployment.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-router
  namespace: mysql-router
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: mysql-router
  template:
    metadata:
      labels:
        app: mysql-router
        version: v1
    spec:
      containers:
      - name: mysql-router
        image: mysql/mysql-router
        env:
        - name: MYSQL_HOST
          value: "mysql-service"
        - name: MYSQL_PORT
          value: "3306"
        - name: MYSQL_USER
          value: "root"
        - name: MYSQL_PASSWORD
          value: "root@123"
        imagePullPolicy: Always
        ports:
        - containerPort: 6446

To connect to external MySQL instances trough VIP/ClusterIP use mysql-service service and if deployment and service is in same namespace use mysql-service as hostname or put there a CLusterIP from kubectl get service mysql-service

apiVersion: v1
kind: Service
metadata:
  name: mysql-router-service
  namespace: mysql-router
  labels:
    app: mysql-router
spec:
  selector:
    app: mysql-router
  ports:
  - name: mysql
    port: 6446
    protocol: TCP
    targetPort: 6446
  type: ClusterIP

You can connect within kubernetes cluster to mysql-router-service hostname in same namespace and outside namespace to mysql-router-service.namespace.svc or outside kubernetes cluster use NodePort or LoadBalancer.

Milan Baran
  • 4,133
  • 2
  • 32
  • 49
  • my MySQL cluster is none kubernetes cluster. I have tried your solution, but it can not connect. – Sachith Muhandiram Aug 04 '20 at 14:11
  • 1
    Can you telnet on mysql-service 3306? – Milan Baran Aug 04 '20 at 14:31
  • 1
    Yes, I know its not in kubernetes cluster that's why you need service without selector and provide IPs explicitly. All other services are accessed within kubernetes cluster so ClusterIP is sufficient. You need to telnet to mysql-service from pod inside cluster trough kubectl exec command to get it working tho! – Milan Baran Aug 04 '20 at 14:34
  • 2
    Yet, I get `CrashLoopBackOff ` to container creating and `Succesfully contacted mysql server at mysql-service. Checking for cluster state. Can not connect to database. Exiting.` – Sachith Muhandiram Aug 06 '20 at 10:30
  • 1
    I'm not familiar with mysql router, so I will just guess. #1 The mysql-service will round robin the traffic between router and mysql. That could be a problem. Read more about kubernetes service SessionAffinity aka sticky connection or try to connect trough service just to one IP to test for this problem. #2 Check your password twice! #3 Check mysql user if it can connect from any IP – Milan Baran Aug 06 '20 at 11:53