Ingress Controller

Kubernetes Ingress Controller

The nvelox-ingress-controller watches standard Kubernetes Ingress resources and translates them into nvelox configuration. It runs as a sidecar alongside nvelox, writing config and triggering hot reloads.

Architecture

The controller follows a simple pipeline:

  1. Watch — controller-runtime watches Ingress, Secret, Service, and EndpointSlice resources
  2. Translate — a pure function converts Ingress rules into nvelox YAML config
  3. Write — atomic YAML write with SHA256 hash gate to avoid unnecessary reloads
  4. Reload — SIGHUP sent to the nvelox sidecar process

IngressClass

The controller watches for Ingress resources with spec.ingressClassName: nvelox. Only Ingresses matching this class are translated.

Architecture diagram
Kubernetes API
    |
    | (watch Ingress/Secret/Service)
    v
Controller (sidecar pod)
    |
    | translate to nvelox YAML
    v
Atomic write + SHA256 gate
    |
    | SIGHUP
    v
Nvelox process (same pod)
    |
    | proxy traffic
    v
Backend Services
Minimal Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    nvelox.io/redirect-https: "true"
spec:
  ingressClassName: nvelox
  tls:
    - secretName: my-app-tls
      hosts:
        - app.example.com
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app
                port:
                  number: 8080

Annotations

All nvelox-specific behavior is configured via annotations on the Ingress resource. Annotations are prefixed with nvelox.io/.

nvelox.io/redirect-https

Set to "true" to redirect HTTP requests to HTTPS. Returns a 301 with the same host and path but https:// scheme.

nvelox.io/rate-limit-per-second

Per-IP requests per second. Example: "100".

nvelox.io/rate-limit-per-minute

Per-IP requests per minute. Example: "6000".

nvelox.io/sticky-cookie

Enable session affinity with a cookie. Value is the cookie name. Example: "nvelox-sticky".

nvelox.io/allow-cidrs

Comma-separated CIDR ranges to allow. All other IPs are denied. Example: "10.0.0.0/8,192.168.0.0/16".

nvelox.io/deny-cidrs

Comma-separated CIDR ranges to deny. Example: "203.0.113.0/24".

nvelox.io/strip-prefix

Strip a path prefix before forwarding to the backend. Example: "/api" removes /api from the request path.

nvelox.io/request-headers

Inject headers into requests before forwarding. Format: "Header-Name: value". Multiple headers separated by comma. Example: "X-Forwarded-Proto: https".

nvelox.io/response-headers

Inject headers into responses before sending to the client. Same format as request-headers. Example: "X-Server: nvelox".

All annotations example
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: full-example
  annotations:
    nvelox.io/redirect-https: "true"
    nvelox.io/rate-limit-per-second: "100"
    nvelox.io/rate-limit-per-minute: "6000"
    nvelox.io/sticky-cookie: "nvelox-sticky"
    nvelox.io/allow-cidrs: "10.0.0.0/8,172.16.0.0/12"
    nvelox.io/deny-cidrs: "10.0.100.0/24"
    nvelox.io/strip-prefix: "/api"
    nvelox.io/request-headers: "X-Forwarded-Proto: https"
    nvelox.io/response-headers: "X-Server: nvelox"
spec:
  ingressClassName: nvelox
  tls:
    - secretName: example-tls
      hosts:
        - example.com
  rules:
    - host: example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-svc
                port:
                  number: 8080

Helm Chart

Install the ingress controller via Helm. The chart deploys the controller and nvelox as a sidecar in a single pod, plus the required RBAC resources and IngressClass.

Helm install
helm repo add nvelox https://nvelox.github.io/charts
helm repo update

helm install nvelox-ic nvelox/nvelox-ingress-controller \
  --namespace nvelox-system \
  --create-namespace \
  --set image.repository=ghcr.io/nvelox/nvelox-ingress-controller \
  --set image.tag=0.1.0
Key Helm values
# values.yaml
replicaCount: 1

image:
  repository: ghcr.io/nvelox/nvelox-ingress-controller
  tag: 0.1.0
  pullPolicy: IfNotPresent

nvelox:
  image:
    repository: ghcr.io/nvelox/nvelox
    tag: latest

ingressClass:
  name: nvelox
  default: false

resources:
  requests:
    cpu: 100m
    memory: 128Mi

RBAC Permissions

The controller needs cluster-scoped read access to watch Ingress, Secret, Service, and EndpointSlice resources. The Helm chart creates these automatically:

  • ingresses — get, list, watch
  • secrets — get, list, watch
  • services — get, list, watch
  • endpointslices — get, list, watch
  • ingressclasses — get, list, watch
Note: The controller has read-only access. It never modifies Kubernetes resources — it only reads them and writes local nvelox config files.

Troubleshooting

Ingress not picked up

Verify spec.ingressClassName is set to nvelox and the IngressClass resource exists.

503 Bad Gateway

Check that the backend Service has valid endpoints: kubectl get endpoints <service>. Also verify nvelox.io/request-headers: "X-Forwarded-Proto: https" is set if the backend enforces HTTPS.

TLS certificate errors

The TLS secret referenced in spec.tls[].secretName must exist and be of type kubernetes.io/tls with valid tls.crt and tls.key data.

Config not updating

The controller uses a SHA256 hash gate — if the generated config hasn't changed, no reload is triggered. Check controller logs for translation errors.

Debug commands
# Check IngressClass
kubectl get ingressclass nvelox

# Check ingress status
kubectl describe ingress my-app

# Controller logs
kubectl logs -n nvelox-system -l app=nvelox-ingress-controller

# Nvelox sidecar logs
kubectl logs -n nvelox-system -l app=nvelox-ingress-controller -c nvelox

# Verify endpoints
kubectl get endpoints my-app -o wide
Iris