Utiliser peertube en lecture seule

Salut,

Dans le cadre d’un PRA (réplication master / slave postgres), j’aimerais savoir si cela est possible d’avoir une instance (le slave) en lecture seul ?
Quels sont les tables dans lesquelles, même si on ne pousse pas de nouvelles videos, peertube devra pouvoir continuer d’écrire ? tracker ?

Est il possible qu’au moins les urls vers les videos continuent de fonctionner avec une base en lecture seule ?

Je ne suis pas sûr de saisir quel est le but de tout ça. Mais avoir une base en lecture seule risque de poser de gros problème pour :

  • interactions locales (follow, likes, commentaires, modération, etc…)
  • la gestion de la fédération (follow, likes, commentaires entrant)
  • la gestion de la redondance : votre instance ne pourra plus enregistrer le fait que certains serveurs externe redonde les vidéos, ou arrête de redonder. Ce qui pourra entrainer des problèmes de lecture de vidéo (si une instance distante arrête de redonder, et que votre instance n’en tient pas compte)
  • probablement le renouvellement des tokens d’authentification: il ne sera plus possible de se (re)connecter, et tout le monde sera déconnecté au bout de 24h
  • enregistrement des statistiques de visualisation

Ça c’est ce qui me passe par la tête. Sachant que je ne suis pas vraiment dev sur le Core de Peertube, il y a sans doute plein de choses que j’oublie.

Il s’agit de basculer sur l’application en mode dégradé le temps que l’application « maitre » soit de nouveau disponible.
Bien sur, on dira aux gens que lorsqu’ils sont sur cette instance, il ne peuvent plus écrire des commentaires, se connecter etc …
Il faut surtout que les liens vers les videos continuent de fonctionner.
Oui, dans ce que tu as lister il manque bien sur d’autres choses, comme l’erreur que je vois actuellement dans les logs :

{"err":{"stack":"Error\n    at Query.run (/var/www/peertube/versions/peertube-v5.1.0/node_modules/sequelize/lib/dialects/postgres/query.js:50:25)\n    at /var/www/peertube/versions/peertube-v5.1.0/node_modules/sequelize/lib/sequelize.js:315:28\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)","message":"ne peut pas exécuter CREATE FUNCTION dans une transaction en lecture seule","name":"SequelizeDatabaseError","parent":{"stack":"error: ne peut pas exécuter CREATE FUNCTION dans une transaction en lecture seule\n    at Parser.parseErrorMessage (/var/www/peertube/versions/peertube-v5.1.0/node_modules/pg-protocol/dist/parser.js:287:98)\n    at Parser.handlePacket (/var/www/peertube/versions/peertube-v5.1.0/node_modules/pg-protocol/dist/parser.js:126:29)\n    at Parser.parse (/var/www/peertube/versions/peertube-v5.1.0/node_modules/pg-protocol/dist/parser.js:39:38)\n    at Socket.<anonymous> (/var/www/peertube/versions/peertube-v5.1.0/node_modules/pg-protocol/dist/index.js:11:42)\n    at Socket.emit (node:events:513:28)\n    at addChunk (node:internal/streams/readable:315:12)\n    at readableAddChunk (node:internal/streams/readable:289:9)\n    at Socket.Readable.push (node:internal/streams/readable:228:10)\n    at TCP.onStreamRead (node:internal/stream_base_commons:190:23)","message":"ne peut pas exécuter CREATE FUNCTION dans une transaction en lecture seule","length":146,"name":"error","severity":"ERREUR","code":"25006","file":"utility.c","line":"414","routine":"PreventCommandIfReadOnly","sql":"CREATE OR REPLACE FUNCTION immutable_unaccent(text)\n  RETURNS text AS\n$func$\nSELECT public.unaccent('public.unaccent', $1::text)\n$func$  LANGUAGE sql IMMUTABLE;"},"sql":"CREATE OR REPLACE FUNCTION immutable_unaccent(text)\n  RETURNS text AS\n$func$\nSELECT public.unaccent('public.unaccent', $1::text)\n$func$  LANGUAGE sql IMMUTABLE;","parameters":{}},"level":"error","message":"Cannot start application.","label":"tube.reseau-canope.fr:443","timestamp":"2023-04-25T15:10:27.565Z"}

