Nginx to traefik
⚡ Cross-platform DevOps AI Skill Pack — Horus (IaC) + Zeus (GitOps) agents, ingress→Gateway migration & architecture-diagram painter for Claude Code, Codex CLI, Gemini CLI & Antigravity
npx -y skills add qwedsazxc78/devops-ai-skill --skill nginx-to-traefikAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 9 stars9 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Class-swap migration that ports services from NGINX Ingress to Traefik Ingress (`ingressClassName: traefik`) while keeping both controllers running in parallel. DNS A-records are the only cutover lever. Designed for eye-of-horus-gitops conventions: nginx files move to archive/ (never deleted), Traefik Ingresses live in kustomization.resources (never patches), backend Service names and secretName are written verbatim (Kustomize namePrefix does not touch them). Operator-declared LB IPs only — never auto-derived from cluster state. State stored in docs/reports/nginx-to-traefik/<slug>/.
SKILL.md
8.6 KB, as published. Nobody here has run it
nginx-to-traefik Skill
Invoked by Zeus pipeline *nginx-to-traefik.
This skill is the first half of the chained migration NGINX → Traefik
Ingress → Gateway API. Used standalone it ports a batch of services to
Traefik while leaving the NGINX controller serving everyone else. Used
under skill nginx-to-gateway (the orchestrator), its state.yaml output
is consumed as the input to skill gateway-api-migration with
--source-class traefik.
Canonical references
| File | When to read |
|---|---|
references/nginx-to-traefik-env-config.md | Step 0b — env-config schema and operator prompts |
references/annotation-translation.md | Step 3 — annotation mapping |
references/dns-cutover-runbook.md | Step 10 — printed/linked at end of run |
Bundled scripts
| Script | Used by | Purpose |
|---|---|---|
scripts/inventory_nginx_ingresses.py | Step 1 | Per-overlay nginx Ingress inventory |
scripts/generate_traefik_ingress.py | Step 3 | Emit <service>-traefik-ingress.yaml |
scripts/update_kustomization.py | Step 5, 6 | Idempotent edits to kustomization.yaml + app.ingress.yaml |
scripts/validate_cross_consistency.sh | Step 7b | 4-way DNS↔verify↔ingress↔cert cross-check |
Activation
Triggered explicitly by *nginx-to-traefik from Zeus. Not auto-triggered.
Invocation forms
*nginx-to-traefik # interactive: inventory + propose batches
*nginx-to-traefik <env> # process all services in one env
*nginx-to-traefik <env> <batch> # named batch (b1 | b2)
*nginx-to-traefik <env> <service> # single service
*nginx-to-traefik --resume # continue from state.yaml
Step Flow
| Step | Action | Script |
|---|---|---|
| 0 | Tool check (kustomize, yq, git) | inline command -v |
| 0b | Load references/nginx-to-traefik-env-config.md; prompt operator for Traefik + nginx LB IPs if missing, write to config, then continue | inline |
| 1 | Inventory active nginx ingresses per env | inventory_nginx_ingresses.py |
| 2 | Propose batch plan, wait for y/N confirmation | inline |
| 3 | Generate <service>-traefik-ingress.yaml per service | generate_traefik_ingress.py |
| 4 | git mv nginx file to archive/ | inline |
| 5 | Edit kustomization.yaml: add Traefik file to resources:, drop nginx from patches: | update_kustomization.py |
| 6 | Update common.traefik/overlays/<env>/app.ingress.yaml managed-cert host list | update_kustomization.py |
| 7 | kustomize build both modules for the env | inline |
| 7b | 4-way consistency check | validate_cross_consistency.sh |
| 8 | Update scripts/dns-create-traefik.sh batch list | inline |
| 9 | Update scripts/verify-traefik-<env>.sh URL list | inline |
| 10 | Print commit message + file list (never auto-commit) | inline |
Step 0 — Tool check
Run command -v kustomize yq git. HALT on any missing.
Step 0b — Env-config
Read references/nginx-to-traefik-env-config.md. If state.yaml.envConfig
is missing entries for the target env, issue the 5 prompts listed in the
reference and write the captured values back. Never derive LB IPs from
any cluster resource — this is invariant §5.3 from the spec.
Step 1 — Inventory
Invoke inventory_nginx_ingresses.py --overlay-dir <common.service/overlays/<env>>. Filter to ingressClass == "nginx".
Write to state.yaml.inventory[]. HALT if zero nginx ingresses found.
Step 2 — Batch plan
Group inventory entries by host TLD + service criticality. Default batches:
b1 = read-mostly services, b2 = write-heavy services. Print the proposed
batch plan and ask y/N. HALT on decline.
Step 3 — Generate Traefik Ingress per service
For each service in the active batch, invoke generate_traefik_ingress.py --input <service>-nginx-ingress.yaml --output <service>-traefik-ingress.yaml.
Capture stderr WARN lines into state.yaml.warnings[]. Compute SHA256 of
each output for state.yaml.outputs.traefikIngresses[].sha256.
Step 4 — Archive nginx file
git mv <service>-nginx-ingress.yaml archive/. HALT if the file is already
under archive/. Backup the pre-edit path in state.yaml.backups[].
Step 5 — Kustomization resource edit
update_kustomization.py --overlay-dir <overlay> \
--replace <service>-nginx-ingress.yaml=<service>-traefik-ingress.yaml \
--drop-patch <service>-nginx-ingress.yaml
The script is idempotent: re-running step 5 on a complete state is a no-op.
Step 6 — Managed-cert host list
For each new Traefik Ingress, ensure its primary host is present in
common.traefik/overlays/<env>/app.ingress.yaml.spec.tls[].hosts and
spec.rules[].host. Use update_kustomization.py --app-ingress <path> --add-host <host>.
Step 7 — kustomize build
kustomize build common.service/overlays/<env> > /tmp/svc-build.yaml
kustomize build common.traefik/overlays/<env> > /tmp/traefik-build.yaml
HALT on non-zero exit. Roll back step 4–6 via git restore of backed-up
files.
Step 7b — Cross-consistency check
Invoke validate_cross_consistency.sh with the four host sources. HALT
on non-zero exit. The stderr stale-host list goes into the report.
Step 8 — DNS script update
Locate scripts/dns-create-traefik.sh. Find or create the array
HOSTS_<ENV_UPPER>_<BATCH_UPPER>=(...). Insert each new host (idempotent
via grep -q before append). Record the diff in state.yaml.steps["8"].
Step 9 — Verify script update
Same pattern as Step 8 but URLS_<ENV>_<BATCH> in
scripts/verify-traefik-<env>.sh. URL format: https://<host>/.
Step 10 — Print commit message and file list
Never auto-commit. Print:
- The full set of files touched (Step 3 outputs + Step 4 moves + Step 5/6 edits + Step 8/9 edits).
- A suggested commit message in Conventional Commits zh-TW style.
- A pointer to
references/dns-cutover-runbook.mdfor the operator to follow after the commit lands.
State file (state.yaml)
The state file lives at docs/reports/nginx-to-traefik/<slug>/state.yaml
where <slug> is <env>-<batch>-<isodate>. Schema:
schemaVersion: 1
skillVersion: "1.0.0"
env: dev
batch: b1
createdAt: 2026-05-14T10:00:00Z
envConfig:
capturedAt: <iso>
envs:
dev: { nginxLbIp: ..., traefikLbIp: ..., certIssuer: ..., managedCertNamespace: ..., managedCertResourceName: ... }
inventory:
- { file: argocd-nginx-ingress.yaml, name: argocd-server, namespace: argocd, hosts: [argocd.dev.example.com] }
batchPlan:
b1: [argocd-server, grafana]
outputs:
traefikIngresses:
- { file: argocd-traefik-ingress.yaml, host: argocd.dev.example.com, namespace: argocd, backend: argocd-server, port: 80, sha256: <hex> }
backups:
- { path: argocd-nginx-ingress.yaml, restorePath: archive/argocd-nginx-ingress.yaml }
steps:
"0": { status: pass }
"0b": { status: pass, prompts: 0 }
"1": { status: pass, count: 2 }
"2": { status: pass, confirmed: true }
"3": { status: pass, generated: 2, warnings: 0 }
"4": { status: pass, moved: 2 }
"5": { status: pass, edits: 2 }
"6": { status: pass, hostsAdded: 2 }
"7": { status: pass }
"7b": { status: pass, staleHosts: [] }
"8": { status: pass, hostsAdded: 2 }
"9": { status: pass, urlsAdded: 2 }
"10": { status: pass }
warnings: []
verdict: COMPLETE
The outputs.traefikIngresses[] list is the hand-off contract for skill C
(nginx-to-gateway): when chained, skill C reads this list and passes
--source-class traefik --source-state <statePath> to skill B.
Halt conditions
| Step | Halt cause |
|---|---|
| 0 | Required tool missing |
| 0b | Operator declines to supply env-config values |
| 1 | Zero nginx Ingresses found |
| 2 | Operator declines batch plan |
| 3 | generate_traefik_ingress.py exit code != 0 |
| 4 | File already under archive/ |
| 5 | kustomization.yaml schema mismatch |
| 7 | kustomize build non-zero |
| 7b | Cross-consistency check non-zero |
After halt, the skill writes state.yaml.verdict: HALTED with the failing
step. --resume re-runs from the failed step.