docs(ing2gw): add NGINX-to-Gateway migration guide#2623
docs(ing2gw): add NGINX-to-Gateway migration guide#2623ctauchen merged 6 commits intotigera:mainfrom
Conversation
❌ Deploy Preview for calico-docs-preview-next failed. Why did it fail? →
|
✅ Deploy Preview succeeded!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
9a03ad3 to
2336d43
Compare
There was a problem hiding this comment.
Pull request overview
Adds a native, in-browser NGINX Ingress → Gateway API migration experience to the Calico docs site by embedding a React-based converter (via @tigera/ingress-to-gateway-web) and wiring up the required docs, dependencies, and CI auth for GitHub Packages.
Changes:
- Introduces a new
IngressConverterwrapper component that renders the converter UI and outputs (playbook + YAML) on the docs page. - Adds new “Migrating from NGINX” docs pages (current + Calico v3.31) and links them in the Calico sidebars.
- Configures Yarn + GitHub Actions to authenticate to GitHub Packages for
@tigera/*dependency installation.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/___new___/components/IngressConverter/index.tsx |
New wrapper component integrating @tigera/ingress-to-gateway-web and rendering playbook markdown + YAML output. |
src/___new___/components/index.ts |
Exposes IngressConverter via the shared components barrel export for MDX imports. |
calico/networking/ingress-gateway/migrate-from-nginx.mdx |
New “Migrating from NGINX” doc page that embeds <IngressConverter />. |
calico_versioned_docs/version-3.31/networking/ingress-gateway/migrate-from-nginx.mdx |
Versioned v3.31 equivalent of the new migration page. |
sidebars-calico.js |
Adds the new migration page to the Calico sidebar navigation. |
calico_versioned_sidebars/version-3.31-sidebars.json |
Adds the new migration page to the Calico v3.31 sidebar navigation. |
package.json |
Adds @tigera/ingress-to-gateway-web and marked dependencies. |
yarn.lock |
Locks new dependencies (@tigera/ingress-to-gateway-*, marked, and yaml range change). |
.yarnrc.yml |
Configures @tigera scope to use GitHub Packages with NODE_AUTH_TOKEN. |
.github/workflows/validate.yml |
Sets NODE_AUTH_TOKEN during installs to allow fetching from GitHub Packages. |
.github/workflows/vale.yml |
Sets NODE_AUTH_TOKEN during installs to allow fetching from GitHub Packages. |
|
|
||
| function MarkdownRenderer({ children }: { children: string }) { | ||
| const html = marked.parse(children, { async: false }) as string; | ||
| // biome-ignore lint/security/noDangerouslySetInnerHtml: markdown is generated by our own report engine, not user input |
There was a problem hiding this comment.
marked will render raw HTML by default, and conversion.output.report is derived (directly/indirectly) from user-pasted YAML. Rendering it via dangerouslySetInnerHTML without sanitization creates an XSS risk. Consider sanitizing the generated HTML (e.g., reuse the repo’s existing sanitize-html dependency) or configure the markdown pipeline to disallow embedded HTML before injecting it.
| function MarkdownRenderer({ children }: { children: string }) { | |
| const html = marked.parse(children, { async: false }) as string; | |
| // biome-ignore lint/security/noDangerouslySetInnerHtml: markdown is generated by our own report engine, not user input | |
| import sanitizeHtml from 'sanitize-html'; | |
| function MarkdownRenderer({ children }: { children: string }) { | |
| const rawHtml = marked.parse(children, { async: false }) as string; | |
| const html = sanitizeHtml(rawHtml, { | |
| allowedTags: sanitizeHtml.defaults.allowedTags, | |
| allowedAttributes: sanitizeHtml.defaults.allowedAttributes, | |
| }); |
| export default function IngressConverter() { | ||
| const conversion = useConversion(); | ||
| const [step, setStep] = useState<Step>('input'); | ||
|
|
||
| const handleConvert = useCallback(() => { | ||
| const result = conversion.handleConvert(); |
There was a problem hiding this comment.
This new React component doesn’t appear to have a Jest test alongside it, while other components under src/___new___/components/* commonly have snapshot tests in __test__/ (e.g., src/___new___/components/Explore/__test__/index.test.tsx). Adding at least a basic render/snapshot test would help prevent regressions when updating @tigera/ingress-to-gateway-web or the wrapper logic.
| cache: yarn | ||
| - name: Authenticate GitHub Packages | ||
| run: yarn config set --home npmScopes.tigera.npmAuthToken "${{ secrets.GITHUB_TOKEN }}" | ||
| - name: Install dependencies | ||
| run: yarn install --immutable |
There was a problem hiding this comment.
Using NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} for GitHub Packages typically requires explicit workflow/job permissions (at least packages: read). Without setting permissions: packages: read, installs from npm.pkg.github.com can fail depending on repo/org default token permissions. Consider adding an explicit permissions block to ensure deterministic installs.
| - name: Authenticate GitHub Packages | ||
| if: steps.changed.outputs.skip == 'false' | ||
| run: yarn config set --home npmScopes.tigera.npmAuthToken "${{ secrets.GITHUB_TOKEN }}" | ||
| - name: Install dependencies | ||
| if: steps.changed.outputs.skip == 'false' |
There was a problem hiding this comment.
This workflow now authenticates to GitHub Packages during yarn install, but it doesn’t declare permissions: packages: read. If the repository’s default GITHUB_TOKEN permissions don’t include packages access, dependency installation from npm.pkg.github.com will fail. Consider adding explicit packages: read permissions (workflow- or job-level).
268266a to
02d7b30
Compare
slack.projectcalico.org now returns 403 and is failing the crawler test on every PR. The live Calico community Slack is calicousers.slack.com (already on the link-check skip list). Found via netlify-tigera deploy preview failure on unrelated PR tigera#2623.
f15e7bf to
0d6a522
Compare
|
|
||
| # Migrating from NGINX Ingress | ||
|
|
||
| NGINX Ingress Controller [retired in March 2026](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) — no more releases, bugfixes, or security patches. Calico Ingress Gateway, powered by Envoy Gateway, is the recommended replacement. |
There was a problem hiding this comment.
This needs to be toned down, neutral statement of how you can use Calico Ingress Gateway instead.
| This guide explains the conceptual mapping from NGINX Ingress to Gateway API, walks through a step-by-step migration workflow, and points you at an open-source tool that drafts your Gateway API resources from existing Ingress YAML. | ||
|
|
||
| :::warning About the conversion tool | ||
| The [open-source converter](https://tigera.github.io/ing2gw/) maps annotations mechanically. It cannot judge intent, exercise traffic, or guarantee behavioral parity. Treat its output as a **starting draft, not a finished migration**. Every generated resource must be reviewed, validated, and tested in a non-production cluster before cutover. The tool may produce incorrect or incomplete output for edge cases — verify, then verify again. |
There was a problem hiding this comment.
Move from warning to tip, make this more about if you're ready to get started you can jump straight to the tool. Small mention of non-prod nature of the output. Let's leave details to the end section of the page.
|
|
||
| NGINX Ingress Controller [retired in March 2026](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) — no more releases, bugfixes, or security patches. Calico Ingress Gateway, powered by Envoy Gateway, is the recommended replacement. | ||
|
|
||
| This guide explains the conceptual mapping from NGINX Ingress to Gateway API, walks through a step-by-step migration workflow, and points you at an open-source tool that drafts your Gateway API resources from existing Ingress YAML. |
There was a problem hiding this comment.
Should we be consistent that it's NGINX Ingress --> CIG, rather than Gateway API?
|
|
||
| ## Why Gateway API | ||
|
|
||
| NGINX Ingress encodes behavior in vendor-specific annotation strings on `Ingress` objects. Gateway API encodes the same behavior in typed CRDs that any conformant controller (Envoy Gateway, Istio, Cilium, kgateway, etc.) can read. The mental shift: |
There was a problem hiding this comment.
| NGINX Ingress encodes behavior in vendor-specific annotation strings on `Ingress` objects. Gateway API encodes the same behavior in typed CRDs that any conformant controller (Envoy Gateway, Istio, Cilium, kgateway, etc.) can read. The mental shift: | |
| NGINX Ingress encodes behavior in vendor-specific annotation strings on `Ingress` objects. Gateway API encodes the same behavior in typed CRDs that any conformant controller (such as Envoy Gateway, Istio, Cilium, and kgateway) can read. The mental shift: |
|
|
||
| Keep NGINX live and serving traffic until parity is proven under representative load. | ||
|
|
||
| ### 7. Cutover |
There was a problem hiding this comment.
Perhaps "Remove NGINX" or similar
| ### 8. Have a rollback path | ||
|
|
||
| Until cutover is final, keep the original `Ingress` resources and the ingress-nginx controller deployable. Rolling back should be a DNS change or undoing the percentage shift — not a manifest re-apply under fire. | ||
|
|
There was a problem hiding this comment.
I don't see what this adds. It tells you to not delete things until you delete them? In the previous step?
|
|
||
| Until cutover is final, keep the original `Ingress` resources and the ingress-nginx controller deployable. Rolling back should be a DNS change or undoing the percentage shift — not a manifest re-apply under fire. | ||
|
|
||
| ## Common gotchas |
- Tone down opening (neutral statement of CIG as replacement) - Frame mapping as NGINX Ingress -> CIG, not generic Gateway API - Top admonition: warning -> tip (jump to tool, brief non-prod note) - Detailed warning moved to bottom Conversion tool section - 'What converts cleanly, what doesn't' -> 'and what doesn't' - 'Step-by-step workflow' -> 'Migration workflow' - Steps renamed 'Step N: <verb phrase>' throughout - Step 7 'Cutover' -> 'Remove NGINX' - Step 8 'Have a rollback path' merged into Step 6 (parallel run) - 'Common gotchas' -> 'Common problems' - Conversion tool section expanded (input/output, auto-detect note) - 'Reminder:' plain text -> :::warning admonition - Need help? adds Calico Users Slack link - Drop 'bugfix(es)' from CalicoTerminology vocab; prose says 'bug fixes' Per inline review on PR tigera#2623.
slack.projectcalico.org persistently returns 403 to the docs crawler test, blocking every PR's tigera netlify deploy preview. The live Calico community Slack is at calicousers.slack.com, already on the link-check skiplist. This is on a page unrelated to the migration guide (calico/getting-started/kubernetes/openshift/ovn-to-calico.mdx) but bundling the one-line URL change here so PR tigera#2623 can land without waiting on a separate fix to main. Verified two back-to-back netlify-tigera failures on identical content to confirm this is not a transient flap.
|
Pushed restructure per spec — summary:
Two unrelated CI fixes bundled to unblock the deploy preview (tigera netlify):
Ready for another look. |
Adds migrate-from-nginx.mdx for OSS calico (current + v3.31). Concept-first structure: Why Gateway API → Migration workflow (Steps 1-7 with kubectl-only commands) → Common problems → Conversion tool. Tool is constrained to one section + two uniform admonitions (:::tip jump-to + :::note Step 3 pointer + :::warning starting-draft disclaimer). Annotation reference is hosted at tigera.github.io/ing2gw/#/reference; this page links out to it. Co-developed and reviewed with ctauchen on PR tigera#2623.
- Brands: kgateway, Lua - Terminology: conformant, cutover(s), reimplement(ed|ing|s)
Netlify-to-Netlify HEAD requests to hypershift-docs.netlify.app hang for ~45 minutes during the crawler test, timing out every PR's tigera deploy preview. Domain is reachable from outside Netlify (200 in <0.2s); adding to the link-check skiplist alongside other known-flaky Netlify-hosted hosts. Link still rendered to readers; only the crawler test skips it.
aa4e414 to
d69964c
Compare
Docusaurus 3.x doesn't render the space-separated title syntax (`:::tip Title`); titles must use bracket syntax (`:::tip[Title]`). Without this, the opening fence renders as literal `:::` text and the title bleeds into the body. Switch the top tip and bottom warning to bracket syntax.
- Step 3 :::note -> :::info (blue) so it visually pops - Bottom warning -> :::caution[Important] for proper warning styling (yellow). Tigera custom.css overrides --ifm-color-warning-* to brand-blue, so :::warning rendered as blue rather than yellow; :::caution uses default Docusaurus yellow tokens. - Restructure the caution body so the 'starting draft' sentence reads as its own headline paragraph above the review checklist.
Step 4 referenced 'generated config' / 'generated.yaml' as if the file was always produced by the conversion tool. Step 3 is tool-agnostic, so rename to 'Validate the resources', link the artifact explicitly back to Step 3, and use 'gateway-api.yaml' as the placeholder with a one-line note covering both authored and generated manifests.
Adds migrate-from-nginx.mdx for OSS calico (current + v3.31). Concept-first structure: Why Gateway API → Migration workflow (Steps 1-7 with kubectl-only commands) → Common problems → Conversion tool. Tool is constrained to one section + two uniform admonitions (:::tip jump-to + :::note Step 3 pointer + :::warning starting-draft disclaimer). Annotation reference is hosted at tigera.github.io/ing2gw/#/reference; this page links out to it. Co-developed and reviewed with ctauchen on PR #2623.

Summary
Adds a step-by-step guide for migrating NGINX Ingress resources to Calico Ingress Gateway (Envoy Gateway).
The migration tool is not embedded in the docs anymore — it still runs entirely in the browser (no YAML leaves the user's machine), but now lives on its own site at tigera.github.io/ing2gw and is linked from the guide.
Why split the tool from the guide
The tool is a draft generator, not an authoritative migration. Embedding it directly in the docs gave readers the impression that paste-in / paste-out was a complete migration. Splitting the two keeps the docs as the source of truth on the process (review, validate with
egctl, stage, parallel run, switchover) and lets the tool iterate on its own cadence without docs PRs.Changes
calico/networking/ingress-gateway/migrate-from-nginx.mdx(current + v3.31)<IngressConverter />wrapper, vendored@tigera/ingress-to-gateway-webbundle,markeddep, and the GitHub Packages auth step invale.yml(no longer needed)cutover,conformant,reimplementtoCalicoTerminology; addLua,kgatewaytoCalicoBrandsTest plan
/calico/latest/networking/ingress-gateway/migrate-from-nginx/calico/3.31/...