<p>I am trying to implement SonarQube in a Kubernetes cluster. The deployment is running properly and is also exposed via a Virtual Service. I am able to open the UI via the <code>localhost:port/sonar</code> but I am not able to access it through my external ip. I understand that sonar binds to localhost and does not allow access from outside the remote server. I am running this on GKE with a MYSQL database. Here is my YAML file:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: sonarqube
  namespace: sonar
  labels:
    service: sonarqube
    version: v1
spec:
  replicas: 1
  template:
    metadata:
      name: sonarqube
      labels:
        name: sonarqube
    spec:
      terminationGracePeriodSeconds: 15
      initContainers:
        - name: volume-permission
          image: busybox
          command:
            - sh
            - -c
            - sysctl -w vm.max_map_count=262144
          securityContext:
            privileged: true
      containers:
        - name: sonarqube
          image: sonarqube:6.7
          resources:
            limits:
              memory: 4Gi
              cpu: 2
            requests:
              memory: 2Gi
              cpu: 1
          args:
            - -Dsonar.web.context=/sonar
            - -Dsonar.web.host=0.0.0.0
          env:
            - name: SONARQUBE_JDBC_USERNAME
              valueFrom:
                secretKeyRef:
                  name: cloudsql-db-credentials
                  key: username
            - name: SONARQUBE_JDBC_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: cloudsql-db-credentials
                  key: password
            - name: SONARQUBE_JDBC_URL
              value: jdbc:mysql://***.***.**.*:3306/sonar?useUnicode=true&amp;characterEncoding=utf8
          ports:
            - containerPort: 9000
              name: sonarqube-port
---
apiVersion: v1
kind: Service
metadata:
  labels:
    service: sonarqube
    version: v1
  name: sonarqube
  namespace: sonar
spec:
  selector:
    name: sonarqube
  ports:
    - name: http
      port: 80
      targetPort: sonarqube-port
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sonarqube-internal
  namespace: sonar
spec:
  hosts:
    - sonarqube.staging.jeet11.internal
    - sonarqube
  gateways:
    - default/ilb-gateway
    - mesh
  http:
    - route:
        - destination:
            host: sonarqube
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sonarqube-external
  namespace: sonar
spec:
  hosts:
    - sonarqube.staging.jeet11.com
  gateways:
    - default/elb-gateway
  http:
    - route:
        - destination:
            host: sonarqube
---
</code></pre>

<p>The deployment completes successfully. My exposed services gives a public ip that has been mapped to the host url but I am unable to access the service at the host url. </p>

<p>I need to change the mapping such that sonar binds with the server ip but I am unable to understand how to do that. I cannot bind it to my cluster ip, neither to my internal or external service ip. </p>

<p>What should I do? Please help!</p>

Sankalan Parajuli
<p>I had the same issue recently and I managed to get this resolved today.</p>
<p>I hope the following solution will work for anyone facing the same issue!.</p>
<h1>Environment</h1>
<ul>
<li>Cloud Provider: <strong>Azure - AKS</strong>
<ul>
<li>This should work regardless of whatever provider you use.</li>
</ul>
</li>
<li>Istio Version: 1.7.3</li>
<li>K8 Version: 1.16.10</li>
</ul>
<h1>Tools - Debugging</h1>
<ul>
<li><code>kubectl logs -n istio-system -l app=istiod</code>
<ul>
<li>logs from Istiod and events happening in the control plane.</li>
</ul>
</li>
<li><code>istioctl analyze -n &lt;namespace&gt;</code>
<ul>
<li>This generally gives you any warnings and errors for a given namespace.</li>
<li>Lets you know if things are misconfigured.</li>
</ul>
</li>
<li>Kiali - <code>istioctl dashboard kiali</code>
<ul>
<li>See if you are getting inbound traffic.</li>
<li>Also, shows you any misconfigurations.</li>
</ul>
</li>
<li>Prometheus - <code>istioctl dashboard prometheus</code>
<ul>
<li>query metric - <code>istio_requests_total</code>. This shows you the traffic going into the service.</li>
<li>If there's any misconfiguration you will see the <strong>destination_app</strong> as <strong>unknown</strong>.</li>
</ul>
</li>
</ul>
<h1>Issue</h1>
<ul>
<li>Unable to access sonarqube UI via external IP, but accessible via localhost (port-forward).</li>
<li>Unable to route traffic via Istio Ingressgateway.</li>
</ul>
<h1>Solution</h1>
<h3>Sonarqube Service Manifest</h3>
<pre><code>apiVersion: v1
kind: Service
metadata:
  name: sonarqube
  namespace: sonarqube
  labels:
    name: sonarqube
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 9000
    targetPort: 9000
  selector:
    app: sonarqube
status:
  loadBalancer: {}