Il me semble que Posgresql a des options pour avoir des clusters qui permettent de gérer ça automatiquement, sans notion de primaire/secondaire.
(je dis ça, mais mes connaissances sur le sujet sont très anciennes, et plutôt vagues)

Oui bien sur, les clusters existent, mais je pense que peertube n’est pas compatible.
Par exemple, si on 2 instances peertube identiques qui pointe sur la même base (sur le cluster) de donnée, ils vont, comme le message d’erreur l’indique au démarrage du service :

CREATE OR REPLACE FUNCTION immutable_unaccent(text)\n RETURNS text AS\n$func$\nSELECT public.unaccent(‹ public.unaccent ›, $1::text)\n$func$

d’ailleurs c’est bizarre cette requête au démarrage du service …
Chacun des serveurs va exécuter cette commande, qui est identique et cela va donc poser problème.
J’imagine en plus que ce ne sera pas la seule, puisqu’il y a je penses quelques task queue qui seront redondants …

Mon objectif est bien d’'avoir une instance peertube en failover. Par faire du load balancing, mais pouvoir basculer sur l’instance de secours, en cas de problème.

Ah mais ce n’est pas du tout la même chose !
Peertube n’est pas du tout fait pour avoir 2 Peertubes sur la même base de donnée. Ça va poser de très gros problèmes si tu fais ça.

Peertube est, et doit, rester mono-instance (en tout cas à l’heure où je parle).

oui, c’est pour cela que je partais plutot sur une replication de la base, et pas une base « partagée »

Saurais tu si on pourquoi il fait se create function au démarrage du service ?
Aussi, saurais tu si on peu désactiver dans le production.yaml par exemple, d’une façon global, le fait de pouvoir, s’authentifier, ajouter des commentaires, publier des videos …

Avoir des écarts de conf entre les 2 pourrait avoir des effets inattendu, notamment sur la fédération.

Je pense que ce n’est pas la bonne piste.
Tout ça donnerait un setup extrêmement compliqué, et surtout très fragile (la moindre maj de Peertube pourrait tout casser, et il y aurait d’inonbrables effets de bord).

Déjà, il faut se demander à quel point la haute disponibilité est nécessaire. Si on parle de coupures de quelques secondes/minutes lors des maj Peertube, ce n’est pas forcément gênant. Il y a même moyen que ça ne se remarque pas (Nginx pouvant servir tout ce qui est fichier statiques, une personne déjà entrain de regarder une vidéo ne verra même pas la différence).

Pour le cas des pannes matérielles, il y a des solutions plus robustes, et simples à mettre en place. Par exemple, utiliser un cluster de VM. Il y a plein d’outils libres (et/ou open source) qui permettent de mettre en place ce genre de clusters (Ganeti, Proxmox, …).
Avec ce genre de système, tu peux très facilement avoir 2 VMs synchronisées. Une primaire, et une secondaire. Si la primaire disparait, la secondaire démarre automatiquement. Tu peux aussi migrer à chaud les VMs si tu as besoin d’intervenir sur les hôtes.
Niveau stockage, tout va être répliqué entre 2 machines hôtes (via DRBD par exemple). Et si en plus tu as du RAID 1 ou 10 (par ex) sur les machines hôtes, tes données sont clonées sur 4 disques au total ! Autant dire que les risques de perte de donnée à cause d’une panne matérielle deviennent faibles.

Sans compter que tu peux aussi utiliser du stockage via le protocole S3 pour les vidéos en elle-même, ce qui permet encore un autre niveau de redondance !

