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 StatefulSet is 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 ClusterIP for internal access or a LoadBalancer for 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.type to anon, token, or jwt, and provide the corresponding credentials.
  • Enable/disable JetStream: Toggle jetstream.enabled.
  • Configure JetStream persistence: Define jetstream.memoryStorage and jetstream.fileStorage sizes.
  • Customize ports: Change cluster.port and cluster.gatewayPort.
  • Set up TLS: Configure tls.enabled, tls.certFile, and tls.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.

Want structured learning?

Take the full Nats course →