Nouvelles Du Monde

Migration de l’hébergement classique vers le sans serveur

Migration de l’hébergement classique vers le sans serveur

2023-11-29 18:37:01

Photo de couverture par Chris Briggs sur Unsplash

C’est enfin l’année où je vais m’éloigner de mon serveur dédié qui fonctionne depuis 15 ans. C’était une aventure amusante, mais la maintenance de ce serveur coûte trop de temps et d’argent. Avant d’entrer dans les détails techniques, voyons ce que j’attends de cette migration :

  • Une base de code plus propre (je peux enfin nettoyer mes affaires, peut-être supprimer quelque chose et moderniser d’autres parties)
  • Fini les déploiements FTP ou compliqués/peu clairs : tout doit être géré par des pipelines CI/CD
  • Réduction des coûts; cela semble bizarre, mais la dernière chose que je souhaite, c’est une augmentation des coûts (aujourd’hui, c’est environ 30 € par mois pour l’hébergement et mon objectif est de ramener ce montant en dessous ou à proximité de 10 € – remarque : je paie beaucoup plus pour les domaines et ceux-ci les coûts ne sont pas inclus ici car ils resteront les mêmes).

Cet article sera probablement le début d’une série – et je veux commencer par quelque chose de pas trop simple, mais pas difficile du tout.


Exemple : principalement statique et un peu dynamique

Considérons le site Web suivant que j’ai créé : html5skript.florian-rappl.de. En son cœur, il s’agit principalement d’un site Web statique standard. Son objectif était de fournir à mes étudiants du matériel de cours pour un cours sur les applications Web utilisant HTML5 (avec CSS3 et JavaScript). Il était donc tout à fait naturel de présenter le matériel en ligne déjà sous une forme qui contient tout ce qu’ils apprendront.

L’image suivante montre le site Web en action :

Il y a une considération particulière à prendre en compte : pour présenter les appels d’API et le traitement des données, le site Web peut être consulté via une API créée à l’aide d’ASP.NET (Webforms). Comment procéder ici ? Eh bien, j’opterais pour une application Web statique Azure. Il s’agit principalement d’un stockage statique (idéal pour le cas d’utilisation), mais peut également être enrichi à l’aide d’Azure Functions. Comme la recherche est plutôt petite, nous pouvons décider si nous portons le code C#/.NET “standard” ou réécrivons la recherche en utilisant JavaScript/Node.js.

Actuellement, comme mentionné, le site Web est hébergé sur un serveur Web dédié. Le serveur Web est principalement exploité à partir d’un outil appelé Plesk, qui fait abstraction du système d’exploitation sous-jacent (dans ce cas, Windows Server). Il est important de noter que le site Web est un sous-domaine d’un domaine existant (qui gère les paramètres DNS) et dispose d’une base de données dédiée (« html5 »).

La zone de sous-domaine du site Web dans l'outil d'administration de Plesk

Bien que les paramètres ne soient globalement pas si mauvais, la base de données doit être préservée. À l’heure actuelle, cette base de données n’est pas utilisée sur le site Web, mais elle contient néanmoins des informations pertinentes qui doivent être correctement archivées. Comme il s’agit d’une base de données MySQL, nous pouvons y accéder sur le Web à l’aide de l’outil phpMyAdmin :

phpMonAdmin

Nous utilisons l’outil pour réaliser un export au format “SQL”. De cette façon, nous sommes en mesure de conserver le contenu localement, ainsi que de l’exporter ultérieurement vers une autre base de données MySQL. Nous y reviendrons dans un autre article. Pour l’instant, l’important est que la base de données doit également être migrée – mais pas pour cette partie de la migration globale.

Ensuite, nous créerons une nouvelle application Web statique Azure dans l’offre gratuite. Nous choisissons “personnalisé” comme option de déploiement. De cette façon, nous sommes libres d’héberger/déployer le code comme nous le souhaitons.

Application Web statique Azure

Pour ma page d’accueil personnelle, je regroupe le code dans un projet Azure DevOps gratuit. J’ai déjà créé le projet dans le passé, il ne me reste donc plus qu’à entrer et ajouter un autre référentiel.

