Request an exact quote
Containers & PaaS migration path

From Red Hat OpenShift to Kubernetes (upstream)

Leaving OpenShift's per-core subscription for vanilla Kubernetes, mapping Routes, BuildConfigs, and SCCs to CNCF equivalents, and the security-model shift to plan for.

Effort
High
Est. timeline
~21 wks
Kubernetes (upstream) model
Free (self-managed)
Open source
Yes
▶ Model your savings in the interactive calculator

OpenShift is a per-core subscription across your worker nodes, and it bundles a lot of opinionated platform on top of Kubernetes. Moving to upstream Kubernetes removes the license, but the real work is replacing everything OpenShift quietly provided, the integrated registry, build system, ingress model, and security defaults, with CNCF equivalents you now assemble and own. Go in knowing exactly what you’re rebuilding.

What OpenShift adds over vanilla Kubernetes

OpenShift is not just Kubernetes with a console. It ships an integrated image registry, source-to-image (S2I) builds via BuildConfig, the Route ingress object, DeploymentConfig, SecurityContextConstraints (SCC) for pod security, an OAuth/identity layer, an opinionated web console, and Operator Lifecycle Manager. Each of those is something you must replace or re-implement.

What the subscription actually buys

It helps to name what the subscription buys, because you are about to rebuild it. OpenShift ships an integrated platform where the registry, build system, ingress, identity, and security policy are wired together and supported as one product. A developer pushes source, an ImageStream trigger fires a BuildConfig, S2I produces an image, and a DeploymentConfig rolls it out, all inside the cluster with one console and one support contract. Upgrades arrive as a tested bundle rather than a set of independently versioned components you reconcile yourself. On upstream Kubernetes each of those becomes a discrete choice: which ingress controller, which registry, which CI system, which identity provider, which policy engine, and who owns keeping them compatible across upgrades. None of it is hard in isolation. The cost is that you now own the integration and the on-call for it. Scope the platform-team time honestly before you sign off on the license savings, because that trade is the whole decision.

What maps to what

  • Routes → Ingress or the Gateway API (with an ingress controller such as NGINX or Envoy-based options).
  • BuildConfig + ImageStream + S2I → external CI (Tekton, Argo Workflows, GitHub Actions) plus a registry like Harbor.
  • DeploymentConfig → standard Deployment (triggers and rollout hooks become CI/GitOps steps).
  • SCC → Pod Security Admission (PSA), optionally with a policy engine (Kyverno or OPA Gatekeeper) for finer control.
  • Internal registry → Harbor (or Quay, which is also available standalone).
  • OpenShift OAuth → external OIDC (Keycloak, Dex) wired into the API server.
  • ockubectl; the web console → Headlamp, Lens, or the Kubernetes Dashboard.
  • Operators mostly port, OLM is available upstream, and many operators publish community builds.

Choosing a distribution

“Upstream Kubernetes” still needs a lifecycle owner. Common choices: kubeadm or Cluster API for roll-your-own; RKE2/Rancher, k3s, or Talos Linux for a managed-feel open distribution. This decision drives upgrades, HA, and node provisioning, so make it before you migrate workloads.

The security-model shift to plan for

The conversion that surprises teams is SCC to Pod Security Admission. OpenShift’s SCCs are stricter and shaped differently from upstream PSA levels (privileged / baseline / restricted). Workloads that “just ran” under a permissive SCC may need explicit securityContext settings, and anything relying on OpenShift’s default non-root UID ranges needs review. Audit this early, it’s a correctness and security issue, not a cosmetic one.

Converting the manifests

The containers themselves rarely change, but the objects wrapping them do. Convert each DeploymentConfig to a standard Deployment and move its triggers and lifecycle hooks into CI or GitOps steps. Replace ImageStream references with direct image pulls from your new registry, updating every manifest that pointed at the internal OpenShift registry. Turn Routes into Ingress rules, and re-check any Route-level annotations that have no clean Ingress equivalent. Where an app depended on OpenShift’s automatic non-root UID assignment, add an explicit securityContext so the pod still runs under Pod Security Admission. Do this conversion in version control so the target is declarative and reviewable, not hand-edited on a live cluster.

A safe migration flow

  1. Inventory Routes, BuildConfigs, ImageStreams, DeploymentConfigs, SCCs, and Operators in use.
  2. Stand up the target cluster on your chosen distribution, with ingress, a registry (Harbor), CI, and an OIDC provider.
  3. Convert manifests, replace OpenShift-specific objects with standard Kubernetes YAML, and move build logic into external pipelines.
  4. Migrate workloads with Velero (backup/restore of namespaces and persistent volumes) and redeploy via GitOps (Argo CD or Flux).
  5. Validate per namespace: pods schedule under PSA, ingress resolves, images pull from the new registry, CI rebuilds, and auth works.
  6. Cut over namespace by namespace, keeping the OpenShift cluster available for rollback through hypercare.

