A NodePort
allocates an IP that is internal to the cluster, hence the need to port forward.
To pass that internal port to an external port you need to change the spec.type
to LoadBalancer
.
I found the term "LoadBalancer" to be confusing as it conflicts with the term used by services such as AWS for their own load balancers (eg ELB in Amazon). In Kubernetes a LoadBalancer
service will load balance between any pods that match the criteria you specify, or in this case just the one.
The trick is, if you're in an environment with actual load balancers then the service will automatically map to an external load balancer so you can access the service with a real IP.
This can also be done with an Ingress
but that can only be used for http and https services with an ingress controller eg NGINX. Because MQTT is a different protocol the service is used to pass the connection through.
In my case I'm not on a cloud service so there is no load balancer like ELB provided by default - you have to add your own (see what I mean about confusing). I installed a local MetalLB load balancer in the cluster and the port magically appeared in one of the pools of local IPs I allocated.
From there you just need to set up DNS (in your router perhaps) so that the name you want corresponds with the allocated IP. My broker now appears on mqtt.local
on port 1883
Here's the yaml that worked for me:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mosquitto
namespace: mosquitto
spec:
replicas: 1
selector:
matchLabels:
name: mosquitto
template:
metadata:
labels:
name: mosquitto
spec:
containers:
- name: mosquitto
image: eclipse-mosquitto:2.0.12
ports:
- containerPort: 1883
volumeMounts:
- name: mosquitto-config
mountPath: /mosquitto/config/mosquitto.conf
subPath: mosquitto.conf
volumes:
- name: mosquitto-config
configMap:
name: mosquitto-configmap
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mosquitto-configmap
namespace: mosquitto
data:
mosquitto.conf: |-
listener 1883
allow_anonymous true
---
apiVersion: v1
kind: Service
metadata:
name: mosquitto-service
namespace: mosquitto
annotations: # <-- Which IP pool to use
metallb.universe.tf/address-pool: lb-static-ips
spec:
type: LoadBalancer # <-- Changed
selector:
name: mosquitto
ports:
- name: mosquitto
protocol: TCP
port: 1883
targetPort: 1883
# nodePort: 30007 <--- LoadBalancer will figure this out
... and this is the YAML for metalLB:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: http # one IP address for virtual http hosts
protocol: layer2
addresses:
- 10.3.3.152/32
- name: lb-static-ips # IP addresses for services
protocol: layer2
addresses:
- 10.3.3.153-10.3.3.160