Vue lecture

Des vacances au clair de lune (ou comment faire son Geforce Now privé)

Il aura fallu beaucoup trop de temps pour que ça se produise, et je l’aurai travaillé au corps une paire de fois le gaillard, mais voilà, ceci est le premier billet invité de l’unique, l’irremplaçable Pierre-Marie ! Parce que c’était à la fois trop con comme cible de jeu, mais surtout trop rigolo vu le mix de technos abordées, parce qu’on va parler de Pokemon, de Sunshine/Moonlight (le titre ne ment pas), de wakeonlan, de Kubernetes, de Fission. Oui, tout ça en même temps. Vous comprenez mon enthousiasme ?

La puissance des algorithmes de ciblage

Au détour de mon scrolling sur X, je suis tombé sur un post parlant de jeux vidéos (l’algorithme est bien foutu) et sur une injonction à s’inscrire sur PokeMMO.
Pas fan hardcore de Pokémon, j’ai quand même bien poncé les deux premières gen et me suis tenté à la troisième.
Je fais partie des gens qui n’attendent plus grand chose de Game Freak qui, selon moi, ressort en boucle les mêmes jeux sans vraiment d’innovation.
Au contraire, côté développement non officiel, on retrouve des jeux dérivés comme Pokémon Showdown, qui malgré que ce ne soit pas mon style de jeu, attire une grande communauté et qui aurait pu donner des idées à Nintendo pour renouveler la licence.
J’ai, par exemple, plus apprécié le rom hack Pokémon Adventures Red Chapter basé sur l’excellent manga Pokémon La Grande Aventure que le remake Let’s Go Evoli.
Bref, je suis donc allé voir ce qu’était ce PokeMMO, et me suis motivé pour me lancer dessus. Ça tombe bien, je pars 2 semaines en vacances et il faudra bien occuper mes soirées au coin de la clim. (article commencé au mois de Juillet). PokeMMO propose un installer pour Windows, Linux, iOS, Android et même un package pour OS alternatif (j’ai vu pas mal de gens qui installaient ça sur une console portable de type Retroid).
Personnellement, j’ai à ma disposition une PsVita et une Switch, toutes deux libérées et qui me servent lors de mes sessions retrogaming. L’option téléphone/tablette est pour moi rédhibitoire ne possédant pas de manette compatible et aimant beaucoup trop les boutons physiques pour jouer au tactile.
Installer Android sur Switch me semblant trop fastidieux, j’ai décidé de partir sur une autre voie. Étant obligé d’être connecté pour jouer quoi qu’il arrive (le O de MMO, hein), je me penche sur Moonlight, que j’avais déjà testé il y presque 10 ans. Il y a des clients pour Switch et PsVita (et pour beaucoup d’autres OS/appareils) donc ça pourrait correspondre à mes besoins.

Installation de Sunshine/Moonlight

Moonlight, pour vulgariser, c’est un client non-officiel pour le protocole Nvidia Gamestream qui vient se connecter à un ordinateur distant pour le contrôler à distance. Il a la force de supporter les contrôleurs locaux et de transmettre au PC distant à la manière d’un Steam Link. Pour pouvoir streamer vers un client Moonlight, il faut un serveur sur la machine cible. Le logiciel Nvidia GeForce Experience permet cela mais la « nouveauté » par rapport à mon essai d’il y a 10 ans, c’est le serveur Sunshine qui permet de s’affranchir du logiciel de Nvidia.

L’installation de Sunshine se fait via l’installateur dédié à la distribution cible en quelques secondes. Une fois installé, Sushine se configure via une interface web accessible en local. Elle permet de gérer les différents clients (appairage, suppression…), les différentes applications et les options de streaming (encodage, bitrate…).

Le première étape est de créer un couple utilisateur/motdepasse pour protéger l’accès à cette interface.

Interface de configuration de Sunshine: Creation du mot de passe

Par défaut, Sunshine propose deux applications: Bureau et Steam Big Picture (même si Steam n’est pas installé sur le système)

Interface de configuration de Sunshine: Applications

J’installe donc PokeMMO et le configure comme Application dans Sunshine. Je reprends simplement les valeurs trouvées dans le raccourci Bureau qui a été crée lors de l’installation. Il détecte même la miniature automatiquement.

