Manage Redis Service via KubeCarrier

This example will show you how to manage Redis service cross cluster via KubeCarrier.

Prerequisites

Management Cluster

In this example, you will need a KubeCarrier Management Cluster where KubeCarrier will be installed.
For setting up KubeCarrier Management Cluster, please refer to KubeCarrier Requirements and KubeCarrier Installation for more details.

Accounts

In this example, we will create two Account objects, one is Provider(service provider), who will provide Redis service via KubeCarrier, and another one is Tenant(service consumer), who will create Redis instance and consume Redis service.
You can do:

Management Cluster

$ kubectl apply \
  -f https://raw.githubusercontent.com/kubermatic/kubecarrier/master/docs/manifests/accounts.yaml

This will create two Account objects for you: team-a(Provider), and team-b(Tenant). Please refer to Accounts Usage for more details.

Service Cluster

To provide Redis service, a Service Cluster needs to be created and registered to KubeCarrier by the service provider.

For setting up a Service Cluster, please refer to Setting up A Service Cluster for more details.

Catalog

To select which services to offer to which tenants, a Catalog object needs to be created:

Management Cluster

$ kubectl apply -n team-a \
  -f https://raw.githubusercontent.com/kubermatic/kubecarrier/master/docs/manifests/catalog.yaml

This will create a Catalog object which selects all CatalogEntries and offers them to all Tenants. Please refer to Catalog Usage for more details.

Redis Operator

We will use Redis Operator from Opstree Solutions in this example. For installing it in the Service Cluster, you will need to clone the repository, and do:

Service Cluster

$ helm upgrade --create-namespace redis-operator ./helm-charts/redis-operator --install --namespace redis-operator

Alternatively, you can save the following manifests to a redis-operator.yaml file:

---
# Source: redis-operator/templates/service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: redis-operator
  labels:
    control-plane: "redis-operator"
    app.kubernetes.io/name: redis-operator
    helm.sh/chart: redis-operator-0.4.0
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/instance: redis-operator
    app.kubernetes.io/version: 0.4.0
---
# Source: redis-operator/templates/role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: redis-operator
  labels:
    control-plane: "redis-operator"
    app.kubernetes.io/name: redis-operator
    helm.sh/chart: redis-operator-0.4.0
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/instance: redis-operator
    app.kubernetes.io/version: 0.4.0
subjects:
- kind: ServiceAccount
  name: redis-operator
  namespace: redis-operator
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
---
# Source: redis-operator/templates/operator-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-operator
  labels:
    control-plane: "redis-operator"
    app.kubernetes.io/name: redis-operator
    helm.sh/chart: redis-operator-0.4.0
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/instance: redis-operator
    app.kubernetes.io/version: 0.4.0
spec:
  replicas: 1
  selector:
    matchLabels:
      name: redis-operator
  template:
    metadata:
      labels:
        name: redis-operator
    spec:
      containers:
      - name: "redis-operator"
        image: "quay.io/opstree/redis-operator:v0.4.0"
        imagePullPolicy: Always
        command:
        - /manager
        args:
        - --leader-elect
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 100Mi
      serviceAccountName: "redis-operator"
      serviceAccount: "redis-operator"

Then you can use the following commands to install it:

Service Cluster

$ kubectl create namespace redis-operator
$ kubectl apply -f https://raw.githubusercontent.com/OT-CONTAINER-KIT/redis-operator/v0.4.0/helm-charts/redis-operator/crds/crd-redis.yaml
$ kubectl apply -n redis-operator -f redis-operator.yaml

You should see the Redis operator deployment is up and running in a few seconds:

Service Cluster

$ kubectl get -n redis-operator deployments
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
redis-operator   1/1     1            1           1m

CatalogEntrySet

When the Redis operator is up and running, we can register the Redis CRD into KubeCarrier Management Cluster so that team-b can consume this Redis service.

The only thing that you need to do is to create a CatalogEntrySet object with the following content in Management Cluster:

apiVersion: catalog.kubecarrier.io/v1alpha1
kind: CatalogEntrySet
metadata:
  name: redis
spec:
  metadata:
    displayName: Redis
    description: The redis database
    shortDescription: The redis database
  discover:
    webhookStrategy: None
    crd:
      name:  redis.redis.redis.opstreelabs.in
    serviceClusterSelector: {}
  derive:
    expose:
    - versions:
      - v1beta1
      fields:
      - jsonPath: .spec.global.password
      - jsonPath: .spec.global.image
      - jsonPath: .spec.mode
      - jsonPath: .spec.size
      - jsonPath: .spec.redisExporter.enabled
      - jsonPath: .spec.redisExporter.image
      - jsonPath: .spec.service.type
      - jsonPath: .spec.redisConfig

