Cluster RabbitMQ+HAProxy con Docker
Nell'ottica di "tutte le volte che mi invento qualcosa di interessante ora me lo segno", una rapida spiegazione di come costruire un cluster RabbitMQ (per MQTT) sotto Docker.
La struttura della cartella di lavoro è la seguente:
rabbitmq
|--> etc
|-> enabled_plugins
|-> rabbitmq.conf
|-> definitions.json
haproxy
|--> haproxy.cfg
docker-compose.yml
Questo è il docker-compose, che si occupa di avviare le tre istanze di rabbitmq e l'istanza di haproxy:
version: "3.8"
services:
haproxy:
image: "haproxy:alpine"
hostname: "haproxy"
volumes:
- "./haproxy/:/usr/local/etc/haproxy:ro"
depends_on:
- "rabbit1"
- "rabbit2"
- "rabbit3"
ports:
# interfaccia web HAProxy
- "6010:6010"
# porta AMQP per cluster rabbitmq
- "1883:1883"
rabbit1:
image: "rabbitmq:3.8.9-management-alpine"
hostname: "rabbit1"
volumes:
- "./rabbitmq/etc/:/etc/rabbitmq/"
ports:
# interfaccia web
- "6001:15672"
environment:
- "RABBITMQ_ERLANG_COOKIE=supersecretcookiestringsecret"
rabbit2:
image: "rabbitmq:3.8.9-management-alpine"
hostname: "rabbit2"
volumes:
- "./rabbitmq/etc/:/etc/rabbitmq/"
ports:
# interfaccia web
- "6002:15672"
depends_on:
- "rabbit1"
environment:
- "RABBITMQ_ERLANG_COOKIE=supersecretcookiestringsecret"
rabbit3:
image: "rabbitmq:3.8.9-management-alpine"
hostname: "rabbit3"
volumes:
- "./rabbitmq/etc/:/etc/rabbitmq/"
ports:
# interfaccia web
- "6003:15672"
depends_on:
- "rabbit1"
environment:
- "RABBITMQ_ERLANG_COOKIE=supersecretcookiestringsecret"
Nota che in questo assetto vengono aperte le seguenti porte:
- 1883: MQTT
- 6010: interfaccia web per amministrazione HAProxy
- 6001/2/3: interfacce web per l'amministrazione dei nodi rabbitmq
Questi sono i file di configurazione di RabbitMQ (in questa configurazione abbiamo attivato l'interfaccia web di configurazione e il plugin MQTT). La riga relativa al caricamento del file delle definizioni può essere omessa al primo avvio; successivamente, dopo aver configurato il cluster mediante API o interfaccia web, si può esportare la configurazione stessa dalla pagina web e usare il file per avere il cluster già configurato per gli avvii successivi.
rabbitmq.conf
# Caricamento iniziale della struttura del server rabbit (se non disponibile
# si può omettere).
load_definitions=/etc/rabbitmq/definitions.json
cluster_formation.node_type = disc
cluster_formation.classic_config.nodes.1 = rabbit@rabbit1
cluster_formation.classic_config.nodes.2 = rabbit@rabbit2
cluster_formation.classic_config.nodes.3 = rabbit@rabbit3
enabled_plugins
[rabbitmq_management, rabbitmq_mqtt].
E questo è il file di configurazione di HAProxy (con attiva l'interfaccia web di gestione):
defaults
timeout connect 5s
timeout client 100s
timeout server 100s
listen rabbitmq-servers-mqtt
bind :1883
mode tcp
balance roundrobin
timeout client 3h
timeout server 3h
server rabbit1 rabbit1:1883 check inter 5s rise 2 fall 3
server rabbit2 rabbit2:1883 check inter 5s rise 2 fall 3
server rabbit3 rabbit3:1883 check inter 5s rise 2 fall 3
frontend stats
bind :6010
mode http
stats enable
stats uri /
stats refresh 10s
stats admin if TRUE
Nota: al primo avvio il cluster RabbitMQ ha solo l'utente guest/guest, che può accedere solo da interfaccia locale (quindi da dentro la macchina). Per poter accedere all'interfaccia web è necessario creare un nuovo utente mediante riga di comando.
Per individuare il nome (container id) del container docker relativo al primo RabbitMQ:
docker ps
Per aprire una shell dentro il container:
docker exec -ti CONTAINERID /bin/bash
Per creare un nuovo utente e dargli accesso all'interfaccia web:
rabbitmqctl add_user NOMEUTENTE PASSWORD
rabbitmqctl set_user_tags NOMEUTENTE administrator
Come spiegato prima, usando l'interfaccia web si può ora esportare un file di configurazione, che potrà essere caricato nei successivi riavvii del cluster mediante la direttiva load_definitions del rabbitmq.conf.