Fermer

avril 4, 2019

Aller sans serveur avec les travailleurs de Cloudflare20 minutes de lecture



À propos de l'auteur

Leonardo Losoviz est le créateur de PoP un framework pour la construction de sites Web modulaires basés sur PHP et les guidons, et optimisé par WordPress. Il habite à Kuala…
Plus à propos de Leonardo

Cloudflare Workers permet aux développeurs de construire et d'étendre les capacités de sites sans serveur. Dans cet article, nous allons apprendre le fonctionnement de Cloudflare Workers et savoir s’il est judicieux de l’ajouter à notre pile technologique.

(Cet article est sponsorisé.) C’est une vérité universellement reconnue qu’un site Web en quête de succès doit être en manque de vitesse. Et ainsi, ça passe sans serveur.

À la base, sans serveur est une stratégie pour l'architecture d'un site Web, basée sur le déploiement de fichiers statiques (les bons vieux fichiers HTML, CSS et images) sur un hébergement basé sur un nuage et sur l'amélioration des capacités du site Web. en accédant à une fonctionnalité dynamique basée sur le cloud et facturée à l'utilisation. Sans serveur, il n’ya rien de mystique ni de mystérieux: son résultat final est simplement un site Web ou une application.

Malgré son nom, "sans serveur" ne signifie pas "sans serveur". Cela signifie simplement «sans mon propre serveur». Cela signifie que mon site est toujours hébergé sur un serveur, mais en déchargeant cette responsabilité sur le fournisseur de services en nuage, je peux consacrer toute mon énergie à développer mon propre produit (le site Web) sans avoir à vous soucier de l'infrastructure.

Serverless est très attrayant pour plusieurs raisons:

  • Low-cost
    Vous ne payez que ce que vous utilisez. L'hébergement de fichiers statiques sur le cloud peut coûter quelques centimes par mois (voire même être gratuit dans certains cas).
  • Rapide
    Les fichiers statiques peuvent être remis à l'utilisateur à partir d'un réseau de distribution de contenu (CDN) situé à proximité du site.
  • Sécurisé
    Le fournisseur de services infonuagiques maintient constamment la plate-forme sous-jacente à jour.
  • Facilité d'adaptation
    L'activité de ce fournisseur consiste à mettre à niveau l'infrastructure à la demande.

Serverless est de plus en plus populaire en raison de la disponibilité croissante des services offerts par les fournisseurs de cloud, des générateurs de sites statiques simples mais puissants basés sur des modèles (tels que Jekyll Hugo ou Gatsby ) et des moyens pratiques d'introduire des données dans le processus (par exemple, via l'un des nombreux CMS basés sur git).

Le réseau, c'est l'ordinateur: introduction des travailleurs Cloudflare

Cloudflare un des plus grandes plates-formes de réseau de nuage du monde, est bien versé i n Nous fournissons les avantages que nous recherchons sans serveur: depuis un certain temps, ils ont mis à disposition leur CDN complet pour rendre nos sites rapides, nous ont proposé une protection contre les attaques DDoS afin de sécuriser nos sites, et ont rendu leur service DNS 1.1.1.1 gratuit afin que nous puissions nous permettre de la vie privée sur Internet, parmi de nombreux autres services.

Leur nouvelle offre sans serveur, Cloudflare Workers (ou simplement «Workers»), s’appuie sur le même réseau mondial en nuage de plus de 165 centres de traitement des données. . Cloudflare Workers est un service qui fournit un environnement d’exécution JavaScript léger pour compléter les applications existantes ou en créer de nouvelles.

L’empilement sur le réseau étendu de Cloudflare fait de Cloudflare Workers un gros problème. Cloudflare peut faire évoluer son infrastructure en fonction des pics de demande, desservant une application sans serveur à partir d'emplacements situés sur cinq continents et prenant en charge des millions d'utilisateurs, ce qui rend nos applications rapides, fiables et évolutives.

 Carte du centre de données Cloudflare
Le réseau Cloudflare est alimenté par 165 centres de données à travers le monde. ( Grand aperçu )

De plus, Cloudflare Workers fournit des fonctionnalités uniques qui en font un service encore plus attrayant. Voyons cela en détail.

