OAM for deploying microservices-based application
Following is what I have learned so far, I have ended this article with an error that I faced. I'll update once I rectify it.
What is OAM?
An open-source specification for defining cloud-native apps on any cloud platform.
Provides a higher level of abstraction for defining & deploying apps thereby allowing developers to focus on the app rather than the underlying infrastructure.
A standardized way of defining application components & their dependencies, along with the necessary deployment, scaling, & health monitoring info.
Enables developers to create reusable app components & deploy them across multiple environments with ease.
Designed to work with Kubernetes-based tech such as Helm, Custom Resource Definitions (CRDs), & Kubernetes Operators, providing a consistent & modular approach to building cloud-native apps.
OAM standard
A set of core concepts, including components, traits, scopes, & workflows.
Components: individual app components, such as services, databases, & worker nodes.
Traits: non-functional requirements, such as scaling, monitoring, & security.
Scopes: boundaries of a component or trait, such as the namespace or cluster it runs in.
Workflows: order in which components & traits are deployed & define dependencies between them.
Provides a set of APIs & conventions for implementing the standard in different environments. For eg: there are OAM controller APIs for managing OAM resources in Kubernetes, as well as OAM CLI tools for creating & deploying OAM apps.
OAM capabilities
Abstraction: Abstract details of infrastructure & focus on defining components, traits, & workflows. This makes it easier to manage & deploy complex apps across different environments.
Flexibility: Flexible way of defining & managing apps, allowing developers to use tools & frameworks as per requirement. This paves the way for apps that are optimized for performance, scalability, & cost-effectiveness.
Portability: Standardized approach to app management that can run on any cloud platform. This makes it easier to deploy & manage apps across different environments without having to modify app code.
Scalability: Built-in support for scaling apps based on resource utilization or other criteria. Allows to automatically adjust app capacity to meet changing demands, without manual intervention.
Extensibility: Extends capabilities of the platform through the use of traits. This provides the option to add new functionality to apps without modifying the underlying infrastructure or app code.
Deploying microservices-based application
Developers can define the components & relationships of their microservice applications, such as databases, APIs, & front-end components, along with their operational characteristics, such as scaling & monitoring.
Following is an example of an OAM yaml file for a microservice-based application
apiVersion: core.oam.dev/v1alpha2 kind: Application metadata: name: example-app spec: components: - name: frontend type: webservice settings: image: frontend:v1 port: 80 traits: - type: autoscaler properties: minReplicas: 1 maxReplicas: 10 cpuThresholdPercentage: 80 - name: backend type: webservice settings: image: backend:v1 port: 8080 traits: - type: ingress properties: host: example.com path: /api
Here, we have an app with two components: a frontend web service & a backend web service.
Each component has a set of settings that define its image & port.
The frontend component also has an autoscaler trait that automatically scales the component based on CPU usage.
The backend component has an ingress trait that exposes the component to the internet using the example.com domain & the /api path.
Real-world example: Hipster Shop
Following is an example of a real-world OAM yaml for a microservice-based app. Hipster Shop is an open-source, microservice-based e-commerce website app.
apiVersion: core.oam.dev/v1alpha2
kind: Application
metadata:
name: hipster-shop
spec:
components:
- name: frontend
type: webservice
settings:
image: gcr.io/hipster-shop/frontend:v0.1.7
port: 80
env:
- name: PRODUCT_CATALOG_SERVICE_ADDR
value: productcatalogservice:3550
- name: CURRENCY_SERVICE_ADDR
value: currencyservice:7000
- name: CART_SERVICE_ADDR
value: cartservice:7070
- name: RECOMMENDATION_SERVICE_ADDR
value: recommendationservice:8080
- name: SHIPPING_SERVICE_ADDR
value: shippingservice:50051
- name: CHECKOUT_SERVICE_ADDR
value: checkoutservice:5050
traits:
- type: autoscaler
properties:
minReplicas: 1
maxReplicas: 10
cpuThresholdPercentage: 80
- type: ingress
properties:
host: hipster.example.com
path: /
- name: cartservice
type: webservice
settings:
image: gcr.io/hipster-shop/cartservice:v0.2.4
port: 7070
traits:
- type: autoscaler
properties:
minReplicas: 1
maxReplicas: 5
cpuThresholdPercentage: 80
- name: currencyservice
type: webservice
settings:
image: gcr.io/hipster-shop/currencyservice:v0.2.4
port: 7000
- name: checkoutservice
type: webservice
settings:
image: gcr.io/hipster-shop/checkoutservice:v0.2.4
port: 5050
env:
- name: PAYMENT_SERVICE_ADDR
value: paymentservice:50051
- name: paymentservice
type: webservice
settings:
image: gcr.io/hipster-shop/paymentservice:v0.2.4
port: 50051
- name: productcatalogservice
type: webservice
settings:
image: gcr.io/hipster-shop/productcatalogservice:v0.2.4
port: 3550
- name: recommendationservice
type: webservice
settings:
image: gcr.io/hipster-shop/recommendationservice:v0.2.4
port: 8080
traits:
- type: autoscaler
properties:
minReplicas: 1
maxReplicas: 5
cpuThresholdPercentage: 80
- name: shippingservice
type: webservice
settings:
image: gcr.io/hipster-shop/shippingservice:v0.2.4
port: 50051
The above app has multiple components, each representing a microservice.
Each component has a set of settings that define its image & port, as well as any environment variable needed for configuration.
Some components also have autoscaler traits to automatically scale based on CPU usage.
The frontend component also has an ingress that exposes the component to the internet using the hipster.example.com domain. This is not defined in the application yaml file, but rather in a separate component yaml file that is referenced in the component's 'traits' section
apiVersion: oam.dev/v1alpha2 kind: Component metadata: name: frontend namespace: hipster-shop spec: workload: apiVersion: apps/v1 kind: Deployment metadata: name: frontend spec: replicas: 1 template: metadata: labels: app: frontend spec: containers: - name: frontend image: "gcr.io/google-samples/microservices-demo/frontend:v0.1.3" ports: - containerPort: 80 env: - name: PRODUCT_CATALOG_SERVICE_ADDR value: "productcatalogservice:3550" - name: CURRENCY_SERVICE_ADDR value: "currencyservice:7000" - name: CART_SERVICE_ADDR value: "cartservice:7070" - name: RECOMMENDATION_SERVICE_ADDR value: "recommendationservice:8080" - name: SHIPPING_SERVICE_ADDR value: "shippingservice:50051" - name: CHECKOUT_SERVICE_ADDR value: "checkoutservice:5050" traits: - type: ingress properties: domain: hipster.example.com http: "/": 80
- The above example also includes environment variables that define the addresses of other microservices that the frontend component depends on.
The yaml files can be deployed in napptive. However, at the point of writing this, I'm getting an error as seen below.
As per the error, I tried the below 2 approaches, but I still get the same error:
traits:
- name: frontend-autoscaler # haven't seen name field for traits
type: autoscaler
properties:
minReplicas: 1
maxReplicas: 10
cpuThresholdPercentage: 80
---
traits:
- type: autoscaler
properties:
name: frontend-autoscaler
minReplicas: 1
maxReplicas: 10
cpuThresholdPercentage: 80
This blog is part of sharing my learnings as part of the Napptive x wemakedevs hackathon track 3. In case of any suggestions, please connect with me on LinkedIn or Twitter. #WeMakeDevs
Subscribe to my newsletter
Read articles from Sebastian James directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Sebastian James
Sebastian James
I am a developer who loves to learn, explore & work with various tech stacks which brings value to people.