Connect Frontend, Backend, CORS, and Ingress
Deploy both images to Minikube, route two hostnames through ingress, and allow the browser origin explicitly.
Kubernetes Services solve Pod-to-Pod addressing, but a browser needs externally resolvable HTTP routes. The chart creates one ingress hostname per component: simple-app.test for React and api.simple-app.test for FastAPI.
Download this chapter's files
Use your browser to download either ivia-chapter-09.tar.gz or ivia-chapter-09.zip. The archive is self-contained; you do not need this tutorial repository.
Open a terminal after the browser download:
cd ~/Downloads
tar -xzf ivia-chapter-09.tar.gz
cd ivia-chapter-09
All remaining relative paths in this chapter start from that extracted directory.
The challenge
Challenge: deploy the full-stack snapshot and load the frontend through ingress with a successful cross-origin API request.
Prerequisites
- Running Minikube, kubectl, Helm, and Docker.
- The node label
ivia.ch/nodetype=app. - Ports 80 and 443 available to Minikube's ingress path.
- The full-stack snapshot; no local frontend/backend containers should occupy ports needed for testing.
Learning goals
- Build frontend and backend images into Minikube
- Enable nginx ingress
- Map test hostnames
- Trace browser-to-API traffic
- Diagnose CORS separately from networking
Build images where Minikube can use them
minikube image build -t simple-backend:local fullstack-app/backend
minikube image build -t simple-frontend:local fullstack-app/frontend
minikube image ls | grep -E 'simple-(frontend|backend)'
Enable ingress and deploy
minikube addons enable ingress
kubectl wait --namespace ingress-nginx \
--for=condition=Ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=180s
kubectl label node minikube ivia.ch/nodetype=app --overwrite
helm upgrade --install simple-app \
oci://harbor.ivia.ch/ivia-generic-helm-chart/ivia-generic-helm-chart \
--version 4.8.0 -n tutorial --create-namespace \
--atomic --timeout 5m \
-f fullstack-app/values.yaml
kubectl get pods,services,ingresses -n tutorial
Values mount a runtime config.js containing http://api.simple-app.test. Backend CORS_ORIGINS permits only http://simple-app.test. The ingress annotations disable HTTPS redirection for this local exercise; production should use valid TLS.
Resolve local hostnames
First validate without changing DNS:
MINIKUBE_IP=$(minikube ip)
curl --fail --resolve simple-app.test:80:$MINIKUBE_IP http://simple-app.test/
curl --fail --resolve api.simple-app.test:80:$MINIKUBE_IP http://api.simple-app.test/health
curl --fail --resolve api.simple-app.test:80:$MINIKUBE_IP \
-H 'Origin: http://simple-app.test' \
-H 'Access-Control-Request-Method: GET' \
-X OPTIONS -i http://api.simple-app.test/api/greeting
For browser access, append both names to /etc/hosts:
echo "$(minikube ip) simple-app.test api.simple-app.test" | sudo tee -a /etc/hosts
Open http://simple-app.test and inspect the browser Network panel. The document comes from the frontend host; /api/greeting comes from the API host.
Expected validation
Both Pods are 1/1 Running. Both Ingress objects list their host. The preflight response includes access-control-allow-origin: http://simple-app.test, and the browser displays Hello from a configured FastAPI pod!.
Troubleshooting and common pitfalls
- Ingress has no address: wait for the addon controller and inspect
kubectl get pods -n ingress-nginx. - Browser DNS error: verify both host entries and flush browser DNS cache; curl
--resolveconfirms routing independently. - HTTP redirects to HTTPS: ensure values include
nginx.ingress.kubernetes.io/ssl-redirect: "false". - CORS failure despite HTTP 200: backend must permit the exact frontend origin, including scheme and port.
ImagePullBackOff: verify local images andIfNotPresentpull policy.- Docker-driver ingress unreachable: run
minikube tunnelin a separate terminal if your platform requires it, then use127.0.0.1for hosts. - Editing frontend source for API URL: change the chart-managed runtime ConfigMap instead; one image should serve multiple environments.
You now have a complete request path from browser to ingress to two Kubernetes Services. That is real full-stack platform work.