Agado Dev

Fly.io, Edge deployment

Une illustration montrant des serveur autour de la terre

1. Introduction

Pour les applications simples, j'utilise encore et toujours la même ancienne architecture depuis des années. Bien qu'elle ne soit pas particulièrement sophistiquée ou à la pointe de la technologie, elle s'est toujours avérée efficace pour les petits projets ou les démarrages

Architecture Web simple avec Nginx, un serveur d'applications, une base de données Postgresql et un stockag objets

Le serveur Nginx sert des fichiers statiques tels que HTML, CSS et JavaScript tout en agissant comme un reverse-proxy pour servir les requêtes API vers le serveur d'applications Node.js. Ce serveur traite la logique métier et interagit avec une base de données PostgreSQL pour les données relationnelles et un Object Storage pour les fichiers volumineux et non structurés tels que les ressources multimédias.

Cette configuration garantit une gestion efficace des données qu'elles soient structurées ou non structurées, des performances élevées pour servir le front-end et une séparation nette des préoccupations. Elle nécessite un travail et des compétences minimes en matière d'infra ou d'exploitation, ce qui en fait un excellent choix pour les petites équipes ou les startups. De plus, elle est hautement portable et peut être déployée presque partout, des fournisseurs de cloud aux serveurs locaux, sans dépendances ni configurations complexes.


En tant que développeur français, j’ai trouvé que Clever Cloud était une excellente solution pour ce type d’architecture. Il fournisse une plateforme facile à utiliser avec des services managé pour Node.js, PostgreSQL et l'Object Storage, nécessitant une expertise DevOps minimale. L’accent mis par Clever Cloud sur l’automatisation, l’évolutivité et la fiabilité en a fait un choix privilégié lors de mes expériences sur des projets early stage qui doivent être déployés rapidement sans se soucier de la complexité de l’infrastructure. De plus, le fait d’être un fournisseur européen garantit la conformité aux réglementations locales et offre un excellent support technique.

Le besoin

Récemment, pour quelques applications à vocation internationale, j'ai eu besoin de capacités d'edge computing pour garantir une faible latence et une expérience utilisateur fluide dans le monde entier. C'est pourquoi j'ai décidé d'essayer Fly.io. Ses fonctionnalités intégrées de load balancing et de déploiement régional pourraient en faire un excellent choix pour cette architecture.


2. Concepts de base de Fly.io

Qu'est ce Fly.io?

Fly.io est une plate-forme PaaS (Platform-as-a-Service) complète avec des capacités d'edge computing intégrées, conçue pour les déploiements à l'échelle mondiale. Elle permet de déployer des applications dans 35 régions du monde, en acheminant automatiquement les demandes des utilisateurs vers l'instance la plus proche pour une latence minimale. Fly.io dispose d'un puissant système de private networking gobal qui connecte en toute sécurité toutes vos instances déployées, permettant une communication transparente entre les services de différentes régions.

Fly.io est une plateforme PaaS polyvalente qui offre une large gamme de fonctionnalités allant au-delà de ses capacités principales d'edge computing. Elle prend en charge des bases de données managées, notamment des déploiements PostgreSQL multi-régions. Fly.io intègre également un stockage d'objets via Tigris.

Pour les applications nécessitant des ressources de calcul intensives, Fly.io propose des instances GPU, idéales pour des tâches comme les charges de travail en IA/ML, le traitement vidéo et les calculs scientifiques. La plateforme inclut aussi des volumes persistants pour les charges de travail avec état, des certificats TLS personnalisés pour des communications sécurisées et une CLI pour un workflows de développement fluides.

Comment ça marche?

Le principe fondamental de Fly.io repose sur les Fly Machines (VM), sur lesquelles il est possible de déployer des applications via un Dockerfile.

Fly.io fonctionne différemment des plateformes de conteneurs traditionnelles. Il ne lance pas directement les conteneurs. À la place, comme expliqué dans cet article de blog détaillé, Fly.io utilise containerd pour extraire les images Docker en systèmes de fichiers. Ces systèmes de fichiers sont ensuite montés sur des microVMs Firecracker, qui exécutent l'application dans un environnement sécurisé et isolé. Cette approche innovante combine la simplicité des workflows orientés Docker avec les avantages en termes de performance et de sécurité des VMs, supprimant le besoin d'un runtime complet de conteneur.

Une Fly Machine démarre extrêmement rapidement, en environ 300 ms, ce qui en fait une solution idéale pour les scénarios d'autoscaling ou de récupération rapide après un crash. Cette rapidité garantit un temps d'arrêt minimal et une mise à l'échelle rapide pour gérer efficacement les variations de charge d'une application.


3. Exemple de déploiement

Exemple : Build d'un frontend et déploiement dans Nginx

Cette section montre comment déployer une application frontend sur Fly.io en utilisant un monorepo pnpm et Turbo pour optimiser les builds.

Configuration Fly

La configuration de Fly est simple, car Nginx nécessite peux de ressources pour servir les fichiers statiques

fly.toml

#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
app = "<your_app_name>"
primary_region = 'cdg'
[build]
dockerfile = 'Dockerfile'
[http_service]
internal_port = 80
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 1
processes = ['app']
[[vm]]
memory = '256MB'
cpu_kind = 'shared'
cpus = 1

Configuration Nginx

