vernemq/docker-vernemq

Harcoded spec.type in template api-service.yaml

FMBIoT opened this issue · 0 comments

Information
I was trying to install vernemq using the Helm Chart and enabling the HTTP API to allow Prometheus to collect metrics.
For development purposes, I needed to use NodePort, so I used the following values:

image:
  tag: 1.13.0
service:
  type: NodePort
  mqtt:
    enabled: 'true'
    nodePort: '31883'
  ws:
    enabled: 'true'
    nodePort: '30080'
  api:
    enabled: 'true'
additionalEnv:
- name: DOCKER_VERNEMQ_ALLOW_ANONYMOUS
  value: 'on'
- name: DOCKER_VERNEMQ_ACCEPT_EULA
  value: 'yes'
- name: DOCKER_VERNEMQ_LISTENER__MAX_CONNECTIONS
  value: '65000'

As you can see, the api is enabled and the service.type is NodePort.

Problem
After running the helm install command (helm install vernemq vernemq/vernemq -f values.yaml), an error seems to occur:
Error: INSTALLATION FAILED: Service "edb-vernemq-api" is invalid: spec.ports[0].nodePort: Forbidden: may not be used when type is 'ClusterIP'

If I run the helm install with the flag --dry-run , the output shows the problem:

# Source: vernemq/templates/api-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: vernemq-api
  labels:
    app.kubernetes.io/name: vernemq
    helm.sh/chart: vernemq-1.9.0
    app.kubernetes.io/instance: vernemq
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  ports:
    - port: 8888
      targetPort: api
      name: api
      nodePort: 38888
  selector:
    app.kubernetes.io/name: vernemq
    app.kubernetes.io/instance: vernemq

The spec.type does not change. Verifying this in the Helm template on GitHub confirms my suspicion:

spec:
  type: ClusterIP
  {{- if .Values.service.clusterIP }}
  clusterIP: {{ .Values.service.clusterIP }}
  {{- end }}
{{- if .Values.service.api.sessionAffinity }}
  sessionAffinity: {{ .Values.service.api.sessionAffinity }}
  {{- if .Values.service.api.sessionAffinityConfig }}
  sessionAffinityConfig:
    {{ toYaml .Values.service.api.sessionAffinityConfig | nindent 4 }}
  {{- end -}}
{{- end }}
  ports:
    - port: {{ .Values.service.api.port }}
      targetPort: api
      name: api
      {{- if eq .Values.service.type "NodePort" }}
      nodePort: {{ .Values.service.api.nodePort }}
      {{- end }}

The spec.type is hardcoded, while the ports have the possibility to use NodePort.

Solution

If I am not wrong, the solution is to use an if-else statement as shown in the service.yaml

{{- if (or (eq .Values.service.type "ClusterIP") (empty .Values.service.type)) }}
  type: ClusterIP
  {{- if .Values.service.clusterIP }}
  clusterIP: {{ .Values.service.clusterIP }}
  {{- end }}
{{- else if eq .Values.service.type "LoadBalancer" }}
  type: {{ .Values.service.type }}
  {{- if .Values.service.loadBalancerIP }}
  loadBalancerIP: {{ .Values.service.loadBalancerIP }}
  {{- end }}
  {{- if .Values.service.loadBalancerSourceRanges }}
  loadBalancerSourceRanges:
    {{ toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }}
  {{- end -}}
{{- else }}
  type: {{ .Values.service.type }}
{{- end }}