Service access from outside minikube

In the process of running a few integration style tests, we have attempted to enable access to kafka which is deployed locally using skaffold (minikube running within a local docker container) from an application running on my host machine (a kafka producer or another application acting as a stimulator of the test). We have tried various combinations including port forwarding and changing from ClusterPort to NodePort. So far, no success. How should this be done?

Sometimes I need to see what’s on a kafka topic and I hate using a console consumer. I found that if I edited my hosts file and port-forwarded kafka/zookeeper I was able to connect to kafka.

Host file:

127.0.0.1 kafka-0.kafka-headless.kafka.svc.cluster.local
127.0.0.1 kafka-zookeeper-0.kafka-zookeeper-headless.kafka.svc.cluster.local


Port Forwards:

kubectl.exe port-forward -n kafka kafka-zookeeper-0 2181:2181

kubectl.exe port-forward -n kafka kafka-0 9092:9092

This lets me configure a consumer (on my local OS, not in the cluster) to connect using localhost:9092.

1 Like

We recently added support for mongodb and postgresql to be accessible from outside of a cluster (running in a container) and the solution involved creating virtual services for each, updating the Istio Gateway resource and updating the Istioctl command that is performed by leafctl. I imagine the same could be done for kafka if desired. Feel free to make a feature request to get this added to leafctl:

https://tasks.leidos-leaf.com/servicedesk/customer/portal/9

If you want to take a crack at it yourself, you can deploy istio similar to this (assuming you’re using istioctl… which if you’re using leafctl you are)

istioctl install -y \
    --namespace=istio-system \
    --set values.global.istioNamespace=istio-system \
    --set values.gateways.istio-ingressgateway.runAsRoot=true \
    --set profile=default \
    --set "components.ingressGateways[0].name=istio-ingressgateway" \
    --set "components.ingressGateways[0].k8s.service.externalIPs[0]=<MINIKUBE_IP>" \
    --set "components.ingressGateways[0].k8s.service.ports[0].name=status-port" \
    --set "components.ingressGateways[0].k8s.service.ports[0].port=15021" \
    --set "components.ingressGateways[0].k8s.service.ports[0].targetPort=15021" \
    --set "components.ingressGateways[0].k8s.service.ports[1].name=http2" \
    --set "components.ingressGateways[0].k8s.service.ports[1].port=80" \
    --set "components.ingressGateways[0].k8s.service.ports[1].targetPort=80" \
    --set "components.ingressGateways[0].k8s.service.ports[2].name=https" \
    --set "components.ingressGateways[0].k8s.service.ports[2].port=443" \
    --set "components.ingressGateways[0].k8s.service.ports[2].targetPort=443" \
    --set "components.ingressGateways[0].k8s.service.ports[3].name=mongodb" \
    --set "components.ingressGateways[0].k8s.service.ports[3].port=27017" \
    --set "components.ingressGateways[0].k8s.service.ports[3].targetPort=27017" \
    --set "components.ingressGateways[0].k8s.service.ports[4].name=postgresql" \
    --set "components.ingressGateways[0].k8s.service.ports[4].port=5432" \
    --set "components.ingressGateways[0].k8s.service.ports[4].targetPort=5432" \
    --set "components.ingressGateways[0].k8s.service.ports[5].name=kafka" \
    --set "components.ingressGateways[0].k8s.service.ports[5].port=9092" \
    --set "components.ingressGateways[0].k8s.service.ports[5].targetPort=9092"

Then make a corresponding Istio Gateway resource and kubectl apply it:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: istio-ingressgateway
  namespace: istio-system
spec:
  selector:
    app: istio-ingressgateway
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"
    - port:
        number: 443
        name: https
        protocol: HTTPS
      tls:
        mode: SIMPLE
        credentialName: istio-tls
      hosts:
        - "*"
    - port:
        number: 27017
        name: mongodb
        protocol: TCP
      hosts:
        - "*"
    - port:
        number: 5432
        name: postgresql
        protocol: TCP
      hosts:
        - "*"
    - port:
        number: 9092
        name: kafka
        protocol: TCP
      hosts:
        - "*"

Then make a corresponding Istio VirtualService resource for kafka and kubectl apply it:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: kafka
  namespace: kafka
spec:
  gateways:
  - istio-system/istio-ingressgateway
  hosts:
  - '*'
  tcp:
  - match:
    - port: 9092
    route:
    - destination:
        host: kafka.kafka.svc.cluster.local
        port:
            number: 9092

Full disclosure, I haven’t had time to test the above, but it’s the approach I would probably take if looking to add this as a feature to leafctl. As with any leafctl command… this is only recommeneded for local development purposes. If everything works as intended… you should be able to access kafka at localhost:9092 without needing to modify your /etc/hosts

Well, I am definitely at the beginning of the learning curve with istio.

The istioctl install command responds with the following error:

zsh: no matches found: components.ingressGateways[0].name=istio-ingressgateway

ahh try applying the Gateway resource before running the istioctl command (the second code block in the above) my apologies for transposing the order
Please see latest reply, this was incorrect

