Linux things 🐧

un blog sur les technologies des logiciels libres et autres digressions

Navidrome et l'autohébergement hybride V2

Sun, 24 Mar 2024 14:46:17 +0100
# nomad   # consul   # docker   # tailscale  

Introduction

Suite Ă  cet article, There’s endless choice, but you’re not listening’: fans quitting Spotify to save their love of music, j’ai re-dĂ©couvert Navidrome que j’avais dĂ©couvert via le trĂšs bien informĂ© Korben comme souvent.

Je me suis dit que c’Ă©tait l’occasion de tester en auto-hĂ©bergĂ©, car mes musiques sont Ă©videment chez moi et surtout c’Ă©tait l’occasion de mettre en oeuvre ma nouvelle stack favorite Nomad.
Pour rappel j’avais fais une doc sur l’auto-hĂ©bergement hybride en 2017 avec Docker swarm, VPNcloud, syncthing, traefik, etc. Il faut avouer que c’Ă©tait une usine Ă  gaz de l’enfer ☠.
Heureusement si vous avez suivi mon article Une infra avec Nomad, Consul et Tailscale vous devriez pouvoir mettre en place cette V2 rapidement.

Pourquoi hybride ?

Je souhaite bĂ©nĂ©ficier des fonctionnalitĂ©s anti-DDOS des hĂ©bergeurs cloud et ainsi ne pas exposer l’IP fournie par mon FAI qui de toute façon n’est pas garantie fixe. Aussi je souhaite pouvoir hĂ©berger sur le cloud quelques services (typiquement Uptime Kuma).
Cette présentation nécessite donc deux VMs chez un hébergeur, une pour Nomad en mode serveur et client avec une IP publique, et une VM pour un serveur Consul. Leurs configurations sont indiquées dans mon précédent article.
Vous pouvez toutefois ĂȘtre en mode full auto-hĂ©bergĂ©, il suffira de faire pointer le DNS de votre domaine vers votre IP fixe et faire en sorte qu’un serveur avec caddy-docker-proxy puisse rĂ©pondre aux requĂȘtes HTTPS.

Le serveur Ă  la maison

Depuis 2017 j’ai investi dans un mini PC NUC (core I3/16Go RAM, 1To SSD) qui fait l’affaire, mais un RaspberryPi avec un disque externe le fera aussi sous condition.
En effet un RaspberryPi a une architecture ARM et non pas x86, cela imposera donc des images Docker sous ce format. Navidrome a le bon goĂ»t de proposer des images Docker ARM (merci Go), il faudra choisir une des images ARM selon la version et l’OS de votre RaspberryPi (Ă  priori linux/arm64 Ă  partir du 4 si l’OS est en 64 bits).

Manjaro

Mon NUC il est installĂ© avec Manjaro car il est connectĂ© Ă  la TV et sert aussi Ă  voir des vidĂ©os. Aussi j’ai du appliquer la configuration suivante pour Ă©viter qu’il mette le NUC en veille au bout d’un certain temps. Bien sĂ»r si vous avez installĂ© une distribution serveur cela ne s’applique pas.

avec un terminal exécutez les commandes suivantes (source):

sudo su - gdm -s /bin/bash
dbus-launch gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type 'nothing'
exit
sudo shutdown -r now

Tailscale, Nomad, Consul, CNI-plugins, Docker

J’utilise les paquets de Manjaro (pour d’autres OS voir l’article prĂ©cĂ©dent) :

sudo pacman -S tailscale nomad consul docker cni-plugins
tailscale login

renseignez les informations de votre compte tailscale puis vérifier avec tailscale status

récupérez votre IP tailscale avec tailscale ip

Consul

/etc/consul.d/consul.hcl

data_dir = "/var/lib/consul"
# sur Manjaro, le paquet consul créé le répertoire /var/lib/consul
# sur Ubuntu serveur c'est en général dans /opt/consul
bind_addr = "IP_TAILSCALE_NUC"
retry_join = ["IP_TAILSCALE_NODE3"]

Pour rappel selon ma précédente doc le serveur consul est installé sur le node3.

sudo systemctl enable consul
sudo systemctl start consul

Nomad

/etc/nomad.d/defaults.hcl

## https://www.nomadproject.io/docs/agent/configuration/index.html

