Skip to main content
The cpln convert command transforms Kubernetes manifests into Control Plane resources, enabling seamless migration from Kubernetes environments.

When to use this

Kubernetes migration

Migrate existing K8s workloads, secrets, and storage to Control Plane

Reuse existing manifests

Leverage your existing Kubernetes YAML files without rewriting them

Preview conversions

See how K8s resources translate to Control Plane before applying

CI/CD integration

Convert and apply K8s manifests in automated pipelines

Supported resources

Workload conversions

Kubernetes KindControl Plane KindNotes
DeploymentWorkloadType determined by spec analysis
ReplicaSetWorkloadType determined by spec analysis
ReplicationControllerWorkloadLegacy K8s resource
StatefulSetWorkloadType determined by spec analysis
DaemonSetWorkloadType determined by spec analysis
JobWorkload (cron)Converted to cron with default schedule
CronJobWorkload (cron)Schedule preserved from spec

How workload type is determined

The converter analyzes your Kubernetes spec to automatically select the appropriate Control Plane workload type:
Job and CronJob resources always become cron workloads.
  • CronJobs preserve their schedule from spec.schedule
  • Jobs use a default schedule of * * * * * (every minute)
The workload becomes stateful if any container mounts a volumeset (from PersistentVolumeClaim or volumeClaimTemplates).Stateful takes precedence over standard when both conditions are met.
The workload becomes standard if any of these conditions are true:
  • A container has no ports or more than one port
  • A container uses gRPC health probes (liveness or readiness)
  • The workload has rollout options (from K8s strategy, updateStrategy, minReadySeconds, or podManagementPolicy)
If none of the above conditions apply, the workload becomes serverless. This is the default for simple deployments with a single HTTP port.

Secret and config conversions

Kubernetes KindControl Plane KindNotes
SecretSecretDirect conversion
ConfigMapSecret (dictionary)Stored as dictionary secret

Storage conversions

Kubernetes KindControl Plane KindNotes
PersistentVolumeClaimVolumesetPersistent storage

How secrets are converted

Kubernetes Secrets are converted based on their type field:
K8s Secret TypeControl Plane Secret Type
kubernetes.io/dockerconfigjsondocker
kubernetes.io/basic-authuserpass
kubernetes.io/tlstls
With payload keyopaque
Defaultdictionary
ConfigMaps are always converted to dictionary secrets, with all key-value pairs preserved.

How volumesets are configured

PersistentVolumeClaims are converted to volumesets with these settings:
PropertySource (in priority order)Default
CapacityPersistentVolume spec.capacity.storage → PVC spec.resources.requests.storage10 GB
Performance classStorageClass parameters (see below)general-purpose-ssd
File system typePV volume source fsType → StorageClass parameters.fsTypeext4
High-performance SSD detection: If the StorageClass parameters contain any of these values, the volumeset uses high-throughput-ssd:
  • AWS: io1, io2
  • GCP: pd-extreme
  • Azure: UltraSSD_LRS
  • VMware: thick
  • Other: fast, persistent_1

Auto-generated resources

When workloads reference secrets (via environment variables or volume mounts), the converter automatically creates:
  1. Identity - Named identity-{workload-name}, linked to the workload
  2. Policy - Named policy-{workload-name}, granting reveal permission on referenced secrets
This ensures workloads can access their secrets without manual policy configuration.

Firewall and public exposure

The converter analyzes your Kubernetes Services and Ingresses to determine if a workload should be publicly accessible:
Kubernetes ConfigurationControl Plane Firewall
Service type LoadBalancer matching pod labelsExternal inbound allowed (0.0.0.0/0)
Ingress routing to a Service matching pod labelsExternal inbound allowed (0.0.0.0/0)
No public exposure detectedExternal inbound blocked (default)
All workloads have external outbound traffic allowed by default (0.0.0.0/0).

Informational resources

These Kubernetes resources are not directly converted but inform the conversion:
ResourceHow it’s used
HorizontalPodAutoscalerSets minScale, maxScale, scaleToZeroDelay, and CPU target
ServiceProtocol inference, public exposure detection
IngressPublic exposure detection
ServiceAccountImage pull secrets extraction
EndpointSliceService-to-Pod mapping for selectorless services
PersistentVolumeCapacity and file system type for volumesets
StorageClassPerformance class and file system type for volumesets

