Wildcard Routes for Service Mesh Ingress
For my lab, I usually don’t need a specific route pointing to the istio ingress gateway. Neither do I need, for most scenarios, app-specific gateway definitions.
Without gateway injection (available in service mesh 2.3), the routes would have to be created in the same namespace where the “standard” ingress gateway is deployed, or another SMCP-managed gateway.
So, I here’s the setup for a wildcard route and respective istio configs, that is generic, as are my use cases / small apps.
First, allow wildcard subdomains in your ingress controller:
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
name: default
namespace: openshift-ingress-operator
spec:
...
routeAdmission:
wildcardPolicy: WildcardsAllowed
...
Then, in the namespace where the generic ingress gateway is deployed, create the route:
kind: Route
apiVersion: route.openshift.io/v1
metadata:
name: mesh-apps
namespace: istio-system
spec:
host: wildcard.mesh.apps.ocp4.out-of-my-head.de
to:
kind: Service
name: istio-ingressgateway
weight: 100
port:
targetPort: https
tls:
termination: passthrough
wildcardPolicy: Subdomain
Yes, wildcard
is correct. in the UI it should show up as *.mesh.apps...
.
Now, let’s create the gateway (Istio resource):
kind: Gateway
apiVersion: networking.istio.io/v1beta1
metadata:
name: mesh-apps-gateway
namespace: istio-system
spec:
servers:
- port:
number: 8443
protocol: HTTPS
name: https
hosts:
- '*.mesh.apps.ocp4.out-of-my-head.de'
tls:
mode: SIMPLE
credentialName: le-mesh-apps
selector:
istio: ingressgateway
The referenced credential is a secret that’s actually created by a hetzner-dns webhook for the cert-manager. More on that in a later blog post.
OK so, now I’m pretty much all set to just add apps to my mesh. Sample app to the rescue: https://github.com/jeichler/api-endpoint
Let’s deploy it (manifests to get started can also be found in the repo)
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: api-endpoint
app.openshift.io/runtime: quarkus
name: api-endpoint
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: api-endpoint
strategy:
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/name: api-endpoint
sidecar.istio.io/inject: "true"
spec:
affinity:
podAntiAffinity:
preferedDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- api-endpoint
topologyKey: kubernetes.io/hostname
containers:
- env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: QUARKUS_OPTS
value: -Dquarkus.http.host=0.0.0.0
- name: QUARKUS_HOME
value: /home/quarkus/
image: quay.io/jaeichle/api-endpoint:latest
name: api-endpoint
ports:
- containerPort: 9080
name: http
protocol: TCP
resources:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "100m"
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
restartPolicy: Always
securityContext: {}
serviceAccountName: api-endpoint
serviceAccount: api-endpoint
terminationGracePeriodSeconds: 30
I’ll skip PDBs, service account creation etc. here and keep it short.
The service:
apiVersion: v1
kind: Service
metadata:
name: api-endpoint
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 9080
selector:
app.kubernetes.io/name: api-endpoint
So far, so good.
Now, to expose my app, I don’t need to do anything else than just create a VirtualService.
kind: VirtualService
apiVersion: networking.istio.io/v1beta1
metadata:
name: api-endpoint-mesh
spec:
hosts:
- api-endpoint.mesh.apps.ocp4.out-of-my-head.de
gateways:
- istio-system/mesh-apps-gateway
http:
- route:
- destination:
host: api-endpoint.bookinfo.svc.cluster.local
port:
number: 8080
weight: 100
tls:
- match:
- sniHosts:
- api-endpoint.mesh.apps.ocp4.out-of-my-head.de
port: 443
route:
- destination:
host: api-endpoint.bookinfo.svc.cluster.local
port:
number: 8080
weight: 100
After that, just run curl or open one of the endpoints in the browser. /ping
being the most lightweight one, which then returns PONG. yay.
Now, that makes exposing new apps in my mesh fairly easy. A simple passthrough route, a gateway, that’s already there. so it’s just the bits I need for my application.