# state directory
data_dir = "/var/lib/nomad"
# sur Manjaro, le paquet nomad créé le répertoire /var/lib/nomad
# sur Ubuntu serveur c'est en général dans /opt/nomad
bind_addr = "IP_TAILSCALE_NUC"

# binaries shouldn't go in /var/lib
plugin_dir = "/usr/lib/nomad/plugins"


server {
  # license_path is required for Nomad Enterprise as of Nomad v1.1.1+
  #license_path = "/etc/nomad.d/license.hclic"
  enabled          = false
  bootstrap_expect = 1
}

client {
  enabled = true
  servers = ["IP_TAILSCALE_NODE1"]

  host_network "tailscale" {
    cidr = "IP_TAILSCALE_NUC/32"
  }

}

plugin "docker" {
  config {
    volumes {
      enabled      = true
    }
    extra_labels = ["job_name", "job_id", "task_group_name", "task_name", "namespace", "node_name", "node_id"]
  }
}

consul {
  address = "127.0.0.1:8500"
}

on lance Nomad

sudo systemctl enable nomad
sudo systemctl start nomad

Si tout est ok, vous devriez voir sur les interfaces web de consul et nomad votre serveur :

  • Pour consul : http://IP_TAILSCALE_NODE3:8500/ui/dc1/nodes
  • pour nomad : http://IP_TAILSCALE_NODE1:4646/ui/clients

La configuration de votre cluster Nomad est terminĂ©e, votre serveur est prĂȘt Ă  recevoir des conteneurs.

Leur configuration Docker est ici. On va transformer le docker-compose au format HCL :

docker-compose:

version: "3"
services:
  navidrome:
    image: deluan/navidrome:latest
    user: 1000:1000 # should be owner of volumes
    ports:
      - "4533:4533"
    restart: unless-stopped
    environment:
      # Optional: put your config options customization here. Examples:
      ND_SCANSCHEDULE: 1h
      ND_LOGLEVEL: info  
      ND_SESSIONTIMEOUT: 24h
      ND_BASEURL: ""
    volumes:
      - "/path/to/data:/data"
      - "/path/to/your/music/folder:/music:ro"

navidrome.hcl

job "navidrome" {
  datacenters = ["dc1"]
  type = "service" 
  group "home" {
     count = 1

     network {
			port "http" {
			     to     = 4533 # container port the app runs on
			     static = 4533   # host port to expose
			     host_network = "tailscale"
			  }        
      }

     task "navidrome" {
     		driver = "docker"

			constraint {
			 attribute = "${attr.unique.hostname}"
			 value     = "nuc"
			}

			env {
				ND_SCANSCHEDULE= "1h"
				ND_LOGLEVEL = "info"  
				ND_SESSIONTIMEOUT = "24h"
				ND_BASEURL = ""
			}
			config {
			   image = "deluan/navidrome:latest"
				volumes = [
				 "/data/volumes/navidrome/:/data",
				 "/data/musiques:/music"
				]				
			   ports = [
			      "http"
			   ]
			}

			resources {
			   cpu = 500
			   memory = 500
			}

			service {
				name = "navidrome"
			   tags = ["global", "app"]
			   provider = "consul"
			   port = "http"
			}
     	}

   }
}

Explications

datacenters = ["dc1"] indique le nom de mon datacenter, par simplicitĂ© c’est le mĂȘme entre mes VMs sur le cloud et chez moi. Si vous avez un usage professionnel, vous pouvez indiquer un autre datacenter, mais en pratique cela nĂ©cessitera un autre serveur consul et nomad dans ce DC.

host_network = "tailscale" cette directive force Consul a enregistrer votre service sur L’IP de Tailscale. Sans celle-ci le serveur Consul rĂ©soudrait le service navidrome.service.consul vers l’IP locale du NUC, c’est Ă  dire 192.168.X.X ce qui ne fonctionnerait Ă©videmment pas.

value = "nuc" correspond au nom de votre serveur, tapez la commande hostname pour connaitre le votre. Cela force ainsi Nomad a déployer le conteneur Navidrome sur ce serveur.

volumes = [
 "/data/volumes/navidrome/:/data",
 "/data/musiques:/music"
]	