Basic usage

cpln convert --file <k8s-file>
This outputs the converted Control Plane resources to stdout.

Options

OptionDescription
--filePath to K8s JSON/YAML file. Use --file - for stdin
--protocolOverride port protocol for all containers: http, http2, grpc, tcp
--verboseShow original K8s resources with ignored properties highlighted

How port protocol is inferred

When you don’t specify --protocol, the converter automatically infers the protocol for each container port using a multi-level strategy (in priority order):
1

Service appProtocol (highest priority)

If a Kubernetes Service explicitly declares appProtocol on a port that targets this container, that protocol is used.
spec:
  ports:
    - port: 50051
      targetPort: 50051
      appProtocol: grpc  # Explicitly declares gRPC
2

Service port name prefix

The converter checks if any Service port targeting this container has a name with a protocol prefix.
spec:
  ports:
    - name: grpc-api  # "grpc" prefix → gRPC protocol
      port: 50051
3

Container port name prefix

The container’s own port name is checked for protocol prefixes.
ports:
  - name: http-web  # "http" prefix → HTTP protocol
    containerPort: 8080
4

Health probe type

If the port has a liveness or readiness probe, the probe type determines the protocol:
  • grpc probe → gRPC
  • httpGet probe → HTTP
  • tcpSocket probe → TCP
5

Well-known port number (lowest priority)

Common port numbers are mapped to their typical protocols. See the tables below.

Recognized protocol prefixes

Port names starting with these prefixes are automatically mapped:
PrefixProtocol
http, https, ws, wssHTTP
http2, h2, h2cHTTP/2
grpc, grpc-web, grpcwebgRPC

Well-known port mappings

These port numbers are automatically assigned protocols when no other signal is available:
PortProtocol
80, 81, 443HTTP
3000, 3001, 3002HTTP
8000, 8008, 8080, 8081, 8088HTTP
8443, 9090HTTP
If no protocol can be inferred, the converter defaults to tcp.

Example conversion

1

Create a Kubernetes manifest

Create a file named k8s.yaml:
k8s.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
2

Convert the manifest

cpln convert --file k8s.yaml
kind: workload
name: example-deployment
spec:
  type: serverless
  containers:
    - name: nginx
      image: 'nginx:latest'
      ports:
        - number: 80
          protocol: http
  defaultOptions:
    capacityAI: false
    autoscaling:
      minScale: 3
      maxScale: 3
3

Apply the converted resources

Convert and apply in one command:
cpln apply --file k8s.yaml --k8s true
Or pipe the conversion output:
cpln convert --file k8s.yaml | cpln apply --file -

More conversion examples

A simple Deployment with one HTTP port becomes serverless:
k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api
  template:
    spec:
      containers:
        - name: api
          image: my-api:v1
          ports:
            - containerPort: 8080
Converts to a serverless workload (single port, no volumes, no gRPC probes).

Override protocol inference

To bypass automatic protocol inference and set a specific protocol for all ports, use the --protocol flag:
# Force all ports to use gRPC
cpln convert --file k8s.yaml --protocol grpc

# Force all ports to use TCP
cpln convert --file k8s.yaml --protocol tcp

Verbose mode

Use --verbose to see which K8s properties were converted and which were ignored:
cpln convert --file k8s.yaml --verbose
Ignored properties are highlighted in yellow and marked with (ignored).

Delete converted resources

To remove resources that were applied from a K8s manifest:
cpln delete --file k8s.yaml --k8s true

Troubleshooting

Some Kubernetes resources don’t have direct Control Plane equivalents. Use --verbose to see which properties are ignored during conversion.
ConfigMaps are converted to dictionary secrets. Reference them in your workload using environment variables or volume mounts pointing to the secret.
HorizontalPodAutoscaler settings inform the workload’s autoscaling configuration. Check the converted workload’s defaultOptions.autoscaling section.
Services are used to inform port mappings but don’t create standalone resources. Ports are configured directly on the workload’s container spec.
PersistentVolumeClaims are converted to volumesets. Ensure the PVC is referenced by a StatefulSet’s volumeClaimTemplates for proper conversion.

Next steps