La configuration Nginx (nginx.conf) est paramétrée pour rediriger les requêtes API vers le réseau privé de Fly.io afin de communiquer avec l'API. Le résolveur DNS de Fly.io, fdaa::3, facilite la découverte de services internes, et l'API backend est ciblée via son adresse interne (http://<your_api_name>.internal).

nginx.conf

server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api/ {
resolver [fdaa::3]; # The custom Fly.io DNS server
proxy_pass http://<your_api_name>.internal:<your_api_internal_port>;
rewrite /api/(.*) /$1 break;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_request_buffering off; # Disable request buffering for large file uploads
client_max_body_size 50M;
}
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}

Le bloc de configuration de la localisation /api/ gère le proxy des requêtes API via le réseau privé de Fly.io, tandis que le bloc root sert les assets du frontend


Etape de build: Dockerfile Multi-Stage

Le Dockerfile utilise un build multi-stage avec pnpm et turbo pour optimiser le workflow du monorepo. L'étape de prune de Turbo garantit que seuls les fichiers et dépendances pertinents sont inclus dans l'image finale.

Dockerfile

# syntax = docker/dockerfile:1
# Adjust versions as desired
ARG NODE_VERSION=23
FROM node:${NODE_VERSION}-slim AS base
# Adjust versions as desired
ARG PNPM_VERSION=9.13.2
ARG TURBO_VERSION=2.3.3
ARG FRONT_APP_PACKAGE=<@example/front-package_name>
LABEL fly_launch_runtime="<name_your_app>"
WORKDIR /usr/src/app
RUN corepack enable && corepack prepare pnpm@$PNPM_VERSION --activate
RUN npm install turbo@$TURBO_VERSION --global
RUN pnpm config set store-dir ~/.pnpm-store
# Pruner stage. cf https://turbo.build/repo/docs/reference/prune
FROM base as pruner
COPY . .
RUN pnpm turbo prune --scope=$FRONT_APP_PACKAGE --docker
# Builder stage
FROM base AS builder
# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3
# Install deps
COPY --from=pruner /usr/src/app/out/pnpm-lock.yaml ./pnpm-lock.yaml
COPY --from=pruner /usr/src/app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY --from=pruner /usr/src/app/out/json/ .
RUN pnpm install
# Build application
COPY --from=pruner /usr/src/app/out/full/ .
RUN --mount=type=secret,id=SOME \
--mount=type=secret,id=REQUIRED \
--mount=type=secret,id=SECRET \
VITE_SOME="$(cat /run/secrets/SOME)" \
VITE_REQUIRED="$(cat /run/secrets/REQUIRED)" \
VITE_SECRET="$(cat /run/secrets/SECRET)" \
pnpm run build:front
# Final stage for app image
FROM nginx
# Copy built application
COPY --from=builder /usr/src/app/front/dist /usr/share/nginx/html
COPY front/nginx.conf /etc/nginx/conf.d/default.conf
# Start the server
EXPOSE 80
CMD [ "/usr/sbin/nginx", "-g", "daemon off;" ]

Ce Dockerfile exécute les étapes suivantes:

  1. Base Stage: Prépare l'environnement avec pnpm et turbo

  2. Pruner Stage: Utilise turbo pour supprimer les fichiers inutiles du monorepo

  3. Builder Stage: Installe les dépendances et construit le frontend

  4. Final Stage: Copie les assets construits dans un conteneur Nginx pour le déploiement


CI/CD avec GitHub Actions

Le pipeline CD est simple, en utilisant l'action GitHub superfly/flyctl-actions/setup-flyctl pour déployer l'application front:

fly-deploy-front.yml

# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
name: Fly Deploy Front
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy front app
runs-on: ubuntu-latest
concurrency: deploy-front-group
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: >
flyctl deploy --config front/fly.toml --remote-only
--build-secret SOME=${{ secrets.SENTRY_DSN }}
--build-secret REQUIRED=${{ secrets.OP_KEY }}
--build-secret SECRETS=${{ secrets.AUTH_DOMAIN }}
env:
FLY_API_TOKEN: ${{ secrets.FLY_FRONT_TOKEN }}
// ...

Ce pipeline garantit des déploiements rapides et sécurisés en intégrant la gestion des secrets et les outils CLI de Fly.io directement dans le workflow GitHub.

Et voilà, plutôt simple, non ?


4. Coûts

Fly.io est économique, ce qui en fait une option attrayante pour les développeurs et les petites équipes. Par exemple, une plateforme de développement utilisant l'architecture simple décrite ci-dessus a un coût mensuel d'environ 16$

Un exemple de cout d'une plateforme de dev:
 1 machine: $6.81
 1 machine: $8.74
Stockage: $0.31

Total: $15.86

Conclusion

  • Fly.io est une solution extrêmement efficace et polyvalente

  • Elle répond parfaitement aux exigences du cas d'usage présenté en introduction

  • Sa scalabilité la rend adaptable à d'autres cas d'usage

Fly.io propose une solution évolutive et polyvalente qui répond aux besoins des applications distribuées géographiquement. Les capacités edge de Fly.io et son approche developer-friendly en font un choix remarquable pour les applications web modernes.

Cependant, pour des cas d'usage ne nécessitant pas d'edge computing, Clever Cloud reste un choix solide grâce à sa conformité régionale et son support local