Validation and cutover

Validation is per namespace and should be explicit, not a glance at a green dashboard. Confirm that pods schedule and stay running under the PSA level you assigned, that Ingress resolves the same hostnames with working TLS, and that images pull from the new registry rather than the retired internal one. Run the CI pipeline end to end so a source change rebuilds and redeploys, and check that external OIDC login grants the roles your rebuilt RBAC expects. Reconcile the whole namespace through GitOps so what is running matches what is committed. Only then move traffic, and keep the OpenShift namespace intact through a hypercare window so you can re-point back if a wave regresses.

What to do next

OpenShift → upstream Kubernetes removes the per-core subscription but converts a turnkey platform into an assembly-and-own model. The heavy lifting is re-tooling builds and ingress and migrating SCC-based security to Pod Security Admission, not moving the containers themselves. Choose your distribution first, rebuild the platform services, then migrate workloads with Velero and GitOps. Model the per-core savings in the calculator above against the engineering time you’re taking on, and treat the figures as provisional until you scope your own platform team.

Tooling & automation for this path

Re-platform workloads to upstream Kubernetes; replace Routes with Ingress, BuildConfigs with external CI + registries, SCCs with PodSecurity; validate via GitOps.

Primary references: official Kubernetes (upstream) documentation ↗ and the Red Hat OpenShift documentation ↗ , always verify version-specific behavior against them before you migrate.

Frequently asked questions

Do I have to replace OpenShift Routes, or can Kubernetes read them directly?

Routes are an OpenShift-specific object and upstream Kubernetes does not understand them. You replace each Route with an Ingress resource (or a Gateway API HTTPRoute) served by an ingress controller such as NGINX or an Envoy-based option. Path-based routing, TLS termination, and host rules all carry over conceptually, but the YAML is different and edge-case features like Route-level rewrite annotations need re-checking.

What breaks when I move workloads from SecurityContextConstraints to Pod Security Admission?

OpenShift assigns a non-root UID from a per-namespace range and enforces stricter SCCs than upstream defaults. Under Pod Security Admission you choose privileged, baseline, or restricted per namespace, and pods that relied on OpenShift's automatic UID handling may fail to start until you set an explicit securityContext. Audit this before cutover because it is a security and correctness issue, not cosmetic.

Can Velero move my OpenShift namespaces to upstream Kubernetes as-is?

Velero backs up and restores namespaces and their persistent volumes, so the data and standard objects move cleanly. It will not rewrite OpenShift-specific objects for you: BuildConfigs, ImageStreams, DeploymentConfigs, Routes, and SCCs still need converting to standard Kubernetes YAML before or after the restore. Treat Velero as the data-and-workload mover, not the OpenShift-ism translator.

How do I replace source-to-image builds after leaving OpenShift?

Source-to-image and BuildConfig move out of the cluster into an external CI system such as Tekton, Argo Workflows, or GitHub Actions, which builds images and pushes them to a registry like Harbor. ImageStreams and their trigger-on-new-image behavior become CI pipeline steps plus a GitOps sync. This is usually the largest single chunk of the migration.

Model your 3-year cost

Pre-filled for Red Hat OpenShift → Kubernetes (upstream); adjust every figure with your own numbers. Estimates are illustrative, not vendor quotes, see our methodology.

Sized at 512 vCPU cores, cost is computed on this.
Stay on Red Hat OpenShift (3yr)
$245,760
Move to Kubernetes (upstream) (3yr + migration)
$96,288
Projected savings
$149,472 (61%)
Payback period
13.0 mo
Build a decision report from these numbers:

Illustrative, editable figures, not vendor pricing (defaults reviewed May 2026).

Request a vendor-accurate Kubernetes (upstream) quote

A guided builder that turns your estimates into a requirements report (RFQ) you can send to a vendor, partner, or distributor for a binding quote, then feed the real prices back into the calculator above. How our estimates work.

  1. 1Size it
  2. 2Requirements
  3. 3Your details
  4. 4Channels & export

How big is your Red Hat OpenShift estate?

vSphere licenses physical cores across all hosts (16-core minimum per CPU). Not sure? Enter rough numbers, the distributor confirms exact counts later.

512 vCPU cores
Default mid-size assumption (512 vCPU cores)