Architecture basée sur la V8 pour un accès rapide et à faible coût

Les ingénieurs de Cloudflare se sont mis à la tâche des ouvriers architectes, comme ils l’ont expliqué avec fierté en profondeur . Alors que presque tous les fournisseurs offrant le cloud computing ont une architecture basée sur des conteneurs et des machines virtuelles, Workers utilise «Isolates», technologie qui permet à V8 (le moteur JavaScript de Google Chrome) d'exécuter des milliers de processus sur un serveur unique. de manière efficace et sécurisée.

Par rapport aux machines virtuelles, Isolates réduit considérablement la surcharge nécessaire à l'exécution du code utilisateur, ce qui se traduit par une exécution plus rapide et une utilisation réduite de la mémoire.

 Architecture des isolats
Les isolats autorisent des milliers de processus. pour fonctionner efficacement sur une seule machine ( Grand aperçu )

Cloudflare Workers n'est pas la première plateforme informatique en nuage sans serveur en exploitation: par exemple, Amazon a proposé AWS Lambda et Lambda @ Edge. Cependant, Cloudflare affirme qu'en raison d'une charge similaire exécutée par Isolates, les travailleurs surpassent la concurrence là où cela compte le plus: la vitesse et l'argent.

Lower Price

un travailleur offrant 50 millisecondes de CPU coûte 0,50 USD par million de demandes, l'équivalent en Lambda coûte 1,84 USD par million. Par conséquent, les travailleurs en cours d'exécution coûtent environ 3 fois moins cher que Lambda par cycle de processeur .

Un accès plus rapide

L'équipe Cloudflare a effectué des tests comparant les travailleurs contre AWS Lambda et Lambda @ Edge . ] et a conclu que Workers est 441% plus rapide qu'une fonction Lambda et 192% plus rapide que Lambda @ Edge.

 Tableau de comparaison des vitesses
Ce graphique montre le pourcentage de demandes envoyées à Lambda, Lambda @ Edge et Les travailleurs de Cloudflare étaient plus rapides qu'un nombre donné de millisecondes. ( Grand aperçu )

Les meilleures performances de Cloudflare Workers sont confirmées par le site tiers serverless-benchmark.com qui mesure les performances des fournisseurs sans serveur et fournit en continu statistiques mises à jour.

 Comparaison des performances
Statistiques relatives aux frais généraux (délai entre la demande et la réponse sans le temps réel pris par la fonction) et au démarrage à froid (délai nécessaire à une fonction pour répondre à l'événement) pour Cloudflare Workers et ses concurrents. ( Grand aperçu )

Codé en JavaScript, basé sur l'API Service Workers

Comme il est basé sur la V8, la programmation pour les travailleurs se fait dans les langages pris en charge par V8: JavaScript et langages prenant en charge. compilation à WebAssembly, telle que Go et Rust. Le code de la V8 est fusionné avec Workers au moins une fois par semaine de sorte que nous pouvons toujours nous attendre à ce qu'il prenne en charge la dernière version mise en œuvre de ECMAScript .

Les travailleurs sont calqué sur le Service Workers disponible dans les navigateurs Web modernes, et ils utilisent la même API chaque fois que possible. Ceci est significatif: étant donné que les travailleurs du service font partie de la fondation pour créer une application Web progressive (PWA) la création de travailleurs se fait via une API que les développeurs connaissent déjà (ou sont en train d'apprendre). ) pour la création d’applications Web modernes.

De plus, s’appuyer sur l’API de Service Workers permet aux développeurs d’augmenter leur productivité dans la mesure où il permet l’isomorphisme du code. Même si cela n'est pas toujours faisable en raison des différents contextes (alors qu'un Service Worker s'exécute dans le navigateur, Cloudflare Worker s'exécute sur le réseau), certains cas d'utilisation pourraient s'appliquer aux deux contextes.

Par exemple, parmi les opérateurs de service. les recettes décrites dans serviceworke.rs les recettes de API Analytics Load Balancer et Dependency Injection peuvent être mises en œuvre côté client. et le réseau utilisant le même code (ou la majeure partie). Et même lorsque la fonctionnalité n’a de sens que du côté client ou du réseau, elle peut être partiellement implémentée à l’aide de fragments de code indépendants du contexte et réutilisables.

De plus, en utilisant la même API pour les opérateurs de service. et Cloudflare Workers facilite l’amélioration progressive. Une application peut exécuter un Service Worker autant que possible et avoir recours à un Cloudflare Worker lorsque l'utilisateur visite le site pour la première fois (lorsque le Service Worker n'est toujours pas installé sur le client) ou lorsque les Service Workers ne sont pas pris en charge ( par exemple lorsque le navigateur est ancien ou qu’il s’agit simplement d’opéra mini).