</code></pre>
<ul>
<li>Your <strong>targetport</strong> is the container port. To avoid any confusion just assign the service <strong>port</strong> number as same as the service <strong>targetport</strong>.</li>
<li>The port name is very important here. “Istio required the service ports to follow the naming form of ‘protocol-suffix’ where the ‘-suffix’ part is optional” - <a href="https://kiali.io/documentation/v1.15/validations/#_kia0601_port_name_must_follow_protocol_suffix_form" rel="nofollow noreferrer">KIA0601 - Port name must follow [-suffix] form</a></li>
</ul>
<h3>Istio Gateway and VirtualService manifest for sonarqube</h3>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: sonarqube-gateway
  namespace: sonarqube
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 9000
      name: http
      protocol: HTTP
    hosts:
    - &quot;XXXX.XXXX.com.au&quot;
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sonarqube
  namespace: sonarqube
spec:
  hosts:
  - &quot;XXXX.XXXX.com.au&quot;
  gateways:
  - sonarqube-gateway
  http:
  - route:
    - destination:
        host: sonarqube
        port:
          number: 9000
</code></pre>
<ul>
<li>Gateway protocol must be set to <strong>HTTP</strong>.</li>
<li><strong>Gateway Server Port</strong> and <strong>VirtualService Destination Port</strong> is the same. If you have different app <strong>Service Port</strong>, then your <strong>VirtualService Destination Port</strong> number should match the app <strong>Service Port</strong>. The <strong>Gateway Server Port</strong> should match the app <strong>Service Targetport</strong>.</li>
<li>Now comes to the fun bit! The <strong>hosts</strong>. If you want to access the service outside of the cluster, then you need to have your host-name (whatever host-name that you want to map the sonarqube server) as an <strong>DNS A record</strong> mapped to the External Public IP address of the <strong>istio-ingressgateway</strong>.</li>
<li>To get the <strong>EXTERNAL-IP</strong> address of the ingressgateway, run <code>kubectl -n istio-system get service istio-ingressgateway</code>.</li>
<li>If you do a simple nslookup (run - <code>nslookup &lt;hostname&gt;</code>), The IP address you get must match with the IP address that is assigned to the istio-ingressgateway service.</li>
</ul>
<h3>Expose a new port in the ingressgateway</h3>
<ul>
<li>Note that your sonarqube gateway port is a new port that you are introducing to Kubernetes and you’re telling the cluster to listen on that port. But your load balancer doesn’t know about this port. Therefore, <strong>you need to open the specified gateway port on your kubernetes external load balancer</strong>. Ref - <a href="https://github.com/istio/istio/issues/7242#issuecomment-406808437" rel="nofollow noreferrer">Info</a></li>
<li>You don’t need to manually change your load balancer service. You just need to update the ingress gateway to include the new port, which will update the load balancer automatically.</li>
<li>You can identify if the port is causing issues by running <code>istioctl analyze -n sonarqube</code>. You should get the following warning;</li>
</ul>
<p><code>[33mWarn[0m [IST0104] (Gateway sonarqube-gateway.sonarqube) The gateway refers to a port that is not exposed on the workload (pod selector istio=ingressgateway; port 9000) Error: Analyzers found issues when analyzing namespace: sonarqube. See https://istio.io/docs/reference/config/analysis for more information about causes and resolutions.</code></p>
<ul>
<li>You should get the corresponding error in the control plane. Run <code>kubectl logs -n istio-system -l app=istiod</code>.</li>
<li>At this point <strong>you need to update the Istio ingressgateway service to expose the new port</strong>. Run <code>kubectl edit svc istio-ingressgateway -n istio-system</code> and add the following section to the ports.</li>
</ul>
<p><a href="https://i.stack.imgur.com/3xjvK.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/3xjvK.png" alt="enter image description here" /></a></p>
<h3>Bypass creating a new port</h3>
<ul>
<li>In the previous section you saw how to expose a new port. This is optional and depending on your use case.</li>
<li>In this section you will see how to use a port that is already exposed.</li>
<li>If you look at the service of the istio-ingressgateway. You can see that there are default ports exposed. Here we are going to use port 80.</li>
</ul>
<p><a href="https://i.stack.imgur.com/T9fTC.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/T9fTC.png" alt="enter image description here" /></a></p>
<ul>
<li>Your setup will look like the following;
<a href="https://i.stack.imgur.com/JvwLi.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/JvwLi.png" alt="enter image description here" /></a></li>
</ul>
<p><a href="https://i.stack.imgur.com/5nAuB.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/5nAuB.png" alt="enter image description here" /></a></p>
<ul>
<li>To void specifying the port with your host name just add match uri prefix, as shown in the virtualservice manifest.</li>
</ul>
<h3>Time for testing</h3>
<ul>
<li>If everything works up to this point as expected, then you are good to go.</li>
</ul>
<p><a href="https://i.stack.imgur.com/uneFD.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/uneFD.png" alt="enter image description here" /></a></p>
<ul>
<li>During testing I made one mistake by not specifying the port. If you get 404 status, Which is still a good thing, in this way you can verify what server it is using. If you setup things correctly, it should use the <strong>istio-envoy</strong> server, not the <strong>nginx</strong>.</li>
</ul>
<p><a href="https://i.stack.imgur.com/DQnHs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/DQnHs.png" alt="enter image description here" /></a></p>
<ul>
<li>Without specifiying the port. This will only work if you add the match uri prefix.</li>
</ul>
<p><a href="https://i.stack.imgur.com/CuqkT.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/CuqkT.png" alt="enter image description here" /></a></p>