In the spec.discover.crd.name, we specify the name of Redis CRD in the Service Cluster, and KubeCarrier will try to search in the Service Clusters which are subject to the serviceClusterSelector, and register the CRDs with the name redis.redis.redis.opstreelabs.in in the Management Cluster.

Also, from a service provider perspective, you can define which version of CRD, and which fields of the CRD you would like to make available for users. Please refer to Catalog Entries and CatalogEntrySet API for more details.

Let’s save the above CatalogEntrySet in a redis-catalogentryset.yaml file and create it for team-a:

Management Cluster

$ kubectl apply -n team-a -f redis-catalogentryset.yaml --as=team-a-member

Two new CRDs will be added to the Management Cluster.

Management Cluster

$ kubectl get crds | grep redis
redis.eu-west-1.team-a                          2021-02-24T10:05:41Z
redis.internal.eu-west-1.team-a                 2021-02-24T10:05:28Z

redis.eu-west-1.team-a is a “slimmed-down” version of redis.redis.redis.opstreelabs.in CRD from Service Cluster, only containing fields specified in the CatalogEntrySet, and redis.internal.eu-west-1.team-a is a copy of redis.redis.redis.opstreelabs.in CRD.

Redis Service

Now, we can create a Redis instance for team-b, let’s check the available service Offerings for team-b:

$ kubectl get offerings -n team-b --as=team-b-member
NAME                     DISPLAY NAME   PROVIDER   AGE
redis.eu-west-1.team-a   Redis          team-a     13s

Then we can create a Redis instance with the following content as a team-b member:

apiVersion: eu-west-1.team-a/v1beta1
kind: Redis
metadata:
  name: redisinstance
spec:
  global:
    password: "1234"
    image: opstree/redis:v2.0
  mode: "standalone"
  redisExporter:
    enabled: false
    image: quay.io/opstree/redis-exporter:1.0
  size: 3
  redisConfig: {}
  service:
    type: ClusterIP

Let’s save the above Redis instance in a redis.yaml file and create it as a team-b member:

Management Cluster

kubectl apply -n team-b --as=team-b-member -f redis.yaml

After this Redis custom resource is created, a Redis instance will be provisioned for team-b in the Service cluster.

There will be a namespace in Service Cluster, which is created by KubeCarrier for team-b, we can get the name of the namespace by looking into the ServiceClusterAssignment object:

Management Cluster

$ kubectl get -n team-a serviceclusterassignments team-b.eu-west-1 -o json | jq .status.serviceClusterNamespace.name
"team-b-wqpd2"

Then you can see the Pod of Redis instance is running in that namespace:

Service Cluster

$ kubectl get -n team-b-wqpd2 pods
NAME                         READY   STATUS    RESTARTS   AGE
redisinstance-standalone-0   1/1     Running   0          22m

Register Another Service Cluster

If team-a would like to provide Redis service from another Service Cluster, team-a can just register a Service Cluster with Redis operator installed, and the Redis service from the new Service Cluster will be discovered automatically by KubeCarrier.

Please follow Setting up A Service Cluster and Redis Operator to prepare another Service Cluster (we can name it as eu-west-2) with Redis operator installed.

After you register the new Service Cluster to KubeCarrier, you will see two more CRDs in the Management Cluster in few seconds:

Management Cluster

$ kubectl get crds | grep redis
redis.eu-west-1.team-a                          2021-02-25T09:07:58Z
redis.eu-west-2.team-a                          2021-02-25T09:15:41Z
redis.internal.eu-west-1.team-a                 2021-02-25T09:07:33Z
redis.internal.eu-west-2.team-a                 2021-02-25T09:15:26Z

Also, there will be one more available service Offering for team-b:

$ kubectl get offerings -n team-b --as=team-b-member
NAME                     DISPLAY NAME   PROVIDER   AGE
redis.eu-west-1.team-a   Redis          team-a     13s
redis.eu-west-2.team-a   Redis          team-a     13s

Now team-b can provision Redis instance from eu-west-2 Service Cluster:

apiVersion: eu-west-2.team-a/v1beta1
kind: Redis
metadata:
  name: redisinstance
spec:
  global:
    password: "1234"
    image: opstree/redis:v2.0
  mode: "standalone"
  redisExporter:
    enabled: false
    image: quay.io/opstree/redis-exporter:1.0
  size: 3
  redisConfig: {}
  service:
    type: ClusterIP

Save the above Redis object in a redis-eu-west-2.yaml file, and create it in the Management Cluster as a team-b member:

Management Cluster

$ kubectl apply -n team-b --as=team-b-member -f redis-eu-west-2.yaml

Then you should be able to see that the Pod of Redis instance is running in eu-west-2 Service Cluster.