Introduction
The system that I’m working on has an API deployed to Kubernetes and exposed through Kubernetes Ingress and Istio Gateway (for some historical and technical reasons, we need to use Kubernetes Ingress in some environments and Istio Gateway in others). For local development, we have been using Minikube and:
- Ingress DNS addon, which enables nginx ingress controller and deploys a custom DNS server that maps host names in available ingresses to minikube IP. This means we can access ingress using DNS like
http://app.minikube.test
- MetalLB to assign an accessible IP for Istio ingress gateway load balancer. With this we can access Istio Gateway through port
80
at the assigned IP and don’t need to use NodePort
Also worth noting that we want our local development to match other environments as much as possible so using NodePort is not something we are interested in.
This sorts of work until our team all converted to M1/M3 MacBook, which breaks Minikube custom DNS server
This post covers the approach that we come up with
Solution
What we do is to run a local DNS server (CoreDNS) on the host machine (MacBook) which resolves all DNS requests for specific suffix to either minikube IP (for Kubernetes Ingres) or IP assigned to Istio Ingress Gateway. Below is how it looks like:
CoreDNS Setup
When we deploy our application to minikube, we also run a CoreDNS container on the host with the following Corefile
configuration:
. {
log
errors
health {
lameduck 5s
}
ready
template IN A {
match "ingress\.minikube\.test\.$"
answer "{{ .Name }} 60 IN A {$INGRESS_CONTROLLER_IP}"
fallthrough
}
template IN A {
match "istio\.minikube\.test\.$"
answer "{{ .Name }} 60 IN A {$ISTIO_GATEWAY_IP}"
}
}
this config uses CoreDNS template
plugin to:
- return value of environment variable
INGRESS_CONTROLLER_IP
(which is set to minikube ip) when DNS request is for domain*.ingress.minikube.test
- return value of environment variable
ISTIO_GATEWAY_IP
when DNS request is for domain*.istio.minikube.test
- this variable is set to the IP assigned by MetalLB and can be retrieved using:
kubectl get svc -n istio-system istio-ingressgateway -o json | jq -r '.status.loadBalancer.ingress[0].ip'
- this variable is set to the IP assigned by MetalLB and can be retrieved using:
the container is run and listens on port 1053
on the host machine using following command:
|
|
Resolver file
Next, we create a resolver file on MacBook at /etc/resolver/minikube.test
:
domain minikube.test
nameserver 127.0.0.1
port 1053
search_order 1
timeout 5
basically this file tells Mac to use DNS server at 127.0.0.1:1053
to resolve DNS for any domain with suffix minikube.test
And that’s it. Now we can use DNS name like foo.ingress.minikube.test
or bar.istio.minikube.test
to reach applications foo
/bar
deployed to minikube (provided correct Ingress
/Gateway
/VirtualService
are setup)
Note
- I use Minikube for demonstration here but nothing here is specific to Minikube (beside the command
minikube ip
)- One minor downside/difference of this compared to Minikube Ingress DNS is that it resolves DNS for all requests matching the suffixes, no matter whether there is any
Ingress
/Gateway
for those domains