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 »).
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 :
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.
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.
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: '...'
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 :
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)'
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.
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
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"
}
}
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)
{
// ...
}
}
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;
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)'
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 :
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