Saudações.
Esse tutorial é um guia rápido de instalação e uso do NATS, um sistema de mensageria feito em GO.
Pré-requisitos (constam em outros artigos aqui do blog):
- Instalação do Linux (Debian ou Alpine);
- Internet no servidor (sua VPS ou host);
- Docker CE instalado (opcional);
1 – Sobre NATS
NATS é um sistema de mensagens open-source, leve e de alto desempenho, projetado para construir sistemas distribuídos modernos no paradigma event-driven architecture.
Ele suporta pub/sub, request/reply e streaming com persistência (via JetStream).
Ele faz tudo usando um único binário, o que resulta em um sistema rápido e uso mínimo de recursos e latência sub-milissegundo.
Ele é um rival de peso para as demais alternativas e acaba substituindo ou complementando soluções como RabbitMQ, Kafka, Redis Pub/Sub e gRPC.
Self-hosted: O NATS é open-source, licenciado sob Apache 2.0, e o servidor pode ser rodado localmente ou em qualquer infraestrutura sem custo algum. Você simplesmente baixa o binário ou container e executa. Não há limite de mensagens, conexões ou nada imposto pelo software em si na versão open-source.
1.1 – Recursos
NATS opera com três padrões principais de comunicação:
- Pub/Sub: Um publicador envia mensagens em um “subject” (tópico) e todos os assinantes recebem. Ideal para eventos broadcast entre aplicativos distribuidos;
- Request/Reply: Comunicação síncrona entre serviços, como uma chamada RPC.
- Queue Groups (Filas) — múltiplos consumidores competem pela mesma mensagem. Só um recebe, ótimo para balanceamento de carga.
Com o JetStream (persistência nativa) ele oferece:
- Streaming de mensagens com replay
- Key/Value store
- Object store
1.2 – Finalidade
NATS é uma tecnologia de conectividade que unifica Cloud, On-Premise, Edge e IoT.
Os casos de uso mais comuns são:
- Microserviços: Comunicação assíncrona e síncrona entre serviços sem precisar de service mesh;
- IoT e Edge Computing: conexão de dispositivos com baixo consumo de recursos;
- Sistemas de telemetria em tempo real: Veículos, fábricas, monitoramento;
- Filas de trabalho distribuídas: Processamento paralelo e balanceamento de carga;
- Event-driven architectures: Sistemas reativos baseados em eventos;
- Multi-cloud e multi-região: Conectar serviços espalhados por diferentes clouds;
1.3 – Vantagens e diferenciais
Ele oferece alguns diferenciais e relação aos concorrentes como Kafka e RabbitMQ:
- Extremamente leve: Roda em um único binário, consome pouquíssima memória;
- Latência sub-milissegundo: Capaz de entregar milhões de mensagens por segundo com latências sub-milissegundo em sistemas globalmente distribuídos NATS.io;
- Tudo em um só lugar: Pub/sub, streaming, KV store e object store no mesmo sistema;
- Suporte nativo a leaf nodes: Permite que sites/edges funcionem offline e sincronizem quando reconectam;
- Clientes oficiais: Go, Rust, JavaScript, TypeScript, Python, Java, C#, C, Ruby, Elixir e CLI — além de 30+ clientes da comunidade;
1.4 – Conceitos
Agora vamos explorar os conceitos, recursos e regras do paradigma NATS.
O sistema utiliza os seguintes termos para organizar o fluxo de trabalho:
- Subjects: São os “endereços” das mensagens. Um subject é uma string simples como
orders.createdouusers.signup. Utilizam separação por pontos para criar hierarquias. - Wildcards: O NATS suporta dois tipos de curinga:
(asterisco): Corresponde a um único token (palavra):*orders.*captura:orders.createdorders.updated;
(maior que): Corresponde a um ou mais tokens:>orders.>captura:orders.createdorders.us.east
- Messages: Uma mensagem possui duas partes principais:
- subject (destino);
- payload (dados em bytes): O payload máximo padrão é 1 MB;
- Publishers: Enviam mensagens para subjects específicos. Não precisam saber se há subscribers;
- Subscribers: Softwares que fazem conexão com o NATS para receber mensagens de um ou mais subjects. Podem usar wildcards para escutar várias filas;
- At-most-once delivery (Core NATS): No NATS Core, se um subscriber não estiver conectado no momento da publicação, ele perde a mensagem. Essa semântica de “no máximo uma vez” garante performance máxima;
- At-least-once delivery (JetStream): Com JetStream habilitado, as mensagens são persistidas e podem ser reproduzidas, garantindo que consumidores recebam ao menos uma cópia.
Quanto a topologia de rede, podemos ter:
- Standalone: Um único servidor NATS (nats-server), ideal para ambientes pequenos, de teste e desenvolvimento;
- Cluster: Múltiplos servidores formam um cluster full-mesh para alta disponibilidade. Se um nó cai, os outros assumem automaticamente;
- Supercluster: Clusters conectados via gateway para arquiteturas multi-região ou multi-cloud;
- Leaf Nodes: Nós leves que se conectam a um cluster central, ideais para edge computing, IoT ou ambientes com recursos limitados.
1.5 – Portas
O NATS usa 3 portas, é recomendável que elas sejam alcançadas apenas pelos clientes legítimos. Proteja-as por firewall, por criptografia (TLS/HTTPs) e por autenticação.
Portas TCP usadas pelo servidor NATS (nats-server):
4222: Conexões de clientes da mensageria;6222: Roteamento entre servidores (cluster);8222: Monitoramento HTTP;
1.6 – Core NATS e JetStream
O Core é a camada base de mensageria que oferece:
- Publish/Subscribe;
- Request/Reply;
- Queue Groups (load balancing);
- Semântica at-most-once;
A camada de persistência integrada é provida pelo recurso JetStream que adiciona:
- Streams (armazenamento de mensagens);
- Consumers (leitura controlada de streams);
- Replay policies (instant ou original);
- Retention policies (limits, interest, workqueue);
- Key/Value Store;
- Object Store;
- Semântica at-least-once e exactly-once;
2 – NATS no HOST
Vamos fazer a instalação do NATS no Debian direto no HOST (VPS, VM). Esse ambiente é recomendado para ambientes grandes onde será necessário colocar o NATS dedicado ou em cluster.
2.1 – NATS no Debian
# Atualizar sistema local
apt -y update;
apt -y upgrade;
apt -y dist-upgrade;
apt -y autoremove;
# Instalar NATS
apt -y install nats-server;
# Ativar durante o boot
systemctl enable nats-server;
# Ativar imediatamente
systemctl start nats-server;
2.2 – NATS no Alpine
O pacote do Alpine instala apenas o binário, sem configuração padrão e sem script de serviço no OpenRC. Vamos por partes!
Primeiro instale o binário:
# Atualizar sistema local
apk update;
apk upgrade;
# Instalar o NATS
apk add nats-server;
# Usuario e grupo
addgroup -S nats;
adduser -S -G nats -H -h /var/empty nats;
# Diretorios e arquivos exclusivos
mkdir -p /etc/nats;
mkdir -p /var/log/nats;
touch /etc/nats/nats.conf;
# Ajustes de permissoes
chown -R nats:nats /etc/nats;
chown -R nats:nats /var/log/nats;
Vamos criar a configuração padrão:
# Criar configuracao padrao do NATS
(
echo;
echo 'listen: 0.0.0.0:4222';
echo 'http: 0.0.0.0:8222';
echo;
echo 'log_file: "/var/log/nats/nats.log"';
echo 'logtime: true';
echo;
) > /etc/nats/nats.conf;
Agora crie o script da unit no OpenRC com suporte a reinicialização automática:
# Criar unit do openrc para o servico nats-server
(
echo '#!/sbin/openrc-run';
echo;
echo 'supervisor=supervise-daemon';
echo;
echo 'name="nats-server"';
echo 'description="NATS Server"';
echo 'command="/usr/bin/nats-server"';
echo 'command_args="-c /etc/nats/nats.conf"';
echo 'command_user="nats:nats"';
echo 'pidfile="/run/nats-server.pid"';
echo 'supervise_daemon_args="--respawn-delay 2 --respawn-max 10"';
echo '#-command_background=true';
echo;
echo 'depend() {';
echo ' need net';
echo ' after firewall';
echo '}';
echo;
echo 'start_pre() {';
echo ' checkpath --directory --owner nats:nats --mode 0755 /run/nats';
echo ' checkpath --directory --owner nats:nats --mode 0755 /var/log/nats';
echo '}';
echo;
) > /etc/init.d/nats-server;
# Tornar script executavel
chmod +x /etc/init.d/nats-server;
# Ativar durante o boot
rc-update add nats-server default;
# Iniciar imediatamente
service nats-server stop;
service nats-server start;
3 – Configuração do NATS
O NATS pode ser usado sem configuração, o que resulta num servidor de mensageria aberto, bom para redes confinadas de containers.
Para os demais casos é necessário ser bem explicito na configuração, começando pela autenticação.
3.1 – Autenticação e contas
O exemplo abaixo ensina como criar o usuário “admin” com senha “tulipanats” para colocar no arquivo de configuração que será armazenado na pasta do volume e entregue ao container:
# Instalar mkpasswd do pacote whois
which mkpasswd >/dev/null || apt -y install whois;
# Gerar hash criptografico baseado na senha
PASSWORD="tulipanats";
HASHPWD=$(mkpasswd -m bcrypt -R 10 "$PASSWORD");
# Obs: o hash muda a cada vez que gera pois o salt randomico
# e' combinado com a senha para gerar o hash
echo;
echo "Senha.: $PASSWORD";
echo "Hash..: $HASHPWD";
echo;
# Exemplo de saida:
#
# Senha.: tulipanats
# Hash..: $2b$10$KLtY/djKBZOeDFwkgCZ2hO008dIFkIS4018.jY0PW9HZoQYirDFdy
#
# $2b$10$KLtY/djKBZOeDFwkgCZ2hO008dIFkIS4018.jY0PW9HZoQYirDFdy
# │ │ │
# │ │ └─── Hash da senha salgada, hash( salt + senha )
# │ └───── Custo (rounds = 10, potencia de 2 = 1024 revolucoes)
# └───────── Versão do bcrypt
3.2 – Configuração principal
Configuração fica por padrão em /etc/nats/nats.conf nos sistemas rodando no HOST.
Exemplo com comentários:
# Configuração de rede
# - Endereço e porta para conexões de clientes
listen: 0.0.0.0:4222
# - Porta para monitoramento HTTP
http: 0.0.0.0:8222
# Nome do servidor para identificação em logs e monitoramento
server_name: nats-tutorial
# Tamanho maximo do payload (padrao: 1MB)
max_payload: 1048576
# Log
log_file: "/var/log/nats/nats.log"
logtime: true
debug: false
trace: false
# Controle de acesso
# - Usuário com privilégios administrativos
system_account: SYS
# - Contas de autenticacao:
accounts: {
SYS: {
users: [
{
user: admin,
password: "$2b$10$KLtY/djKBZOeDFwkgCZ2hO008dIFkIS4018.jY0PW9HZoQYirDFdy"
}
]
},
CLIENTS: {
jetstream: enabled
users: [
{
user: app,
password: "$2b$10$KLtY/djKBZOeDFwkgCZ2hO008dIFkIS4018.jY0PW9HZoQYirDFdy"
}
]
}
}
# - Com token universal
# - authorization: { token: "ak-c51d2fd1-4332-11f1-ac26-000c2940f0ad" }
# Persistencia de mensageria (limites: 1 GB de RAM, 20 GB de disco)
jetstream {
store_dir: /data
max_mem_store: 1GB
max_file_store: 20GB
}
3 – NATS no Docker
O uso mais difundido do NATS é em containers por meio de serviços em nuvem própria (Swarm, Kubernetes).
3.1 – Configuração do NATS no container
Ao rodar o NATS na configuração padrão ele não implementará a proteção por usuário e senha, vital para a segurança.
Vou usar a pasta /storage/nats-server como base do volume, lá estarão os logs, o arquivo de configuração e o armazenamento do JetStream.
# Diretorio para o volume
mkdir -p /storage/nats-server;
# - Diretorio de configuracoes
mkdir -p /storage/nats-server/config;
# - Diretorio de logs
mkdir -p /storage/nats-server/logs;
# - Diretorio do JetStream
mkdir -p /storage/nats-server/jetstream;
Configuração em /storage/nats-server/config/nats.conf
# Configuração de rede
# - Endereço e porta para conexões de clientes
listen: 0.0.0.0:4222
# - Porta para monitoramento HTTP
http: 0.0.0.0:8222
# Nome do servidor para identificação em logs e monitoramento
server_name: nats-tutorial
# Tamanho maximo do payload (padrao: 1MB)
max_payload: 1048576
# Log
log_file: "/data/logs/nats.log"
logtime: true
debug: false
trace: false
# Controle de acesso
# - Usuário com privilégios administrativos
system_account: SYS
# - Contas de autenticacao:
accounts: {
SYS: {
users: [
{
user: admin,
password: "$2b$10$KLtY/djKBZOeDFwkgCZ2hO008dIFkIS4018.jY0PW9HZoQYirDFdy"
}
]
},
CLIENTS: {
jetstream: enabled
users: [
{
user: app,
password: "$2b$10$KLtY/djKBZOeDFwkgCZ2hO008dIFkIS4018.jY0PW9HZoQYirDFdy"
}
]
}
}
# - Com token universal
# - authorization: { token: "ak-c51d2fd1-4332-11f1-ac26-000c2940f0ad" }
# Persistencia de mensageria (limites: 1 GB de RAM, 20 GB de disco)
jetstream {
store_dir: /data
max_mem_store: 1GB
max_file_store: 20GB
}
3.2 – Rede Docker
Padrão “network_public” que costumo usar nos meus tutoriais:
# Rede de containers
docker network create network_public \
\
-d bridge \
-o com.docker.network.bridge.name=br-net-public \
-o com.docker.network.driver.mtu=1500 \
-o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
\
--subnet 10.249.0.0/16 \
--gateway 10.249.255.254;
3.3 – Container completo com persistência (JetStream) e configuração
Exemplo completo pronto para produção segura, persistência ativa usando JetStream e configuração para implementar autenticação e logs.
# Rodar NATS em container - Configuração completa
# - Limite de RAM: 2048 MB (2 GB)
# - Reserva de RAM: 1024 MB
# - Volume para o JetStream
# Pasta para o volume
DATADIR=/storage/nats-server;
mkdir -p $DATADIR;
# Baixar imagem
docker pull nats:latest;
# Renovar/rodar
docker rm -f nats-server-js 2>/dev/null;
docker run \
-d --restart=always \
--name nats-server \
-h nats-server.intranet.br \
\
--read-only \
--tmpfs /run:rw,noexec,nosuid,size=4m \
--tmpfs /tmp:rw,noexec,nosuid,size=4m \
-v $DATADIR:/data \
-v $DATADIR/config/nats.conf:/etc/nats.conf:ro \
\
--cpus=1 \
--memory=2048m \
--memory-swap=2048m \
--memory-reservation=1024m \
--oom-score-adj=-500 \
\
--ulimit nofile=1048576:1048576 \
--ulimit memlock=-1 \
--sysctl net.core.somaxconn=16384 \
\
--network network_public \
-p 4222:4222 \
-p 8222:8222 \
\
nats:latest \
-c /etc/nats.conf;
# Analisando
docker inspect nats-server;
docker diff nats-server;
docker logs nats-server;
#-docker logs -f nats-server;
3.4 – Container do NATS sem persistência, sem configuração
Exemplo criando container optimizado, com restrição de recursos, sem persistência de mensagens (perde se o serviço for parado ou interrompido abruptamente) e sem autenticação (aborto para uso dos containers na mesma rede docker). Não vou publicar as portas externamente (sem o “-p”).
# Rodar NATS em container
# - Limite de RAM: 1024 MB (1 GB)
# - Reserva de RAM: 512 MB
# Baixar imagem
docker pull nats:latest;
# Renovar/rodar
docker rm -f nats-server-fast 2>/dev/null;
docker run \
-d --restart=always \
--name nats-server-fast \
-h nats-server-fast.intranet.br \
\
--read-only \
--tmpfs /run:rw,noexec,nosuid,size=4m \
--tmpfs /tmp:rw,noexec,nosuid,size=4m \
\
--cpus=1 \
--memory=1024m \
--memory-swap=1024m \
--memory-reservation=512m \
--oom-score-adj=-500 \
\
--ulimit nofile=1048576:1048576 \
--ulimit memlock=-1 \
--sysctl net.core.somaxconn=16384 \
\
--network network_public \
\
nats:latest;
# Nao publicar portas de NATS aberto
# -p 4222:4222
# -p 8222:8222
# Analisando
docker inspect nats-server-fast;
docker diff nats-server-fast;
docker logs nats-server-fast;
#-docker logs -f nats-server-fast;
3.5 – Container com persistência (JetStream) sem configuração
# Rodar NATS em container
# - Limite de RAM: 1024 MB (1 GB)
# - Reserva de RAM: 512 MB
# - Volume para o JetStream
# Pasta para o volume
DATADIR=/storage/nats;
mkdir -p $DATADIR;
# Baixar imagem
docker pull nats:latest;
# Renovar/rodar
docker rm -f nats-server-js 2>/dev/null;
docker run \
-d --restart=always \
--name nats-server-js \
-h nats-server-js.intranet.br \
\
--read-only \
--tmpfs /run:rw,noexec,nosuid,size=4m \
--tmpfs /tmp:rw,noexec,nosuid,size=4m \
-v $DATADIR:/data \
\
--cpus=1 \
--memory=1024m \
--memory-swap=1024m \
--memory-reservation=512m \
--oom-score-adj=-500 \
\
--ulimit nofile=1048576:1048576 \
--ulimit memlock=-1 \
--sysctl net.core.somaxconn=16384 \
\
--network network_public \
-p 4222:4222 \
-p 8222:8222 \
\
nats:latest \
--jetstream \
--store_dir /data;
# Analisando
docker inspect nats-server-js;
docker diff nats-server-js;
docker logs nats-server-js;
#-docker logs -f nats-server-js;
3.6 – Service para Compose
A configuração abaixo está com o JetStream ativado, para desativar basta remover o objeto “command” completamente.
services:
nats-server:
image: nats:latest
container_name: nats-server
hostname: nats-server.intranet.br
restart: always
read_only: true # equivalente a --read-only
tmpfs:
- /run:rw,noexec,nosuid,size=4m
- /tmp:rw,noexec,nosuid,size=4m
volumes:
# Dados persistentes (JetStream)
- ${DATADIR:-/storage/nats-server}:/data
# Arquivo de configuração (deve existir no host)
- ${DATADIR:-/storage/nats-server}/config/nats.conf:/etc/nats.conf:ro
cpus: '1'
mem_limit: 2048m
memswap_limit: 2048m
mem_reservation: 1024m
oom_score_adj: -500
ulimits:
nofile:
soft: 1048576
hard: 1048576
memlock:
soft: -1
hard: -1
sysctls:
net.core.somaxconn: 16384
networks:
- network_public
ports:
- "4222:4222" # Cliente NATS
- "8222:8222" # Endpoint de monitoramento
command: >
-c /etc/nats.conf
networks:
network_public:
external: true
name: network_public
3.7 – Service em Stack para Compose
Exemplo de atributos na stack para travar o NATS em nós do Swarm tipo manager e especificamente no nó chamado “manager-01“:
services:
nats-server:
image: nats:latest
hostname: nats-server.intranet.br
read_only: true
tmpfs:
- /run:rw,noexec,nosuid,size=4m
- /tmp:rw,noexec,nosuid,size=4m
volumes:
- ${DATADIR:-/storage/nats-server}:/data
- ${DATADIR:-/storage/nats-server}/config/nats.conf:/etc/nats.conf:ro
networks:
- network_public
ports:
- "4222:4222"
- "8222:8222"
command: >
-c /etc/nats.conf
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
- node.hostname == manager-01
resources:
limits:
cpus: '1'
memory: 2048M
reservations:
memory: 1024M
networks:
network_public:
external: true
name: network_public
4 – NATS com HTTPs e TLS via Traefik
Para usar o NATS atravessando a Internet é obrigatório o uso de HTTPs para proteger o acesso à API e TLS para proteger o protocolo de mensageria direta.
Configure previamente o DNS com o nome apontando para o IP público do servidor, exemplo:
- nats.seudominio.com.br
4.1 – Traefik com TLS offload
O Traefik deve abrir a porta do TLS 4222/TCP e receber o redirecionamento do Docker direto nela, logo, o NATS não poderá receber a porta 4222 diretamente pois ela é desprotegida por padrão.
Primeiramente, configurar o e-mail do LetsEncrypt:
# Email de registro no letsencrypt
EMAIL="voce@seudominio.com.br";
# Gravar no arquivo para consulta
echo "$EMAIL" > /etc/email;
Rodando Traefik:
#!/bin/sh
# Variaveis
# - Nome do container
NAME=traefik-app;
# - Imagem do software traefik
IMAGE=traefik:latest;
# - Email de registro no letsencrypt
EMAIL=$(head -1 /etc/email);
# - Diretorio do volume (dados persistentes)
DATADIR=/storage/$NAME;
# Preparar volume:
mkdir -p $DATADIR/letsencrypt;
mkdir -p $DATADIR/logs;
mkdir -p $DATADIR/config;
# Obter imagem atualizada:
docker pull $IMAGE;
# Remover instância atual:
docker rm -f $NAME 2>/dev/null;
# Renovar/criar/rodar:
docker run \
-d --restart=unless-stopped --name $NAME -h $NAME.intranet.br \
\
--network network_public \
\
-p 80:80 \
-p 443:443 \
-p 4222:4222 \
\
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v $DATADIR/letsencrypt:/etc/letsencrypt \
-v $DATADIR/config:/etc/traefik \
-v $DATADIR/logs:/logs \
\
--tmpfs /run:rw,noexec,nosuid,size=4m \
--tmpfs /tmp:rw,noexec,nosuid,size=4m \
--read-only \
\
$IMAGE \
\
--global.checkNewVersion=false \
--global.sendAnonymousUsage=false \
\
--api.insecure=true \
\
--log.level=INFO \
--log.filePath=/logs/error.log \
\
--accessLog.filePath=/logs/access.log \
\
--entrypoints.web.address=:80 \
--entrypoints.web.http.redirections.entryPoint.to=websecure \
--entrypoints.web.http.redirections.entryPoint.scheme=https \
--entrypoints.web.http.redirections.entryPoint.permanent=true \
\
--entrypoints.websecure.address=:443 \
\
--entrypoints.nats-tls.address=:4222 \
\
--providers.docker=true \
--providers.file.directory=/etc/traefik \
\
--certificatesresolvers.letsencrypt.acme.email=$EMAIL \
--certificatesresolvers.letsencrypt.acme.storage=/etc/letsencrypt/acme.json \
--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web;
4.2 – Rodando o NATS seguro
A porta internat do NATS para HTTP (8222) não será publicada, o acesso a ela se dará pelo Traefik via HTTPs.
A porta 4222 não será publicada pois agora pertence ao Traefik.
No container do NATS colocaremos as labels para instruir o Traefik a conduzir o trafego HTTPs para a porta interna 8222 e o Trafego TLS na porta externa 4222 para a porta interna 4222.
# Rodar NATS em container - Configuração completa
# - Limite de RAM: 2048 MB (2 GB)
# - Reserva de RAM: 1024 MB
# - Volume para o JetStream
# Nome de DNS
FQDN="nats.meudominio.com.br";
#- FQDN="nats.$(hostname -f)";
#- FQDN="nats.$(hostname -d)";
# Pasta para o volume
DATADIR=/storage/nats-server;
mkdir -p $DATADIR;
# Baixar imagem
docker pull nats:latest;
# Renovar/rodar
docker rm -f nats-server 2>/dev/null;
docker run \
-d --restart=always \
--name nats-server \
-h nats-server.intranet.br \
\
--read-only \
--tmpfs /run:rw,noexec,nosuid,size=4m \
--tmpfs /tmp:rw,noexec,nosuid,size=4m \
-v $DATADIR:/data \
-v $DATADIR/config/nats.conf:/etc/nats.conf:ro \
\
--cpus=1 \
--memory=2048m \
--memory-swap=2048m \
--memory-reservation=1024m \
--oom-score-adj=-500 \
\
--ulimit nofile=1048576:1048576 \
--ulimit memlock=-1 \
--sysctl net.core.somaxconn=16384 \
\
--network network_public \
\
--label "traefik.enable=true" \
--label "traefik.http.routers.nats-8222.rule=Host(\`$FQDN\`)" \
--label "traefik.http.routers.nats-8222.entrypoints=web,websecure" \
--label "traefik.http.routers.nats-8222.tls=true" \
--label "traefik.http.routers.nats-8222.tls.certresolver=letsencrypt" \
--label "traefik.http.services.nats-8222.loadbalancer.passHostHeader=true" \
--label "traefik.http.services.nats-8222.loadbalancer.server.port=8222" \
\
--label "traefik.tcp.routers.nats-4222.entrypoints=nats-tls" \
--label "traefik.tcp.routers.nats-4222.rule=HostSNI(\`$FQDN\`)" \
--label "traefik.tcp.routers.nats-4222.tls=true" \
--label "traefik.tcp.routers.nats-4222.tls.certresolver=letsencrypt" \
--label "traefik.tcp.services.nats-4222.loadbalancer.server.port=4222" \
\
nats:latest \
-c /etc/nats.conf;
# Analisando
docker inspect nats-server;
docker diff nats-server;
docker logs nats-server;
#-docker logs -f nats-server;
4.3 – Stack Traefik + NATS
Configuração final do serviço Traefik com NATS.
Observe as variáveis ACME_EMAIL e NATS_FQDN.
networks:
network_public:
external: true
services:
traefik:
image: traefik:latest
container_name: traefik-app
hostname: traefik-app.intranet.br
restart: unless-stopped
read_only: true
networks:
- network_public
ports:
- "80:80"
- "443:443"
- "4222:4222"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /storage/traefik-app/letsencrypt:/etc/letsencrypt
- /storage/traefik-app/config:/etc/traefik
- /storage/traefik-app/logs:/logs
tmpfs:
- /run:rw,noexec,nosuid,size=4m
- /tmp:rw,noexec,nosuid,size=4m
command:
- --global.checkNewVersion=false
- --global.sendAnonymousUsage=false
- --api.insecure=true
- --log.level=INFO
- --log.filePath=/logs/error.log
- --accessLog.filePath=/logs/access.log
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.web.http.redirections.entryPoint.scheme=https
- --entrypoints.web.http.redirections.entryPoint.permanent=true
- --entrypoints.websecure.address=:443
- --entrypoints.nats-tls.address=:4222
- --providers.docker=true
- --providers.file.directory=/etc/traefik
- --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}
- --certificatesresolvers.letsencrypt.acme.storage=/etc/letsencrypt/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
nats:
image: nats:latest
container_name: nats-server
hostname: nats-server.intranet.br
restart: always
read_only: true
networks:
- network_public
volumes:
- /storage/nats-server:/data
- /storage/nats-server/config/nats.conf:/etc/nats.conf:ro
tmpfs:
- /run:rw,noexec,nosuid,size=4m
- /tmp:rw,noexec,nosuid,size=4m
deploy:
resources:
limits:
cpus: "1"
memory: 2048m
reservations:
memory: 1024m
mem_swappiness: 0
ulimits:
nofile:
soft: 1048576
hard: 1048576
memlock: -1
sysctls:
net.core.somaxconn: 16384
labels:
- "traefik.enable=true"
- "traefik.http.routers.nats-8222.rule=Host(`${NATS_FQDN}`)"
- "traefik.http.routers.nats-8222.entrypoints=web,websecure"
- "traefik.http.routers.nats-8222.tls=true"
- "traefik.http.routers.nats-8222.tls.certresolver=letsencrypt"
- "traefik.http.services.nats-8222.loadbalancer.passHostHeader=true"
- "traefik.http.services.nats-8222.loadbalancer.server.port=8222"
- "traefik.tcp.routers.nats-4222.entrypoints=nats-tls"
- "traefik.tcp.routers.nats-4222.rule=HostSNI(`${NATS_FQDN}`)"
- "traefik.tcp.routers.nats-4222.tls=true"
- "traefik.tcp.routers.nats-4222.tls.certresolver=letsencrypt"
- "traefik.tcp.services.nats-4222.loadbalancer.server.port=4222"
command:
- -c=/etc/nats.conf
5 – Verificando o NATS
Esses são os procedimentos para testar o funcionamento do NATS.
5.1 – Endpoints de teste
Na porta HTTP 8222 do NATS, acesse as seguintes endpoints:
- /varz – Exibir as variáveis, estatisticas e informações do servidor;
- /debug/vars – Variaveis de debug;
- /connz – Informações de conexões;
- /routez – Informações sobre roteamento de mensagens;
- /gatewayz – Informações sobre os gateways usados no cluster;
- /leafz – Informações sobre o nó;
- /raftz – Informações do cluster (Raft);
- /subsz – Informações sobre os sistemas inscritos (subscribers);
- /accountz – Informações sobre contas ativas;
- /accstatz – Informações de contabilidade por conta ativa;
- /jsz – Informações sobre o JetStream;
- /healthz – Endpoint de health check do servidor;
- /healthz?js-enabled=true
- /healthz?js-server-only=true
Exemplo:
# URL do NATS:
NATS_URL="https://nats.seudominio.com.br";
# Conferir saude do NATS:
curl -s "$NATS_URL/healthz"; echo;
# Retorno:
# {"status":"ok"}
6 – Acessando o NATS
A conexão deve ser feita na porta 4222 (TCP, texto puro para mensageria) via telnet. Para acesso externo seguro será necessário estabelecer conexão TLS primeiro.
6.1 – Caixa de ferramentas
Criando container do nats-box (Alpine Linux com cliente nats) para testes do nats-server na mesma rede de containers network_public:
# Container para teste do NATS
# Pasta para volume, necessario para salvar contexto de acesso
DATADIR=/storage/nats-box;
mkdir -p $DATADIR;
# Rodar/renovar
docker pull natsio/nats-box:latest;
docker rm -f nats-box 2>/dev/null;
docker run \
-d \
--name nats-box \
--hostname nats-box.intranet.br \
\
--network network_public \
-v $DATADIR:/nsc \
\
natsio/nats-box:latest \
tail -f /dev/null;
# Obter shell no container nats-box:
docker exec -it nats-box ash;
Agora estaremos dentro do container nats-box. Analise do comando cliente nats:
# Comando: nats
nats;
# usage: nats [<flags>] <command> [<args> ...]
# NATS Utility
# NATS Server and JetStream administration.
# See 'nats cheat' for a quick cheatsheet of commands
# Commands:
# account Account information and status
# audit Audit a NATS deployment
# auth NATS Decentralized Authentication
# bench Benchmark utility
# consumer JetStream Consumer management
# context Manage nats configuration contexts
# counter Access distributed Counters
# errors Error code documentation
# events Show Advisories and Events
# kv Interacts with a JetStream based Key-Value store
# latency Perform latency tests between two NATS servers
# object Interacts with a JetStream based Object store
# publish Generic data publish utility
# request Generic request-reply request utility
# reply Generic service reply utility
# rtt Compute round-trip time to NATS server
# schema Schema tools
# server Server information
# service Services discovery and management
# stream JetStream Stream management
# subscribe Generic subscription client
# top Shows top-like statistic for connections on a specific server
# trace Trace message delivery within an NATS network
# Pass --help to see global flags applicable to this command.
6.2 – Caixa de ferramentas
Primeiro contato com a administração do NATS via CLI:
# Testes iniciais da porta do servico de mensageria
# - Login e senha de admin
USER="admin";
PASS="tulipanats";
# 1 - O servidor responde no protocolo NATS?
nats --server nats://$USER:$PASS@nats-server:4222 server ping;
#
# nats-tutorial rtt=1.826998ms
# ---- ping statistics ----
# 1 replies max: 1.00 min: 1.00 avg: 1.00
#
# 2 - A autenticação e account estao corretas?
nats --server nats://$USER:$PASS@nats-server:4222 account info;
# User: admin
# Account: SYS
# Expires: never
# Client ID: 8
# Client IP: 2001:db8:10:180::a ([2001:db8:10:180::a]:42200)
# RTT: 1ms
# Headers Supported: true
# Maximum Payload: 1.0 MiB
# Connected URL: nats://admin:tulipanats@nats-server:4222
# Connected Address: [2001:db8:10:180::9]:4222
# Connected Server ID: ND7B3BQXUJHYQGVKRBGMNHSQQFOVLVGNKV76EQGNRGUKQVJ
# Connected Server Version: 2.12.8
# Connected Server Name: nats-tutorial
# TLS Connection: no
#
# Could not obtain account information: JetStream not enabled for account (10039)
#
# 3 - Publica e recebe mensagem basica?
nats --server nats://$USER:$PASS@nats-server:4222 pub teste "oi";
# 20:22:23 Published 2 bytes to "teste"
6.3 – Contexto administrativo
Criar contexto para usuário admin dentro do nats-box:
# - Login e senha de administrador
USER="admin";
PASS="tulipanats";
# Criar contexto salvo
nats context save \
admin-srv01 \
--server nats://nats-server:4222 \
--user $USER --password $PASS;
# NATS Configuration Context "admin-srv01"
# Server URLs: nats://nats-server:4222
# Username: admin
# Password: **********
# Path: /nsc/.config/nats/context/admin-srv01.json
# Selecionar contexto admin para uso:
nats context select admin-srv01;
Principais comandos de administração:
# Informacoes gerais do servidor
nats server info;
# Ping no servidor (latência)
nats server ping;
# Estatísticas em tempo real
nats server report;
# Status do JetStream
nats server report jetstream;
# Verificar conexões ativas
nats server report connections;
# Verificar accounts
nats server report accounts;
6.4 – Contexto de usuário
Vamos criar o contexto de acesso no cliente nats para acessos e uso da mensageria:
# - Login e senha de usuario
USER="app";
PASS="tulipanats";
# Criar contexto salvo
nats context save \
user-srv01 \
--server nats://nats-server:4222 \
--user $USER --password $PASS;
# NATS Configuration Context "srv01"
# Server URLs: nats://nats-server:4222
# Username: app
# Password: **********
# Path: /nsc/.config/nats/context/srv01.json
# Definir contexto de usuario como padrão
nats context select user-srv01;
# Testando
# - Ping
nats server ping;
# - Enviar mensagem de teste de mensageria
nats pub test_inbox "hello world";
# 20:42:32 Published 11 bytes to "test_inbox"
# - Exemplos
nats pub meu.topico "Ola NATS";
nats pub meu.topico '{"evento": "teste", "valor": 42}'
# Publicar múltiplas vezes (sinais duplicados)
nats pub meu.topico "mensagem" --count 5;
# 21:08:00 Published 8 bytes to "meu.topico"
# 21:08:00 Published 8 bytes to "meu.topico"
# 21:08:00 Published 8 bytes to "meu.topico"
# 21:08:00 Published 8 bytes to "meu.topico"
# 21:08:00 Published 8 bytes to "meu.topico"
# Publicar com delay de 1 segundo entre mensagens
nats pub meu.topico "refresh-system" --count 10 --sleep 1s;
# 21:08:34 Published 14 bytes to "meu.topico"
# 21:08:35 Published 14 bytes to "meu.topico"
# 21:08:36 Published 14 bytes to "meu.topico"
# 21:08:37 Published 14 bytes to "meu.topico"
# 21:08:38 Published 14 bytes to "meu.topico"
# 21:08:39 Published 14 bytes to "meu.topico"
# 21:08:40 Published 14 bytes to "meu.topico"
# 21:08:41 Published 14 bytes to "meu.topico"
# 21:08:42 Published 14 bytes to "meu.topico"
# 21:08:43 Published 14 bytes to "meu.topico"
7 – Usando Pub/Sub
Vamos explorar o recurso de publisher/subscriber (pub/sub).
Os publicadores (publishers) são os sistemas que enviam mensagens para um subject (assunto) que se comporta como uma caixa de entrada de mensagens.
Os inscritos (subscribers) são os sistemas que escutam mensagens para esse subject aguardando mensagens.
Quando existem vários subscribers a mensagem é enviada a todos em modo broadcast Cada subscriber recebe todas as mensagens que batem com o wildcard de subject que escutar criando um padrão fan-out.
fazer desenho aqui
Publisher -> subject "orders.new" -> Subscriber A
-> Subscriber B
-> Subscriber C
Enviando mensagem (pub):
# Subject de destino
SUBJECT="orders.new";
# Payload da mensagem
PAYLOAD="{ 'order': 188281, 'uuid': 'e9fa669e-c1c3-4153-b218-a375b61de7ff' }";
# - Enviar mensagem para o NATS
nats pub "$SUBJECT" "$PAYLOAD";
# 20:52:54 Published 67 bytes to "orders.new"
As mensagens acima serão perdidas pra sempre se não houver nenhum inscrito para o tópico orders.new.
Rodar consumer (inscrito, consumidor) para acompanhar as mensagens:
# Subject de escuta
WILDCARD="orders.*";
# - Conectar para consumo de mensagens
nats sub "$WILDCARD";
Com o nats sub rodando, rode novamente o envio nats pub para o subject orders.new e observe o recebimento.
No terminal do subscribe o retorno será:
# nats sub "orders.*";
21:11:40 Subscribing on orders.*
[#1] Received on "orders.new"
{ 'order': 188281, 'uuid': 'e9fa669e-c1c3-4153-b218-a375b61de7ff' }
.
.
.
.
“A vida vai ficando cada
vez mais dura perto do topo.“
Friedrich Nietzsche
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
