This section describes how applications are deployed using application configurations.
A component schematic can be deployed into any number of runtimes, any number of times. We call each deployment of a component an instance. Each time a component is deployed, it must be deployed with a configuration. This section of the specification describes configurations.
An application configuration (sometimes abbreviated to configuration) is managed by the app operator role, and provides information specific to the current instance of a component. The following information is considered specific to the runtime instance of a component:
- Information about this particular instance, such as:
- Name
- Release version
- Description
- Values for the defined
parameters
for a component, and for its respective components - Trait assignments to add operational functionality, together with any trait configuration
An instance is a trackable deployment of an application configuration. A component instance is an instance of a component that is created during the deployment of an application configuration. It is created when a component is deployed together with a configuration. Each subsequent upgrade of a component modifies the given instance. And each subsequent upgrade of an application configuration can modify any of the component instances controlled by that application configuration. For the purposes of this specification, workflow practices such as rollback or redeploy are considered to be special cases of upgrade (that is, if the rules here apply to upgrade, they also apply to the other workflow practices). When a deployment of a component is deleted, the instance is considered to be deleted. This does not, however, imply that all data related to the instance must be deleted, or that deletion events cannot be recovered or undone.
When an instance is first created, it is in its initial release state. Each time an upgrade operation occurs, we say that a new release of that instance occurs. (There is, however, no assumption that there is a corresponding release
object stored somewhere).
In 12 factor applications, a release is defined as a build plus a set of configs. That is, any change to either a build or configuration produces a new release. In the Open Application Model, the analog is that component, trait, and scope definitions combined with an application configuration jointly constitute a release.
For OAM applications, release is defined thus:
A release is a named application configuration, together with its description of correlated components, scopes, and traits
In addition, as an application configuration is released, its component instances (running copies of a named component) are also released.
To accommodate this definition of a release, an OAM platform SHOULD make the following assumptions:
- A component schematic (as defined in the component model section) is immutable. It should not be changed after creation.
- Any change to an application configuration results (conceptually) in a new release that supersedes older releases.
- If an application configuration is updated, and the new version includes components not present in the original application configuration, component instances MUST be created
- If an application configuration is updated, and the new version does not have a record of a component that the previous application configuration contained, that component instance MUST be deleted
- Traits similarly SHOULD be attached and detached according to the same guidelines
- Components' relationships to Application Scopes SHOULD be applied or removed according to the same guidelines
The Component Model chapter of the specification defines how schematics are constructed. The resulting schematics may then be used to instantiate a component on a OAM-compliant runtime.
Component schematics can be deployed into numerous different runtimes. But at runtime, there is a one-to-one correspondence between an instance of an configuration and an application configuration.
Conceptually speaking, an application configuration is managed as part of the application operator role. It has three main sections:
- Parameters that can be supplied by an application operator at deployment time.
- A list of application scopes, each of which has overrides for that scope's parameters.
- Component instance definition that defines how an instance of a component spec should be deployed. This section itself has three parts:
- Overrides of component parameters
- A list of traits, each of which has overrides for that trait's parameters.
- A list of application scopes that the component should be deployed into.
The top-level attributes of a application configuration define its metadata, version, kind, and spec.
Attribute | Type | Required | Default Value | Description |
---|---|---|---|---|
apiVersion |
string |
Y | The specific version of the specification in use. At present only core.oam.dev/v1alpha1 is defined. |
|
kind |
string |
Y | The string ApplicationConfiguration |
|
metadata |
Metadata |
Y | Application configuration metadata. | |
spec |
Spec |
Y | A container for exposing application configuration attributes. |
The specification defines three major things: Parameters that can be overridden at deployment time, a set of scopes to create, and component instances to create.
Attribute | Type | Required | Default Value | Description |
---|---|---|---|---|
variables |
[]Variable |
N | Variables that can be referenced in parameter values and properties. | |
scopes |
[]Scope |
N | Application scope definitions. If defined, scopes are accessible by components from any other application configurations. | |
components |
[]Component |
N | Component instance definitions. |
The Variables section defines variables that may be used elsewhere in the application configuration. The variable
section provides a way for an application operator to specify common values that can be substituted into multiple other locations in this configuration (using the [fromVariable(VARNAME)]
syntax).
Attribute | Type | Required | Default Value | Description |
---|---|---|---|---|
name |
string |
Y | The parameter's name. Must be unique per configuration. | |
value |
string |
Y | The scalar value. |
A name
is any Unicode letter or numeric character, _
, -
, and .
. A value
is any sequence of printable Unicode characters.
The function [fromVariable(VARNAME)]
(where VARNAME
corresponds to the name
field in a variable definition) may be used in predefined locations (parameter values and properties objects) to access the value
of a parameter.
The scope section defines application scopes that will be created with this application configuration.
Attribute | Type | Required | Default Value | Description |
---|---|---|---|---|
name |
string |
Y | The name of the application scope. Must be unique to the deployment environment. | |
type |
string |
Y | The fully-qualified GROUP/VERSION.KIND name of the application scope. | |
properties |
Properties |
N | Overrides of properties that are exposed by this scope. |
The name field must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), underscores (_), dots (.), and alphanumerics between.
This section defines the instances of components to create with this application configuration.
Attribute | Type | Required | Default Value | Description |
---|---|---|---|---|
componentName |
string |
Y | The name of the component to create an instance of. | |
instanceName |
string |
Y | The name of the instance of this component. | |
parameterValues |
[]ParameterValue |
N | Overrides of parameters that are exposed by the application scope type defined in type . |
|
traits |
[]Trait |
N | Specifies the traits to attach to this component instance. | |
applicationScopes |
[]string |
N | Specifies the application scopes that the component should be deployed into. Each item is a name referenced to the pre-defined Scopes. |
In addition to being unique, the instanceName
must follow these naming rules:
The componentName field is required and must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), underscores (_), dots (.), and alphanumerics between.
The instanceName segment is required and must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), underscores (_), dots (.), and alphanumerics between.
The trait section defines an instance of a trait and its properties (parameter overrides).
Attribute | Type | Required | Default Value | Description |
---|---|---|---|---|
name |
string |
Y | The name of the Trait. This is used to reference to the definition/schema of the Trait. For one type of trait, there could be only one config/deploy in one component. | |
properties |
Properties |
N | Overrides of properties that are exposed by this trait. |
The name field is required and must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), underscores (_), dots (.), and alphanumerics between.
A properties object (for trait and scope configuration) is an object whose structure is determined by the trait or scope property schema. It may be a simple value, or it may be a complex object.
Properties are validated against the schema appropriate for the trait or scope.
For example, if a trait defines a schema for properties that requires an array of integers with at least one member, the properties
object is expected to be an array of integers with at least one member. During validation of the properties
object, the trait's property schema will be applied.
If no schema is supplied, a property will be passed to the trait runtime without structural validation. As long as it parses as YAML or JSON, it will be considered valid.
Any string value in a properties
object MAY contain a [fromVariable(VARNAME)]
function call.
Values supplied to parameters that are used to override the parameters exposed by other types.
Attribute | Type | Required | Default Value | Description |
---|---|---|---|---|
name |
string |
Y | The name of the component parameter to provide a value for. | |
value |
string |
N | The value of this parameter. |
A name
is any Unicode letter or numeric character, _
, -
, and .
. A value
is any sequence of printable Unicode characters.
The value
field allows use of the [fromVariable(VARNAME)]
function.
The following is an example of a complete YAML file that expresses configuration and traits. This example illustrates the four configurational elements above.
apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: my-app-deployment
annotations:
version: v1.0.0
description: "Description of this deployment"
spec:
variables:
- name: VAR_NAME
value: SUPPLIED_VALUE
scopes:
- name: core.oam.dev/v1alpha1.Network
parameterValues:
- name: PARAM_NAME
value: SUPPLIED_VALUE
components:
- componentName: my-web-app-component
instanceName: my-app-frontent
parameterValues:
- name: PARAMETER_NAME
value: SUPPLIED_VALUE
- name: ANOTHER_PARAMETER
value: "[fromVariable(VAR_NAME)]"
traits:
- name: Ingress
properties:
CUSTOM_OBJECT:
DATA: "[fromVariable(VAR_NAME)]"
The example above illustrates a complete application configuration scopes, component instances, their traits, and parameter overrides that allow users to specify values at deployment time from the command line.
This section is non-normative. OAM compliant tooling need not implement this section.
This section uses a fictional tool called oamctl
to illustrate a workflow pattern for OAM app operations.
The following example shows two separate components:
- a front-end web app in a container, run as a core Server workload type
- a back-end Cassandra database, represented by an extended workload type.
apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
name: frontend
annotations:
version: v1.0.0
description: "A simple webserver"
spec:
workloadType: core.oam.dev/v1.Server
parameters:
- name: message
description: The message to display in the web app.
type: string
value: "Hello from my app, too"
containers:
- name: web
env:
- name: MESSAGE
fromParam: message
image:
name: example/charybdis-single:latest
apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
name: backend
annotations:
version: v1.0.0
description: "Cassandra database"
spec:
workloadType: data.oam.dev/v1.Cassandra
parameters:
- name: maxStalenessPrefix
description: Max stale requests.
type: int
value: 100000
- name: defaultConsistencyLevel
description: The default consistency level
type: string
value: "Eventual"
workloadSettings:
- name: maxStalenessPrefix
fromParam: maxStalenessPrefix
- name: defaultConsistencyLevel
fromParam: defaultConsistencyLevel
Note that each component allows certain parameters to be overridden. For example, the message
parameter is exposed for configuration in the frontend component. Within the component config, the parameter is piped to an environment variable where the component code can read the value.
Components can be designed for reuse by expose such parameters, as these parameters can be tweaked for different deployment scenarios.
An application configuration combines any number of components and sets operational characteristics and configuration for a deployed instance of each component.
apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: custom-single-app
annotations:
version: v1.0.0
description: "Customized version of single-app"
spec:
variables:
- name: message
value: "Well hello there"
components:
- componentName: frontend
instanceName: web-front-end
parameterValues:
- name: message
value: "[fromVariable(message)]"
In this example, the ops config allows a user to override only one of the parameters in the frontend
component, and it does not allow the user to change any of the backend
parameters. This allows the author of this ops config to control configuration options for the components therein.
The operator can now deploy the components together with this configuration to create running instances of the components:
$ oamctl install -c ./config.yaml ./frontend.yaml ./backend.yaml -p "message=overridden message!"
Traits are attached by application operators. In the next part of this example, traits are added to the two components defined previously.
Our system supports a few different traits:
$ oamctl trait-list
╔════════════╤═════════╤═════════════════════════════════════════════╗
║ NAME │ VERSION │ PRIMITIVES ║
╟────────────┼─────────┼─────────────────────────────────────────────╢
║ autoscaler │ 0.1.0 │ Server, Worker ║
╟────────────┼─────────┼─────────────────────────────────────────────╢
║ ingress │ 0.1.0 │ SingletonServer, Server ║
╚════════════╧═════════╧═════════════════════════════════════════════╝
Here is how the previous application configuration looks with an Ingress
trait attached to the front-end component:
apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: custom-single-app
annotations:
version: v1.0.0
description: "Customized version of single-app"
spec:
variables:
- name: message
value: "Well hello there"
- name: domainName
value: "www.example.com"
components:
- componentName: frontend
instanceName: web-front-end
parameterValues:
- name: message
value: "[fromVariable(message)]"
traits:
- name: Ingress
properties:
- name: host
from: domainName
- name: path
value: "/"
This example attaches an ingress
to route traffic from another network (public, perhaps) to the internal service. This configuration shows how the trait is both attached and configured. In this example, a new parameter named domainName
is added to the application configuration, allowing a user to override the host
parameter of the ingress
trait.
An implementation of this would then direct inbound traffic bound for www.example.com
to the front-end
component.
Up to this point, the frontend component is deployed into the default "root" network and health scopes, as all core workload types are required to be in all core application scope types.
The backend component is an extended workload type and is therefore not automatically deployed into the default "root' application scopes.
In this example, a network scope is defined and attached to an SDN. Both components are then added to the same network scope for direct network connectivity and a shared set of network policies that can be defined by the infrastructure operator on the SDN itself. The SDN name is parameterized in the application configuration to allow an application operator to deploy this configuration into any SDN.
apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: my-vpc-network
spec:
variables:
- name: networkName
value: "my-vpc"
scopes:
- name: network
type: core.oam.dev/v1alpha1.Network
properties:
- name: network-id
value: "[fromVariable(networkName)]"
- name: subnet-id
value: "my-subnet"
---
apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: custom-single-app
annotations:
version: v1.0.0
description: "Customized version of single-app"
spec:
variables:
- name: message
value: "Well hello there"
- name: domainName
value: "www.example.com"
components:
- componentName: frontend
instanceName: web-front-end
parameterValues:
- name: message
value: "[fromVariable(message)]"
traits:
- name: Ingress
properties:
- name: host
value: "[fromVaraible(domainName)]"
- name: path
value: "/"
applicationScopes:
- my-vpc-network
- componentName: backend
instanceName: database
applicationScopes:
- my-vpc-network
This example now shows a complete installation of the application configuration composed of two components, an ingress trait, and a network scope with parameters exposed to an application operator to customize the domain name, the network to deploy it to, and a custom message for the web front end to display.
Tables | Next |
---|---|
5. Traits | 7. Workload Types |