This post is part of a series on deploying JupyterHub on Jetstream2:
- Deploy Kubernetes on Jetstream2
- Install Traefik Ingress Controller
- Deploy JupyterHub
- Setup HTTPS with cert-manager
This guide covers how to install Traefik as an ingress controller on a Jetstream2 Kubernetes cluster and configure DNS. Traefik replaces ingress-nginx, which has been retired. Traefik supports both the standard Kubernetes Ingress API and the newer Gateway API, making it a forward-compatible choice.
This guide assumes you already have a running cluster — see Deploy Kubernetes on Jetstream2 if you need to create one first. Make sure KUBECONFIG is set and kubectl get nodes works.
Install Traefik
Install the Traefik Helm chart:
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm upgrade --install traefik traefik/traefik \
--namespace traefik --create-namespaceThis deploys Traefik (this tutorial tested with v3.7) and creates a Kubernetes Service of type LoadBalancer. On Jetstream2, this automatically provisions an OpenStack Octavia load balancer with a floating IP.
Wait for the external IP to be assigned (takes about 2 minutes):
kubectl get svc -n traefik traefik -wOnce the EXTERNAL-IP column shows an address, note it:
export IP=$(kubectl get svc -n traefik traefik -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $IP149.165.173.224
Verify the Traefik pod is running:
kubectl get pods -n traefikNAME READY STATUS RESTARTS AGE
traefik-798b4cb98f-8bwfd 1/1 Running 0 2m46s
Use a Fixed Floating IP
By default, Traefik creates a new OpenStack load balancer with a random floating IP. If you delete and recreate the cluster, this IP changes. To use a fixed IP instead:
- Create a floating IP in OpenStack:
openstack floating ip create public
export FIXED_IP=<FLOATING_IP>- Find the Traefik load balancer:
export LB=$(openstack loadbalancer list --name traefik -f value -c id)Note: The
openstack loadbalancercommand requirespython-octaviaclient. Install it withpip install python-octaviaclientif the command is not found.
- Associate the fixed IP with the load balancer’s VIP port:
LB_VIP_PORT_ID=$(openstack loadbalancer show $LB -c vip_port_id -f value)
EXISTING_FIP=$(openstack floating ip list --port $LB_VIP_PORT_ID -f value -c ID)
if [ -n "$EXISTING_FIP" ]; then
openstack floating ip unset --port $EXISTING_FIP
fi
openstack floating ip set --port $LB_VIP_PORT_ID $FIXED_IP
export IP=$FIXED_IPAlternative — request the IP at install time: You can instead ask Traefik to request a specific floating IP by passing
--set service.spec.loadBalancerIP=$FIXED_IPto thehelm upgrade --installcommand in the Install Traefik section. This flag only takes effect on a fresh install; if Traefik is already running,helm uninstall traefikfirst, then reinstall with the flag. (Discovered by Ana V. Espinoza during live testing — see the migration guide.)
Configure DNS
Using the Jetstream Subdomain
Jetstream2 provides a subdomain for each project:
subdomain.$PROJ.projects.jetstream-cloud.org
where PROJ is the ID of your Jetstream2 allocation (all lowercase). Create a DNS record pointing to the Traefik IP:
export PROJ="xxx000000"
export SUBDOMAIN="jhub"
openstack recordset create $PROJ.projects.jetstream-cloud.org. $SUBDOMAIN --type A --record $IP --ttl 3600If you get a “Duplicate recordset” error, update the existing record:
openstack recordset set $PROJ.projects.jetstream-cloud.org. $SUBDOMAIN.$PROJ.projects.jetstream-cloud.org. --record $IPUsing a Custom Domain
If you have a custom domain, create an A record pointing to $IP with your DNS provider.
Test the Traefik Ingress
Deploy a simple echo server to verify that Traefik and DNS are working. The repository includes an echo-test.yaml manifest that creates a Deployment, a Service, and an Ingress with ingressClassName: traefik.
Edit the host field in echo-test.yaml to match your subdomain, then deploy:
kubectl create -f echo-test.yamlWait for the pod to be ready:
kubectl get pods -wCheck that the Ingress got the Traefik IP:
kubectl get ingressNAME CLASS HOSTS ADDRESS PORTS AGE
echo-ingress traefik testpage.cis230085.projects.jetstream-cloud.org 149.165.173.224 80 4s
Then test with curl:
curl http://testpage.$PROJ.projects.jetstream-cloud.orgTesting Traefik Ingress on Jetstream!
Once verified, clean up the test deployment:
kubectl delete -f echo-test.yamlWith Traefik installed and DNS configured, continue to Deploy JupyterHub. You can also skip ahead to Setup HTTPS with cert-manager if you already have JupyterHub running.