Yeah, I tried that last night all ready. The second two commands seemed to succeed (the gateway and virtual service commands). Note I was using dry-run, because I was not sure what was going wrong. Anyway, still the same error.

~/code/deployment-scripts  dev !1  minikube                                                                                                                                        ≡ 
 ❯  istioctl install --dry-run -y \
    --namespace=istio-system \
    --set values.global.istioNamespace=istio-system \
    --set values.gateways.istio-ingressgateway.runAsRoot=true \
    --set profile=default \
    --set components.ingressGateways[0].name=istio-ingressgateway \
    --set components.ingressGateways[0].k8s.service.externalIPs[0]=192.168.49.2 \
    --set components.ingressGateways[0].k8s.service.ports[0].name=status-port \
    --set components.ingressGateways[0].k8s.service.ports[0].port=15021 \
    --set components.ingressGateways[0].k8s.service.ports[0].targetPort=15021 \
    --set components.ingressGateways[0].k8s.service.ports[1].name=http2 \
    --set components.ingressGateways[0].k8s.service.ports[1].port=80 \
    --set components.ingressGateways[0].k8s.service.ports[1].targetPort=80 \
    --set components.ingressGateways[0].k8s.service.ports[2].name=https \
    --set components.ingressGateways[0].k8s.service.ports[2].port=443 \
    --set components.ingressGateways[0].k8s.service.ports[2].targetPort=443 \
    --set components.ingressGateways[0].k8s.service.ports[3].name=mongodb \
    --set components.ingressGateways[0].k8s.service.ports[3].port=27017 \
    --set components.ingressGateways[0].k8s.service.ports[3].targetPort=27017 \
    --set components.ingressGateways[0].k8s.service.ports[4].name=postgresql \
    --set components.ingressGateways[0].k8s.service.ports[4].port=5432 \
    --set components.ingressGateways[0].k8s.service.ports[4].targetPort=5432 \
    --set components.ingressGateways[0].k8s.service.ports[5].name=kafka \
    --set components.ingressGateways[0].k8s.service.ports[5].port=9090 \
    --set components.ingressGateways[0].k8s.service.ports[5].targetPort=9090
zsh: no matches found: components.ingressGateways[0].name=istio-ingressgateway
 ~/code/deployment-scripts  dev !1                                                                                                                                                  ≡ 
 ❯  ls
README.md  instioGatewayCreation.txt  istioSetupVirtualServices.txt  istioctl_InstallWithServiceAccess.txt
 ~/code/deployment-scripts  dev !1  minikube                                                                                                                                        ≡ 
 ❯  kubectl apply -f instioGatewayCreation.txt
gateway.networking.istio.io/istio-ingressgateway configured

 ~/code/deployment-scripts  dev !1  minikube                                                                                                                                        ≡ 
 ❯  istioctl install --dry-run -y \
    --namespace=istio-system \
    --set values.global.istioNamespace=istio-system \
    --set values.gateways.istio-ingressgateway.runAsRoot=true \
    --set profile=default \
    --set components.ingressGateways[0].name=istio-ingressgateway \
    --set components.ingressGateways[0].k8s.service.externalIPs[0]=192.168.49.2 \
    --set components.ingressGateways[0].k8s.service.ports[0].name=status-port \
    --set components.ingressGateways[0].k8s.service.ports[0].port=15021 \
    --set components.ingressGateways[0].k8s.service.ports[0].targetPort=15021 \
    --set components.ingressGateways[0].k8s.service.ports[1].name=http2 \
    --set components.ingressGateways[0].k8s.service.ports[1].port=80 \
    --set components.ingressGateways[0].k8s.service.ports[1].targetPort=80 \
    --set components.ingressGateways[0].k8s.service.ports[2].name=https \
    --set components.ingressGateways[0].k8s.service.ports[2].port=443 \
    --set components.ingressGateways[0].k8s.service.ports[2].targetPort=443 \
    --set components.ingressGateways[0].k8s.service.ports[3].name=mongodb \
    --set components.ingressGateways[0].k8s.service.ports[3].port=27017 \
    --set components.ingressGateways[0].k8s.service.ports[3].targetPort=27017 \
    --set components.ingressGateways[0].k8s.service.ports[4].name=postgresql \
    --set components.ingressGateways[0].k8s.service.ports[4].port=5432 \
    --set components.ingressGateways[0].k8s.service.ports[4].targetPort=5432 \
    --set components.ingressGateways[0].k8s.service.ports[5].name=kafka \
    --set components.ingressGateways[0].k8s.service.ports[5].port=9090 \
    --set components.ingressGateways[0].k8s.service.ports[5].targetPort=9090
zsh: no matches found: components.ingressGateways[0].name=istio-ingressgateway
 ~/code/deployment-scripts  dev !1                                                                                                                                                  ≡ 
 ❯  ls
README.md  instioGatewayCreation.txt  istioSetupVirtualServices.txt  istioctl_InstallWithServiceAccess.txt
 ~/code/deployment-scripts  dev !1  minikube                                                                                                                                        ≡ 
 ❯  kubectl apply -f istioSetupVirtualServices.txt 