Projet Azure DevOps

Nouveau référentiel Azure DevOps

Une fois créé, je peux cloner le nouveau référentiel localement. Ensuite, j’ai ajouté tous les fichiers nécessaires à la partie application Web statique. Une recommandation ici est de mettre en place une certaine structure. Pour ce site Web, j’ai opté pour ce qui suit :

  • README.md savoir ce que fait le référentiel et comment l’utiliser
  • public dossier pour les fichiers statiques qui ne nécessitent aucune étape de construction
  • azure.pipelines.yml pour la mise en place du pipeline CI/CD

Les fichiers doivent tous être copiés dans public maintenant. À ce stade, nous devons mettre en place le pipeline.

trigger:
- master

pool:
  vmImage: ubuntu-latest

steps:
- task: AzureStaticWebApp@0
  inputs:
    app_location: '/public'
    skip_app_build: true
    skip_api_build: true
    azure_static_web_apps_api_token: '...'
Passer en mode plein écran

Quitter le mode plein écran

Copie du jeton de déploiement d’Azure Static Web App dans la déclaration du pipeline (azure_static_web_apps_api_token) n’est pas sécurisé. Une meilleure façon consiste à utiliser un groupe variable pour cela :

Créer un groupe de variables avec un secret

Pour accéder à ce secret, vous pouvez modifier le pipeline pour qu’il ressemble à ceci :

trigger:
- master

variables:
- group: deployment-tokens

pool:
  vmImage: ubuntu-latest

steps:
- task: AzureStaticWebApp@0
  inputs:
    app_location: '/public'
    skip_app_build: true
    skip_api_build: true
    azure_static_web_apps_api_token: '$(html5skript-token)'
Passer en mode plein écran

Quitter le mode plein écran

Il est maintenant temps de voir si la partie statique fonctionne déjà comme il se doit. Accéder à l’URL fournie par Azure mène au site Web comme prévu.

L'application Web fonctionne

Toutefois, comme indiqué précédemment, la partie dynamique n’est – à ce stade – pas opérationnelle. Réparons ça. Comme mentionné, le code original était un projet ASP.NET qui lisait les fichiers HTML et créait un index basé sur leur contenu. Outre la mise en œuvre d’une fonctionnalité de recherche, l’API pourrait également gérer des entrées telles que cos(2), évaluant essentiellement des expressions mathématiques. Ce dernier était plutôt une plaisanterie.

Comme contenu renvoyé par l’API donnée, une chaîne JSON ou JSON-P a été utilisée. Ce dernier est en fait un script qui appelle une fonction fournie à l’aide du callback paramètre de requête. Autrefois, c’était un moyen de contourner tout problème CORS… Heureusement, aujourd’hui, nous pouvons faire mieux.

Pour simplifier les choses, nous allons créer une fonction Azure basée sur .NET 7 qui sera un portage du code existant. Pour la récupération précédente du système de fichiers inexistant, nous utiliserons un instantané statique pris lors du déploiement (comme les fichiers statiques et l’API sont déployés de manière synchronisée, c’est très bien). Le tout sera placé dans le api répertoire (en plus du public dossier que nous avons déjà créé).

Nous commencerons par le cspros fichier déterminant les dépendances, instantané des fichiers et version d’Azure Function :

 Sdk="Microsoft.NET.Sdk">
  
    net7.0
    v4
    Exe
  
  
     Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
     Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.16.2" OutputItemType="Analyzer" />
     Include="Microsoft.Azure.Functions.Worker" Version="1.20.0" />
  
  
     Include="$(ProjectDir)..publiclectures**" CopyToOutputDirectory="PreserveNewest" />
     Update="host.json">
      PreserveNewest
    
     Update="local.settings.json">
      PreserveNewest
      Never
    
  

Passer en mode plein écran

Quitter le mode plein écran

L’associé local.settings.json confirme également le mode opérationnel de la fonction Azure – en préparation pour le mode pris en charge le plus longtemps, nous passons en mode isolé :

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
  }
}
Passer en mode plein écran

