How to use Open Application Model to run applications on Kubernetes

Abhishek Gupta
ITNEXT
Published in
6 min readFeb 20, 2020

--

The Open Application Model (OAM) is a specification for building cloud-native apps with Rudr as its Kubernetesspecific implementation. In this blog, we will look at a couple of examples to reinforce OAM and Rudr related concepts covered in the previous blog.

We will start off by running a simple application on Kubernetes using Rudr components and then see an example of how to use a Rudr Trait.

code is available on GitHub

Pre-requisites

At its core, Rudr is a custom controller which runs as a Kubernetes Deployment. To install Rudr, you will need a Kubernetes cluster with versions 1.15.x or 1.16.x(these are the supported versions at the time of writing). Any cluster will work, but I have used Azure Kubernetes Service for the examples in this blog.

If you want to use AKS, all you need is an Azure subscription (grab a free account here!) and the Azure CLIto setup a managed Kubernetes cluster using the az aks create command.

Here is an example which spins up a single node cluster running Kubernetes version 1.15.7

az aks create --resource-group <AZURE_RESOURCE_GROUP> --name <AKS_CLUSTER_NAME> --kubernetes-version 1.15.7 --node-count 1 --node-vm-size Standard_B2s --node-osdisk-size 30 --generate-ssh-keys//point kubectl to AKS
az aks get-credentials --resource-group <AZURE_RESOURCE_GROUP> --name <AKS_CLUSTER_NAME>
//confirm
kubectl get nodes

After installing Helm 3, you can proceed with Rudrsetup

//clone the repo
git clone https://github.com/oam-dev/rudr.git
//install it using Helm
helm install rudr ./charts/rudr --wait
//confirm Rudr Deployment
kubectl get deployment rudr
//check Rudr CRDs
kubectl get crds -l app.kubernetes.io/part-of=core.oam.dev

Deploy a simple app with Rudr

We will start off with a basic example of deploying a simple application using the following Rudr objects: ComponentSchematic and ApplicationConfig.

The application is very simple — it’s a containerized app that exposes an endpoint which responds with Hello World! by default or Hello <greeting> if the GREETING environment variable is set. To run this in Kubernetes, the obvious route is to use a Deploymentobject. Instead, we will create Rudr Custom Resource Definitions (CRDs) to represent our application, submit them to Kubernetes and let the Rudr controller/operator take care of dealing with specific Kubernetes resources.

Deploy Rudr CRDs

We will start by creating a ComponentSchematic. Let's introspect it:

apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
name: greeter-component
spec:
workloadType: core.oam.dev/v1alpha1.Server
containers:
- name: greeter
image: abhirockzz/greeter-go
env:
- name: GREETING
fromParam: greeting
ports:
- protocol: TCP
containerPort: 8080
name: http
resources:
cpu:
required: 0.1
memory:
required: "128"
parameters:
- name: greeting
type: string
default: abhi_tweeter

This is a ComponentSchematic called greeter-component whose workloadType is core.oam.dev/v1alpha1.Server - this determines the type of Kubernetes resource created to handle this component. It has a single container which refers to the abhirockzz/greeter-go image on Docker Hub. The parameters section defines a configurable attribute named greeting whose default value abhi_tweeter. This parameter is referenced as an environment variable in the env attribute of the containers section.

Create the ComponentSchematic as such:

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/rudr-k8s-sample/master/deploy/component.yaml//outputcomponentschematic.core.oam.dev/greeter-component created

This will just create a ComponentSchematic object in Kubernetes - you can use kubectl get componentsto confirm. The ComponentSchematic cannot really do much on its own. It needs another Rudr entity to work with - the ApplicationConfig. Let's see what that looks like in this case:

apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: greeter-app-config
spec:
components:
- componentName: greeter-component
instanceName: greeter-app

The ApplicationConfig is what instantiates a ComponentSchematic - in this case, it refers to the greeter-component ComponentSchematic.

Create the ApplicationConfig:

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/rudr-k8s-sample/master/deploy/app-config.yaml//output
applicationconfiguration.core.oam.dev/greeter-app-config configured

To confirm:

kubectl get applicationconfiguration.core.oam.dev/greeter-app-config -o yaml

Take a closer look at the status section - you should see something similar to this:

apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
...
status:
components:
greeter-component:
deployment/greeter-app: running
service/greeter-app: created
phase: synced
phase: synced

Check the Kubernetes objects

Rudr created a bunch of Kubernetes resources for us - Deployment, Pod and Service

To check the Deployment

kubectl get deployment/greeter-appNAME          READY   UP-TO-DATE   AVAILABLE   AGE
greeter-app 1/1 1 1 42s

Check the Pod

kubectl get pod -l=app.kubernetes.io/name=greeter-app-configNAME                           READY   STATUS    RESTARTS   AGE
greeter-app-586b5d4ddc-wrqtb 1/1 Running 0 2m30s

