Kuberig

Kuberig

  • Docs
  • Blog
  • Help

›Getting started

Getting started

  • Intro
  • Quick Start
  • DSL Intro

Environments

  • Initializing an Environment
  • Managing Container Versions
  • Environment Support

Resource Coding

  • Coding Resources
  • Resource Grouping
  • Resource Apply Action
  • DSL Details

Code Samples

  • Defining a ConfigMap
  • Defining a Secret
  • Defining a Deployment
  • Defining a Service
  • Defining an Ingress

Reference

  • Configuration
  • Repository Organisation
  • Encryption Support
  • Service Account Setup

DSL Intro

In the Quick Start we deployed some resources but did not go into the details of to use the KubeRig DSL to define them.

Using the KubeRig DSL it is possible to generate Kubernetes resources in a smart and typesafe way. Lets dig into it!

Step 1

The example resources are based on the Using Ingress section of the Kind docs.

As a first step we have converted the yaml files to DSL code one-on-one. But we can do a better job now that it is code.

package ingress

import io.kuberig.annotations.EnvResource
import kinds.extensions.v1beta1.IngressDsl
import kinds.extensions.v1beta1.ingress
import kinds.v1.PodDsl
import kinds.v1.ServiceDsl
import kinds.v1.pod
import kinds.v1.service

class IngressExample {

    @EnvResource
    fun fooApp(): PodDsl {
        return pod {
            metadata {
                name("foo-app")
                labels {
                    label("app", "foo")
                }
            }
            spec {
                containers {
                    container {
                        name("foo-app")
                        image("hashicorp/http-echo")
                        args {
                            arg("-text=foo")
                        }
                    }
                }
            }
        }
    }

    @EnvResource
    fun fooService(): ServiceDsl {
        return service {
            metadata {
                name("foo-service")
            }
            spec {
                selector("app", "foo")
                ports {
                    port {
                        // Default port used by the image
                        port(5678)
                    }
                }
            }
        }
    }

    @EnvResource
    fun barApp(): PodDsl {
        return pod {
            metadata {
                name("bar-app")
                labels {
                    label("app", "bar")
                }
            }
            spec {
                containers {
                    container {
                        name("bar-app")
                        image("hashicorp/http-echo")
                        args {
                            arg("-text=bar")
                        }
                    }
                }
            }
        }
    }

    @EnvResource
    fun barService(): ServiceDsl {
        return service {
            metadata {
                name("bar-service")
            }
            spec {
                selector("app", "bar")
                ports {
                    port {
                        // Default port used by the image
                        port(5678)
                    }
                }
            }
        }
    }

