Conteneur Discourse avec UnixSocket pour Redis ?

Je me demande si quelqu’un utilise unixsocket /var/discourse/shared/... pour Redis dans son conteneur autonome ? Il semble que redis-rb prenne également en charge les sockets de domaine avec :

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

Selon cet article sur Medium, se connecter via un socket de domaine Unix est environ 20 % plus rapide que d’utiliser des sockets TCP…

De plus, l’utilisation de sockets de domaine Unix faciliterait l’exécution de plusieurs conteneurs autonomes sans avoir à séparer vos conteneurs web et de données… Sinon, je pense que vous risquez de rencontrer des conflits avec Redis écoutant sur 127.0.0.1…

J’essaie actuellement de configurer deux conteneurs totalement autonomes sur un seul hôte, et comme ils sont tous deux destinés à des sites très petits, je préférerais la flexibilité de les garder dans des conteneurs autonomes… Malheureusement, le fait que Redis (et probablement Postgres aussi) écoute sur 127.0.0.1 entraînera des conflits…

1 « J'aime »

Bonjour @ryanerwin,

Il semble que vous ne compreniez pas tout à fait les conteneurs et Docker ; laissez-moi vous aider.

Redis s’exécute par défaut dans le conteneur autonome sur le port 6379 :

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

74

Sortons maintenant du conteneur et vérifions netstat pour Redis :

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

Vous voyez donc que Redis écoute sur localhost à l’intérieur du conteneur ; et localhost à l’intérieur du conteneur n’a pas été (n’est pas) exposé à l’extérieur du conteneur.

Ainsi, si vous avez de nombreux conteneurs Discourse autonomes en cours d’exécution, il n’y aura aucun conflit Redis entre les conteneurs car Redis n’a pas été exposé à l’extérieur de chaque conteneur.

C’est pourquoi on l’appelle un « conteneur »… :slight_smile:

Chaque socket à l’intérieur du conteneur doit être explicitement exposé pour être disponible à l’extérieur du conteneur.

J’espère que cela aide, même un peu.


Notez que les sockets de domaine Unix sont très cool… J’ai seulement répondu à votre commentaire concernant les conflits Redis perçus entre les conteneurs autonomes et je n’ai pas abordé le sujet des sockets de domaine Unix.

5 « J'aime »

C’est ainsi que je pensais que cela fonctionnerait avec Discourse exécuté dans Docker également. Cependant, lorsque je l’ai réellement exécuté, j’ai vu pendant le processus d’amorçage :

INFO -- : > cd /var/www/discourse && git reset --hard
# oO0OoO0OoO0Oo Redis démarre oO0OoO0OoO0Oo
# Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=195, vient de démarrer
# Configuration chargée
# Impossible de créer le socket d'écoute TCP *:6379 : bind : Adresse déjà utilisée
Vérification des fichiers : 100 % (27893/27893), terminé.

J’avais trouvé ce fil de discussion sur « l’installation échoue à cause d’un autre conteneur Redis », mais le problème était en réalité un manque d’espace disque… J’ai réorganisé certaines choses et cela fonctionne très bien avec plusieurs conteneurs autonomes.

2 « J'aime »

Cher @ryanerwin,

C’est une excellente nouvelle de lire que vous avez identifié le problème sous-jacent et que vous comprenez maintenant que Redis s’exécute « dans le conteneur » et n’est pas exposé (d’un point de vue E/S de socket) en dehors du conteneur (tel que configuré par défaut).

Concernant l’utilisation de sockets de domaine Unix avec Redis, je pense que c’est une excellente idée. Je ne l’ai pas encore configuré, et je n’ai lu aucun article expliquant comment procéder pour Discourse. Je vous encourage donc à continuer d’explorer cette option.

Si j’ai le temps, je ferai des recherches supplémentaires et essaierai de configurer Redis pour qu’il utilise un socket de domaine Unix dans Discourse sur un serveur de test. En attendant, si vous parvenez à résoudre cela et à partager vos résultats, ce serait grandement apprécié. Je suis sûr que beaucoup d’autres s’intéressent également à ce sujet intéressant concernant Redis.

Merci.