Interface de configuration de Sunshine: Création de l’application PokeMMO

J’installe le client Moonlight sur les deux appareils. Le client détecte automatiquement le PC supportant Sunshine et affiche un code d’appairage à entrer dans Sunshine.

Interface de Moonlight: Détection

Interface de configuration de Moonlight: Appairage

Interface de Sunshine: appairage

L’appairage se déroule sans problème et je peux tester le stream en local.

Interface de Moonlight: Écran d’accueil

Je lance l’application Bureau et ça me permet de confirmer qu’il est bien possible d’ouvrir une session Windows à distance.

Interface de Moonlight: Bureau

Pour le stream distant, il faut juste s’assurer que Upnp est activé sur le routeur et cocher une case dans la configuration de Sunshine.

Interface de configuration de Sunshine: Activation de l’Upnp

(ndr: sinon il faut définir les ports et ouvrir manuellement/créer les redirections de port; l’IP fixe pour le PC de jeu est fortement recommandée dans ce cas)

Fini ?

On aurait pu s’arrêter là, mais bon, je suis pas fan de laisser tourner le PC H24 pendant 2 semaines juste pour l’utiliser quelques heures. Moonlight propose une fonctionnalité bien pratique de Wake On LAN pour démarrer un ordinateur à distance, mais voilà, ça ne fonctionne qu’en réseau local (en même temps c’est dans le nom).
Il faut donc trouver le moyen de le faire fonctionner à distance. J’ai plusieurs dispositifs à ma disposition.
Mon routeur PfSense permet de d’envoyer des paquets WoL mais uniquement via l’interface, pas d’API disponible. Il faudrait se connecter à l’interface via VPN pour lancer la commande. C’est trop lourd et pas assez flexible.
Solution suivante, utiliser le cluster k3s qui tourne à la maison.

Utilisation de k3s

On teste la faisabilité du process en lançant un pod temporaire contenant la commande wakeonlan mais ça ne fonctionne pas car l’appareil ciblé n’est pas sur le LAN du cluster k3s comme l’est le pod.
En cherchant un peu, on trouve qu’il faut configurer le pod pour qu’il tourne dans le réseau hôte, le réseau des nœuds.

kubectl run tmp --rm -it --image nixery.dev/shell/wakeonlan -it --overrides='{"kind":"Pod", "apiVersion":"v1", "spec": {"hostNetwork":\ntrue}}' -- wakeonlan a1:b2:c3:d4:e5:f6

Et ça marche !!

Reste à trouver le moyen de lancer ça simplement, via un appel HTTP par exemple. Je viens justement de déployer un système de micro-services : Fission.
Fission permet de déployer des fonctions de micro-services à la manière d’un système Serverless comme Lambda. Ça me permettrait de recevoir une requête HTTP avec en paramètre l’adresse MAC cible et d’envoyer la requête WoL avec un simple code python.

Installation de Fission

L’installation de Fission est simple si on passe par leur chart Helm. On a juste à surcharger quelques valeurs grâce au fichier values.yml suivant.

## Fission chart configuration
##

## routerServiceType to consider while creating Fission Router service.
## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP.
##
routerServiceType: ClusterIP

## defaultNamespace represents the namespace in which Fission custom resources will be created by the Fission user.
## This is different from the release namespace.
## Please consider setting `additionalFissionNamespaces` if you want more than one namespace to be used for Fission custom resources.
##
defaultNamespace: fission

# Add Fission helm repo
helm repo add fission-charts https://fission.github.io/fission-charts
# Install CRDs 
kubectl create -k "github.com/fission/fission/crds/v1?ref=v1.21.0"
# Install Fission
helm install fission fission-charts/fission-all -f values.yml -n fission --create-namespace
# Install Fission CLI binary
curl -Lo fission https://github.com/fission/fission/releases/download/v1.21.0/fission-v1.21.0-linux-amd64 && chmod +x fission && sudo mv fission /usr/local/bin/

Configuration de Fission

La documentation fission nous apprend qu’on peut modifier les spécifications des pods. Il y a même un tutoriel pour déployer un exemple.