    @EnvResource
    fun exampleIngress(): IngressDsl {
        return ingress {
            metadata {
                name("example-ingress")
                annotations {
                    annotation("ingress.kubernetes.io/rewrite-target", "/")
                }
            }
            spec {
                rules {
                    rule {
                        http {
                            paths {
                                path {
                                    path("/foo")
                                    backend {
                                        serviceName("foo-service")
                                        servicePort(5678)
                                    }
                                }
                                path {
                                    path("/bar")
                                    backend {
                                        serviceName("bar-service")
                                        servicePort(5678)
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

}

In this example we use the @EnvResource annotation. Methods annotated with @EnvResource are expected to return a DSL type that exist in the kinds package.

Step 2

Both the foo and bar pod and service are similar so we can extract this in a dedicated class.

package ingress

import io.kuberig.annotations.EnvResource
import kinds.v1.PodDsl
import kinds.v1.ServiceDsl
import kinds.v1.pod
import kinds.v1.service

abstract class HttpEchoApp(private val name: String) {

    @EnvResource
    fun appPod(): PodDsl {
        return pod {
            metadata {
                name("$name-app")
                labels {
                    label("app", name)
                }
            }
            spec {
                containers {
                    container {
                        name("$name-app")
                        image("hashicorp/http-echo")
                        args {
                            arg("-text=$name")
                        }
                    }
                }
            }
        }
    }

    @EnvResource
    fun appService(): ServiceDsl {
        return service {
            metadata {
                name("$name-service")
            }
            spec {
                selector("app", name)
                ports {
                    port {
                        // Default port used by the image
                        port(5678)
                    }
                }
            }
        }
    }
}

We can now use this class to create FooApp and BarApp specific classes. This shows that you can place the @EnvResource annotation on methods of parent classes.

class FooApp : HttpEchoApp("foo")
class BarApp : HttpEchoApp("bar")

The @EnvResource annotation is great to start with but it is limited because it can only be used to define a single resource.

Level Up Please!

For more complex scenarios we can use the @EnvResources annotation. When a method is annotated with the @EnvResources annotation we can use the emit function of the DslResourceEmitter to define multiple resources.

Lets take our example to the next level.

Our top level IngressExample class should not be too difficult. We should be able to just specify some configuration of what we want.

package ingress

import io.kuberig.annotations.EnvResources

class IngressExample {

    @EnvResources
    fun exampleIngressResources() {
        HttpEchoApps.echoApps("foo", "bar")
    }

}

The new HttpEchoApps object exposes an echoApps method that takes in some configuration, in this case only names are needed.

package ingress

import io.kuberig.dsl.support.DslResourceEmitter.emit
import kinds.extensions.v1beta1.IngressDsl
import kinds.extensions.v1beta1.ingress

object HttpEchoApps {

    fun echoApps(vararg appNames: String) {
        val apps = appNames.map {
            appName -> HttpEchoApp(appName)
        }

        apps.forEach { app ->
            app.emitResources()
        }

        emit(exampleIngress(apps))
    }

    private fun exampleIngress(apps: List<HttpEchoApp>): IngressDsl {
        return ingress {
            metadata {
                name("example-ingress")
                annotations {
                    annotation("ingress.kubernetes.io/rewrite-target", "/")
                }
            }
            spec {
                rules {
                    rule {
                        http {
                            paths {
                                apps.forEach { app ->
                                    path(app.appIngressPath())
                                }
                            }
                        }
                    }
                }
            }
        }
    }

}

THe HttpEchoApps object uses the names to create an instance of HttpEchoApp for every name that comes in.

Next it asks each HttpEchoApp to emit the resources needed to deploy an HttpEchoApp.

And as a last action the ingress resource is created by using the list of HttpEchoApp instances. In the paths block we ask each HttpEchoApp for the ingressPath and add it to the ingress.

The HttpEchoApp looks pretty similar as before.

package ingress

import io.kuberig.dsl.support.DslResourceEmitter.emit
import io.k8s.api.extensions.v1beta1.HTTPIngressPathDsl
import io.k8s.api.extensions.v1beta1.hTTPIngressPath
import kinds.v1.PodDsl
import kinds.v1.ServiceDsl
import kinds.v1.pod
import kinds.v1.service

class HttpEchoApp(private val name: String) {
    // Default port used by the image
    private val portNumber = 5678
    
    fun emitResources() {
        emit(appPod())
        emit(appService())
    }
    
    private fun appPod(): PodDsl {
        return pod {
            metadata {
                name("$name-app")
                labels {
                    label("app", name)
                }
            }
            spec {
                containers {
                    container {
                        name("$name-app")
                        image("hashicorp/http-echo")
                        args {
                            arg("-text=$name")
                        }
                    }
                }
            }
        }
    }

    private fun appService(): ServiceDsl {
        return service {
            metadata {
                name("$name-service")
            }
            spec {
                selector("app", name)
                ports {
                    port {
                        port(portNumber)
                    }
                }
            }
        }
    }

    fun appIngressPath(): HTTPIngressPathDsl {
        return hTTPIngressPath {
            path("/$name")
            backend {
                serviceName("$name-service")
                servicePort(portNumber)
            }
        }
    }
}

The @EnvResource annotations have been removed and the pod and service definition methods have become private.

The appIngressPath method is new and generates a part of the ingress resource that is used in the HttpEchoApps.exampleIngress method.

Everything that is specific to an HttpEchoApp is now defined inside the HttpEchoApp class.

Next steps

I hope this example shows the potential of the KubeRig DSL and has sparkelled your enthusiasm!

There is much more to KubeRig so read on!

Last updated on 12/30/2020
← Quick StartInitializing an Environment →
  • Step 1
  • Step 2
  • Level Up Please!
  • Next steps
Kuberig
Docs
HomeQuick StartDSL Intro
Community
Stack OverflowDiscordTwitter
More
BlogGitHubStar
Follow @kuberigio
Copyright © 2021 Rigeldev BV