Finally, the Kubernetes Service resource

kubectl get service/greeter-appNAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
greeter-app ClusterIP 10.0.135.117 <none> 8080/TCP 4m15s

Test the application

The simplest way to access the application is using port forwarding

make sure you replace the name of the Pod

kubectl port-forward pod/<pod name> 9090:8080Forwarding from 127.0.0.1:9090 -> 8080
Forwarding from [::1]:9090 -> 8080

Now you can simply curl the endpoint

curl localhost:9090//output
Hello abhi_tweeter!

That’ it! This was a very simple example of an application running in Kubernetes which was created using Rudr constructs only.

As an excercise, you can try creating the following ApplicationConfig and follow the steps outline above to access the application and what the result is

Note that this ApplicationConfig uses parameterValues section to override the parameters defined in the ComponentSchematic.

apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: greeter-app-config-2
spec:
components:
- componentName: greeter-component
instanceName: greeter-app-2
parameterValues:
- name: greeting
value: foobar

Using a Trait

In the previous example, the Deployment object which was created had one Pod (single app instance). You can scale it up using kubectl scale command, but I think you get the flow now - we will not do that! Let's make use if the Manual scaler Trait in Rudr to achieve this.

We will continue to use the same ComponentSchematic and introduce a new ApplicationConfig definition to ensure that there are two replicas of our application. We will do this wih the help of manual scaler trait

apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: greeter-app-config-3
spec:
components:
- componentName: greeter-component
instanceName: scalable-greeter-app
parameterValues:
- name: greeting
value: scalable
traits:
- name: manual-scaler
properties:
replicaCount: 2

The greeter-app-config-3ApplicationConfiguration references the greeter-component ComponentSchematic. Notice the traits section where we use a manual-scalerand specify replicaCount as 2. Just to make sure we are able to differentiate this from the previous application, we override the paramater to pass in the value of greeting as scalable

Create the ApplicationConfiguration

kubectl apply -f https://raw.githubusercontent.com/abhirockzz/rudr-k8s-sample/master/deploy/manual-scaler-trait/app-config.yaml//output
applicationconfiguration.core.oam.dev/greeter-app-config-3 created

Wait for few seconds and confirm that Rudr has triggered the creation of Kubernetes objects:

kubectl get applicationconfiguration.core.oam.dev/greeter-app-config-3 -o yaml

You should see a status section

status:
components:
greeter-component:
deployment/scalable-greeter-app: running
service/scalable-greeter-app: created
phase: synced

If deployment/scalable-greeter-app in unavailable state, please retry after a 10 seconds or so

Confirm the Deployment object

kubectl get deployment/scalable-greeter-appNAME                   READY   UP-TO-DATE   AVAILABLE   AGE
scalable-greeter-app 2/2 2 2 4m

Check the individual Pods as well

kubectl get pods -l=app.kubernetes.io/name=greeter-app-config-3NAME                                    READY   STATUS    RESTARTS   AGE
scalable-greeter-app-6488f64cb4-mj6nw 1/1 Running 0 5m
scalable-greeter-app-6488f64cb4-rpfvp 1/1 Running 0 5m

To access the application, just run a one-off Pod with curl installed in it. Once you're inside the Pod, you can simply use curl $SCALABLE_GREETER_APP_SERVICE_HOST:$SCALABLE_GREETER_APP_SERVICE_PORT to invoke the endpoint of the the application.

kubectl run curl --image=radial/busyboxplus:curl -i --tty --rm[ root@curl-6bf6db5c4f-5hw6t:/ ]$ curl $SCALABLE_GREETER_APP_SERVICE_HOST:$SCALABLE_GREETER_APP_SERVIC
E_PORT
Hello scalable!

SCALABLE_GREETER_APP_SERVICE_HOST and SCALABLE_GREETER_APP_SERVICE_PORT are available as environment varialbes thanks to the ClusterIP Service created by Rudr.

The expected response is Hello scalable! since we had overridden the greeting parameter in the ApplicationConfiguraton

Clean up

You can use the az aks delete command to delete the entire AKS cluster or delete the individual ApplicationConfiguration to trigger a cascade removal of all the related Kubernetes resources associated with it (Deployment etc.). To remove the Rudr deployment, simply use helm delete rudr and kubectl delete crd -l app.kubernetes.io/part-of=core.oam.dev if you also want to delete the Rudr CRDs (components, configurations etc.)

That’s all for this two-part series on the basics of Open Application Model and Rudr along with a hands-on example to get a feel of how to actually use it on Kubernetes. If you found this article helpful, please like and follow 🙌 Happy to get feedback via Twitter or feel free to drop a comment.

--

--

Principal Developer Advocate at AWS | I ❤️ Databases, Go, Kubernetes