virtualservice.networking.istio.io/kafka created

 ❯  istioctl install --dry-run -y \
    --namespace=istio-system \
    --set values.global.istioNamespace=istio-system \
    --set values.gateways.istio-ingressgateway.runAsRoot=true \
    --set profile=default \
    --set components.ingressGateways[0].name=istio-ingressgateway \
    --set components.ingressGateways[0].k8s.service.externalIPs[0]=192.168.49.2 \
    --set components.ingressGateways[0].k8s.service.ports[0].name=status-port \
    --set components.ingressGateways[0].k8s.service.ports[0].port=15021 \
    --set components.ingressGateways[0].k8s.service.ports[0].targetPort=15021 \
    --set components.ingressGateways[0].k8s.service.ports[1].name=http2 \
    --set components.ingressGateways[0].k8s.service.ports[1].port=80 \
    --set components.ingressGateways[0].k8s.service.ports[1].targetPort=80 \
    --set components.ingressGateways[0].k8s.service.ports[2].name=https \
    --set components.ingressGateways[0].k8s.service.ports[2].port=443 \
    --set components.ingressGateways[0].k8s.service.ports[2].targetPort=443 \
    --set components.ingressGateways[0].k8s.service.ports[3].name=mongodb \
    --set components.ingressGateways[0].k8s.service.ports[3].port=27017 \
    --set components.ingressGateways[0].k8s.service.ports[3].targetPort=27017 \
    --set components.ingressGateways[0].k8s.service.ports[4].name=postgresql \
    --set components.ingressGateways[0].k8s.service.ports[4].port=5432 \
    --set components.ingressGateways[0].k8s.service.ports[4].targetPort=5432 \
    --set components.ingressGateways[0].k8s.service.ports[5].name=kafka \
    --set components.ingressGateways[0].k8s.service.ports[5].port=9090 \
    --set components.ingressGateways[0].k8s.service.ports[5].targetPort=9090
zsh: no matches found: components.ingressGateways[0].name=istio-ingressgateway

I gave this a quick test and my apologies… the order is actually correct. The issue is that we’re trying to run that istioctl command outside of the context of a script directly in your shell and I believe it doesn’t know how to handle the array index references. I’ve wrapped the istioctl flags that reference indices in quotes and this appears to work (just replace minikube ip):

istioctl install -y \
    --namespace=istio-system \
    --set values.global.istioNamespace=istio-system \
    --set values.gateways.istio-ingressgateway.runAsRoot=true \
    --set profile=default \
    --set "components.ingressGateways[0].name=istio-ingressgateway" \
    --set "components.ingressGateways[0].k8s.service.externalIPs[0]=<MINIKUBE_IP>" \
    --set "components.ingressGateways[0].k8s.service.ports[0].name=status-port" \
    --set "components.ingressGateways[0].k8s.service.ports[0].port=15021" \
    --set "components.ingressGateways[0].k8s.service.ports[0].targetPort=15021" \
    --set "components.ingressGateways[0].k8s.service.ports[1].name=http2" \
    --set "components.ingressGateways[0].k8s.service.ports[1].port=80" \
    --set "components.ingressGateways[0].k8s.service.ports[1].targetPort=80" \
    --set "components.ingressGateways[0].k8s.service.ports[2].name=https" \
    --set "components.ingressGateways[0].k8s.service.ports[2].port=443" \
    --set "components.ingressGateways[0].k8s.service.ports[2].targetPort=443" \
    --set "components.ingressGateways[0].k8s.service.ports[3].name=mongodb" \
    --set "components.ingressGateways[0].k8s.service.ports[3].port=27017" \
    --set "components.ingressGateways[0].k8s.service.ports[3].targetPort=27017" \
    --set "components.ingressGateways[0].k8s.service.ports[4].name=postgresql" \
    --set "components.ingressGateways[0].k8s.service.ports[4].port=5432" \
    --set "components.ingressGateways[0].k8s.service.ports[4].targetPort=5432" \
    --set "components.ingressGateways[0].k8s.service.ports[5].name=kafka" \
    --set "components.ingressGateways[0].k8s.service.ports[5].port=9092" \
    --set "components.ingressGateways[0].k8s.service.ports[5].targetPort=9092"

I have made a few edits as I was referencing the wrong port (was using 9090 in my examples instead of the correct 9092). I still don’t have a convenient means of testing this on hand, but you’re still welcome to see if it works for you.

EDIT: So I finally had a little time to give this approach a proper test… and unfortunately it doesn’t appear to be working as I would have believed it would (this is the approach we’ve used to make mongo and postgres available from outside of the cluster… I assumed it would be pretty cut and dry to do the same for kafka, but looks like I was mistaken) I did give @Stephen.A.Gorman’s solution a test drive and it worked well, kudos to him :slight_smile: Until we are able to investigate making this a possibility without modifying the etc/hosts file, I would suggest just using Stephen’s suggestion. Apologies for any and all misinformation here.