Intro
Kubernetes Ingress resources route external HTTP and HTTPS traffic to services inside a cluster. The IngressClass object determines which ingress controller should implement a particular Ingress. Without a correct IngressClass, an Ingress resource may be ignored or handled by the wrong controller, causing traffic failures that are hard to debug.
This guide is for developers, DevOps engineers, and platform teams who operate Kubernetes clusters. It focuses on the commands and checks needed to observe IngressClass state, apply safe configuration changes, diagnose common failures, and recover from misconfigurations. Instead of a broad overview, each section includes concrete kubectl commands, example outputs, and decision paths for when an expected state is not met.
Operational safety is the through line: observe before changing, limit the blast radius, use placeholders instead of secrets, verify results, and document recovery steps. The goal is not just to list commands, but to show how they fit into a repeatable troubleshooting workflow for ingress traffic.
Version and Environment Inventory
Before changing anything, collect the relevant version, topology, and current state. This section covers how to identify which ingress controller is installed, which IngressClass resources exist, and how to verify compatibility.
First, check the Kubernetes server version and client version. IngressClass was introduced in Kubernetes 1.18 and became more prominent in 1.19 with the networking.k8s.io/v1 API. If you are on an older cluster, the API group may be different.
kubectl version --short
Example output:
Client Version: v1.24.0
Server Version: v1.24.0
Next, list all IngressClass resources in the cluster. IngressClass is a cluster-scoped resource, so no namespace is needed.
kubectl get ingressclass
Example output:
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 2d
aws ingress.k8s.aws/alb <none> 2d
The controller field shows which ingress controller will process Ingresses that reference this class. Parameters can link to additional configuration such as a ConfigMap. If the IngressClass is marked as default, it will have an annotation ingressclass.kubernetes.io/is-default-class: "true".
To see the details of a specific IngressClass, including annotations and parameters:
kubectl describe ingressclass nginx
Example snippet:
Name: nginx
Labels: <none>
Annotations: ingressclass.kubernetes.io/is-default-class: true
Controller: k8s.io/ingress-nginx
Events: <none>
To confirm which ingress controller pods are running and in which namespace:
kubectl get pods -A -l app.kubernetes.io/name=ingress-nginx
Example output:
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx ingress-nginx-controller-78f5c7b9d-x2k9d 1/1 Running 0 2d
Prerequisites for using Ingress and IngressClass include:
- A running Kubernetes cluster, version 1.19 or later for stable IngressClass.
- An ingress controller deployed (nginx-ingress, AWS ALB, Traefik, etc.).
- Proper RBAC permissions to view and modify Ingress, Service, and IngressClass objects.
- A default StorageClass is not required but Ingress may reference TLS secrets.
Keep the local test small. Before touching a production ingress, test with a minimal Ingress manifest in a dedicated namespace. For example, create a simple echo service and an Ingress with a specific IngressClass, then test with kubectl port-forward to verify traffic routing before exposing a cloud load balancer.
Safe Configuration Path
This section covers how to safely modify IngressClass-related configuration without disrupting traffic. The core principle is to make one scoped change at a time and verify its effect before moving on.
1. Identify the current IngressClass used by an Ingress
An Ingress resource can reference an IngressClass by name using the ingressClassName field. If the field is empty, the default IngressClass is used (if defined). Check which class an existing Ingress is using:
kubectl get ingress <ingress-name> -n <namespace> -o jsonpath='{.spec.ingressClassName}'
Example:
kubectl get ingress my-app -n dev -o jsonpath='{.spec.ingressClassName}'
Output might be empty if the default is being used. Then check the default class:
kubectl get ingressclass -o jsonpath='{.items[?(@.metadata.annotations.ingressclass\.kubernetes\.io/is-default-class=="true")].metadata.name}'
2. Change an Ingress to use a different IngressClass
Suppose you have two ingress controllers, nginx and aws, and you want to switch an Ingress from the default to aws. First, create a patch file or use a strategic merge patch.
kubectl patch ingress my-app -n dev --type='json' -p='[{"op": "replace", "path": "/spec/ingressClassName", "value":"aws"}]'
This is a low-risk change because you can quickly revert by setting the value back to the previous one. Always verify that the controller referenced by the new class is running and healthy before patching.
3. Set a default IngressClass
If multiple IngressClasses exist and you want to define a default for new Ingresses, annotate one class as default.
kubectl annotate ingressclass nginx ingressclass.kubernetes.io/is-default-class=true
To remove default status from another class:
kubectl annotate ingressclass aws ingressclass.kubernetes.io/is-default-class-
The dash at the end removes the annotation key. Note that only one IngressClass can be default at a time. If you set a new default while another exists, the old default loses its default status automatically.
4. Update IngressClass parameters
Some ingress controllers support additional configuration via a parameters object, often a ConfigMap. For example, nginx-ingress can use a ConfigMap to set proxy timeouts or SSL settings. To update parameters safely:
kubectl edit configmap <configmap-name> -n <namespace>
Make a backup first:
kubectl get configmap <configmap-name> -n <namespace> -o yaml > cm-backup.yaml
After editing, the ingress controller will reload its configuration (usually automatically). Verify the reload by checking controller logs:
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=20
Look for lines like:
I0825 10:00:00.123456 7 controller.go:149] "Configuration changes detected, backend reload required"
5. Delete an unused IngressClass
Before deleting, ensure no Ingress resources reference it. List all Ingresses with ingressClassName=aws:
kubectl get ingress -A -o json | jq '.items[] | select(.spec.ingressClassName == "aws") | .metadata.name'
If none, you can delete the IngressClass:
kubectl delete ingressclass aws
Recovery is possible by recreating the IngressClass from a manifest or from a previous YAML export.
Verification and Diagnostics
After making changes, you need to verify that traffic is flowing correctly and diagnose any issues. This section provides a structured approach.
Step 1: Check Ingress resource status
The Ingress status field reports the address assigned by the controller. If the status is empty or shows an error, the controller may not be processing the Ingress.
kubectl describe ingress my-app -n dev
Look at the Events section and the Address field. Example of a healthy Ingress:
Name: my-app
Namespace: dev
Address: a1b2c3d4e5f6g7h8.elb.amazonaws.com
Default backend: default-http-backend:80
Rules:
Host Path Backends
---- ---- --------
example.com
/ my-service:80 (10.0.0.1:8080)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 10m ingress-controller Scheduled for sync
If the Address remains empty, check controller logs for errors.
Step 2: Verify end-to-end connectivity
Use curl from within the cluster to test the service directly and through the ingress controller. First, find the controller pod name and exec into it or use port-forward.
kubectl port-forward -n ingress-nginx service/ingress-nginx-controller 8080:80
In another terminal:
curl -H "Host: example.com" http://localhost:8080/
Expected output from the echo service:
Hello from my-service!
If you receive a 404 or 503, check if the service selector matches the pods and if the service is reachable.
Step 3: Check ingress controller logs
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=50
Common log messages for missing IngressClass:
E0825 10:05:00.123456 7 controller.go:114] "Ignoring ingress because of ingress class" ingress="dev/my-app" ingressClass="aws"
This indicates that the Ingress references a class not handled by this controller. Either change the class or deploy the correct controller.
Step 4: Validate DNS and TLS
If using host-based routing, ensure the DNS record points to the ingress controller's external address. Use dig or nslookup:
dig example.com
Check that the resolved IP matches the Ingress status address. For TLS, verify the certificate is valid:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
Step 5: Debug with events for IngressClass
IngressClass itself rarely has events, but related resources do.
kubectl get events -n dev --field-selector involvedObject.name=my-app
This shows sync events, errors, and warnings.
Failure Modes and Recovery
This section outlines common failure scenarios related to IngressClass and how to recover.
Failure: Ingress ignored because no IngressClass is set and no default class exists
Symptom: Ingress status stays empty, no errors on Ingress, but no traffic routing. Diagnosis:
kubectl get ingressclass
If no class has the default annotation, then an Ingress with empty ingressClassName is ignored.
Check if your Ingress has ingressClassName set:
kubectl get ingress my-app -n dev -o yaml | grep ingressClassName
If empty, set the class explicitly:
kubectl patch ingress my-app -n dev -p '{"spec":{"ingressClassName":"nginx"}}'
Or set a default class as described earlier.
Failure: Wrong controller selected
Symptom: Traffic does not reach the backend, controller logs show "Ignoring ingress because of ingress class" with a class name that does not match the intended controller. Diagnosis:
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=20 | grep ingress
Recovery: Change the Ingress's ingressClassName to a class that the running controller manages. Use kubectl patch as shown, or edit the manifest.
Failure: IngressClass parameters misconfigured
Symptom: Controller reload fails, error in logs about invalid parameters. Diagnosis: Check controller logs for parameter parsing errors. For nginx, it may say "invalid ConfigMap" or "nginx reload failed". Recovery: Revert the ConfigMap to a known-good version:
kubectl apply -f cm-backup.yaml
Then check controller pod logs for successful reload.
Failure: IngressClass deleted while Ingresses still reference it
Symptom: Ingress resources show a warning or are not processed. Diagnosis:
kubectl get ingress -A -o json | jq '.items[] | select(.spec.ingressClassName == "missing-class") | [.metadata.name, .metadata.namespace]'
Recovery: Recreate the IngressClass or update the Ingresses to use an existing class. To quickly recreate with minimal manifest:
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx
EOF
Failure: RBAC blocks controller from reading IngressClass
Symptom: Controller logs show forbidden errors when trying to list IngressClass. Diagnosis:
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=20 | grep forbidden
Recovery: Ensure the controller's ServiceAccount has RBAC permissions to get, list, watch IngressClass. Check the ClusterRole and ClusterRoleBinding for the ingress controller.
kubectl describe clusterrole ingress-nginx
If missing, add a rule:
- apiGroups: ["networking.k8s.io"]
resources: ["ingressclasses"]
verbs: ["get", "list", "watch"]
Failure: Default IngressClass conflict
Symptom: Ingresses are routed unpredictably, or controllers log conflicts. Diagnosis:
kubectl get ingressclass -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.ingressclass\.kubernetes\.io/is-default-class}{"\n"}{end}'
If more than one shows true, remove the default annotation from all but the one you intend.
Operations Checklist
Use this checklist before and after making changes to IngressClass or related Ingress resources.
Pre-change checklist
- [ ] Verify cluster version is 1.19+ for stable IngressClass API.
- [ ] List all IngressClasses and identify the default:
kubectl get ingressclass. - [ ] Confirm the ingress controller for the target class is running and healthy.
- [ ] For a specific Ingress, check current
ingressClassNameand note it. - [ ] Backup any ConfigMap or Ingress manifest that will be modified.
- [ ] Ensure you have edit permissions and a rollback plan.
Change execution checklist
- [ ] Apply one change at a time (e.g., patch one Ingress, update one ConfigMap).
- [ ] Use targeted commands, not broad deletions.
- [ ] If changing default class, verify only one class has the default annotation afterward.
- [ ] Record the timestamp and the exact command used.
Post-change verification checklist
- [ ] Check Ingress status address is populated:
kubectl get ingress <name> -n <ns>. - [ ] Inspect controller logs for errors or reload messages.
- [ ] Test connectivity with curl/ping and verify expected response.
- [ ] If TLS is involved, verify certificate validity.
- [ ] Check events for the Ingress resource.
- [ ] Monitor for a few minutes to ensure no intermittent failures.
Recovery verification
If a change fails, revert to the previous state using backups or reverse patches. Then run the same verification steps to confirm recovery. Document the failure mode and the rollback command for future incident response.
Conclusion
Kubernetes IngressClass is a small but critical piece of ingress routing. A misconfigured class can silently break traffic or route to the wrong controller. The commands and workflows in this guide provide a systematic way to observe, change, verify, and recover IngressClass-related configuration.
Start with low-risk verification: list IngressClasses, check the default, inspect one Ingress, and follow a single change through to successful traffic routing. Keep a record of current state, use backups, and always define recovery steps before making changes. By applying these principles, you will reduce downtime and increase confidence when managing ingress in Kubernetes.
Next steps: choose a test Ingress in a non-production namespace, switch its IngressClass, and watch how the controller reacts. Then simulate a missing class and practice recovery. Use the operations checklist as a foundation for your team's runbook.