Using an Istio gateway to access a Spring Boot application in minikube
In the last days I was trying to run and experiment with Istio. I followed the getting started guide by Istio itself, but I couldn’t make it run with kind. I followed some guides, but I didn’t want to install explicitly an nginx ingress, because I like it when things are as lightweight as possible when I’m learning new stuff.
So here’s a guide how to run a Spring Boot application and access it through an Istio Gateway.
Setting up the environment
To follow this guide, you need an installation of kubectl. The other needed tools will be installed in the following steps.
Install and set up minikube
Install minikube:
- Download the latest release.
- Copy the release to a directory (like
C:\minikube). - Execute the
minikubecommand to assure that it runs. - Start a minikube cluster:
minikube start - Execute
kubectl get pods --all-namespacesto assure that the command runs against your cluster. - Allow the invocation of the
dockercommand:minikube -p minikube docker-env --shell powershell | Invoke-Expression. From now on, everydockercommand in this window will be executed against your minikube. - In a new CLI window execute the following command to open up access to your ingress in the minikube instance:
minikube tunnel
Install istioctl
- Download the latest istioctl release.
- Install the istioctl CLI tool.
Install istio in Kubernetes cluster
Now you are ready to bring Istio into your Kubernetes cluster!
- Install
istioctlwith profile demo in the cluster:
istioctl install --set profile=demo -y
- Verify it via the following command:
kubectl get pods --all-namespaces
The output should be something like the following:
NAMESPACE NAME READY STATUS RESTARTS AGE
istio-system istio-egressgateway-7984f88c64-9hrmx 1/1 Running 0 4m47s
istio-system istio-ingressgateway-57988c96c4-g9d7m 1/1 Running 0 4m47s
istio-system istiod-7d5c56bcbf-v9dpb 1/1 Running 0 5m3s
- For our experiment we’ll use the namespace
sidecar-test.
Create the namespace:
kubectl create namespace sidecar-test
- Add a label to allow Istio to auto-inject an Envoy sidecar proxy to your Pods in the
sidecar-testnamespace:
kubectl label namespace sidecar-test istio-injection=enabled
Set up the application
Now it’s time to set up the application. I’ll not make stuff with 2 or more services, as I want a basic setup as a starting point for further experiments.
So, create a basic Spring Boot application with a RestController and /books route. You can also use any other application with this route. Just make sure, that the following steps are granted:
- Initialize your Spring Boot application
- Create the controller:
package de.dkwr.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@org.springframework.web.bind.annotation.RestController
@RequestMapping("books")
public class RestController {
@GetMapping()
public String getBook() {
return "Hello world!";
}
}
- Configure the application to run on Port 8080 (this is the default port for a Spring Boot application)
- Build a Docker image with the following Dockerfile:
FROM openjdk:17
COPY ./build/libs/demo-0.0.1-SNAPSHOT.jar ./src/
WORKDIR /src
CMD ["java", "-jar", "./demo-0.0.1-SNAPSHOT.jar"]
And the following command:
docker build . -t demo-v1:latest
Run the application in the cluster
Now you have a cluster, a running istio daemon and a docker image of an application, waiting to be deployed in your cluster. Let’s do this!
Create the Kubernetes resource files:
service.yml:
apiVersion: v1
kind: Service
metadata:
name: demo
namespace: sidecar-test
spec:
ports:
- port: 8080
name: http
selector:
app: demo
deployment.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
namespace: sidecar-test
spec:
revisionHistoryLimit: 3
replicas: 1
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
containers:
- name: demo
image: demo-v1:latest
imagePullPolicy: Never
ports:
- containerPort: 8080
Apply the files:
kubectl apply -f service.yml
kubectl apply -f deployment.yml
Check that the pod is running:
kubectl get pods -n sidecar-test
And that the route is available:
kubectl exec "$(kubectl get pod -l app=demo -n sidecar-test -o jsonpath='{.items[0].metadata.name}')" -c demo -n sidecar-test -- curl -sS demo:8080/books
This should output Hello world!
But we want to make it available through the Istio ingress gateway. So let’s define it:
gw.yml:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: demo-gateway
namespace: sidecar-test
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: demo
namespace: sidecar-test
spec:
hosts:
- "*"
gateways:
- demo-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
host: demo
port:
number: 8080
The gateway is called demo-gateway. We apply a VirtualService resource to which can be accessed through any host. Every route will be routed to the demo application.
Access the application
Now you can access http://localhost/books in your browser.
Conclusion
Here I showed you how to do a very basic setup of Istio on your local machine with minikube. If you want to try it out, you can also use kind, but I don’t recommend it, as you don’t have an external LoadBalancer.
I hope that one day I can make a post with advanced topics on this. There are also some other challenges, like using it with different services, mesh them up, setup security sidecars and use different hosts.
But that’s it, so far!