# On créé un dossier dédié
mkdir wol-fn
cd wol-fn
# On initialise le dossier specs
fission spec init
# On créé l'environnement qui fera touner le code python
fission -n fission env create --spec --name python-wol --image ghcr.io/fission/python-env --builder ghcr.io/fission/python-builder
# On créé le dossier de la fonction
mkdir wol
# On créé un fichier requirements.txt avec le module python dont nous avons besoin
echo "wakeonlan" > wol/requirements.txt
# On créé le fichier contenant le code python à exécuter
touch wol/wol.py

from flask import request
from wakeonlan import send_magic_packet
import re

def main():
    mac = request.args.get('mac')
    if mac is None:
        return "Please send a MAC address"
    else:
        if re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", mac.lower()):
            send_magic_packet(mac)
            return "Sending magic packet to 255.255.255.255 with broadcast 255.255.255.255 MAC %s port 9" % (mac)
        else:
            return "%s is not a valid MAC format" % (mac)

On créé la spécification pour la fonction qui décrit quel code doit être exécuté et le trigger HTTP qui détermine quelle URL déclenche son exécution.

# On créé la spécification pour la fonction
fission -n fission function create --spec --name wol-fn --env python-wol --src "wol/*" --entrypoint wol.main
# On créé la spécification pour la route.
# Avec les annotations permettant de créer l'ingress rule sur Traefik
fission -n fission route create --spec --name wol-fn-get --method GET --url /wake --function wol-fn --createingress --ingressrule "test.domain.tld=/wake" --ingressannotation "kubernetes.io/ingress.class=traefik" --ingressannotation "traefik.ingress.kubernetes.io/router.entrypoints=websecure" --ingressannotation 'traefik.ingress.kubernetes.io/router.tls="true"' --ingressannotation "traefik.ingress.kubernetes.io/router.tls.certresolver=letsencrypt"

On a maintenant un dossier contenant la fonction et son environnement standard.

wol-fn
├── specs
│   ├── README
│   ├── env-python-wol.yaml
│   ├── fission-deployment-config.yaml
│   ├── function-wol-fn.yaml
│   └── route-wol-fn-get.yaml
└── wol
    ├── requirements.txt
    └── wol.py

On va modifier le fichier env-python-wol.yaml pour ajouter notre configuration spécifique.

---
apiVersion: fission.io/v1
kind: Environment
metadata:
  creationTimestamp: null
  name: python-wol
spec:
  builder:
    command: build
    container:
      name: builder
      resources: {}
    image: ghcr.io/fission/python-builder
    podspec:
      containers:
      - name: builder
        resources: {}
  imagepullsecret: ""
  keeparchive: false
  poolsize: 3
  resources: {}
  runtime:
    container:
      name: python-wol
      resources: {}
    image: ghcr.io/fission/python-env
    podspec:
      containers:
      - name: python-wol
        resources: {}
+     hostNetwork: true
+     dnsPolicy: ClusterFirstWithHostNet
  version: 3

La directive hostNetwork permet comme vu plus haut de faire tourner le pod sur le réseau hôte.
Avec juste cette modification, on a une erreur à l’exécution du code parce que le pod n’arrive pas à aller chercher l’archive contenant le code de la fonction sur le stockage partagé de Fission.

{
    "level": "error",
    "ts": "2025-08-22T15:55:03.884Z",
    "logger": "generic_pool_manager.generic_pool.fetcher_client",
    "caller": "client/client.go:114",
    "msg": "error specializing/fetching/uploading package, retrying",
    "error": "Internal error - error fetching deploy package: failed to download url : Get \"http://storagesvc.fission/v1/archive?id=%2Ffission%2Ffission-functions%2Ffc6798a9-95c3-47cb-8797-28f842162f83\": dial tcp: lookup storagesvc.fission on 9.9.9.9:53: no such host",
    "url": "http://X.X.X.X:8000/specialize",
    "stacktrace": "github.com/fission/fission/pkg/fetcher/client.sendRequest\n\tpkg/fetcher/client/client.go:114\ngithub.com/fission/fission/pkg/fetcher/client.(*client).Specialize\n\tpkg/fetcher/client/client.go:56\ngithub.com/fission/fission/pkg/executor/executortype/poolmgr.(*GenericPool).specializePod\n\tpkg/executor/executortype/poolmgr/gp.go:467\ngithub.com/fission/fission/pkg/executor/executortype/poolmgr.(*GenericPool).getFuncSvc\n\tpkg/executor/executortype/poolmgr/gp.go:553\ngithub.com/fission/fission/pkg/executor/executortype/poolmgr.(*GenericPoolManager).GetFuncSvc\n\tpkg/executor/executortype/poolmgr/gpm.go:242\ngithub.com/fission/fission/pkg/executor.(*Executor).createServiceForFunction\n\tpkg/executor/executor.go:239\ngithub.com/fission/fission/pkg/executor.(*Executor).serveCreateFuncServices.func1\n\tpkg/executor/executor.go:143"
}

