Enabling Kubernetes self-service the operator method

Enabling Kubernetes Self-service the Operator Way

Enabling Kubernetes self-service the operator method

Home » News » Enabling Kubernetes self-service the operator method
Table of Contents
Image

Image via lisa runnels from Pixabay

This article gifts an method for the use of a customized operator and the Operator SDK to grow to be a choice of YAML recordsdata right into a customized useful resource. It outlines the stairs for growing a particular useful resource CustomizedResource / CustomizedResourceDefinition that you’ll be able to use to deploy a predefined set of sources, equivalent to a specific coverage, governance, or deployment.

The number one goal of this newsletter is to show how operators can function governance gear in a multitenant surroundings. By delegating get admission to controls to tenant groups, platform directors can permit self-service functions inside their organizations with out jeopardizing coexistence amongst tenants.

[ Learn how to extend the Kubernetes API with operators

Prerequisites for this instructional

  1. You have an working out of the fundamentals of Kubernetes and you’re the administrator of the cluster the place you’re deploying. To practice this situation, a neighborhood system example is excellent sufficient.
  2. An working out of Ansible fundamentals is essential.
  3. You want get admission to to a container symbol repository to post pictures constructed right through this workout.

Get began

For this instructional, you’ll be able to simulate a situation or an issue commentary you are attempting to unravel.

You need your cluster’s tenants to be able to create or delete a namespace in a multitenant surroundings.

However, this situation poses some issues that you wish to have to unravel to respond to this request:

  • There is a unmarried useful resource kind form: Namespace. Providing create or delete get admission to to this useful resource would probably grant get admission to to delete namespaces belonging to any other tenant in the similar cluster.
  • Tenants can create namespaces with out restrictions with out mapping to useful resource quotas or LDAP bindings to the namespace, amongst others.

Now I’ll discover how you’ll be able to resolve this drawback and make this situation a self-service capacity for tenants the use of operators.

Step 1: Install the dependent libraries

The dependencies required for your PATH variables are

  1. Kubectl
  2. Container runtime equivalent to Podman
  3. Operator SDK (see documentation)

Step 2: Set up the surroundings

Log in to OpenShift or Kubernetes as kubeadmin (choose a neighborhood example).

Clone an empty git repo in your native system. This is had to retailer the code you generate. Then transfer into the cloned folder.

For this situation, think you might have 2 tenants:

  • Tenant 1 is known as Acme
  • Tenant 2 is known as Umbrella

In this newsletter, I goal to create 2 customized sources Kind: AcmeNamespace and Kind: UmbrellaNamespace, which is able to create a namespace and fix to the suitable cluster useful resource quota and carry out different movements. Once the permissions are mapped, tenants in Acme can’t intervene with namespaces belonging in Umbrella.

Initiate an operator assignment:

$ operator-sdk init --domain mytenant.com --plugins ansible

Create customized useful resource definitions to your sources:

$ operator-sdk create api --group tenants 
    --version v1alpha1 --kind AcmeNamespace --generate-role

$ operator-sdk create api --group tenants 
    --version v1alpha1 --kind UmbrellaNamespace --generate-role

Open the generated codebase in an IDE.

Step 3: Understand the codebase generated via the Operator SDK

For the needs of this newsletter, you’ll undergo a extra simplistic, minimal viable product (MVP) method. In this example, you’ll edit most effective the recordsdata required to make it paintings, with out the rest further. For a manufacturing surroundings, you might wish to upload extra tests and common sense in step with your necessities.

You want the next recordsdata to practice along side this newsletter, that are created when the operator-sdk create api command is completed in step 2:

  • config/crd: Contains 2 customized useful resource definitions (CRDs). One for each and every kind you added form: AcmeNamespace and form UmbrellaNamespace.
  • roles/api call: This is the Ansible position that will get completed when the operator encounters an example of the customized useful resource outlined up to now.

A CRD is what an operator tracks. When the operator receives a useful resource or YAML example belonging to this CRD, it plays an motion. A CRD incorporates the OpenAPI schema specification which defines the construction of the useful resource YAML report.

In this newsletter you’ll use a free-form OpenAPI spec key x-kubernetes-preserve-unknown-fields: true, which defines that it could possibly settle for any structure.

Step 4: Build the Ansible position

Under roles/acmenamespace/duties create a report known as primary.yaml. The primary.yaml is the entrypoint for this position:

---
- call: Create namespace
  kubernetes.core.k8s:
    definition:
      apiVersion: v1
      form: Namespace
      metadata:
        call: " ansible_operator_meta.name "
        labels:
          tenant: acme

This process creates a brand new namespace. You can upload further LDAP bindings as essential. You too can upload different sources equivalent to safety context constraints (SCC), prohibit levels, labels, or another sources you imagine as default tenant settings.

Do the similar for Umbrella tenants however with a distinct label tenant: Umbrella inside the report roles/umbrellanamespace/duties/primary.yaml.

Note: In order to show off customized tenant explicit configuration, I’m including in a community coverage to this namespace:

---
- call: Create namespace
  kubernetes.core.k8s:
    definition:
      apiVersion: v1
      form: Namespace
      metadata:
        call: " ansible_operator_meta.name "
        labels:
          tenant: umbrella

- call: Create default community coverage to permit networking between namespaces owned via tenant umbrella.
  kubernetes.core.k8s:
    definition:
      apiVersion: networking.k8s.io/v1
      form: NetworkPolicy
      metadata:
        call: allow-ingress-from-all-namespaces-under-umbrella-tenant
        namespace: " ansible_operator_meta.name "
      spec:
        podSelector: null
        ingress:
          - from:
              - namespaceSelector:
                  fitLabels:
                    tenant: umbrella

In the similar method as with the former tenant, you’ll be able to upload your customized configuration and sources right here.

Step 5: Prepare the cluster to just accept those new namespaces

To make certain your cluster maps the brand new namespaces to the suitable useful resource quotas, you’ll be able to wish to get ready the cluster.

Create a useful resource quota mapping to the labels you used to outline the tenants above:

$ oc create clusterquota acme 
     --project-label-selector tenant=acme 
     --hard pods=10 
     --hard secrets and techniques=20

$ oc create clusterquota umbrella 
     --project-label-selector tenant=umbrella 
     --hard requests.cpu=4

If you utilize Podman for your surroundings, exchange occurrences of docker to podman within the report Makefile:

$ sed -i 's/docker/podman/g' Makefile

Publish the operator you constructed to a container symbol repository. Modify the MakeFile within the root listing and exchange the price for the IMG variable with your individual public repository. You would possibly wish to log in in your repository first.

## Change
IMG ?= controller:newest

## To your in-house repo
IMG ?= docker.io/datatruckerio/operatorize-tenancy:newest 

Execute the operator to the cluster:

$ make podman-build podman-push
$ make deploy

The operator namespace is created routinely via the operators as <project-name>-system.

You’ll wish to supply authorization for the carrier account created for the operator by the use of RBAC. To stay the assignment moderately easy, you’ll be able to upload the carrier account to the cluster-admin position which grants all privileges. For an actual deployment, you must surely create a particular cluster position and position binding with most effective the desired permissions to be provisioned via the Ansible position.

To upload the carrier account to position cluster-admin, execute this command:

$ oc adm coverage add-cluster-role-to-user cluster-admin 
    -z <project-name>-controller-manager 
    -n <project-name>-system

Alternatively, you’ll be able to upload the granular RBAC configuration within the config/rbac folder of your operator.

Push your code to the git repository for garage. You can reuse this repository so as to add extra customized sources or improve the operator later. This is helping in having one operator for a number of customized sources.

Step 6: Test

Create a brand new AcmeNamespace the use of the operator:

apiVersion: tenants.mytenant.com/v1alpha1
form: AcmeNamespace
metadata:
  call: acmenamespace-sample
  namespace: <project-name>-system

Now you’ll be able to see the brand new namespace auto-mapped to the cluster useful resource.

[operatorize-my-stuff]$ oc get namespace | grep acme
acmenamespace-sample                               Active   36s

[operatorize-my-stuff]$ oc describe  clusterresourcequota acme
Name:           acme
Created:        16 hours in the past
Labels:         <none>
Annotations:    <none>
Namespace Selector: ["acmenamespace-sample"]
Label Selector: tenant=acme
AnnotationSelector: map[]
Resource        Used    Hard
--------        ----    ----
pods            0       10
secrets and techniques         6       20

Create Umbrella namespace:

apiVersion: tenants.mytenant.com/v1alpha1
form: UmbrellaNamespace
metadata:
  call: umbrella-example
  namespace: <project-name>-system

Now you’ll be able to see the brand new namespace auto-mapped to the cluster useful resource. You too can see the community coverage deployed. Even if the tenant tries to delete it, the operator will exchange it in its subsequent reconciliation.

[operatorize-my-stuff]$ oc get namespaces | grep umbrella
umbrella-example                                   Active   7m33s

[operatorize-my-stuff]$ oc describe clusterresourcequota umbrella
Name:           umbrella
Created:        16 hours in the past
Labels:         <none>
Annotations:    <none>
Namespace Selector: ["umbrella-example"]
Label Selector: tenant=umbrella
AnnotationSelector: map[]
Resource        Used    Hard
--------        ----    ----
requests.cpu    0       4

[operatorize-my-stuff]$ oc assignment umbrella-example
[operatorize-my-stuff]$ oc get networkpolicy
NAME                                                      POD-SELECTOR   AGE
allow-ingress-from-all-namespaces-under-umbrella-tenant   <none>         90s

[Kubernetes: Everything you need to know]

Tips and methods

You can use this technique for greater than provisioning. A couple of examples:

  • Add a Grafana example ready with configured knowledge resources
  • Add an Ingress useful resource merged with cert-manager to make sure tenants can most effective create TLS ingress
  • Add a namespace with default Prometheus laws, signals, and alert receivers
  • Add egress node labels

You too can convert present Helm charts to a carrier part like authentication-as-a-service or proxy-as-a-service. The operator lets in Ansible automation in its execution, thus enabling a posh record of directions to be completed in a particular order in addition to triggering APIs outdoor the scope of the Kubernetes cluster. The customized sources additionally help you set variables the use of spec, permitting customizations in line with variables. You can to find extra information within the documentation.

Summary

Now that you’ve got 2 separate customized sources form: AcmeNamespace and form: UmbrellaNamespace, you’ll be able to map explicit RBAC permissions permitting most effective participants of tenant Acme to get admission to AcmeNamespace, and participants of Umbrella to get admission to UmbrellaNamespace.

By doing this, the tenants can provision their very own namespaces with out in reality gaining access to delete the opposite tenants’ namespace. Applying governance insurance policies at the items the tenant creates permits self-service functions to tenants in a “git-ops-like” method, that means you’ll be able to retailer all the configuration as YAML recordsdata in a Git repository.

A replica of this situation implementation is saved in my public Github repo for reference.

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 
share this article.

Enjoying my articles?

Sign up to get new content delivered straight to your inbox.

Please enable JavaScript in your browser to complete this form.
Name