OpenShift to Amazon EKS
Objective
Convert a repository built for Red Hat OpenShift into portable Kubernetes that applies on
Amazon EKS, and document in MIGRATION_REPORT.md everything the transformation cannot do
safely. The paired assessment openshift-to-eks-migration-readiness decides which repos to
run this on and what blocks them; this definition executes the change on one repo.
Scope
Transforms:
- OpenShift manifests (
apps.openshift.io, image.openshift.io, route.openshift.io,
template.openshift.io)
- Helm charts whose templates emit OpenShift kinds
- Kustomize overlays referencing OpenShift kinds
- OpenShift
Template objects (objects: + parameters:)
Non-Goals - always reported, never transformed:
- BuildConfig and S2I. There is no in-cluster build on EKS by default. Converting a build
pipeline requires choosing a target (CodeBuild, GitHub Actions, Kaniko, Buildpacks) and an
S2I
assemble/run contract cannot be mechanically turned into a Dockerfile without
inventing behaviour. Emits a scaffold plus a report item.
- ClusterResourceQuota. No Kubernetes equivalent exists. Per-namespace quotas are a
different guarantee (sum of maximums, not a shared pool) and substituting them silently would
remove a control the customer believes they still have.
- SR-IOV, Multus, PerformanceProfile, MachineConfig, Tuned. Node and hardware coupling.
Emits a Karpenter
NodePool scaffold with the observed constraints as comments; never
asserts equivalence.
- Operators and OLM. Availability has to be checked per operator. Reported by bucket.
- EgressIP and EgressFirewall. Deterministic egress is a VPC and firewall design decision,
not a manifest translation.
- Application code. Anything reading
VCAP_SERVICES-style platform env, or the OpenShift
OAuth proxy, is flagged, not rewritten.
- Executing the migration. This produces code. It never applies to a cluster.
Constraints
Correctness
- Never delete a resource. Transform in place, or leave it and report it.
- Preserve every comment, label and annotation that is not OpenShift-specific. An annotation
that only OpenShift consumes (
haproxy.router.openshift.io/*) moves into the report so its
intent is not lost.
- If a transformation is ambiguous, do not guess. Add a
TODO(migration) comment at the
exact site and a report entry. A wrong manifest is worse than an annotated gap, because it
applies cleanly and fails later.
- Never invent a mapping. A construct with no equivalent is reported, not approximated.
This is the same rule that made
ack-resource-adoption-from-iac degrade an unmapped
CloudFormation type to report-only instead of fabricating a Kind.
Source integrity
- The original OpenShift manifests are left in place, untouched. Converted output is written
alongside under
eks/, so the diff is additive and reviewable.
- Stay on the current branch. Do not create, switch or checkout a branch.
Reporting
- Every automatic change and every manual action item traceable to file and line.
- Risk per change (low / medium / high), never a flat list.
- The report states what was not converted and why, by construct.
Workflow
Phase 0: Read additionalPlanContext
├── migration_target: eks-standard | eks-auto-mode | eks-hybrid (default eks-standard)
├── ingress_strategy: gateway-api | alb-ingress (default gateway-api)
├── registry: the ECR registry base URI to rewrite images to (required for APP mappings)
└── namespace: target namespace if it differs from the OpenShift project
Phase 1: Inventory
├── Every manifest, chart, overlay and Template, with its kinds and apiVersions
├── Classify each: MECHANICAL / SCAFFOLD / REPORT-ONLY (see references/01-construct-mapping.md)
└── Record the inventory in the report BEFORE transforming, so nothing is silently skipped
Phase 2: Transform the MECHANICAL set
├── DeploymentConfig -> Deployment (lifecycle hooks -> report + TODO)
├── ImageStreamTag reference -> fully qualified registry URI
├── Route -> HTTPRoute + Gateway, or Ingress + ALB annotations
├── Template -> Helm chart (values from parameters) or Kustomize
├── PVC storageClassName -> gp3, or efs when accessModes includes ReadWriteMany
└── OpenShift-only node labels -> the target NodePool's labels
Phase 3: Emit SCAFFOLDS for the partly-automatable set
├── SCC -> Pod Security Admission namespace labels, plus a Kyverno policy ONLY for the
│ capabilities PSA cannot express (never a blanket policy engine dependency)
├── BuildConfig -> a buildspec or Dockerfile skeleton, clearly marked incomplete
└── PerformanceProfile / MachineConfig -> Karpenter NodePool with observed constraints
as comments
Phase 4: Validate what can be validated locally
├── every emitted YAML parses
├── kubectl apply --dry-run=client (server-side if a cluster is reachable)
├── helm template / kustomize build when charts or overlays were emitted
└── no OpenShift apiVersion survives in eks/ (grep assertion)
Phase 5: MIGRATION_REPORT.md
├── Inventory with the classification of every construct found
├── Automatic changes, per file
├── Manual action items, per construct, with the reason it could not be automated
├── Risk per change
└── Residual blockers, cross-referenced to the readiness Lens question ids
Exit Criteria
- Every construct in the Phase 1 inventory appears in the report with its classification.
Nothing silently skipped.
- Original OpenShift manifests byte-identical; all output under
eks/.
- Zero
*.openshift.io apiVersions in the emitted output.
- Every emitted YAML parses;
--dry-run=client clean.
- Every REPORT-ONLY construct has a report entry naming the construct, the reason, and the
recommended path.
- Every ambiguity carries a
TODO(migration) at the site and a report entry. One without
the other is a defect.
MIGRATION_REPORT.md cross-references the Lens question ids, so an estate that ran the
assessment can join the two.
1---2name: openshift-to-eks3description: Transforms Red Hat OpenShift application manifests, Helm charts, Kustomize overlays and Templates into portable Kubernetes suitable for Amazon EKS. Converts DeploymentConfig, ImageStream references, Routes and OpenShift Templates, resolves SecurityContextConstraints to Pod Security Admission, and produces a migration report covering everything that cannot be automated safely. Trigger: OpenShift migration, OpenShift to EKS, DeploymentConfig, Route, SCC, BuildConfig.4---56# OpenShift to Amazon EKS78## Objective910Convert a repository built for Red Hat OpenShift into portable Kubernetes that applies on11Amazon EKS, and document in `MIGRATION_REPORT.md` everything the transformation cannot do12safely. The paired assessment `openshift-to-eks-migration-readiness` decides **which** repos to13run this on and what blocks them; this definition executes the change on **one** repo.1415## Scope1617Transforms:1819- OpenShift manifests (`apps.openshift.io`, `image.openshift.io`, `route.openshift.io`,20 `template.openshift.io`)21- Helm charts whose templates emit OpenShift kinds22- Kustomize overlays referencing OpenShift kinds23- OpenShift `Template` objects (`objects:` + `parameters:`)2425**Non-Goals** - always reported, never transformed:26271. **BuildConfig and S2I.** There is no in-cluster build on EKS by default. Converting a build28 pipeline requires choosing a target (CodeBuild, GitHub Actions, Kaniko, Buildpacks) and an29 S2I `assemble`/`run` contract cannot be mechanically turned into a `Dockerfile` without30 inventing behaviour. Emits a scaffold plus a report item.312. **ClusterResourceQuota.** No Kubernetes equivalent exists. Per-namespace quotas are a32 different guarantee (sum of maximums, not a shared pool) and substituting them silently would33 remove a control the customer believes they still have.343. **SR-IOV, Multus, PerformanceProfile, MachineConfig, Tuned.** Node and hardware coupling.35 Emits a Karpenter `NodePool` scaffold with the observed constraints as comments; never36 asserts equivalence.374. **Operators and OLM.** Availability has to be checked per operator. Reported by bucket.385. **EgressIP and EgressFirewall.** Deterministic egress is a VPC and firewall design decision,39 not a manifest translation.406. **Application code.** Anything reading `VCAP_SERVICES`-style platform env, or the OpenShift41 OAuth proxy, is flagged, not rewritten.427. **Executing the migration.** This produces code. It never applies to a cluster.4344## Constraints4546### Correctness4748- **Never delete a resource.** Transform in place, or leave it and report it.49- **Preserve every comment, label and annotation** that is not OpenShift-specific. An annotation50 that only OpenShift consumes (`haproxy.router.openshift.io/*`) moves into the report so its51 intent is not lost.52- **If a transformation is ambiguous, do not guess.** Add a `TODO(migration)` comment at the53 exact site and a report entry. A wrong manifest is worse than an annotated gap, because it54 applies cleanly and fails later.55- **Never invent a mapping.** A construct with no equivalent is reported, not approximated.56 This is the same rule that made `ack-resource-adoption-from-iac` degrade an unmapped57 CloudFormation type to report-only instead of fabricating a Kind.5859### Source integrity6061- The original OpenShift manifests are **left in place**, untouched. Converted output is written62 alongside under `eks/`, so the diff is additive and reviewable.63- Stay on the current branch. Do not create, switch or checkout a branch.6465### Reporting6667- Every automatic change and every manual action item traceable to file and line.68- Risk per change (low / medium / high), never a flat list.69- The report states what was **not** converted and why, by construct.7071## Workflow7273```text74Phase 0: Read additionalPlanContext75 ├── migration_target: eks-standard | eks-auto-mode | eks-hybrid (default eks-standard)76 ├── ingress_strategy: gateway-api | alb-ingress (default gateway-api)77 ├── registry: the ECR registry base URI to rewrite images to (required for APP mappings)78 └── namespace: target namespace if it differs from the OpenShift project7980Phase 1: Inventory81 ├── Every manifest, chart, overlay and Template, with its kinds and apiVersions82 ├── Classify each: MECHANICAL / SCAFFOLD / REPORT-ONLY (see references/01-construct-mapping.md)83 └── Record the inventory in the report BEFORE transforming, so nothing is silently skipped8485Phase 2: Transform the MECHANICAL set86 ├── DeploymentConfig -> Deployment (lifecycle hooks -> report + TODO)87 ├── ImageStreamTag reference -> fully qualified registry URI88 ├── Route -> HTTPRoute + Gateway, or Ingress + ALB annotations89 ├── Template -> Helm chart (values from parameters) or Kustomize90 ├── PVC storageClassName -> gp3, or efs when accessModes includes ReadWriteMany91 └── OpenShift-only node labels -> the target NodePool's labels9293Phase 3: Emit SCAFFOLDS for the partly-automatable set94 ├── SCC -> Pod Security Admission namespace labels, plus a Kyverno policy ONLY for the95 │ capabilities PSA cannot express (never a blanket policy engine dependency)96 ├── BuildConfig -> a buildspec or Dockerfile skeleton, clearly marked incomplete97 └── PerformanceProfile / MachineConfig -> Karpenter NodePool with observed constraints98 as comments99100Phase 4: Validate what can be validated locally101 ├── every emitted YAML parses102 ├── kubectl apply --dry-run=client (server-side if a cluster is reachable)103 ├── helm template / kustomize build when charts or overlays were emitted104 └── no OpenShift apiVersion survives in eks/ (grep assertion)105106Phase 5: MIGRATION_REPORT.md107 ├── Inventory with the classification of every construct found108 ├── Automatic changes, per file109 ├── Manual action items, per construct, with the reason it could not be automated110 ├── Risk per change111 └── Residual blockers, cross-referenced to the readiness Lens question ids112```113114## Exit Criteria1151161. Every construct in the Phase 1 inventory appears in the report with its classification.117 Nothing silently skipped.1182. Original OpenShift manifests byte-identical; all output under `eks/`.1193. Zero `*.openshift.io` apiVersions in the emitted output.1204. Every emitted YAML parses; `--dry-run=client` clean.1215. Every REPORT-ONLY construct has a report entry naming the construct, the reason, and the122 recommended path.1236. Every ambiguity carries a `TODO(migration)` at the site **and** a report entry. One without124 the other is a defect.1257. `MIGRATION_REPORT.md` cross-references the Lens question ids, so an estate that ran the126 assessment can join the two.