Files
BaC/content/2023-01-15-Migrer-Nextcloud-dun-stockage-local-a-S3.md
2025-02-27 12:52:48 +01:00

13 KiB
Raw Permalink Blame History

+++ title = "Migrer Nextcloud dun stockage local à S3" date = 2023-01-15 [taxonomies] tags = [ "système", "s3", "garage", "stockage", "nextcloud" ] +++

Ah bah ça, ça tombe bien alors!

La foule en délire

Avertissement

Même si je suis certain de mon coup et que cette procédure a été testé et validé avec succès sur quelques instances Nextcloud, elle doit tout de même se faire à vos risques et périls: je ne peux offrir aucune garantie quant à sa réussite et je ne lai jamais testée sur des instances de grande ampleur (plusieurs dizaines, voire centaines de gigaoctets, avec des partages dans tous les sens). Voilà, tes prévenu, prends tes précautions.

Introduction

Lidée de cette présente est de permettre à tout un chacun de migrer les données hébergées en local sur son instance Nextcloud vers du S3 (dans un garage, pourquoi pas). Cette procédure nétant absolument pas prévu par Nextcloud (aucun outil officiel, même pas une doc), elle a été faite à la main avec sueur et amour ❤️.

Fais une maudite sauvegarde ostie de marde!

Alors, avant de commencer à rentrer dans le dur, deux ou trois précautions à prendre, quoiquil arrive:

  • Éjecte tous tes utilisateurs de linstance. Tous. Mémé, son chien, ton petit frère, faut virer tout le monde. Cest pas des blagues hein, tu le fais, je tattends (Note: le plus simple est dactiver le mode maintenance en ligne de commande via occ maintenance:mode --on). Pour les clients de synchro et les clients Web, cela peut prendre jusquà une demi-heure pour que toutes les sessions soient bien mortes côté serveur, on y reviendra.
  • Fais une putain de sauvegarde de absolument tout. Là, cest pareil, vas-y, je tattends. On se fout que ça prenne 10 minutes ou 2h, mais il faut impérativement que tu ais une sauvegarde de tout: base de données et données utilisateurs.
  • Arme-toi de patience (et dune bière).

La structure S3 sous Nextcloud

Les données ne vont pas être structurées de la même manière sur S3 et sur ton disque local. En fait, quand tu navigues dans ton Nextcloud, tu navigues essentiellement dans la structure de la base de données. En gros, tout est virtuel.

Quand tu passes en S3, cette structure, cette hiérarchie de fichiers qui était si familière, va être complètement explosée: pour des questions doptimisations, le greffon S3 stocke tous les fichiers à plat à la racine du seau S3 en les identifiant avec leur fileid (extrait directement de la base de données).

Il va donc falloir transformer la structure de tes dossiers et fichiers en une structure mangeable par Nextcloud S3. Pour cela et pour éviter de faire des copies dans tous les sens, on va recréer la structure en question avec des liens symboliques dans un dossier de transfert et ensuite, on va faire une synchro complète vers S3.

Première étape: nettoyer la base de données

Cest loin dêtre une obligation mais malheureusement, Nextcloud est extrêmement mauvais pour faire le ménage dans ses propres tables de fichiers et de cache. On va sintéresser à deux tables essentiellement: oc_filecache (qui contient en fait le cache de tous les fichiers, leurs propriétés de base, etc…) et oc_storages (qui contient en fait les différents stockages des différents utilisateurs et le stockage de linstance elle-même).

La première chose à vérifier est assez simple: il faut impérativement sassurer quaucune entrée dans oc_filecache ne fasse référence un stockage inexistant dans oc_storages. Les deux tables sont liés par lattribut oc_filecache.storage = oc_storages.numeric_id.

On peut facilement vérifier le nombre dentrées avec la commande SQL suivante:

SELECT storage, count(storage)
FROM oc_filecache
GROUP BY storage;

SELECT * FROM oc_storages;

Logiquement, la colonne storage de la première requête devrait correspondre exactement à la sortie de la seconde requête. Si ce nest pas le cas, vérifie quil ny a pas une cagade entre les deux. Sur ma vieille instance, mes fichiers les plus anciens étaient en double dans pratiquement toute la table oc_filecache (je suppose que cest une mise à jour qui sest mal passée).

