NATS on Kubernetes, when deployed using Helm, is fundamentally about managing distributed messaging infrastructure as application deployments rather than standalone services.
Let’s see it in action. Imagine we have a simple NATS deployment defined by a Helm chart. This chart will generate Kubernetes resources like Deployments, Services, and ConfigMaps.
Here’s a snippet from a typical values.yaml file for a NATS Helm chart:
cluster:
replicas: 3
name: nats-cluster
port: 6222
serviceType: ClusterIP
auth:
type: "token"
token: "my-super-secret-token"
jetstream:
enabled: true
memoryStorage: 1Gi
fileStorage: 10Gi
When you run helm install my-nats ./nats-chart -f values.yaml, Helm processes this values.yaml and the chart’s templates. It interpolates the values into Kubernetes YAML manifests. For example, the cluster.replicas: 3 will translate into a replicas: 3 field in the NATS Deployment, ensuring three NATS server pods are scheduled. The auth.type: "token" and auth.token: "my-super-secret-token" will configure the NATS servers to require this specific token for client connections, likely by injecting a nats-server.conf into a ConfigMap that the NATS pods mount.
The problem this solves is the complexity of deploying and managing a distributed, fault-tolerant messaging system. Manually configuring NATS servers, handling discovery, ensuring high availability, and managing security across multiple instances is cumbersome. Helm abstracts this away into a declarative, version-controlled package.
Internally, the Helm chart orchestrates several Kubernetes components:
- Deployment/StatefulSet: Manages the NATS server pods, ensuring the desired number of replicas are running and handling rolling updates. A
StatefulSetis often preferred for NATS to ensure stable network identifiers and persistent storage. - Service: Provides a stable IP address and DNS name for clients to connect to the NATS cluster. This might be a
ClusterIPfor internal access or aLoadBalancerfor external access. - ConfigMap: Stores the NATS server configuration files (
nats-server.conf), which are then mounted into the NATS pods. This is where settings like listening ports, authentication mechanisms, and JetStream storage locations are defined. - Secret: If sensitive information like TLS certificates or authentication credentials are used, they are managed via Kubernetes Secrets.
The exact levers you control are primarily through the values.yaml file. You can:
- Scale the cluster: Adjust
cluster.replicas. - Configure authentication: Set
auth.typetoanon,token, orjwt, and provide the corresponding credentials. - Enable/disable JetStream: Toggle
jetstream.enabled. - Configure JetStream persistence: Define
jetstream.memoryStorageandjetstream.fileStoragesizes. - Customize ports: Change
cluster.portandcluster.gatewayPort. - Set up TLS: Configure
tls.enabled,tls.certFile, andtls.keyFile(often referencing Secrets).
A common point of confusion is how NATS cluster discovery works when deployed via Helm. The Helm chart typically configures NATS servers to discover each other using Kubernetes DNS. Each NATS pod will have a DNS name derived from its StatefulSet name and the Kubernetes service discovery mechanism (e.g., nats-0.nats-headless.default.svc.cluster.local). The nats-server.conf will instruct servers to attempt connections to these peer DNS names, forming a cluster automatically.
The next logical step after deploying NATS on Kubernetes is to explore how to secure client connections using JWT authorization for fine-grained access control.