Software Composition
Applications can be found in completely different stages:
- "Application Packaging": application has been prepared and made ready for deployment.
- "Application Deployment" (AKA Runtime): application has been made available and accessible on the device.
Distinguishing which stage terminology refers to is important to understand the scope of following definitions.
ℹ️ Note: Logically there is another intermediate stage: "Application Staging". This is the stage in which the application is set up, configured, and made available for use to the device, but has not yet been deployed (started) to be used. As of now this stage is out of scope in the Margo specification and not being considered, because some of the providers (like the Helm one) do not provide any mechanisms to manage it.
Terminology Scoping
This section does not declare terminology, that is the task of the Technical Lexicon, but rather tries to scope some of the terms to the above mentioned stages.
Application
The term application applies to all stages.
Workload
The term Workload applies only to running software.
Workloads are the result of deploying Components.
Component
The term Component applies to the resources available in packaged software that get deployed as Workloads.
Some providers might support that multiple Workload replicas are deployed from a single Component.
Components are made available over Component Registrys.
Components might have different shapes depending on their type and on which stage is being considered:
- Helm v3 as Component: a Helm Chart
- Helm v3 as Workload: all container images required by the to-be-started pods.
- Compose as Component: a Compose Archive
- Compose as Workload: a so-called Compose file and all the container images required by the to-be-started services.
Stages
1. Software Packaging
C4Context
title Software Packaging stage
Enterprise_Boundary(be, "Backend") {
System(app, "ApplicationDescription", "Application Package")
}
UpdateElementStyle(app, $fontColor="white", $bgColor="blue", $borderColor="grey")
Software at rest is made available as an Application Package, which is a folder with a Margo-defined structure comprising the software application. This Application Package contains:
- An Application Description that is a Margo-specific way to define the composition of one or more Components. These Components are linked in the Application Description document, are deployable as workloads, and are provided in a Margo-supported way, e.g. as Helm Charts or Compose Archives.
- Some application resources: icon, license(s), release notes,...
Application Packages and Components are managed and hosted separately:
- Application Registries store Application Descriptions and their associated application resources. An Application Registry is implemented as a git repository.
- Component Registries store Components
The following diagram shows, at hand of an example, the relationship between an Application Package and the Components listed within its Deployment Profiles:
C4Component
title Application Bundling: Example 1 - Helm and Compose deployment profiles provided
System_Boundary(ar, "Application Registry (Git)") {
System_Boundary(ab1, "Application Package 1") {
Component(atb1, "Application Package", "Reference")
System_Boundary(c99, "Resources") {
Component(rd, "Resources", "Directory")
Component(ic, "Icon", "File(s)")
Component(lc, "License", "File(s)")
Component(rn, "Release Notes", "File(s)")
Rel(rd, ic, "contains")
Rel(rd, lc, "contains")
Rel(rd, rn, "contains")
}
System_Boundary(c1, "Application Description") {
Component(ad, "Application Description", "ApplicationDescription", "YAML document")
System_Boundary(c2, "deploymentProfiles") {
System_Boundary(c3, "helm.v3") {
Component(wldh1, "Helm WorkloadArtifact 1", "Section in YAML document")
}
System_Boundary(c4, "compose") {
Component(wldc1, "Compose WorkloadArtifact 1", "Section in YAML document")
}
}
Rel(ad,wldh1, "defines")
Rel(ad,wldc1, "defines")
}
Rel(atb1, ad, "requires")
Rel(atb1, rd, "requires")
}
}
System_Boundary(crr, "Component Registry") {
Component(hc1, "Helm Chart 1", "Component")
Component(cc1, "Compose Archive 1", "Component")
}
Rel(wldh1, hc1, "refers")
Rel(wldc1, cc1, "refers")
UpdateElementStyle(ad, $fontColor="white", $bgColor="blue", $borderColor="grey")
UpdateElementStyle(hc1, $fontColor="black", $bgColor="khaki", $borderColor="grey")
UpdateElementStyle(cc1, $fontColor="black", $bgColor="lightsalmon", $borderColor="grey")
The following diagram is similar to the previous one, but showing more details on the Component Registry for a Compose Deployment Profile:
C4Component
title Application Bundling: Example 2 - focus on Component Registry
UpdateLayoutConfig($c4BoundaryInRow="1", $c4ShapeInRow="3")
System_Boundary(ar, "Application Registry (Git)") {
System_Boundary(ab1, "Application Package 1") {
Component(atb1, "Application Package")
System_Boundary(c1, "Application Description") {
Component(ad, "Application Description", "YAML document")
System_Boundary(c2, "deploymentProfiles") {
System_Boundary(c4, "compose") {
Component(wldc1, "Compose WorkloadArtifact 1")
}
}
Rel(ad,wldc1, "defines")
}
Component(rd, "Resources", "Directory")
Rel(atb1, ad, "requires")
Rel(atb1, rd, "requires")
}
}
System_Boundary(crr, "Component Registry") {
Component(cc1, "Compose File 1", "Compose")
Component(ca1, "Compose Archive 1", "Component")
Rel(ca1, cc1, "contains")
UpdateRelStyle(cc1, cim1, $offsetY="50")
}
System_Boundary(cir, "Container Image Registry") {
Component(cim1, "Container Image 1", "Archive")
}
Rel(wldc1, ca1, "refers")
Rel(cc1, cim1, "refers")
UpdateElementStyle(ad, $fontColor="white", $bgColor="blue", $borderColor="grey")
UpdateElementStyle(ca1, $fontColor="black", $bgColor="lightsalmon", $borderColor="grey")
The application and contained components are typically configurable with the option of providing default values.
2. Software Deployment
When a device gets the instruction to run an Application (over a desired-state specified with an ApplicationDeployment
object), its Workload Fleet Management Agent interacts with the providers.
That way all Workloads needed for an Application should get started and the desired state should be reached.
C4Context
title Software Deployment stage
UpdateLayoutConfig($c4BoundaryInRow="1", $c4ShapeInRow="2")
Enterprise_Boundary(be, "Backend") {
System(apdb, "ApplicationDeployment", "Application Deployment specification")
System(appb, "ApplicationDescription", "Application Package")
System(cmp, "Component")
Rel(appb, apdb, "instantiation")
Rel(appb, cmp, "requires")
}
Enterprise_Boundary(dev, "Device") {
System(apdd, "ApplicationDeployment", "Application Deployment specification")
System(wls, "Workload")
Rel(apdd, wls, "configures")
}
BiRel(apdb, apdd, "same")
Rel(cmp, wls, "instantiation")
UpdateElementStyle(appb, $fontColor="black", $bgColor="blue", $borderColor="grey")
UpdateElementStyle(appd, $fontColor="black", $bgColor="blue", $borderColor="grey")
UpdateElementStyle(apdb, $fontColor="black", $bgColor="green", $borderColor="grey")
UpdateElementStyle(apdd, $fontColor="black", $bgColor="green", $borderColor="grey")
In this stage the providers are responsible for managing the individual Workloads.
On a Helm v3 Deployment Profiles, a Workload Fleet Management Agent implementation could utilize the Helm API to start the individual Helm Charts.
On a Compose Deployment Profiles, a Workload Fleet Management Agent implementation could utilize the Compose CLI to start the individual Workloads.
The following diagram shows the result of reaching the desired state for an Application with a Helm v3 Deployment Profile (the result of helm install
).
C4Component
title Application Deployment: Helm v3 deployment profile
UpdateLayoutConfig($c4BoundaryInRow="3", $c4ShapeInRow="1")
System_Boundary(dev1, "Device 1") {
System_Boundary(woa1, "Workload Fleet Management Agent") {
Component(atb1, "Application Deployment 1", "ApplicationDeployment", "YAML document")
}
System_Boundary(hel1, "Helm") {
Component(hc1, "Helm Chart 1")
Component(hc2, "Helm Chart 2")
}
System_Boundary(kbl1, "Kubelet") {
Component(pod1, "Pod 1")
Component(pod2, "Pod 2")
Component(pod3, "Pod 3")
}
}
Rel(atb1, hc1, "refers")
Rel(hc1, pod1, "refers")
Rel(atb1, hc2, "refers")
Rel(hc2, pod2, "refers")
Rel(hc2, pod3, "refers")
Rel(hc2, pod3, "refers")
UpdateElementStyle(atb1, $fontColor="white", $bgColor="blue", $borderColor="grey")
The following diagram shows the result of reaching the desired state for an Application with a Compose Deployment Profile (the result of the compose up
CLI call).
C4Component
title Application Deployment: Compose deployment profile
UpdateLayoutConfig($c4BoundaryInRow="3", $c4ShapeInRow="1")
System_Boundary(dev1, "Device 1") {
System_Boundary(woa1, "Workload Fleet Management Agent") {
Component(atb1, "Application Deployment 1", "ApplicationDeployment", "YAML document")
}
System_Boundary(fs1, "File System") {
Component(cc1, "Compose File 1")
Component(cc2, "Compose File 2")
System_Boundary(doc1, "Container Engine") {
Component(srv1, "Service 1")
Component(srv2, "Service 2")
Component(srv3, "Service 3")
}
}
}
Rel(atb1, cc1, "refers")
Rel(atb1, cc2, "refers")
Rel(cc1, srv1, "refers")
Rel(cc2, srv2, "refers")
Rel(cc2, srv3, "refers")
UpdateElementStyle(atb1, $fontColor="white", $bgColor="blue", $borderColor="grey")