En toute logique, la table oc_storages ne devrait contenir que:

  • une entrée local::<chemin vers le stockage de ton nextcloud>
  • plusieurs entrées home::<utilisateur>

Si tu vois des utilisateurs en double, des oc_filecache.storage qui ne correspondent plus à rien, il est temps de faire le ménage.

Note: il est très certainement possible de faire une requête SQL des familles pour accomplir cela en une fois, je nai pas creusé, un truc de plus à faire si besoin…

Toujours dans le même état desprit, cela peut être intéressant de purger les corbeilles et les versions de fichiers (ça fera toujours ça de moins à transférer). À noter quil est nécessaire pour cela de sortir du mode maintenance. Donc, si tu as prévu une migration un jour donné, ça peut être intéressant de commencer à faire le ménage in vivo quelques jours ou quelques semaines avant.

Deuxième étape: préparer les données

Bon voilà, maintenant que tu as mis tout en maintenance, que tu as fait une grosse sauvegarde de tout et que ta base de données est nettoyée (autant que faire se peut en tout cas), on va pouvoir attaquer le vif du sujet.

Donc, on va commencer par établir une liste exhaustive de tous les fichiers des utilisateurs et les mettre dans un fichier assez simple avec une association urn:oid:<numéro de fichiers> vers le chemin actuel.

Pour cela, un petit coup de shell/sql:

mysql -B --disable-column-names -D <ta base de données> << EOF > user_file_list
    SELECT CONCAT('urn:oid:', fileid, ' ', '<chemin vers les données Nextcloud>', SUBSTRING(id from 7), '/', path)
    FROM oc_filecache JOIN oc_storages
    ON storage = numeric_id
    WHERE id LIKE 'home::%'
    ORDER BY id;
EOF

Tu prendras évidemment soin de remplacer le nom de la base de données ainsi que le chemin où se trouve les données. Il sagit bien du répertoire de données; par défaut, il sagit du répertoire data à la racine de linstallation, mais techniquement, ça peut être nimporte où.

Logiquement, tu devrais obtenir un fichier dont les lignes ressemblent à ça(cest, au passage, le bon moment de vérifier que les chemins en question sont bons):

urn:oid:120795 /srv/nextcloud/user1/files/Documents/Welcome to Nextcloud Hub.docx

De la même manière, on va établir la liste des métadonnées (les données exploitées par Nextcloud lui-même et qui sont stockées dordinaire dans le répertoire appdata):

mysql -B --disable-column-names -D <ta base de données> << EOF > meta_file_list
    SELECT CONCAT('urn:oid:', fileid, ' ', SUBSTRING(id from 8), path)
    FROM oc_filecache JOIN oc_storages
    ON storage = numeric_id
    WHERE id LIKE 'local::%'
    ORDER BY id;
EOF

Troisième étape: transférer les données

Lidée générale est de créer des liens symboliques vers les «vraies» données pour éviter de faire une copie en local avant de balancer une copie vers le S3. Comme on vient détablir la liste des données pour les métadonnées et les données utilisateurs, ce nest pas bien compliqué:

mkdir s3_files
cd s3_files
while read target source ; do
    if [ -f "$source" ] ;
    then
        ln -sv "$source" "$target"
    fi
done < ../user_file_list
while read target source ; do
    if [ -f "$source" ] ;
    then
        ln -sv "$source" "$target"
    fi
done < ../meta_file_list

En toute logique, tu devrais te retrouver avec un répertoire contenant quelques dizaines/centaines/milliers de liens symboliques.

Une bonne idée pour vérifier que rien na merdé, cest de compter les liens en question:

ls -l | wc -l
find <chemin vers les données Nextcloud> -type f | wc -l

Tu peux aussi vérifier la taille de lensemble:

du -Lhsc *

Si tu es confort avec les chiffres que tu vois (quau moins ils ont le bon ordre de grandeur), tu peux passer à la suite.

Note: à ce stade, je pars du principe que tu as créé le bucket S3 et la clé correspondante qui va bien dans garage.

Pour la partie transfert en elle-même, jai essayé le client MinIO sans grand succès à chaque fois. Je ne sais pas pourquoi, mais ça a toujours merdé avec ce client.