indique Ă  Navidrome oĂč sont les donnĂ©es. J’ai un rĂ©pertoire /data attachĂ© Ă  un disque dĂ©diĂ©. Attention comme prĂ©cisĂ© dans leur doc le rĂ©pertoire /data/volumes/navidrome doit appartenir Ă  l’utilisateur id 1000, donc bien exĂ©cuter cette commande avant de lancer le conteneur: sudo chown 1000:1000 /data/volumes/navidrome/

resources {
   cpu = 500
   memory = 500
}

indique à Nomad les ressources allouées au conteneur. A priori 500Mhz de CPU et 500Mo de RAM devraient suffir, à adapter selon votre config matériel et votre usage.

Lancement

Vous pouvez maintenant lancer le job depuis votre PC perso si vous avez installĂ© tailscale, Nomad et configurĂ© la variable d’environnement NOMAD_ADDR=http://IP_TAILSCALE_NODE1:4646. Ajouter la variable NOMAD_TOKEN si vous avez activĂ© les ACL sur Nomad.

nomad job run navidrome.hcl

En cas de soucis il faut aller sur l’interface web du serveur Nomad pour consulter le job :

http://IP_TAILSCALE_NODE1:4646/ui/jobs

Si tout va bien, voici l’URL pour crĂ©er votre compte Navidrome admin :

http://IP_TAILSCALE_NUC:4533/

Vous devriez avoir une joli interface web avec vos musiques prĂȘtes Ă  jouer.

Les clients de bureau

Une interface web c’est bien gentil mais rien de vaut un bon client natif. Navidrome propose une liste d’Apps, j’ai testĂ© Supersonic et Sublime Music disponibles tous les 2 sur Manjaro :
yay -S supersonic-desktop-bin et yay -S sublime-music

Une petite préférence pour Supersonic en Go plutÎt que Sublime Music en python mais ce dernier est mieux intégré grùce à GTK.
Pour la connexion au service utilisez l’URL http://IP_TAILSCALE_NUC:4533/ ou celle publique (que l’on va voir maintenant) si vous vous dĂ©placez Ă  l’extĂ©rieur.

Clients Android

Il y aurait peu d’intĂ©rĂȘt Ă  utiliser cette stack si le service n’Ă©tait pas accessible depuis l’extĂ©rieur via un smartphone par exemple ou mĂȘme depuis votre laptop. On va donc crĂ©er un conteneur qui va ajouter des labels pour votre caddy-docker-proxy

job "navidrome-caddy" {
  datacenters = ["dc1"]
  type = "service" 
  group "app" {
     count = 1

     task "navidrome-caddy" {
     		driver = "docker"

			constraint {
			 attribute = "${attr.unique.hostname}"
			 value     = "node1"
			}

			config {
				image = "kamlando/ubuntu-sleep"

				labels = {
					"caddy" = "navi.fredix.xyz"
        			"caddy.reverse_proxy" = "http://navidrome.service.consul:4533"
					# remove the following line when you have verified your setup
					# Otherwise you risk being rate limited by let's encrypt
					"caddy.tls.ca" = "https://acme-v02.api.letsencrypt.org/directory"
				}
			}

			resources {
			   cpu = 10
			   memory = 10
			}
	
			service {
				 name = "navidrome-caddy"
			   tags = ["global", "app"]
			   provider = "consul"

			}
     	}
  }
}

Modifiez value = "node1" avec le hostname de votre serveur Nomad et modifiez le label caddy vers votre domaine puis lancez le job :

nomad job run navidrome-caddy.hcl

Et voilà, votre service Navidrome est exposé sur Internet.

Pour Android j’ai testĂ© le client Ultrasonic logiciel libre en lui donnant comme URL de connexion https://navi.fredix.xyz

Conclusion

Vous savez maintenant auto-hĂ©berger un grand nombre de services chez vous sans devoir montez en gamme cĂŽtĂ© cloud, car les conteneurs ajoutant des labels Ă  caddy-docker-proxy sont positionnĂ©s au minimum acceptĂ© par Nomad : 10Mhz et 10Mo 😝

PS : Vous retrouvez mes fichiers HCL ici : https://codeberg.org/fredix/nomad

(Ce texte a été écrit avec Ghostwriter)