On voit qu’il cherche à contacter storagesvc.fission et qu’il n’arrive pas à résoudre ce hostname, ce qui est normal étant donné qu’il s’agit d’un nom interne au cluster et que le pod tourne désormais sur le hostNetwork. La directive dnsPolicy: ClusterFirstWithHostNet permet de forcer d’essayer la résolution en interne au cluster avant de tenter en externe sur le hostNetwork et résout ce problème.

Il ne reste qu’à déployer.

# On vérifie la syntaxe
fission spec validate
# On déploie
fission spec apply --wait
# On test via Fission CLI
fission -n fission function test --name wol-fn --method GET -q "mac=a1:b2:c3:d4:e5:f6"
# On test via HTTP depuis l'extérieur
curl "https://test/domain.tld/wake?mac=a1:b2:c3:d4:e5:f6"

Pour faire simple, ajouter l’URL en raccourci sur le téléphone et en un clic, le PC est démarré. Personnellement, je l’ai intégré dans mon Home Assistant avec un bouton dédié.

Home Assistant Dashboard

Finalisation de la configuration

Celui qu’on adore détester

Il reste deux ou trois détails à régler. Par défaut, depuis Windows 10, quand on arrête le système, il se place en réalité dans un mode de veille prolongée pour permettre un démarrage plus rapide. Hors le *Wake On LAN* ne fonctionne pas sur ce mode de sommeil. Microsoft documente ça très bien ici. Il y est également expliqué comment désactiver ce mode pour pouvoir rétablir un mode d’extinction « normal ».

Je vous les remets à l’identique:

  • Dans Panneau de configuration, ouvrez l’élément Options d’alimentation
  • Sélectionnez le lien Choisir ce que les boutons d’alimentation font
  • Désactivez la case à cocher Activer le démarrage rapide (recommandé)
  • Sélectionnez Enregistrez les paramètres.

Une fois cette modification effectuée, le Wake On LAN est complètement fonctionnel.

La fin

Et donc, puisqu’on a abordé le sujet, comment se passe l’extinction ? Vous vous rappelez ? le but de tout ce foutoir, c’était d’éviter de garder le PC allumé pendant deux semaines. On a parlé du démarrage, mais quid de l’arrêt ?

Le plus simple est de lancer une session Bureau dans Moonlight et d’aller cliquer sur le menu Démarrer puis le bouton Arrêter comme à la maison. Mais on peut aussi déclarer des applications dans Sunshine et il exécutera la commande associée à cette application.

J’ai donc créer une application nommée Shutdown qui lance la commande suivante shutdown /s /f /t 0.

Interface de configuration de Sunshine: Shutdown Application

Quand elle est lancée depuis le client Moonlight, elle éteint le PC distant.

Feedback et Conclusion

Puisque je suis rentré depuis, je peux débriefer ces 2 semaines d’utilisation, ça fonctionne super, le seul défaut que j’ai eu est qu’une fois le Shutdown n’a pas fonctionné et je ne l’ai pas vu tout de suite. Les fois suivantes, j’ai juste eu à bien vérifier le status dans le menu.

Interface de Moonlight: PC démarré

Interface de Moonlight: PC éteint

À part ça, super expérience ! Bien sur je n’ai pas cherché à jouer à des jeux très performants, mais ça a suffi à mes besoins, même en 4G. Je n’ai pas non plus poussé jusqu’à tenter de jouer sur la 4G en voiture, mais je pense que ça aurait pu marcher.
Je continue à l’utiliser, même à la maison, pour jouer dans le canapé plutôt que devant le PC.

Interface de Moonlight: PokeMMO


Alors, avouez que c’est pas mal en termes de bricolages inutiles donc indispensables, il était donc nécessaire de partager ça avec le plus grand nombre ? (enfin au moins les lecteurs de ce blog)

  •