What is an Application?

An application is a collection of independent and loosely coupled services that work together to provide a set of functionalities that are associated with a business value. While the concept of Application is sometimes associated or perceived as the UI (e.g., the web, a mobile application, etc), in the NAPPTIVE platform this concept refers to all the services that are typically referred to as “the backend” and are running in the cloud, not on the user’s computer or device. These services are responsible for the business logic behind the application and consist of: APIs, databases, machine learning models, processing pipelines, etc. The Napptive platform provides support for an Application entity based on the Open Application Model (OAM).


How is this different from Kubernetes?

The Application is a top level entity from OAM that provides a simple method to define its composition and how it must be deployed. In contrast, Kubernetes does not provide any centralized entity to manage and reason about an application. Deploying an application in Kubernetes requires working with the different low-level entities such as Deployments, Services, Ingresses, Pods, etc. Moreover, those entities require subtle changes when changing from one Cloud Provider to another. With the NAPPTIVE platform and the Application abstraction, those adaptations for a particular cloud provider are no longer required as it is the system who translates the high-level Application entity into the low-level Kubernetes entities. The following diagram describes the rendering process of high-level OAM entities into native Kubernetes ones.

Application rendering in Kubernetes Figure: An Application being translated into low-level Kubernetes entities

But wait, does this not sound like Helm?

Helm charts are the classic method to package the components of an application so that all of them can be deployed together. Helm charts have some problems related to maintainability and understanding the impact of applying a chart in the cluster. However, the main difference with the proposed Application is that once a Helm chart is deployed, reasoning about the application that has been created in Kubernetes after applying the chart requires going through the different low-level entities in Kubernetes to understand if the application is working or not. Having a top-level Application entity brings simplicity to the whole process. Moreover, some components of an Application can be deployed using Helm Charts, so you do not need to migrate your whole system to start working with Napptive. Check how to deploy components using Helm Charts for more information.


Anatomy of an Application

The Application entity defines three types of elements: Components, Policies, and a Workflow that describe the elements of the application, their configuration, and deployment. The following figure shows a classic Wordpress application in OAM.

Application concept Figure: Main elements of an Application

As shown, the application contains two components: mysql-db and wordpress, with each of them being augmented by means of applying traits. The mysql-db component uses a storage trait to create a Secret and set the root password, while the wordpress one uses a service-binding trait to set the environment variables taking values from the secret previously created. Additionally, a napptive-ingress trait is used to create a secure public endpoint to expose the wordpress Web UI to the Internet.

In terms of creating An Application, it is defined in a YAML file with the following schema:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  # Name of the application which will be used to refer to it once deployed.
  name: <name>
spec:
  # List of components that are part of the application.
  components:
      # Each component must have a name. The name will be used during the translation process
      # to Kubernetes entities.
    - name: <component name>
      # Each component is associated with a type. The type works as a template and defines
      # how a high-level component will be translated into Kubernetes.
      type: <component type>
      # Properties that can be configured for the user. This can be use to set the parameters
      # that are defined by the component type.
      properties:
        <parameter values>
      # Traits are extensions that augment the capabilities of a component. For example,
      # changing the replication, importing a config map, etc.
      traits:
        - type: <trait type>
          properties:
            <traits parameter values>
    ...
  # Policies define application-level behaviors that will be applied to all components.
  # For example, setting a common health probe.
  policies:
  - name: <policy name>
    type: <policy type>
    properties:
      <policy parameter values>
  # The workflow defines the steps that are required to deploy an application. All
  # applications are associated with a default workflow if none if specified with
  # a single step to render the components into the target Kubernetes distribution.
  workflow:
    - name: <step name>
      type: <step type>
      properties:
        <step parameter values>   

For instructions to deploy the applications follow the deploy a custom application tutorial.

Components

A Component represents a single microservice from the Application. To define it, select the type of component that adapts best to the use case, and define its properties. The platform provides built-in support for the following types of components:

Type Description
Webservice Describes long-running, scalable, containerized services that have a stable network endpoint to receive external network traffic from customers.
Worker Describes long-running, scalable, containerized services that are running at backend. They do NOT have network endpoint to receive external network traffic.
Stateful Service A long-running, scalable application with guarantees about the ordering and uniqueness of the replicas.
Cron Task Describes cron jobs that run code or a script to completion.
Task Describes jobs that run code or a script to completion.
K8s Objects K8s-objects allow users to specify raw K8s objects in properties
Helm Use this component to deploy Helm charts as part of an application.
Example: Single component application to deploy Nginx using a webservice component.
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: nginx-app
spec:
  components:
    - name: nginx
      type: webservice
      properties:
        image: nginx:1.20.0
        ports:
        - port: 80
          expose: true

For instructions to deploy the applications follow the deploy a custom application tutorial.

For more information, check the built-in component types.

Traits

A Trait represents an extension for an application component. This facilitates reusing components in different situations, and simplifies their packaging as the developer does not need to add any extra information for its deployment. For example, exposing an application component to the public Internet can be easily done by attaching an ingress trait. The trait offers the same abstraction as the component and will create the underlying ingress attending to the installed controller and cloud provider. In this way, the developer can publish the component with its parameters, and when creating the application, the ingress can be easily added. Other examples of traits include mounting volumes, adding labels, exporting logs, exploring monitoring information, etc.

The platform provides built-in support for many types of traits. The most used ones are:

Trait type Description
napptive-ingress Expose a component to the outside with a K8s ingress.
gateway Expose a component to the outside with a K8s ingress.
env Add environment variables to the container
resource Add resource requests and limits to manage the quota.
container-image Set the container image to be used.
command Modify the command that will be launched by the container.
service-binding Bind secrets and configmaps to a component.
storage Add storage to a component
scaler Set a fixed number of replicas for a component.
Example: Using a trait to expose the nginx component.
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: nginx-app
spec:
  components:
    - name: nginx
      type: webservice
      properties:
        image: nginx:1.20.0
        ports:
        - port: 80
          expose: true
      traits:
        # The trait will generate an ingress with a DNS and TLS certificate that is
        # publicly accessible.
        - type: napptive-ingress         
          properties:
            port: 80
            path: /

For instructions to deploy the applications follow the deploy a custom application tutorial.

Check the full list of built-in trait types for more information.

Policies

A Policy defines an application-level behavior that is applied to all components. For example, if we need to add a specific label to all components, instead of attaching a trait to each of them, it is easier to define or use a policy that is applied at the application level. Check the full list of built-in policies types for more information.

Workflows

A workflow defines the steps required to deploy an application. By default, a single step is automatically added to render the components into Kubernetes if a workflow has not been defined. Workflows can be used in practice to orchestrate the deployment of the different components (e.g., wait for the database to boot before launching the next element). Check the documentation to discover the built-in workflow steps supported by the platform.


What’s next