Example project showing how to install & configure Istio using the Kubernetes Gateway API to deploy and access a containerized Spring Boot application using HttpRoute and a local kind cluster
- kind - Kubernetes in Docker
- k9s - definitely a tool you should install locally
- Here are also some kubectl CLI enhancements documented in this gist, like
kubectxto easily switch k8s contexts among others
Fire up a local kind with a control-plane and separate worker node cluster via
kind create cluster --image kindest/node:v1.36.1 --wait 5m --name k8s-deployment-example --config kind-cluster-config.yaml
# show nodes config
kubectl get nodes -o wideThe kind-cluster-config.yaml we use here looks like this:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
extraPortMappings:
- containerPort: 31000
hostPort: 8180
listenAddress: "127.0.0.1"
protocol: TCPWe define a control-plane and separate worker node - and the latter has a extraPortMappings configuration, where we define the hostPort to be 8180, which will let us access our Spring Boot App later (without the need to install a separate external LoadBalancer for kind - like MetalLB or Cloud Provider KIND).
Install Gateway API CRDs, if not present (which is often not installed by default - and also not part of standard kind):
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml
See https://istio.io/latest/docs/setup/additional-setup/download-istio-release/ for your OS:
# Install Istio Control CLI
pamac install istio
# install Istio to your local kind cluster
istioctl install --set profile=minimal -y# Create Istio namespace if not present
kubectl create namespace istio-ingress
# Deploy the Gateway (API) for Istio
kubectl apply -f cluster-setup/istio-gateway.yaml
# Have a look at the deployed gateway (which shouldn't be programmed right now)
kubectl get gateways -n istio-ingressSince we want to be able to access our Spring Boot app later, we need to change the random ports in the Istio Gateway Service:
# The node ports of the Istio Service should be randomly assigned
kubectl -n istio-ingress get svc
# Edit Gateway port to use the kind `containerPort: 31000` definition from kind-cluster-config.yaml, which maps than to 8010
kubectl -n istio-ingress edit svc/gateway-istioOr via k9s:
The 31000 port is defined in the containerPort definition in our kind-cluster-config.yaml, which will than map to hostPort 8180 - this way we will be able to access our Spring Boot App, which we'll deploy in a second.
Now deploy an example app like https://github.com/jonashackt/microservice-api-spring-boot using it's config repository containing the needed Kubernetes Manifests (Service & Deployment): https://github.com/jonashackt/microservice-api-spring-boot-config and this local deployment/kustomization.yaml featuring a reference to config repository containing the k8s manifests for our app - pinned with the branch name (you can also use a SHA via microservice-api-spring-boot-config//deployment?ref=abc123def4567890abc123def4567890abc123def4 or a git tag microservice-api-spring-boot-config//deployment?ref=v1.2.0)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://github.com/jonashackt/microservice-api-spring-boot-config//deployment?ref=mainApply it to our local kind cluster via:
kubectl apply -k deploymentThis should deploy our Spring Boot app, which could be watched e.g. via k9s:
Since we now deployed the Istio Gateway as a API frontend and our Spring Boot App as the backend, we need to configure the Gateway to know, where to route incoming traffic. Therefore we use a HttpRoute defined in deployment/microservice-api-spring-boot-httproute.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: microservice-api-spring-boot-http
namespace: default
spec:
parentRefs:
- name: gateway
namespace: istio-ingress
hostnames: ["127.0.0.1"] # <-- without hostname the service would not be accessible
rules:
- matches:
- path:
type: PathPrefix
value: /api # <-- This will map our Spring Boot App's @RequestMapping("/api")
backendRefs:
- name: microservice-api-spring-boot
port: 80If you want to know more about the different matchers in a HttpRoute, have a look at this post
Apply it to our kind cluster:
kubectl apply -f deployment/microservice-api-spring-boot-httproute.yamlNormally, the HttpRoute should be part of the config repo like https://github.com/jonashackt/microservice-api-spring-boot-config, since it's application specific (I just placed it in this repo for demo purposes, since the config repo is used for other Ingress setups (like Traefik) also)
# Run the following and have a look, if the Status contains a "Route was valid" message
kubectl describe httproute microservice-api-spring-boot-http
# if this is the case, everything should be prepared to access your appFinally access your Spring Boot App in your Browser or via curl:
Using the defined endpoint api/hello should give us an successful response:
https://gist.github.com/jonashackt/df283eb3f5ed587ee1f93cbcfc23be08
https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/
https://istio.io/latest/docs/reference/config/networking/gateway/
https://oneuptime.com/blog/post/2026-02-24-how-to-configure-httproute-with-istio-gateway-api/view
https://oneuptime.com/blog/post/2026-02-20-metallb-kind-local-development/view
https://oneuptime.com/blog/post/2026-02-09-kustomize-remote-bases-git/view