3 « J'aime »

Bonjour @ryanerwin,

J’espère que vous serez ravi d’apprendre que j’ai Discourse fonctionnant avec Redis via un socket Unix dans un conteneur autonome, exactement comme vous l’aviez demandé.

Regardez le bas de cette capture d’écran de Sidekiq :

De plus, voici quelques autres captures d’écran de la construction de l’application :

Mes prochaines étapes sont les suivantes :

  1. Déplacer le socket Unix vers le volume partagé afin qu’il puisse être accessible en dehors du conteneur.
  2. Re-tester avec un nombre minimal de variables d’environnement pour obtenir les modifications “essentielles” nécessaires à son fonctionnement.

En résumé, j’ai créé ce nouveau modèle :

-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

et apporté de légères modifications à mon vieil ami app.yml.

Puisque je n’ai commencé cela qu’aujourd’hui, je prévois de tester un peu plus avant de publier les détails.

J’espère que cela sera utile.


Mise à jour


Fonctionne comme prévu en dehors du conteneur lorsque le socket Unix se trouve sur un volume partagé :

4 « J'aime »

PR pour cela : Create initial redis.socketed.template.yml by unixneo · Pull Request #469 · discourse/discourse_docker · GitHub

Remarque :

Pour implémenter :

  • Modifiez le modèle Redis dans le fichier yml du conteneur
  • Ajoutez une ligne supplémentaire au même fichier yml du conteneur
## Définir REDIS_URL et utiliser redis.socketed.template.yml pour utiliser
## un socket de domaine Unix pour Redis
REDIS_URL: unix:///shared/tmp/redis.sock

Notes d’implémentation :

  1. Si vous vous souciez de la sécurité de la base de données Redis sur l’hôte, il n’est pas nécessaire d’exposer ce socket Unix dans le volume partagé.

  2. Si vous souhaitez définir les permissions du socket Unix à 770 (au lieu de 777), changez le groupe du socket Unix en www-data.

4 « J'aime »

Quelqu’un d’autre a-t-il remarqué que REDIS_URL n’a plus d’effet ? Lors de la (re)construction et même au démarrage du conteneur, malgré le réglage de REDIS_URL pour se connecter via un socket UNIX, il essaie de se connecter via redis://localhost:6379.

D’une part, cela a du sens, car Discourse a des configurations pour l’hôte et le port uniquement et les applique : discourse/app/models/global_setting.rb at main · discourse/discourse · GitHub
Il y aurait un paramètre path pour définir un chemin de socket UNIX, qui remplacerait l’hôte et le port. Et il y aurait un paramètre url, pour définir une URL complète comme unix:///shared/redis_data/redis.sock.

La gem Redis documente que la variable d’environnement REDIS_URL remplacerait tous les autres paramètres, et jusqu’à une certaine version de la gem Discourse/Redis, cela fonctionnait : redis-rb/lib/redis.rb at master · redis/redis-rb · GitHub

L’utilisation du socket UNIX a échoué lorsque Discourse est passé à la version 5 des gems Redis : DEV: Upgrade the Redis gem to v5.4 · discourse/discourse@2ed31fe · GitHub
Je suppose donc que REDIS_URL a échoué dans la gem Redis (ne remplaçant plus les autres options), et non par Discourse (où le code associé n’a pas changé) ?

Ce commit a probablement causé le problème : Use redis-client as transport · redis/redis-rb@08a2100 · GitHub
Je le signalerais dans le dépôt de la gem Redis, ou quelqu’un sait-il que c’est un problème avec la façon dont Discourse l’implémente ?

La variable d’environnement est d’ailleurs correctement transmise. Je l’ai laissée en place et j’ai seulement configuré Redis pour qu’il n’écoute pas sur le socket UNIX, et bien que unicorn démarre correctement, sidekiq échoue, manquant le socket UNIX à la place :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'

Cela correspond à l’idée que REDIS_URL fonctionne toujours, mais uniquement si les paramètres de connexion ne sont pas définis autrement. En regardant la trace d’erreur, global_setting.rb n’applique pas l’hôte et le port pour sidekiq, comme il le fait pour unicorn.