Quitter le mode plein écran

Ensuite, j’ai déplacé le code – en gardant la plupart des fichiers tels quels, à l’exception du recherche.aspx.cs (code derrière). Ici, je l’ai transformé en fonction de déclenchement HTTP :

public class ApiTrigger
{    
    [Function("search")]
    public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req)
    {
        // ...
    }
}
Passer en mode plein écran

Quitter le mode plein écran

Au lieu de l’ancien Server.MapPath(...) j’utilise juste Path.Join(Environement.CurrentDirectory, ...) en supposant que les fichiers concernés (instantané du lectures dossier des ressources statiques) se trouvera à cet emplacement. Le reste fonctionne tel quel, à l’exception de la génération de réponses. Cela se faisait auparavant en utilisant la méthode statique Response classe – maintenant je pourrais simplement renvoyer les données de réponse :

var response = req.CreateResponse(HttpStatusCode.OK);

if (cb != null)
{
    //Write JSON-P Data
    response.Headers.Add("Content-Type", "text/javascript");
    response.WriteString(value.Stringify(cb));
}
else
{
    //Write JSON Data
    response.Headers.Add("Content-Type", "application/json");
    response.WriteString(value.Stringify());
}

return response;
Passer en mode plein écran

Quitter le mode plein écran

Beaucoup plus propre déjà (et avec des fonctionnalités C# plus récentes telles que des étendues, des plages, … – également plus performantes).

Pour créer l’API, nous devons supprimer le skip_api_build propriété et inclure le api_location propriété pointant vers le API dossier.

trigger:
- master

pool:
  vmImage: ubuntu-latest

variables:
- group: deployment-tokens

steps:
- task: AzureStaticWebApp@0
  inputs:
    app_location: '/public'
    api_location: '/api'
    skip_app_build: true
    azure_static_web_apps_api_token: '$(html5skript-token)'

Passer en mode plein écran

Quitter le mode plein écran

Enfin, j’ai remplacé toutes les occurrences de avec https://html5skript.florian-rappl.de/api/search. L’utilisation antérieure de http: était une erreur à plusieurs niveaux. Bien que je puisse garder l’ensemble du protocole URL indépendant, je voulais forcer les HTTP pour le moment. De plus, le chemin a changé de search.aspx à api/search.

Nous pouvons désormais nous engager et reconstruire. Une fois que tout est à jour on fait la migration en changeant le CNAME dans Plesk :

Modification des paramètres DNS

N’oubliez pas d’ajouter également le domaine personnalisé dans Azure Static Web. De cette façon, Azure créera un certificat gratuit pour HTTPS et pourra mapper le domaine entrant à notre site Web.


Conclusion

Il fonctionne plus rapidement et de manière plus rentable (pour le sous-domaine donné, aucun coût supplémentaire ne se produira). La partie cruciale était d’identifier un fournisseur de cloud ou un mode de déploiement qui correspond assez bien à l’application et à l’utilisation prévue. Dans ce cas, l’application est principalement statique avec une petite partie dynamique exécutée sur .NET. Choisir Azure et un service gratuit est logique car je doute que ce site Web/sous-domaine soit utilisé par trop de personnes. Après tout, il s’adressait principalement aux étudiants et je n’ai pas donné cette conférence (ni aucune autre) depuis près d’une décennie. La conférence elle-même continue d’être donnée, mais avec du matériel mis à jour et sans dépendance à ce site Web.

Dans le prochain article, j’examinerai une autre application que j’ai dû porter ; un jeu multijoueur impliquant un serveur WebSocket écrit à partir de zéro (pas de SignalR ou autre chose – ce dinosaure vient d’une époque où WebSockets venait d’atterrir dans le navigateur et où .NET n’avait pas encore de support prêt à l’emploi).

Actuellement, le serveur dédié est toujours opérationnel – mais je dois terminer la migration avant la fin de l’année.



#Migration #lhébergement #classique #vers #sans #serveur
1701347833

Facebook
Twitter
LinkedIn
Pinterest

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

ADVERTISEMENT