À la suite du développement d'un bot Discord en Golang, je me suis retrouvé à arriver au moment où je devais le hoster pour le rendre disponible de manière continue sans avoir trop à l'administrer directement pour les choses simple (comme redémarrer le serveur/bot s'il coupe).

Après une recherche relativement extensive, j'en suis arrivé à deux choix possible : Heroku et Fly.io.

Mon premier essai a été sur Heroku et j'ai été incapable de maintenir le pod en fonctionnement au moment du déploiement (en passant en mode worker et tout), pour une raison que j'ignore, il refusait de go run mon application.

C'est ensuite que j'ai testé Fly.io et je dois dire que c'était un peu le bordel pour trouver la bonne manière de faire tourner le bot sans que ça semble coûter de l'argent et en faisant en sorte que le bot reste en ligne.

Installation

La première chose à faire est d'installer l'outil en ligne de commande, les démarches sont indiqués sur cette page de leur site (et je recommande de le faire, ça facilite des choses pour la suite).

Configuration

Ensuite il faut paramétrer l'instance qui sera spawn par Fly.io pour faire tourner le bot. Pour cela vous devez créer un fichier fly.toml à la racine du projet. Je vous propose la configuration suivante :

app = "mon-bot"
primary_region = "ams"
kill_signal = "SIGINT"
kill_timeout = "5s"

[[services]]
  protocol = "tcp"
  internal_port = 8080
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 1
  http_checks = []
  tcp_checks = []

  [[services.ports]]
  port = 80
  handlers = ["http"]
  force_https = true

  [[services.ports]]
  port = 443
  handlers = ["tls", "http"]

  [services.concurrency]
  type = "connections"
  hard_limit = 25
  soft_limit = 20

Les points principaux sont :

  • app = "mon-bot" qui sera le nom de votre application sur Fly.io
  • primary_region = "ams" qui détermine dans quelle région l'instance doit tourner (si ça vous intéresse de savoir où sont stockés les données), dans mon cas c'est Amsterdam

L'autre point un peu tricky, c'est qu'il faut créer un Dockerfile pour faire tourner le bot parce que le builderpack Go qu'ils ont n'est pas conçu pour permettre de faire fonctionner un bot Discord (mais plus une web app ou une API par exemple, et non un worker).

Le Dockerfile doit avoir une configuration similaire :

FROM golang:1.20-alpine
WORKDIR /app
COPY . .
RUN go build
CMD ./mon-app

Comme vous pouvez le lire, on va builder l'application go pendant le build du conteneur Docker, puis on va lancer le binaire qui a été buildé pour lancer le bot (parce que le lancer directement via go run main.go il y a un risque plus important de fuite de mémoire qui risque de faire crasher le bot ou l'instance).

Déploiement

Prochaine étape, tenter un déploiement en local pour vérifier que la configuration est bonne (mais le bot ne fonctionnera pas encore, je l'expliquerais pourquoi juste après).

Pour cela vous allez utiliser la commande :

fly launch

À ce moment il va demander si vous souhaitez utiliser le fichier de configuration qui existe déjà, il suffit d'accepter et de refuser les options supplémentaires qu'il propose comme lancer un redis ou une base de données.

Cette commande va créer l'app sur votre compte, qui sera accessible sur votre dashboard, et lancer l'instance qui va mettre votre bot en ligne.

Normalement le déploiement se passera correctement mais le bot ne sera toujours pas en ligne, c'est parce qu'il faut renseigner les secrets sur votre dashboard pour que le bot puisse connecter à l'API Discord.

Il faut donc aller sur cette page pour commencer à les ajouter : https://fly.io/apps/mon-bot/secrets

Page pour ajouter/éditer les secrets

Pour être certain que tout soit pris en compte, on peut redémarrer le serveur, cela se fait via la commande (uniquement apparemment, je n'ai pas trouvé comment le faire sur le dashboard) :

⚠️
Il faut être dans le dossier du projet pour faire la commande
fly apps restart

Une fois cela fait, normalement le bot devrait être en ligne.

Déploiement automatique

Vous pouvez faire en sorte de redéployer l'application à chaque fois que vous poussez du code. Pour le faire il faut créer ce fichier dans le chemin suivant : ./.github/workflows/deploy.yml :

name: Fly Deploy
on:
  push:
    branches:
      - main
jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - run: flyctl auth token -t $FLY_API_TOKEN && flyctl deploy --remote-only
        env:
          FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

Pour créer un token de déploiement, il faut aller dans le dashboard à l'adresse suivante : https://fly.io/apps/mon-bot/tokens

Page pour créer un token de déploiement

Du côté de GitHub, il faut aller sur cette page pour renseigner le token :

À partir du push ayant le workflow, une pipeline se lancera à chaque push sur main pour déployer le nouveau code du bot sur Fly.io. Au pire des cas le bot sera indisponible pendant une dizaine de secondes.

Vous devriez avoir tout le nécessaire pour déployer un bot Discord en Go de manière assez rapide et pour un coût nul ou presque (perso je suis à moins de 0,10 centimes sur le premier mois parce que j'avais mal réglé l'instance au départ).