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 Kind | Control Plane Kind | Notes |
|---|---|---|
| Deployment | Workload | Type determined by spec analysis |
| ReplicaSet | Workload | Type determined by spec analysis |
| ReplicationController | Workload | Legacy K8s resource |
| StatefulSet | Workload | Type determined by spec analysis |
| DaemonSet | Workload | Type determined by spec analysis |
| Job | Workload (cron) | Converted to cron with default schedule |
| CronJob | Workload (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:Cron
Cron
Job and CronJob resources always become
cron workloads.- CronJobs preserve their schedule from
spec.schedule - Jobs use a default schedule of
* * * * *(every minute)
Stateful (highest priority)
Stateful (highest priority)
The workload becomes
stateful if any container mounts a volumeset (from PersistentVolumeClaim or volumeClaimTemplates).Stateful takes precedence over standard when both conditions are met.Standard
Standard
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, orpodManagementPolicy)
Serverless (default)
Serverless (default)
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 Kind | Control Plane Kind | Notes |
|---|---|---|
| Secret | Secret | Direct conversion |
| ConfigMap | Secret (dictionary) | Stored as dictionary secret |
Storage conversions
| Kubernetes Kind | Control Plane Kind | Notes |
|---|---|---|
| PersistentVolumeClaim | Volumeset | Persistent storage |
How secrets are converted
Kubernetes Secrets are converted based on theirtype field:
| K8s Secret Type | Control Plane Secret Type |
|---|---|
kubernetes.io/dockerconfigjson | docker |
kubernetes.io/basic-auth | userpass |
kubernetes.io/tls | tls |
With payload key | opaque |
| Default | dictionary |
How volumesets are configured
PersistentVolumeClaims are converted to volumesets with these settings:| Property | Source (in priority order) | Default |
|---|---|---|
| Capacity | PersistentVolume spec.capacity.storage → PVC spec.resources.requests.storage | 10 GB |
| Performance class | StorageClass parameters (see below) | general-purpose-ssd |
| File system type | PV volume source fsType → StorageClass parameters.fsType | ext4 |
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:- Identity - Named
identity-{workload-name}, linked to the workload - Policy - Named
policy-{workload-name}, grantingrevealpermission on referenced secrets
Firewall and public exposure
The converter analyzes your Kubernetes Services and Ingresses to determine if a workload should be publicly accessible:| Kubernetes Configuration | Control Plane Firewall |
|---|---|
Service type LoadBalancer matching pod labels | External inbound allowed (0.0.0.0/0) |
| Ingress routing to a Service matching pod labels | External inbound allowed (0.0.0.0/0) |
| No public exposure detected | External 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:| Resource | How it’s used |
|---|---|
| HorizontalPodAutoscaler | Sets minScale, maxScale, scaleToZeroDelay, and CPU target |
| Service | Protocol inference, public exposure detection |
| Ingress | Public exposure detection |
| ServiceAccount | Image pull secrets extraction |
| EndpointSlice | Service-to-Pod mapping for selectorless services |
| PersistentVolume | Capacity and file system type for volumesets |
| StorageClass | Performance class and file system type for volumesets |
Basic usage
Options
| Option | Description |
|---|---|
--file | Path to K8s JSON/YAML file. Use --file - for stdin |
--protocol | Override port protocol for all containers: http, http2, grpc, tcp |
--verbose | Show 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.2
Service port name prefix
The converter checks if any Service port targeting this container has a name with a protocol prefix.
3
Container port name prefix
The container’s own port name is checked for protocol prefixes.
4
Health probe type
If the port has a liveness or readiness probe, the probe type determines the protocol:
grpcprobe → gRPChttpGetprobe → HTTPtcpSocketprobe → 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:| Prefix | Protocol |
|---|---|
http, https, ws, wss | HTTP |
http2, h2, h2c | HTTP/2 |
grpc, grpc-web, grpcweb | gRPC |
Well-known port mappings
These port numbers are automatically assigned protocols when no other signal is available:- HTTP ports
- gRPC ports
| Port | Protocol |
|---|---|
| 80, 81, 443 | HTTP |
| 3000, 3001, 3002 | HTTP |
| 8000, 8008, 8080, 8081, 8088 | HTTP |
| 8443, 9090 | HTTP |
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
2
Convert the manifest
View output
View output
3
Apply the converted resources
Convert and apply in one command:Or pipe the conversion output:
More conversion examples
- Serverless (default)
- Standard
- Stateful
- Cron
- ConfigMap
A simple Deployment with one HTTP port becomes serverless:Converts to a serverless workload (single port, no volumes, no gRPC probes).
k8s-deployment.yaml
Override protocol inference
To bypass automatic protocol inference and set a specific protocol for all ports, use the--protocol flag:
Verbose mode
Use--verbose to see which K8s properties were converted and which were ignored:
(ignored).
Delete converted resources
To remove resources that were applied from a K8s manifest:Troubleshooting
Resource type not supported
Resource type not supported
Some Kubernetes resources don’t have direct Control Plane equivalents. Use
--verbose to see which properties are ignored during conversion.ConfigMap values not appearing
ConfigMap values not appearing
ConfigMaps are converted to dictionary secrets. Reference them in your workload using environment variables or volume mounts pointing to the secret.
HPA settings not applied
HPA settings not applied
HorizontalPodAutoscaler settings inform the workload’s autoscaling configuration. Check the converted workload’s
defaultOptions.autoscaling section.Service ports not exposed
Service ports not exposed
Services are used to inform port mappings but don’t create standalone resources. Ports are configured directly on the workload’s container spec.
PVC not creating volumeset
PVC not creating volumeset
PersistentVolumeClaims are converted to volumesets. Ensure the PVC is referenced by a StatefulSet’s volumeClaimTemplates for proper conversion.