This lab guides you through setting up Kubernetes Ingress for routing external traffic to internal services. We will deploy sample applications, install an Nginx Ingress controller, and configure host-based routing and TLS.
1. Prerequisites: Kubernetes Cluster
Ensure you have a running Kubernetes cluster. You can use Minikube, Docker Desktop's Kubernetes, or a cloud-managed cluster. For on-premises setups, projects like Tigera Calico for On-Premises Kubernetes (link from original document) can be helpful, but any conformant cluster will do.
2. Initial Cluster Inspection
List Nodes:
Verify your nodes are ready.
kubectlgetno
List Namespaces:
See the existing namespaces in your cluster.
kubectlgetnamespaces
3. Deploy Sample Applications (app1 & app2)
We'll create two simple Nginx applications, each in its own namespace, and expose them via ClusterIP services.
Create and Deploy app1:
kubectlcreatensapp1# The following YAMLs deploy Nginx and expose it via a ClusterIP service named 'my-nginx-clusterip'kubectlapply-napp1-fhttps://raw.githubusercontent.com/xxradar/kuberneteslearning/master/nginx-deployment.yamlkubectlapply-napp1-fhttps://raw.githubusercontent.com/xxradar/kuberneteslearning/master/nginx-expose-clusterip.yaml
Test connectivity to the services from within the cluster (e.g., using a temporary pod with siege or curl):
# Test app1's service (my-nginx-clusterip.app1.svc.cluster.local or just my-nginx-clusterip from within app1 ns)kubectlrunsiege-app1-it-napp1--rm--imagedockersec/siege--siege-c1-r1http://my-nginx-clusterip# Test app2's servicekubectlrunsiege-app2-it-napp2--rm--imagedockersec/siege--siege-c1-r1http://my-nginx-clusterip
(Added -c1 -r1 to siege for a quick test.)
4. Install Nginx Ingress Controller
We will use the Nginx Ingress controller.Note: The manifest URL below points to version 0.32.0. For production or newer clusters, always refer to the official Nginx Ingress Controller deployment documentation for the latest recommended version and instructions.
Verify the Ingress controller installation:
To simplify access to the Ingress controller via its NodePorts:
(Made variable names more descriptive and robust by checking port names first.)
Test direct access to the Ingress controller's NodePorts (replace YOUR_NODE_IP with the IP of one of your Kubernetes nodes; if using Minikube/Kind, localhost or 127.0.0.1 might work).
(Clarified localhost usage.)
5. Configure Host-Based Routing (app1)
Create app1_ingress.yaml:Note on apiVersion:extensions/v1beta1 for Ingress is deprecated and removed in Kubernetes v1.22+. Use networking.k8s.io/v1. The structure of the backend field also changes.
Apply the Ingress resource for app1:
Test access to app1:
(Replace YOUR_NODE_IP with your node's IP or localhost if appropriate.)
6. Configure Host-Based Routing (app2)
Create app2_ingress.yaml:
Apply the Ingress resource for app2:
Test access to app1 and app2:
(Replace YOUR_NODE_IP with your node's IP or localhost.)
You can check the Nginx configuration generated inside the Ingress controller pod to see how it's routing traffic.
(Made step 10 into a proper section and added command to get pod name.)
8. Configure TLS for an Ingress Resource
Create a Self-Signed Certificate and Key:
For testing, we'll create a self-signed certificate. For production, use certificates from a trusted CA.
Create a Kubernetes Secret for TLS:
Store the certificate and key in a TLS secret in the app1 namespace.
Create tlsapp1_ingress.yaml:Note on apiVersion:networking.k8s.io/v1beta1 is also deprecated. Use networking.k8s.io/v1.
Apply the TLS Ingress resource:
Update Your /etc/hosts File:
To test tlsapp1.dockersec.me locally, you need to map this hostname to an IP address that routes to your Ingress controller (e.g., a Node IP, or 127.0.0.1 if using Minikube/Kind or port-forwarding to a node).
Important: Add the following line to your /etc/hosts file on the machine where you are running curl:
(Example: 127.0.0.1 tlsapp1.dockersec.me or 192.168.1.100 tlsapp1.dockersec.me)
Test TLS Access:
(Replace YOUR_NODE_IP_OR_LOCALHOST with the IP used in /etc/hosts.)
kubectl get namespaces # You should see 'ingress-nginx'
kubectl get po -n ingress-nginx -o wide
kubectl get svc -n ingress-nginx
# Ensure the service name 'ingress-nginx-controller' is correct for your installation
export WEB_NODE_PORT=$(kubectl get svc ingress-nginx-controller -n ingress-nginx -o=jsonpath='{.spec.ports[?(@.name=="http")].nodePort}')
export HTTPS_NODE_PORT=$(kubectl get svc ingress-nginx-controller -n ingress-nginx -o=jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
# If port names 'http'/'https' are not set, you might need to use port numbers:
# export WEB_NODE_PORT=$(kubectl get svc ingress-nginx-controller -n ingress-nginx -o=jsonpath="{.spec.ports[?(@.port==80)].nodePort}")
# export HTTPS_NODE_PORT=$(kubectl get svc ingress-nginx-controller -n ingress-nginx -o=jsonpath="{.spec.ports[?(@.port==443)].nodePort}")
echo "HTTP NodePort: $WEB_NODE_PORT"
echo "HTTPS NodePort: $HTTPS_NODE_PORT"
# This should return a 404 from the Ingress controller as no Ingress rules are configured yet.
curl -kv http://YOUR_NODE_IP:$WEB_NODE_PORT
# This might fail or show a self-signed certificate error from the Ingress controller.
curl -kv https://YOUR_NODE_IP:$HTTPS_NODE_PORT
kubectl apply -f app1_ingress.yaml -n app1
# Note: if namespace is in metadata, -n app1 on apply is optional but good practice.
kubectl get ingress -n app1
curl -kv -H "Host: app1.dockersec.me" http://YOUR_NODE_IP:$WEB_NODE_PORT
# This should now route to app1.
curl -kv -H "Host: app2.dockersec.me" http://YOUR_NODE_IP:$WEB_NODE_PORT
# This should still result in a 404 from the Ingress controller.
curl -kv -H "Host: app1.dockersec.me" http://YOUR_NODE_IP:$WEB_NODE_PORT # Should work
curl -kv -H "Host: app2.dockersec.me" http://YOUR_NODE_IP:$WEB_NODE_PORT # Should also work now
# Find the name of your Ingress controller pod
NGINX_INGRESS_POD=$(kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx -o jsonpath='{.items[0].metadata.name}')
# Inspect the nginx.conf
kubectl exec -n ingress-nginx "$NGINX_INGRESS_POD" -- cat /etc/nginx/nginx.conf
# This command uses the hostname for SNI and connects to the HTTPS NodePort.
# The -k flag is used because the certificate is self-signed.
curl -kv https://tlsapp1.dockersec.me:$HTTPS_NODE_PORT
# Alternative using Host header (less common for HTTPS direct to IP:Port but can work if SNI is primary)
# curl -kv -H "Host: tlsapp1.dockersec.me" https://YOUR_NODE_IP_OR_LOCALHOST:$HTTPS_NODE_PORT