Enfin, le recours à une API unique simplifie l’ensemble de la pile de langues, ce qui permet une fois encore au développeur d’obtenir davantage de travail. terminé. Par exemple, la définition d'une stratégie de mise en cache pour le CDN dans Varnish s'effectue via le langage de configuration Varnish, qui possède sa propre syntaxe. Cloudflare Workers, cependant, permet aux développeurs de coder les mêmes tâches via, vous l'avez deviné, l'API Service Workers.

Elle exploite la boîte à outils moderne

En plus des travailleurs qui ne demandent pas aux développeurs d'apprendre Nouveau langage ou nouvelle API, il suit les conventions modernes et intègre les technologies les plus répandues, ce qui nous permet d’utiliser notre boîte à outils actuelle:

Voyons quelques exemples concrets

Il est temps de s’amuser! Jouons avec des travailleurs basés sur des cas d’utilisation courants pour voir comment nous pouvons augmenter nos sites, voire en créer de nouveaux.

Cloudflare met à disposition un outil de test basé sur un navigateur, le Cloudflare Workers Playground . Cet outil est très complet et facile à utiliser: copiez simplement le script Worker dans le panneau de gauche, exécutez-le avec l'URL définie dans la barre en haut à droite, consultez les résultats dans l'onglet "Aperçu" et le code source dans l'onglet "Aperçu". Onglet 'Testing' (à partir duquel nous pouvons également ajouter des en-têtes personnalisés), puis exécutez console.log dans le script pour afficher les résultats dans l'outil de développement, en bas à droite. Pour partager (ou également stocker) votre script, vous pouvez simplement copier l'URL de votre navigateur à ce moment-là.

 Capture d'écran du site Web de Playground
Le terrain de jeu nous permet de tester nos travailleurs Cloudflare ( Grand aperçu )

Commencer par Playground vous mènera loin, mais à un moment donné, vous voudrez tester sur le réseau Cloudflare actuel et, mieux encore, déployer vos scripts pour la production. Pour cela, votre site doit être configuré avec Cloudflare . Si vous êtes déjà un utilisateur de Cloudflare, connectez-vous simplement, accédez à l'onglet "Travailleurs" du tableau de bord, et vous êtes prêt à partir .

Si vous n'êtes pas un utilisateur de Cloudflare, vous pouvez soit inscrivez-vous ou vous pouvez demander un sous-domaine workers.dev sous lequel vous pourrez bientôt déployer vos ouvriers. Le site workers.dev accepte actuellement les réservations de sous-domaines, alors dépêchez-vous et réservez le vôtre avant qu'il ne soit pris par quelqu'un d'autre!

 Capture d'écran de workers.dev
workers.dev accepte actuellement des réservations. des sous-domaines ( Image agrandie )

Les recettes ci-dessous sont extraites du livre de recettes Cloudflare Workers du référentiel d'exemples dans Github et du Blog de Cloudflare . Chaque exemple contient un lien vers le code du script dans Playground.

Hébergement de sites statiques

