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