cpln convert command transforms Kubernetes manifests into Control Plane resources, enabling seamless migration from Kubernetes environments.
When to use this
Kubernetes migration
Reuse existing manifests
Preview conversions
CI/CD integration
Supported resources
Workload conversions
How workload type is determined
The converter analyzes your Kubernetes spec to automatically select the appropriate Control Plane workload type:Pinned via annotation (highest priority)
Pinned via annotation (highest priority)
cpln.io/workload-type annotation on the Deployment, StatefulSet, DaemonSet, ReplicaSet, or its pod template to pin the type explicitly:stateful, and pinning serverless on a workload whose shape conflicts with serverless requirements (e.g., multiple ports) emits a warning and is validated by the API. Jobs and CronJobs always convert to cron and ignore the annotation.Cron
Cron
cron workloads.- CronJobs preserve their schedule from
spec.schedule - Jobs use a default schedule of
* * * * *(every minute)
Stateful
Stateful
stateful if any container mounts a dedicated volumeset (from a PersistentVolumeClaim or volumeClaimTemplates with single-node access modes such as ReadWriteOnce).Claims with multi-node access modes (ReadWriteMany, ReadOnlyMany) convert to shared volumesets, which any workload type can mount — they do not force the stateful type.Stateful takes precedence over standard when both conditions are met.Standard (default)
Standard (default)
standard. The type remains standard unless a stateful condition is detected. Conditions that explicitly confirm standard:- 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)
Conversion annotations
The converter honors these annotations on the workload object metadata (Deployment, StatefulSet, DaemonSet, ReplicaSet, ReplicationController, Job, CronJob) or on its pod template metadata. Object-level annotations take precedence over template-level ones.cron and vm cannot be pinned. Cron workloads carry a job schedule that only Jobs and CronJobs provide (they always convert to cron). VM workloads boot from a disk image instead of running containers, so no container-based Kubernetes kind can convert to one.Environment variables
Container environment variables convert as follows:envFrom expansion follows Kubernetes semantics:
- An explicit
enventry overrides anenvFromvariable with the same name. - A key present in multiple
envFromsources takes the value of the last source. - A
prefixon the source is prepended to every expanded variable name. - ConfigMap
binaryDatakeys are not expanded (Kubernetes does not expose them as environment variables either).
Secret and config conversions
Storage conversions
Domain conversions
How secrets are converted
Kubernetes Secrets are converted based on theirtype field:
How volumesets are configured
PersistentVolumeClaims are converted to volumesets with these settings:accessModes include ReadWriteMany or ReadOnlyMany converts to a shared volumeset (fileSystemType: shared, performanceClass: shared). Shared volumesets can be mounted by workloads of any type and by multiple workloads at once — matching how RWX claims behave on Kubernetes. All other claims convert to dedicated block-storage volumesets, which only stateful (or vm) workloads can mount, one workload at a time.
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
How domains are converted
Kubernetes Ingresses are converted to Control Plane Domains. The converter maps Ingress rules (host + paths) to domain routes, resolving backend Services to workloads.Field mapping
Path type handling
Service-to-workload resolution
The converter resolves each Ingress backend to a Control Plane workload through the following steps:Find the Service
service.name.Match the workload
selector labels are matched against workload pod template labels to find the target workload.Resolve the port
targetPort is resolved to the actual container port:- Numeric targetPort — used directly as the container port
- Named targetPort — resolved by matching the port name in the container spec
- No targetPort — falls back to the Service port number
Domain defaults
All converted domains use these fixed settings:Wildcard and apex domain merging
When an Ingress contains rules for bothexample.com and *.example.com, the converter merges them into a single domain named example.com with acceptAllSubdomains: true. Routes from both rules are combined and deduplicated.
GVC context
If a--gvc is provided, workload links use it directly (e.g., //gvc/my-gvc/workload/api). Otherwise, the converter inserts a {{GVC}} placeholder that you must replace before applying.
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 how each workload should be reachable:firewallConfig.internal.inboundAllowType: same-gvc, so dependent workloads (databases, message brokers, internal APIs) keep talking to each other after migration. Use the cpln.io/internal-inbound-allow-type annotation to override the inference per workload — for example, none to lock a workload down even though a Service selects it.
0.0.0.0/0).Informational resources
These Kubernetes resources are not directly converted but inform the conversion:Basic usage
Options
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):
Service appProtocol (highest priority)
appProtocol on a port that targets this container, that protocol is used.Service port name prefix
Container port name prefix
Health probe type
grpcprobe → gRPChttpGetprobe → HTTPtcpSocketprobe → TCP
Well-known port number (lowest priority)
Recognized protocol prefixes
Port names starting with these prefixes are automatically mapped:Well-known port mappings
These port numbers are automatically assigned protocols when no other signal is available:- HTTP ports
- gRPC ports
tcp.Example conversion
Create a Kubernetes manifest
k8s.yaml:Convert the manifest
View output
View output
Apply the converted resources
More conversion examples
- Standard (default)
- Standard (explicit)
- Stateful
- Cron
- ConfigMap
- Domain (Ingress)
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
Workload type may not be changed (405)
Workload type may not be changed (405)
standard.Pin the type in the K8s manifest so it stays stable across CLI versions:Workloads cannot reach each other after conversion
Workloads cannot reach each other after conversion
inboundAllowType: none). Callers see errors like connection reset by peer while the target’s access log shows rbac_access_denied_matched_policy[none].Include the Services in the conversion input so the converter infers same-gvc, set the cpln.io/internal-inbound-allow-type annotation, or open the firewall after the fact with cpln workload update <name> --set spec.firewallConfig.internal.inboundAllowType=same-gvc.envFrom variables are missing
envFrom variables are missing
envFrom sources expand only when the referenced ConfigMap or Secret is part of the conversion input, because the converter needs the keys. Check the conversion warnings on stderr: a Secret that lives only on Control Plane cannot be expanded — include its manifest in the input or add the variables to env manually.Resource type not supported
Resource type not supported
--verbose to see which properties are ignored during conversion.ConfigMap values not appearing
ConfigMap values not appearing
HPA settings not applied
HPA settings not applied
defaultOptions.autoscaling section.Service ports not exposed
Service ports not exposed
PVC not creating volumeset
PVC not creating volumeset
Ingress not creating a domain
Ingress not creating a domain
Service without selector error
Service without selector error
selector defined so the converter can resolve which workload the Service targets. Services without selectors (e.g., ExternalName services) are not supported for domain conversion.Workload link shows {{GVC}} placeholder
Workload link shows {{GVC}} placeholder
--gvc, workload links contain a {{GVC}} placeholder. Provide --gvc during conversion or replace the placeholder before applying.