Contenitore Discourse con UnixSocket per Redis?

Mi chiedo se qualcuno stia utilizzando unixsocket /var/discourse/shared/... per Redis nel proprio container standalone? Sembra che redis-rb supporti anche i socket di dominio con:

redis = Redis.new(path: "/var/discourse/shared/standalone/redis.sock")

A quanto pare, connettersi tramite socket di dominio Unix è circa il 20% più veloce rispetto all’uso di socket TCP, secondo questo articolo su Medium

Inoltre, l’uso dei socket di dominio Unix renderebbe più semplice eseguire più container standalone senza separare i container web e dati… Altrimenti, penso che si verifichino conflitti con Redis in ascolto su 127.0.0.1…

Sto cercando di configurare due container completamente standalone su un singolo host al momento, e dato che entrambi sono per siti molto piccoli, preferirei la flessibilità di mantenerli in container standalone… Purtroppo, Redis in ascolto su 127.0.0.1 (e presumibilmente anche Postgres) creerà conflitti…

Ciao @ryanerwin

Sembra che tu non abbia ancora compreso appieno il concetto di container e Docker; quindi lasciami aiutarti.

Di default, Redis viene eseguito nel container standalone sulla porta 6379:

cd /var/discourse
./launcher enter app
apt install net-tools
netstat -an | grep :6379 |wc -l 

74

Ora usciamo dal container e controlliamo netstat per Redis:

exit
root@localhost:/var/discourse# netstat -an | grep :6379 |wc -l 
0

Quindi, puoi vedere che Redis è in ascolto su localhost all’interno del container; e localhost all’interno del container non è stato (non è) esposto all’esterno del container.

Di conseguenza, se hai molti container Discourse standalone in esecuzione, non ci saranno conflitti Redis tra i container perché Redis non è stato esposto all’esterno di ciascun container.

È per questo che si chiama “container”… :slight_smile:

Ogni socket all’interno del container deve essere esplicitamente esposto per essere disponibile all’esterno del container.

Spero che questo possa esserti utile in qualche piccolo modo.


Nota che i socket di dominio Unix sono molto interessanti… Ho solo risposto al tuo commento sui presunti conflitti Redis tra container standalone e non ho affrontato l’argomento dei socket di dominio Unix.

Pensavo che funzionasse così anche con Discourse eseguito all’interno di Docker, tuttavia, quando l’ho effettivamente avviato, durante il processo di bootstrap ho visto:

INFO -- : > cd /var/www/discourse && git reset --hard
# oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
# Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=195, just started
# Configuration loaded
# Could not create server TCP listening socket *:6379: bind: Address already in use
Checking out files: 100% (27893/27893), done.

E avevo trovato questo thread su “install fails because of other redis container”, ma il problema era in realtà lo spazio su disco insufficiente… Ho riorganizzato alcune cose e ora funziona perfettamente con più contenitori standalone.

Gentile @ryanerwin,

È ottimo leggere che hai individuato il problema sottostante e ora hai capito che Redis viene eseguito “all’interno del container” e non è esposto (da una prospettiva di I/O dei socket) all’esterno del container (come configurato di default).

Per quanto riguarda l’uso di socket di dominio Unix con Redis, penso che sia un’ottima idea. Non l’ho ancora configurato e non ho letto alcuna guida su come impostarlo per Discourse, quindi ti incoraggio a continuare a esplorare questa opzione.

Se avrò tempo, farò ulteriori ricerche e proverò a configurare Redis per utilizzare un socket di dominio Unix in Discourse su un server di staging. Nel frattempo, se riesci a risolvere la questione e a condividere i risultati, lo apprezzerei molto. Sono sicuro che molti altri siano interessati a questo interessante argomento relativo a Redis.

Grazie.

Ciao @ryanerwin,

Spero che tu sia felice di sapere che ho Discourse in esecuzione con Redis utilizzando un socket Unix in un container standalone, proprio come hai chiesto.

Guarda la parte inferiore di questo screenshot da Sidekiq:

Inoltre, ecco alcuni altri screenshot relativi alla costruzione dell’app:

I miei prossimi passi sono:

  1. Spostare il socket Unix nel volume condiviso in modo che possa essere accessibile al di fuori del container.
  2. Riprovare i test con un numero minimo di variabili ENV per ottenere le modifiche essenziali per far funzionare tutto.

In sostanza, ho creato questo nuovo template:

-rw-r–r-- 1 root root 2028 Jun 6 08:13 redis.socketed.template.yml

Screen Shot 2020-06-06 at 4.18.55 PM

e ho apportato piccole modifiche al vecchio amico app.yml

Dato che ho iniziato tutto oggi, ho intenzione di fare ulteriori test prima di pubblicare i dettagli.

Spero che questo sia utile.


Aggiornamento


Funziona come previsto al di fuori del container quando il socket Unix si trova su un volume condiviso:

PR a riguardo:

Nota:

Per implementare:

  • Modifica il template di Redis nel file yml del contenitore
  • Aggiungi una riga aggiuntiva allo stesso file yml del contenitore
 ## Imposta REDIS_URL e utilizza redis.socketed.template.yml per usare 
 ## un socket di dominio Unix per Redis
 REDIS_URL: unix:///shared/tmp/redis.sock

Note sull’implementazione:

  1. Se sei preoccupato per la sicurezza del database Redis sull’host, non è necessario esporre questo socket Unix nel volume condiviso.

  2. Se desideri impostare i permessi del socket Unix su 770 (invece di 777), modifica il gruppo del socket Unix in www-data.

Qualcun altro ha notato che REDIS_URL non ha più alcun effetto? Durante la (ri)compilazione e anche all’avvio del container, nonostante REDIS_URL sia impostato per connettersi tramite socket UNIX, tenta di connettersi tramite redis://localhost:6379.

Da un lato, ha senso, poiché Discourse ha configurazioni per host e porta e le applica solo: discourse/app/models/global_setting.rb at main · discourse/discourse · GitHub
Ci sarebbe un parametro path per definire un percorso del socket UNIX, che sovrascriverebbe host e porta. E ci sarebbe un parametro url, per definire un URL completo come unix:///shared/redis_data/redis.sock.

La gemma Redis documenta che la variabile d’ambiente REDIS_URL sovrascriverebbe qualsiasi altra impostazione, e fino a una certa versione della gemma Discourse/Redis questo ha funzionato: redis-rb/lib/redis.rb at master · redis/redis-rb · GitHub

L’uso del socket UNIX si è interrotto quando Discourse è passato alla versione 5 delle gemme Redis: DEV: Upgrade the Redis gem to v5.4 · discourse/discourse@2ed31fe · GitHub
Quindi suppongo che REDIS_URL si sia interrotto nella gemma Redis (non sovrascrivendo più altre opzioni), e non da Discourse (dove il codice correlato non è cambiato)?

Probabilmente questo commit l’ha rotto: Use redis-client as transport · redis/redis-rb@08a2100 · GitHub
Lo segnalerei nel repository della gemma Redis, o qualcuno sa che è un problema con il modo in cui Discourse lo implementa?

La variabile d’ambiente, tra l’altro, viene passata correttamente. L’ho lasciata attiva e ho solo configurato Redis per non ascoltare sul socket UNIX, e mentre unicorn si avvia correttamente, sidekiq fallisce, mancando il socket UNIX invece :sweat_smile::

Error in demon processes heartbeat check: No such file or directory - connect(2) for /shared/redis_data/redis.sock
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:116:in `initialize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:116:in `new'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:116:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/ruby_connection.rb:51:in `initialize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:759:in `new'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:759:in `block in connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client/middlewares.rb:12:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:758:in `connect'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:745:in `raw_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:705:in `ensure_connected'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/redis-client-0.24.0/lib/redis_client.rb:285:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/redis_client_adapter.rb:36:in `block (2 levels) in <module:CompatMethods>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/api.rb:912:in `block in cleanup'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/config.rb:175:in `block in redis'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:110:in `block (2 levels) in with'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:109:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:109:in `block in with'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:106:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/connection_pool-2.5.3/lib/connection_pool.rb:106:in `with'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/config.rb:172:in `redis'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq.rb:74:in `redis'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/api.rb:912:in `cleanup'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/api.rb:903:in `initialize'
/var/www/discourse/lib/demon/sidekiq.rb:25:in `new'
/var/www/discourse/lib/demon/sidekiq.rb:25:in `heartbeat_check'
config/unicorn.conf.rb:131:in `block (2 levels) in reload'

Si adatta al quadro il fatto che REDIS_URL funzioni ancora, ma solo se le impostazioni di connessione non sono definite diversamente. Guardando la traccia dell’errore, global_setting.rb non applica host e porta per sidekiq, come fa per unicorn.