Service Type Definitions
This enhancement defines standardized schemas for DCM service types to enable cross-platform portability.
Summary
This ADR defines provider-agnostic schemas for DCM service types. These schemas enable Service Providers to provision six core service types — virtual machines, containers, databases, Kubernetes clusters, standalone storage, and network services — across different infrastructure platforms without vendor lock-in. The key principle is portability first: schemas contain only minimal fields common across all implementations, with platform-specific configuration delegated to provider_hints.
Motivation
Define a generic schema structure that ensures portability across infrastructure platforms while allowing extensibility for platform-specific optimizations without breaking compatibility.
Goals
- Define a generic schema that works for any service_type, ensure portability, and allows extensibility without schema changes.
- Define an initial set of six primary service types applying this pattern:
- VM
Virtual machines with compute, storage, and OS specifications - Container
Containerized workloads running on any container platform - Kubernetes Cluster
Kubernetes Container Platform of any distribution (Kubernetes, OpenShift, EKS, AWS, GKE, etc.) - Database
Database services with various engines (PostgreSQL, MySQL, etc.) - Storage
Standalone persistent volumes decoupled from compute service types - Network
Standalone network interfaces for exposing workloads
- VM
Non-Goals
- Allow runtime editability through API operations so administrators can create and modify templates without code changes
- Tooling to validate Service Provider compliance with catalog schemas (conformance test suites, reference implementations, automated validation frameworks)
- Migration strategies for breaking schema changes
- Provider-specific implementation details (each provider handles translation independently)
- Additional service types beyond VMs, containers, databases, Kubernetes clusters, standalone storage and networking interfaces (deferred to future phases)
- Standalone storage volumes are supported via the storage service type; disk size on VMs and ephemeral allocation on containers remain bundled with compute where applicable.
- Multiple service type schema versions. Initial release supports only the current schema version; service type versioning deferred to future phases.
Proposal
Implementation Details/Notes/Constraints
All schemas use OpenAPI 3.1.0 to leverage JSON Schema features like contains
for array validation.
Generic Service
All service schemas share common fields defined once in common.yaml
Schema Structure
| Field | Required | Type | Description | ReadOnly |
|---|---|---|---|---|
| service_type | Yes | string | Service type identifier (vm, container, database, cluster, storage, network) | No |
| metadata | Yes | Metadata | Service identification and labels | No |
| provider_hints | No | ProviderHints | Platform-specific configuration | No |
| id | No | string | Unique identifier for the resource | Yes |
| status | No | string | Current state of the resource | Yes |
| path | No | string | Resource path or location | Yes |
| status_message | No | string | Message providing details about the current status | Yes |
| create_time | No | date-time | Timestamp when the resource was created | Yes |
| update_time | No | date-time | Timestamp when the resource was last updated | Yes |
Metadata Object
| Field | Required | Type | Description |
|---|---|---|---|
| name | Yes | string | Unique service name identifier |
| labels | No | map[string]string | Key-value pairs for tagging and organization (e.g., environment: production, owner: platform-team) |
ProviderHints Object
| Field | Required | Type | Description |
|---|---|---|---|
| <provider-name> | No | map[string]any | Provider-specific configuration keyed by provider identifier (e.g., kubevirt, vmware, openstack) |
provider_hints is key to portability: providers use hints they recognize and
ignore the rest. This means catalog offering using only common fields (vcpu,
memory, guest_os) can be provisioned by any compatible provider. The
provider_hints section allows adding platform-specific optimizations:
providers use hints they recognize and silently ignore the rest, so the same
catalog item remains portable across platforms.
Specific services
Any service_type can be defined by inheriting from common.yaml and adding type-specific fields. For the first milestone, DCM will support the following service_types:
- Virtual Machine
Virtual machines with CPU, memory, storage, and OS specifications - Container
Fields common to Kubernetes, Docker, Podman, Openshift, CRI-O, containerd - Cluster
Fields common to Kubernetes, OpenShift, EKS, GKE, AKS, and other distributions - Database
Fields common across all database types (SQL, NoSQL, search, time-series, etc.) - Storage
Standalone persistent volumes (capacity, access mode) independent of compute - Network
Standalone network interfaces for exposing workloads
Virtual Machine
The following sections detail the VM schema architecture.
flowchart TD
SC[(Service Catalog)]
API[Service Provider API]
subgraph SP [Service Provider]
direction LR
KV[KubeVirt]
VW[VMware]
OS[OpenStack]
AWS[AWS EC2]
end
Note_Reg
Note_Trans@{ shape: card, label: "Each provider translates
the catalog item to its
native resource format" }
SC --> API
API --> SP
Note_Reg -.- SP
Note_Trans -.-> KV
Note_Trans -.-> VW
Note_Trans -.-> OS
Note_Trans -.-> AWS
Schema
For easier review, the schema is accessible here
vmspec.yaml.
Plus
common fields: service_type, metadata, provider_hints
| Field | Required | Type | Description |
|---|---|---|---|
| vcpu | Yes | Vcpu | Virtual CPU configuration |
| memory | Yes | Memory | Memory configuration |
| storage | Yes | Storage | Storage configuration |
| guest_os | Yes | GuestOS | Operating system specification |
| access | No | Access | VM access configuration |
VM vcpu Object
| Field | Required | Type | Description |
|---|---|---|---|
| count | Yes | integer | Number of virtual CPUs |
VM memory Object
| Field | Required | Type | Description |
|---|---|---|---|
| size | Yes | string | Memory size with unit (e.g., 8GB, 16GB) |
VM storage Object
| Field | Required | Type | Description |
|---|---|---|---|
| disks | Yes | array[Disk] | List of disks; must include one named boot |
Disk names must be unique within the VM.
VM disk Object
| Field | Required | Type | Description |
|---|---|---|---|
| name | Yes | string | Disk identifier; root volume must be named boot |
| capacity | Yes | string | Disk capacity with unit (e.g., 100GB, 2TB) |
VM guest_os Object
| Field | Required | Type | Description |
|---|---|---|---|
| type | Yes | string | OS identifier (e.g., rhel-9, ubuntu-22.04, windows-server-2022) |
VM access Object
| Field | Required | Type | Description |
|---|---|---|---|
| ssh_public_key | No | string | SSH public key for VM access |
Containers
The following sections detail the Container schema architecture.
Schema
For easier review, the schema is accessible here
containerspec.yaml.
Plus
common fields: service_type, metadata, provider_hints
| Field | Required | Type | Description |
|---|---|---|---|
| image | Yes | Image | Container image specification |
| resources | Yes | Resources | CPU and memory limits |
| process | No | Process | Process configuration |
| network | No | Network | Network configuration |
Container image Object
| Field | Required | Type | Description |
|---|---|---|---|
| reference | Yes | string | Container image reference (e.g., quay.io/myapp:v1.2, docker.io/nginx:latest) |
Container resources Object
| Field | Required | Type | Description |
|---|---|---|---|
| cpu | Yes | Cpu | CPU resource constraints |
| memory | Yes | Memory | Memory resource constraints |
Container resources.cpu Object
| Field | Required | Type | Description |
|---|---|---|---|
| min | Yes | integer | Minimum guaranteed CPU cores |
| max | Yes | integer | Maximum allowed CPU cores |
Container resources.memory Object
| Field | Required | Type | Description |
|---|---|---|---|
| min | Yes | string | Minimum guaranteed memory with unit (e.g., 1GB, 2GB) |
| max | Yes | string | Maximum allowed memory with unit (e.g., 2GB, 4GB) |
Container process Object
| Field | Required | Type | Description |
|---|---|---|---|
| command | No | array[string] | Entrypoint override |
| args | No | array[string] | Arguments to the entrypoint |
| env | No | array[EnvVar] | Environment variables |
Container env Object
| Field | Required | Type | Description |
|---|---|---|---|
| name | Yes | string | Environment variable name |
| value | Yes | string | Environment variable value |
Container network Object
| Field | Required | Type | Description |
|---|---|---|---|
| ports | Yes | array[Port] | Ports to expose |
Container port Object
| Field | Required | Type | Description |
|---|---|---|---|
| container_port | Yes | integer | Port number to expose (e.g., 8080, 443) |
| visibility | Yes | string | Port visibility: none, internal, or external |
The visibility field controls how the port is exposed by the Service Provider:
none— the port is not exposed via any networking abstraction (no Service created for this port)internal— the port is exposed within the cluster (e.g., ClusterIP Service in Kubernetes)external— the port is exposed externally (e.g., LoadBalancer or NodePort Service in Kubernetes)
Database
The following sections detail the Database schema architecture.
Schema
For easier review, the schema is accessible here
databasespec.yaml.
Plus
common fields: service_type, metadata, provider_hints
| Field | Required | Type | Description |
|---|---|---|---|
| engine | Yes | string | Database engine type (e.g., postgresql, mysql, mariadb) |
| version | Yes | string | Engine version (e.g., 15, 8.11, 8.0) |
| resources | Yes | Resources | Compute and storage resources |
| replicas | No | integer | Number of replicas to create (default 1) |
| network | No | Network | Network configuration |
Database resources Object
| Field | Required | Type | Description |
|---|---|---|---|
| cpu | Yes | Cpu | CPU resource constraints |
| memory | Yes | Memory | Memory resource constrains |
| storage | Yes | string | Storage size with unit (e.g., 100GB, 2TB) |
Note: The resources are per replica, not per database instance
Database resources.cpu Object
| Field | Required | Type | Description |
|---|---|---|---|
| min | Yes | string | Minimum guaranteed CPU cores with or without unit (e.g. 500m, 1) |
| max | Yes | string | Maximum allowed CPU cores with or without unit (e.g. 500m, 1) |
Database resources.memory Object
| Field | Required | Type | Description |
|---|---|---|---|
| min | Yes | string | Minimum guaranteed memory with unit (e.g., 1GB, 2GB) |
| max | Yes | string | Maximum allowed memory with unit (e.g, 2GB, 4GB) |
Database network Object
| Field | Required | Type | Description |
|---|---|---|---|
| port | No | integer | Port for the database to listen on |
| visibility | No | string | Database visibility: internal, external |
The visibility field controls how the database’s port is exposed by the
Service Provider:
internal- the port is exposed within the Service Provider’s platform (For Kubernetes, creates only aServiceresource ofClusterIPtype)external- the port is exposed externally (For Kubernetes, creates aServiceresource ofLoadBalancerorNodePorttype)
Kubernetes Cluster
The cluster schema works across all Kubernetes distributions: OpenShift, EKS, GKE, AKS, etc.
Schema
For easier review, the schema is available here:
clusterspec.yaml.
Plus
common fields: service_type, metadata, provider_hints
| Field | Required | Type | Description |
|---|---|---|---|
| version | Yes | string | Kubernetes version (e.g., 1.29, 1.30) |
| nodes | Yes | Nodes | Node pool configuration |
Cluster nodes Object
| Field | Required | Type | Description |
|---|---|---|---|
| control_plane | Yes | ControlPlane | Control plane node configuration |
| worker | Yes | Worker | Worker node configuration |
Cluster control_plane Object
| Field | Required | Type | Description |
|---|---|---|---|
| count | Yes | integer | Number of control plane nodes (1, 3, or 5) |
| cpu | Yes | integer | Number of CPUs per node |
| memory | Yes | string | Memory per node with unit (e.g., 16GB, 32GB) |
| storage | Yes | string | Storage per node with unit (e.g., 120GB, 500GB) |
Cluster worker Object
| Field | Required | Type | Description |
|---|---|---|---|
| count | Yes | integer | Number of worker nodes |
| cpu | Yes | integer | Number of CPUs per node |
| memory | Yes | string | Memory per node with unit (e.g., 8GB, 16GB) |
| storage | Yes | string | Storage per node with unit (e.g., 120GB, 500GB) |
Storage
The following sections detail the Storage schema architecture for standalone persistent volumes. See k8s-storage-sp for the Kubernetes reference Service Provider implementation.
Schema
Plus common fields: service_type, metadata, provider_hints
| Field | Required | Type | Description |
|---|---|---|---|
| capacity | Yes | string | Volume size with unit (e.g., 100Gi, 1TB) |
Storage provider_hints (kubernetes)
Platform-specific PVC settings may be supplied under
provider_hints.kubernetes:
| Field | Required | Type | Description |
|---|---|---|---|
| storage_class | No | string | Kubernetes StorageClass name |
| volume_mode | No | string | Filesystem (default) or Block |
| access_mode | No | string | PVC access mode: ReadWriteOnce (default), ReadOnlyMany, ReadWriteMany |
When access_mode is omitted, the Service Provider applies a platform default
(typically ReadWriteOnce for block storage).
Note: access_mode is Kubernetes-specific because it controls both
attachment scope (single node vs. multiple nodes vs. single pod) and permissions
(read-write vs. read-only) at PVC creation time. Other storage platforms handle
attachment and permissions differently (e.g., AWS EBS sets multi-attach
capability via volume type; GCP Persistent Disk sets mode at attach time). The
CatalogItem admin configures this field based on the backend capabilities (e.g.,
Ceph RBD only supports ReadWriteOnce; CephFS only supports ReadWriteMany).
Network
The network schema defines load balancing and service discovery resources for providing network access to workloads. Unlike managing networking as part of compute resources, this service type treats network services as first-class resources.
When to Use Standalone Network
The network service type creates network resources independently from
workloads.
Use standalone network when:
- Exposing existing workloads that were created without network configuration
- Managing network lifecycle independently from workload lifecycle
- Creating endpoints for manually-managed pods or external resources
Use visibility field when:
- Creating a new workload that needs immediate network exposure
- Network resource should be tied to workload lifecycle (created/deleted together)
| Field | Required | Type | Description |
|---|---|---|---|
| ports | Yes | array[Port] | Ports to expose |
| routingLevel | No | string | Whether traffic is handled at the transport level (TCP/UDP) or application level (HTTP/HTTPS) |
Network port Object
| Field | Required | Type | Description |
|---|---|---|---|
| name | No* | string | Port name. *Required when using providerHints.kubernetes.nodePorts. Must be DNS-compatible (RFC 1035). Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ |
| protocol | No | string | Protocol (TCP, UDP, SCTP). Default: TCP |
| port | Yes | integer | Service port (1-65535) |
| targetPort | Yes | integer | Target pod port (1-65535) |
Note: When using
providerHints.kubernetes.nodePorts, all ports must have uniquenamefields. The keys innodePortsmust match these port names.
routingLevel
Specifies whether traffic is handled at the transport level (TCP/UDP) or the application level (HTTP/HTTPS). When omitted, creates a basic service without external routing infrastructure.
- Default: omitted (no external routing)
- Values:
network: Transport-level traffic handling (TCP/UDP)application: Application-level traffic handling (HTTP/HTTPS) with routing capabilities- omitted: Basic service without external routing
Kubernetes Provider Hints
The Kubernetes Network Service Provider uses the following fields in
providerHints.kubernetes:
| Field | Required | Type | Description |
|---|---|---|---|
| selector | No | map[string]string | Label selector to match target pods |
| clusterIP | No | string | Specific cluster IP allocation or “None” for headless |
| nodePorts | No | map[string]int | Map of port names to NodePort values (30000-32767). The Kubernetes Service type is inferred from the combination of routingLevel and nodePorts presence. See Service Type Inference. |
Schema Compatibility
DCM supports only the current API version for each service type. Service Providers must implement the latest schema definitions. Support for multiple service type versions is planned for future releases.
Implementation History
Drawbacks
Alternatives
Comprehensive schemas with all platform features
Description: We considered including all possible fields (CPU topology, security contexts, HA configuration, etc.) in the core schema.
Why rejected: Not all fields exist on all platforms. This would force providers to handle features they don’t support, or force users to understand which fields work where. Portability would be compromised.
Virtual Machine Alternatives
Pure OVF XML Format
Description: We considered using OVF XML directly as our catalog format. This would provide perfect alignment with the standard but creates practical problems. OVF XML is verbose with complex nested structures, XML namespaces, and numeric resource type codes (3 for CPU, 4 for memory).
Pros: Perfect standard compliance, well-understood by virtualization teams
Cons: XML complexity, poor API ergonomics, includes packaging concepts irrelevant to catalog specs
TOSCA Cloud Orchestration
Description: TOSCA (Topology and Orchestration Specification for Cloud Applications) is an OASIS standard designed specifically for cloud resource orchestration. It provides a comprehensive model with node templates, capabilities, requirements, and relationship definitions. While powerful, TOSCA introduces significant complexity with its topology-based approach. For a catalog specification that describes individual resource templates, TOSCA’s relationship modeling and orchestration features are overkill.
Pros: Purpose-built for cloud, handles complex deployments
Cons: Steep learning curve, heavyweight for simple resource specs, less tooling ecosystem
Custom Schema from Scratch
Description: We could design a completely custom schema without reference to existing standards, optimizing purely for our immediate needs. This provides maximum flexibility and simplicity initially but loses the benefit of industry knowledge embedded in standards like OVF. Provider translation becomes harder because engineers must learn our invented vocabulary rather than mapping to familiar concepts they already know from OVF, OpenStack, or other systems.
Pros: Perfect fit for current needs, no standard overhead
Cons: Reinventing solved problems, harder provider adoption, no external validation
OpenStack-Style Flavors
Description: OpenStack’s approach separates compute templates (flavors) from images. Users select a flavor (m1.small, m1.medium) and an image separately. While simple, this creates a two-level hierarchy that feels unnatural for a general catalog system. It also doesn’t handle the full richness of VM configuration, storage configuration, and network interfaces. Initialization is handled separately rather than as part of a cohesive specification.
Pros: Simple flavor model, proven in OpenStack
Cons: Limited to compute specs, doesn’t handle full VM configuration, creates artificial separation
Container Alternatives
Kubernetes Pod Specification
Description: Using Kubernetes Pod/Deployment YAML directly as the catalog format would provide immediate familiarity for Kubernetes users but creates vendor lock-in.
Pros: Familiar to Kubernetes users, rich feature set, comprehensive documentation, established ecosystem
Cons: Kubernetes-specific (incompatible with Docker/Podman standalone), includes orchestration concepts unnecessary for resource specifications, ties catalog to Kubernetes API versions, prevents portability to non-Kubernetes platforms
Compose Specification
Description: The Compose Specification provides a YAML format for defining multi-container applications, now an open specification supported by Docker, Podman, and other runtimes.
Pros: Simple and approachable, widely known format, open specification, good for multi-container applications
Cons: Designed for application composition not individual resource specifications, doesn’t map cleanly to single-container catalog items, less granular than OCI for runtime configuration, focuses on orchestration rather than resource provisioning
Containerfile Build Instructions
Description: Define containers through Dockerfile/Containerfile rather than runtime specifications.
Pros: Reproducible builds, version control friendly, defines complete container image
Cons: Build-time specification not runtime specification, requires build infrastructure in catalog system, doesn’t address runtime configuration (resources, networking, security), mixes build concerns with deployment concerns
Custom Schema
Description: Design a container schema without reference to existing standards like OCI, optimizing purely for DCM’s immediate needs.
Pros: Optimized for DCM requirements, simpler for current use cases, no standard overhead
Cons: Reinventing problems OCI already solved, harder provider adoption (engineers learn new vocabulary instead of familiar OCI concepts), no external validation, loses portability benefits, incompatible with existing container tooling
Database Alternatives
Single Cloud Provider Model
Description: Using AWS RDS, Azure Database, or Google Cloud SQL specification directly as the catalog format.
Pros: Complete feature coverage, well-documented, proven in production
Cons: Vendor lock-in, cloud-specific terminology and features, doesn’t work with on-premise or Kubernetes-based databases, prevents multi-cloud portability
Kubernetes Operator CRD
Description: Using a specific Kubernetes database operator CRD (CloudNativePG, Percona) as the standard.
Pros: Kubernetes-native, rich feature set, battle-tested
Cons: Kubernetes-specific, incompatible with cloud DBaaS providers, ties catalog to specific operator versions, doesn’t support VM-based database deployments
SQL Standard Only
Description: Focus purely on SQL standards (ANSI SQL, SQL:2016) for database specifications.
Pros: Well-established standard, vendor-neutral
Cons: Only covers query language not provisioning/infrastructure, no coverage for NoSQL databases, doesn’t address compute/storage/backup configuration, mixes application concerns with infrastructure.
Custom Schema
Description: Design database schema without reference to existing patterns.
Pros: Optimized for DCM needs, simpler initially
Cons: Reinventing patterns cloud providers and operators already solved, harder adoption, no external validation, incompatible with existing tooling and knowledge
Kubernetes Cluster Alternatives
Full install-config.yaml
Description: Using OpenShift’s complete install-config.yaml format as the catalog schema.
Pros: Comprehensive coverage of all OpenShift deployment options, official Red Hat format, well-documented
Cons: Platform-specific sections create complexity, includes infrastructure credentials and bootstrapping details inappropriate for catalog specifications, ties catalog to OpenShift installer API versions, verbose for users who just want node sizing
Cluster API (CAPI) Specification
Description: Adopting Kubernetes Cluster API CRDs as the standard for all cluster provisioning.
Pros: Kubernetes community standard, cloud-agnostic, supports multiple platforms
Cons: Still maturing as a standard, OpenShift has its own established patterns, CAPI abstractions don’t always align with OpenShift’s architecture, requires CAPI operator infrastructure
Managed OpenShift Service APIs
Description: Using cloud provider managed OpenShift APIs (ROSA for AWS, ARO for Azure) as the specification format.
Pros: Native to cloud providers, optimized for managed OpenShift services
Cons: Cloud-specific, incompatible with on-premise and self-managed OpenShift deployments, each provider has different API structure, doesn’t work with standard OpenShift IPI/UPI installations, prevents portability to vSphere or bare metal
Custom Cluster Schema
Description: Design a cluster schema without reference to existing standards or patterns.
Pros: Optimized for DCM requirements, simpler for current use cases
Cons: Ignores established OpenShift configuration patterns, harder for users familiar with install-config.yaml, no validation against industry knowledge, incompatible with existing automation and tooling
Infrastructure Needed
TBD