Lesson 09 Ingress Resources
Theme:

Lab Guide: Ingress Resources

Build and test Ingress templates in a Helm chart with path-based routing, TLS, and annotations

Prerequisites

minikube Users

If using minikube, enable the Ingress addon: minikube addons enable ingress. This installs the nginx Ingress controller automatically.

Exercise 1: Basic Ingress Template

Create a Helm chart with a conditional Ingress resource that routes traffic based on hostname and path.

Step 1

Create a new Helm chart:

helm create webapp
cd webapp

Step 2

Replace the contents of values.yaml with the following ingress configuration (keep the existing image and service sections):

# Add/replace the ingress section in values.yaml
ingress:
  enabled: true
  className: nginx
  annotations: {}
  hosts:
    - host: webapp.local
      paths:
        - path: /
          pathType: Prefix
          port: 80
  tls: []

Step 3

Open templates/ingress.yaml. If Helm generated one, review it. If not, create it with the following content:

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "webapp.fullname" . }}
  labels:
    {{- include "webapp.labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if .Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ .path }}
            pathType: {{ .pathType }}
            backend:
              service:
                name: {{ include "webapp.fullname" $ }}
                port:
                  number: {{ .port | default 80 }}
          {{- end }}
    {{- end }}
{{- end }}

Step 4

Validate the template renders correctly:

helm template my-webapp . | grep -A 30 "kind: Ingress"

Step 5

Verify that disabling ingress removes the resource:

helm template my-webapp . --set ingress.enabled=false | grep "kind: Ingress"
# Should produce no output

Step 6

Install the chart and test:

helm install my-webapp .
kubectl get ingress
kubectl describe ingress my-webapp

Checkpoint

You should see an Ingress resource with host webapp.local and a single path rule pointing to your service on port 80.

Exercise 2: Multi-Host with TLS

Extend the chart to support two hosts with TLS termination.

Step 1

Create a values override file named values-multi.yaml:

ingress:
  enabled: true
  className: nginx
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  hosts:
    - host: www.webapp.local
      paths:
        - path: /
          pathType: Prefix
          port: 80
    - host: api.webapp.local
      paths:
        - path: /v1
          pathType: Prefix
          port: 80
        - path: /healthz
          pathType: Exact
          port: 80
  tls:
    - secretName: webapp-tls
      hosts:
        - www.webapp.local
        - api.webapp.local

Step 2

Create a self-signed TLS secret for testing:

openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout tls.key \
  -out tls.crt \
  -subj "/CN=webapp.local"

kubectl create secret tls webapp-tls \
  --cert=tls.crt \
  --key=tls.key

Step 3

Render the template with the multi-host values:

helm template my-webapp . -f values-multi.yaml

Verify the output contains:

Step 4

Upgrade the release with the new values:

helm upgrade my-webapp . -f values-multi.yaml
kubectl get ingress my-webapp -o yaml

Checkpoint

The Ingress should now show two hosts, a TLS section, and the ssl-redirect annotation. If using minikube, add entries to /etc/hosts pointing both hostnames to the minikube IP to test with curl.

Exercise 3: Annotations for Rate Limiting and Auth

Add rate limiting and basic authentication annotations via values.

Step 1

Create an htpasswd secret for basic authentication:

# Install htpasswd if needed: brew install httpd (macOS) or apt install apache2-utils
htpasswd -cb auth admin secretpassword
kubectl create secret generic basic-auth --from-file=auth
rm auth

Step 2

Create a values override file named values-secure.yaml:

ingress:
  enabled: true
  className: nginx
  annotations:
    # Rate limiting
    nginx.ingress.kubernetes.io/limit-rps: "5"
    nginx.ingress.kubernetes.io/limit-connections: "3"
    # Basic auth
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Restricted Area"
    # Upload size
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
  hosts:
    - host: secure.webapp.local
      paths:
        - path: /
          pathType: Prefix
          port: 80
  tls: []

Step 3

Render and verify annotations appear in the output:

helm template my-webapp . -f values-secure.yaml | grep -A 20 "annotations:"

You should see all six annotations rendered under metadata.annotations.

Step 4

Upgrade and test the authentication:

helm upgrade my-webapp . -f values-secure.yaml

# Add to /etc/hosts: <minikube-ip> secure.webapp.local
# Test without auth (should get 401):
curl -k http://secure.webapp.local

# Test with auth (should get 200):
curl -k -u admin:secretpassword http://secure.webapp.local

Step 5

Test rate limiting by sending rapid requests:

for i in $(seq 1 20); do
  curl -s -o /dev/null -w "%{http_code}\n" \
    -u admin:secretpassword \
    http://secure.webapp.local
done
# After ~5 requests per second, you should see 503 responses

Checkpoint

You should observe 401 responses without credentials, 200 with correct credentials, and 503 responses when the rate limit is exceeded.

Cleanup

helm uninstall my-webapp
kubectl delete secret webapp-tls basic-auth
rm -f tls.crt tls.key
cd .. && rm -rf webapp