Oui je connais les possibilités d’avoir une machine en standby et de la démarrer en cas de grosse catastrophe (pour info, on est déjà sur du stockage S3).
Mais le je parle d’effectivement des 5 min de coupure pendant les mises à jour par exemple.
Pour nous, ce n’est pas acceptable que les videos de répondent plus. En effet, les videos de notre peertube, seront intégré dans des iframe des pas mal de sites web.
Du coup, si tu vois une solution de cache temporaire avec nginx, ca m’interesse effectivement.
Comme notre stockage S3 est derrière un pseudo CDN, on pourrait activé le cache sur le NGINX de notre CDN. Par contre, cela ne couvrirait pas par exemple les videos qui n’auraient pas été cliqué depuis 1h par exemple et qui ne seraient donc pas en cache
Sachant que les liens iframe des différents sites pointerons sur l’url du peertube, et non pas directement sur l’url du stockage S3, pour pouvoir profiter du player, etc … et que l’url soit toujours la même, même en cas de remplacement de la video

En dehors de certaines mises à jours majeures, les coupures de Peertube lors des maj ne durent que quelques secondes. Le temps du «systemctl restart peertube». Quand on suit la doc officielle, Peertube continue de tourner avec la version précédente pendant toute la phase d’installation des dépendances.

Et pendant ces quelques secondes, Nginx continue de répondre pour les fichiers statiques et les vidéos. Ce ne sont que les requêtes d’API, et l’affichage de la page principale qui vont être bloqué.

Je pense sincèrement que ça ne vaut pas la peine de monter un setup compliqué juste pour 4 maj / an, qui vont avoir un impact mineur. Il serait beaucoup plus simple de planifier les maj en heures creuses.

Oui, je suis un peu d’accord, tu as raison.
C’est vrai aussi que le système de mis à jour permet d’avoir une coupure très courte

Pour info, le site fonctionne temporairement avec une base en lecture seule. C’est dès que l’on fait une action qui demande l’écriture, comme la connexion avec un compte, que cela fait planté toute l’appli

Le site tombe à la première erreur de type insert ou create en base, parce que ces erreurs ne sont pas gérés sur le node, ce qui le fait planter (enfin je pense)
Pour la mise en cache, cela ne fonctionne plus je pense depuis les versions 5.xx étant donné que tout passe par peertube à présent (contrairement à la version 4 ou les appels de videos publique étaient délivrés nginx directement)

Pour info, nous ne basculeront pas sur le serveur de secours pour les mises à jours.
Par contre, il y a une bascule automatique en cas de gros pb (si le site ne répond plus depuis + de 5 min) sur l’instance de secours. Cette dernière est une copie (rsync des fichiers + replication postgres). En cas de bascule il y a un script qui promu le service postgresql, de manière à ce qu’il soit accessible en écriture. Une commande désactive aussi le plugin auth-saml2 pour empêcher les authentifications externes sur cette instance de secours afin qu’il y ait le moins d’écriture possible sur cette instance.

Une autre façon de faire, qui aurait moins d’effets de bord, et serait beaucoup plus stable :

  • une instance primaire videos.domain.tld
  • une instance backup.domain.tld, qui fédère le contenu de videos.domain.tld (et éventuellement redonde les vidéos, mais ce n’est pas obligatoire)
  • quand une maintenance est planifiée sur videos.domain.tld, on modifie temporairement la configuration de Nginx sur videos.domain.tld, pour faire des redirection temporaire des urls /, /videos/watch/..., /embed/..., etc… pour que ça redirige sur la même url, mais sur backup.domain.tld. Quand je parle de redirection, je parle de redirection au sens http, avec un code 307 ( Temporary Redirect)

Attention, ne rediriger que les urls des «pleines pages». Pas les url d’API et cie. Comme ça, une personne qui arrive pour regarder une vidéo (que ce soit sur l’instance, ou via une iframe d’une vidéo embeded), vont basculer sur l’autre instance.

Pour les personnes qui étaient déjà entrain de regarder des vidéos, tout va continuer normalement. Nginx n’étant pas coupé, les vidéos continueront d’être lues comme si de rien n’était. Seules les requêtes de statistiques de vues vont potentiellement échouer.