The Open Application Model (OAM) is a specification for building cloud-native apps with Rudr
as its Kubernetes specific 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 CLI to 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 Rudr
setup
//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 Deployment
object. 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
//output
componentschematic.core.oam.dev/greeter-component created
This will just create a ComponentSchematic
object in Kubernetes - you can use kubectl get components
to 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-app
NAME 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-config
NAME READY STATUS RESTARTS AGE
greeter-app-586b5d4ddc-wrqtb 1/1 Running 0 2m30s
Finally, the Kubernetes Service
resource
kubectl get service/greeter-app
NAME 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:8080
Forwarding 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
usesparameterValues
section to override theparameters
defined in theComponentSchematic
.
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-3
ApplicationConfiguration
references the greeter-component
ComponentSchematic
. Notice the traits
section where we use a manual-scaler
and 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 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
inunavailable
state, please retry after a 10 seconds or so
Confirm the Deployment
object
kubectl get deployment/scalable-greeter-app
NAME READY UP-TO-DATE AVAILABLE AGE
scalable-greeter-app 2/2 2 2 4m
Check the individual Pod
s as well
kubectl get pods -l=app.kubernetes.io/name=greeter-app-config-3
NAME 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
andSCALABLE_GREETER_APP_SERVICE_PORT
are available as environment varialbes thanks to theClusterIP
Service
created byRudr
.
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.