Le cas d'utilisation le plus simple pour Workers est la création d'un nouveau site, répondant de manière dynamique aux demandes sans avoir à se connecter à un serveur d'origine. . Alors, bonjour tout le monde!

 addEventListener ('fetch', event => {
  event.respondWith (new Response ('

Bonjour tout le monde!

')) })

Voir le code dans la Playground

Au lieu d'imprimer la sortie HTML dans le script, nous pouvons également héberger des fichiers HTML statiques avec un service d'hébergement et les récupérer avec un simple script Worker. . En effet, le script Worker peut extraire le contenu de tout fichier disponible sur Internet: alors que le domaine sous lequel Worker est exécuté doit être géré par Cloudflare, le site Web d'origine à partir duquel le script extrait le contenu ne doit pas obligatoirement. Et cela fonctionne non seulement pour les pages HTML, mais aussi pour les ressources CSS et JS, les images et tout le reste.

Le script ci-dessous, par exemple, restitue une page hébergée sous DigitalOcean Spaces : [19659060] addEventListener ('fetch', event => {
  event.respondWith (handleRequest (event.request))
})

fonction async. handleRequest (demande) {
  const parsedUrl = nouvelle URL (request.url)
  let path = parsedUrl.pathname

  let lastSegment = path.substring (path.lastIndexOf ('/'))
  if (lastSegment.indexOf ('.') === -1) {
    chemin + = '/index.html'
  }

  return fetch ("https://cloudflare-example-space.nyc3.digitaloceanspaces.com" + chemin)
}

Voir le code dans Playground

Construction d'API

Un cas d'utilisation important pour les travailleurs est la création d'API. Par exemple, le script ci-dessous alimente un service API indiquant si un domaine redirige ou non vers HTTPS :

 addEventListener ('fetch', event => {
 event.respondWith (handleRequest (event.request))
})

/ **
* Récupérer une requête et suivre les redirections
* @param {demande} demande
* /
fonction async. handleRequest (demande) {
 laisser en-têtes = nouveaux en-têtes ({
   'Content-Type': 'text / html',
   'Access-Control-Allow-Origin': '*'
 })
 const SECURE_RESPONSE = new Response ('secure', {status: 200, en-têtes: en-têtes})
 const INSECURE_RESPONSE = new Response ('non sécurisé', {status: 200, en-têtes: en-têtes})
 const NO_SUCH_SITE = nouvelle réponse ("site Web introuvable", {statut: 200, en-têtes: en-têtes})

 let domain = new URL (request.url) .searchParams.get ('domaine')
 si (domaine === null) {
   renvoie une nouvelle réponse ('S'il vous plaît, passez le domaine via la chaîne de requête', {status: 404})
 }
 essayer {
   let resp = wait fetch (`http: // $ {domain}`, {en-têtes: {'User-Agent': request.headers.get ('User-Agent')}})
   if (resp.redirected == true && resp.url.startsWith ('https')) {
     retourne SECURE_RESPONSE
   }
   else if (resp.redirected == false && resp.status == 502) {
     retourne NO_SUCH_SITE
   }
   autre {
     retourne INSECURE_RESPONSE
   }
 }
  catch (e) {
   renvoie une nouvelle réponse (`Quelque chose s'est mal passé $ {e}`, {status: 404})
 }
}

Voir le code dans la aire de jeux

Les travailleurs peuvent également se connecter à plusieurs origines en parallèle et combiner toutes les réponses en une seule réponse. Par exemple, le script ci-dessous alimente un service API qui récupère simultanément le prix de plusieurs pièces de crypto-monnaie :

 addEventListener ('fetch', event => {
    event.respondWith (fetchAndApply (event.request))
})
  
/ **
 * Faire plusieurs demandes,
 * agréger les réponses et
 * renvoyer en une seule réponse
 * /
fonction async fetchAndApply (demande) {
    const init = {
      méthode: 'GET',
      en-têtes: {'Autorisation': 'XXXXXX'}
    }
    const [btcResp, ethResp, ltcResp] = attendre Promise.all ([
      fetch('https://api.coinbase.com/v2/prices/BTC-USD/spot', init),
      fetch('https://api.coinbase.com/v2/prices/ETH-USD/spot', init),
      fetch('https://api.coinbase.com/v2/prices/LTC-USD/spot', init)
    ])
  
    const btc = wait btcResp.json ()
    const eth = wait ethResp.json ()
    const ltc = wait ltcResp.json ()
  
    laisser combiné = {}
    combiné ['btc'] = btc ['data'] .un montant
    combiné ['ltc'] = ltc ['data'] .un montant
    combiné ['eth'] = eth ['data'] .amount
  
    const responseInit = {
      en-têtes: {'Content-Type': 'application / json'}
    }
    renvoyer une nouvelle réponse (JSON.stringify (combiné), responseInit)
}

Voir le code dans la Playground

Il est également possible de rendre l'API extrêmement dynamique en récupérant des données d'une base de données! Workers KV est un magasin de données global à faible temps de latence et de valeur clé. Il est optimisé pour les lectures rapides et fréquentes et les données doivent être sauvegardées avec parcimonie. Ensuite, c’est une approche sensée pour entrer des données via l’API Cloudflare :

 curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces / $ NAMESPACE_ID / values ​​/ first-key "
-X PUT 
-H "Courriel X-Auth: $ CLOUDFLARE_EMAIL" 
-H "X-Auth-Key: $ CLOUDFLARE_AUTH_KEY" 
--data 'Ma première valeur!'

Les valeurs peuvent ensuite être lues dans le script de travail :

 addEventListener ('fetch', event => {
 event.respondWith (handleRequest (event.request))
})

fonction async. handleRequest (demande) {
 const value = wait FIRST_KV_NAMESPACE.get ("première clé")
 if (valeur === null)
   renvoie une nouvelle réponse ("Valeur non trouvée", {status: 404})

 retourne une nouvelle réponse (valeur)
}

Au moment de la rédaction, KV est encore en version bêta et n'est disponible que pour les testeurs bêta. Si vous souhaitez le tester, vous pouvez contacter l’équipe Cloudflare et demander un accès.

Géo-ciblage

Cloudflare détecte l’adresse IP d'origine de la demande entrante et y ajoute une code de pays de la lettre à l'en-tête 'Cf-Ipcountry'. Le script ci-dessous lit cet en-tête, obtient le code du pays, puis redirige vers la version du site correspondante s'il existe :

 addEventListener ('fetch', event => {
 event.respondWith (fetchAndApply (event.request))
})

fonction async fetchAndApply (demande) {

   const country = request.headers.get ('Cf-Ipcountry'). toLowerCase ()
   let url = new URL (request.url)

   const target_url = 'https: //' + url.hostname + '/' + pays
   const target_url_response = wait fetch (target_url)

   if (target_url_response.status === 200) {
       retourne une nouvelle réponse ('', {
         statut: 302,
         en-têtes: {
           'Location': target_url
         }
       })
   } autre {
       retour chercher (demande)
   }
}

Voir le code dans la Playground

Une approche similaire peut s'appliquer pour l'équilibrage de charge, en choisissant parmi plusieurs origines pour améliorer la vitesse ou la fiabilité.

Sécurité renforcée

Les scripts ci-dessous ajoutent des règles de sécurité et des filtres pour bloquer les visiteurs et les robots indésirables .

Ignorer les requêtes HTTP POST et PUT:

 addEventListener ('fetch', event => {
  event.respondWith (fetchAndApply (event.request))
})

fonction async fetchAndApply (demande) {
  if (request.method === 'POST' || request.method === 'PUT') {
    return new Response ('Désolé, cette page n'est pas disponible.',
        {status: 403, statusText: 'Interdit'})
  }

  retour chercher (demande)
}

Voir le code dans la Playground

Refuser une araignée ou un robot:

 addEventListener ('fetch', event => {
  event.respondWith (fetchAndApply (event.request))
})

fonction async fetchAndApply (demande) {
  if (request.headers.get ('user-agent'). includes ('annoying_robot')) {
    return new Response ('Désolé, cette page n'est pas disponible.',
        {status: 403, statusText: 'Interdit'})
  }

  retour chercher (demande)
}

Voir le code dans la Playground

Empêcher une adresse IP de se connecter:

 addEventListener ('fetch', event => {
  event.respondWith (fetchAndApply (event.request))
})

fonction async fetchAndApply (demande) {
  if (request.headers.get ('cf-connection-ip') === '225.0.0.1') {
    return new Response ('Désolé, cette page n'est pas disponible.',
        {status: 403, statusText: 'Interdit'})
  }

  retour chercher (demande)
}

Voir le code dans la aire de jeu

Tests A / B

Nous pouvons facilement créer un ouvrier pour contrôler les tests A / B :

 addEventListener ('fetch', ' => {
  event.respondWith (fetchAndApply (event.request))
})

fonction async fetchAndApply (demande) {
  nom de const = 'experience-0'
  let group // 'control' ou 'test', défini ci-dessous
  let isNew = false // le groupe a-t-il été attribué?

  // Détermine le groupe dans lequel cette demande se trouve.
  const cookie = request.headers.get ('Cookie')
  if (cookie && cookie.includes (`$ {name} = control`)) {
    groupe = 'contrôle'
  } else if (cookie && cookie.includes (`$ {name} = test`)) {
    groupe = 'test'
  } autre {
    // 50/50 Split
    group = Math.random () 

Voir le code dans la Playground

Distribution de contenu basé sur un périphérique

Le script ci-dessous fournit un contenu différent en fonction du périphérique utilisé :

 ] addEventListener ('fetch', event => {
  event.respondWith (fetchAndApply (event.request))
})

fonction async fetchAndApply (demande) {
  laissez uaSuffix = ''

  const ua = request.headers.get ('user-agent')
  if (ua.match (/ iphone / i) || ua.match (/ ipod / i)) {
    uaSuffix = '/ mobile'
  } else if (ua.match (/ ipad / i)) {
    uaSuffix = '/ tablette'
  }

  retourne chercher (request.url + uaSuffix, request)
}

Voir le code dans Playground

Routage conditionnel

En passant des valeurs personnalisées dans les en-têtes, nous pouvons récupérer le contenu le plus spécifique :

 addEventListener ('fetch', événement => {
  event.respondWith (fetchAndApply (event.request))
})

fonction async fetchAndApply (demande) {
  laisser suffixe = ''
  // En supposant que le client envoie un en-tête personnalisé
  const cryptoCurrency = request.headers.get ('X-Crypto-Currency')
  if (cryptoCurrency === 'BTC') {
    suffixe = '/ btc'
  } else if (cryptoCurrency === 'XRP') {
    suffixe = '/ xrp'
  } else if (cryptoCurrency === 'ETH') {
    suffixe = '/ eth'
  }

  retourne chercher (request.url + suffixe, demande)
}

Voir le code dans Playground

Performances améliorées

Les travailleurs mettent à disposition un API Cache grâce auquel nous pouvons sauvegarder des données de calcul intensif et les préparer pour une utilisation immédiate à partir de ce moment-là:

 fonction asynchrone handleRequest (événement) {
  laisser cache = caches.default
  laisser réponse = attendre cache.match (event.request)
      
  si (! réponse) {
    response = doSuperComputationallyHeavyThing ()
    event.waitUntil (cache.put (event.request, response.clone ()))
  }
        
  retour réponse
}

Par exemple, via l'API de cache, nous pouvons stocker des requêtes GraphQL dont les résultats n'ont pas changé :

 la fonction asynchrone handleRequest (event) {
  laisser cache = caches.default
  laisser réponse = attendre cache.match (event.request)
  
  si (! réponse) {
    response = wait fetch (event.request)
    si (réponse.ok) {
      event.waitUntil (cache.put (event.request, response.clone ()))
    }
  }
        
  retour réponse
}

Beaucoup d'autres

La liste des applications utiles s'allonge encore et encore. Vous trouverez ci-dessous des liens vers plusieurs exemples supplémentaires:

Conclusion: «Le réseau, c'est l'ordinateur»

Parce que la rapidité compte, les sites Web ne fonctionnent plus avec un serveur. Cloudflare Workers est une nouvelle offre qui permet cette transition. Il brouille les frontières entre l’ordinateur et le réseau, permettant aux développeurs de déployer des applications globales fonctionnant sur la structure même d’Internet, en exploitant le réseau mondial de serveurs de Cloudflare pour exécuter notre code à proximité de l’emplacement de nos utilisateurs. Il est rapide, bon marché et sécurisé, et il s'adapte à tous les besoins.

Si vous voulez en savoir plus, consultez le site ou demandez à la communauté .

 Éditorial éclatant (il)




Source link