Du coup, je me suis décidé à passer par awscli pour éviter les emmerdes. Peu importe comment tu linstalles (via le gestionnaire de paquets ou depuis pip), limportant cest quil soit configuré correctement: utilise la même clé et le même secret dans ~/.aws/credentials et noublie pas de mettre la région garage dans ~/.aws/config. Logiquement, cest tout ce dont tu auras besoin.

On se place ensuite dans le répertoire s3_files contenant lensemble des liens symboliques et on sarme dune autre bière et de beaucoup de patience:

aws --endpoint-url http://<adresse de garage>:3900 s3 sync . s3://nextcloud

Évidemment, la commande est à adapter à la situation. Si un transfert merdouille, le simple fait de la relancer doit suffire à retransférer les fichiers qui ont merdé. On peut également surveiller ce quil se passe côté garage pour être certain que rien ne foire de manière hyper évidente.

En toute logique, si tu relances la commande et quil ne se passe plus rien, cest que le transfert est intégralement terminé.

On va donc pouvoir passer au nettoyage/adaptation de la base.

Quatrième étape: adaptation de la base de données

Les données sont transférées mais la base de données à toujours les anciennes références, il faut donc les adapter. Première chose donc, modifier les storages utilisateur:

UPDATE oc_storages
SET id = CONCAT('object::user:', SUBSTRING(id from 7))
WHERE id LIKE 'home::%';

Tu transformes ici les références home::<utilisateur> en référence object::user:<utilisateur> (note que le : seul à la fin est normal). Il faut ensuite transformer le stockage de Nextcloud lui-même:

UPDATE oc_storages
SET id = 'object::store:amazon::<nom du bucket S3>'
WHERE id LIKE 'local::%';

Normalement, tu ne devais avoir quun seul local::* dans cette table. Si ce nest pas le cas, cest peut-être quun truc est resté allumé malgré la maintenance ou quil sest passé autre chose. Quoiquil arrive, ça vaut le coup dêtre vérifié avant de continuer.

Normalement, à partir de cette étape, on ne touchera plus à la table oc_storages et elle ne devrait donc contenir que deux types dentrées:

  • une entrée object::user:<utilisateur> pour chaque utilisateur
  • une entrée object::storage:amazon::<nom du bucket S3>

La casse, les : ou ::, le nom des utilisateurs, le nom du bucket S3, tout cela a une importance, donc il vaut mieux vérifier 3 fois pour être sûr.

Dernière adaptation, il est nécessaire de faire des changements dans la table oc_mounts (qui gère notamment comment les points de montage comme les partages vont être gérés par Nextcloud):

UPDATE oc_mounts
SET mount_provider_class = 'OC\\Files\\Mount\\ObjectHomeMountProvider';

Cette table devrait normalement contenir:

  • une entrée par utilisateur
  • une entrée par partage

La colonne mount_provider_class devrait maintenant être uniforme avec la valeur OC\Files\Mount\ObjectHomeMountProvider (comme dhabitude avec les caractères déchappement de type \, se méfier du résultat).

Dernière étape: configurer Nextcloud et vérifier lensemble

Bon, on a bien transpiré, il est temps de finir la configuration. Dans le fichiers config/config.php de Nextcloud, tu peux maintenant ajouter ton instance garage avec les mêmes informations que tu avais configuré dans awscli directement dans lobjet $CONFIG:

'objectstore' => [
    'class' => '\\OC\\Files\\ObjectStore\\S3',
    'arguments' => [
        'bucket' => '<nom du bucket S3>',
        'autocreate' => false,
        'key'    => '<clé>',
        'secret' => '<secret>',
        'hostname' => '<adresse de garage>'
        'port' => <port de garage>,
        'use_ssl' => false, // à adapter si tu as un reverse proxy avec du TLS
        'region' => 'garage',
        'use_path_style' => true
    ],
],

Tu peux maintenant virer la maintenance, te reconnecter sur linterface Web et vérifier que tout fonctionne correctement. Mon conseil: passer dans quelques partages, ouvrir des fichiers que tu na pas accédé depuis un petit moment. Ça peut être le bon moment aussi pour relancer une synchro complète sur un client vierge histoire de vérifier que tous les accès sont bons.

Dès que tu es suffisamment confiant dans ta migration, tu peux virer les répertoires de données dorigine et virer le répertoire contenant les liens symboliques.

Conclusation

Et ben, on va pouvoir prendre des vacances bien méritées avec ça…