$30 off During Our Annual Pro Sale. View Details »

Migration d’un hébergement classique à une infr...

Migration d’un hébergement classique à une infra cloud PaaS, retour d'expérience

Beaucoup d’hébergements sont encore à base de serveur dédié car c'est ce que tout le monde fait et que c'est souvent le meilleur rapport puissance / prix. Et on peut aussi faire ce que l'on veut dessus.

Mais cette liberté a un coût : c'est à nous de gérer beaucoup de choses : sécurité, migration de version, log, monitoring. Comme c'est un métier à part entière, on le fait souvent mal ou on le délègue, perdant ainsi pas mal de souplesse et de réactivité.

Cette conférence est un retour d'expérience d'une migration vers un hébergement Platform as a Service (PaaS) avec plein de conseils sur la performance et sur le process d'arriver à un hébergement de qualité clair et reproductible.

Vous ne verrez plus votre hébergement du même œil !

Bastien Jaillot

October 13, 2022
Tweet

More Decks by Bastien Jaillot

Other Decks in Programming

Transcript

  1. Retour d’expérience Migration d’un hébergement classique à une infra cloud

    PaaS Bastien Jaillot, architecte @JoliCode – @bastnic
  2. « Les nuits blanches passées sur le site planté nous

    empêchaient d'envisager toute croissance car le serveur ne tiendrait pas »
  3. (Du coup on m’appelle pour des situations qui puent 💩)

    Les situations complexes sont mon dada
  4. On s’adresse à qui ? - À ceux qui subissent

    leurs hébergements - À ceux qui veulent scaler “facilement” leur application. - À ceux qui connaissent déjà ces galères et sont là pour écouter une bonne histoire. - Plus généralement à tous ceux qui déploient un site en production.
  5. Ce que l’on vous demande Version de PHP ? MySQL

    ? Combien de CPU / RAM / Espace disque ?
  6. Ce que l’on DEVRAIT vous demander - Je dois mettre

    à jour X pour des raisons de sécurité, quand puis-je le faire pour éviter un downtime ? - Quelle stratégie de backup / restore ? - Comment ça se passe si besoin de plus de puissance ? - On sait que l’on va devoir mettre à jour les versions logicielles, comment on planifie ça ? - Comment déployer ? - Comment rollback ? - Comment ajouter un worker ? - Comment configurer un cron ? - Comment ajouter une dépendance ?
  7. Ce que l’on DEVRAIT vous demander - Je dois mettre

    à jour XX pour des raisons de sécurité, quand puis-je le faire pour éviter un downtime - Quelle stratégie de backup / restore ? - Comment ça se passe si besoin de plus de puissance ? - On sait que l’on va devoir mettre à jour les versions logicielles, comment on planifie ça ? - Comment déployer ? - Comment rollback ? - Comment ajouter un worker ? - Comment configurer un cron ? - Comment ajouter une dépendance ? - Comment améliorer le process de build ? - Comment gérer les environnements ? - Où sont les logs ? - Tu veux un APM ? - Tu as pensé à faire un tir de charge pour que l’on finetune les process et la mémoire ? - Comment on rotate les logs ? - Combien de releases on garde - Quelles sondes poser ? - Qui gère quoi quand ça plante ? HNO ? - …
  8. Observabilité ? Je dois auditer mais ??? - SSH bloqué

    => il faut que l’ancien administrateur système m’ajoute - Aucune documentation - Script custom pour déployer - Instances Docker mais routing custom - Ni LOG ni APM, les développeurs sont aveugles de fait - RIEN DE STANDARD ouaip, non, on ne va PAS toucher à ça
  9. API www Clients apps BDD cache local des réponses API

    Tout sur un serveur Users Contributors backoffice cache local des réponses API
  10. Architecture du code ? - API / BO : code

    bien legacy et très très très très très très très lent - FRONT : Symfony nickel mais un énorme cache fichier de l’API (??) - Applications mobiles et tierces ne bénéficient pas du cache calculé par le front - la performance n’a jamais été prise en compte à la base, ce sont des rustines pour que le front ne tombe pas => c’est propre, on va pouvoir bosser !
  11. Cache HTTP (avec Varnish) - Ça s’interpose entre le client

    et le site PHP - Ça répond en <1ms, et consomme 0,0000001% CPU - Ça se configure via des en-têtes HTTP - Ça se scripte via du VCL - C’est bon, mangez-en ! J’ai déjà bloggé sur le sujet : https://jolicode.com/blog/scaling-the-symfony-demo-app-to-the-extreme-with-varnish
  12. API www Clients apps BDD Tout sur un serveur Users

    Contributors backoffice Proxy cache
  13. On va proxifier l’API de l’extérieur Il nous faut donc

    un nouvel hébergement : - aucune idée des futures performances de la plateforme - le trafic n’étant pas lisse, on veut du scaling - j’ai 0 temps et le client n’a pas un énorme budget - le site est planté très régulièrement, on va pouvoir prendre nos gros sabots - plein de solutions (cluster kubernetes, plusieurs serveurs dédiés, lambdas, …) (si vous partez sur Kubernetes pour cette taille de site, on se rappelle quand vous aurez échoué)
  14. PaaS chez Clever Cloud ? - on décrit ce que

    l’on veut (une application PHP 8.1 liée à un MySQL 8.0) - c’est tout - ah si, on paie à la ressource consommée. - tout se configure via des variables d’environnement documentées - beaucoup plus cher à CPU égal par rapport à un dédié et plus de latence - mais ça va nous permettre d’optimiser donc ce sera PEUT-ÊTRE dans le même range de prix => pour le moment on n’en sait rien - Clever Cloud = ils sont Français et sympas, pourquoi pas ?
  15. API www Clients apps BDD Tout sur un serveur Users

    Contributors backoffice Proxy cache Infrastructure Clever Cloud
  16. On récupère tout - Clever Cloud : création de l'organisation

    par le client, ajout des comptes admin - New Relic : création par le client d’un compte gratuit - DNS : accès à la config ("oui oui il faut bien saisir le point à la fin") => TTL à 300s - GitHub : accès à tous les repositories de code - Backups : accès aux sauvegardes de bases de données et des fichiers statiques
  17. # Proxy tentative 1, Varnish appelle le legacy mkdir -p

    proxy-varnish/clevercloud && cd proxy-varnish touch clevercloud/varnish.vcl # avec du code VCL pas sympa git init && git add . && git commit -m 'Proxy: add varnish config' clever create -t php "proxy-varnish" -o "Conf AFUP" clever deploy clever open # ouvre l’url en cleverapps.io dans votre navigateur
  18. 2022-01-18T22:04:05+01:00 VCL compilation failed 2022-01-18T22:04:05+01:00 #######------------ 2022-01-18T22:04:05+01:00 Only one IPv4

    and one IPv6 are allowed. 2022-01-18T22:04:05+01:00 **Backend host "api.XXX.com": resolves to too many addresses**.
  19. # Proxy tentative 2, Varnish appelle une app PHP mkdir

    -p proxy-php/clevercloud && cd proxy-php touch clevercloud/varnish.vcl # avec du code VCL pas sympa symfony create <...> git init && git add . && git commit -m 'Proxy: add code' clever create -t php "proxy-php" -o "Conf AFUP" clever deploy clever open # ouvre l’url en cleverapps.io dans votre navigateur
  20. # nginx != apache, .htaccess… 🤦 composer require symfony/apache-pack git

    add . git commit -m "Fix apache config" clever deploy
  21. C’est en prod ! En DEUX minutes nous avons une

    application PHP en production et accessible. Sans AUCUNE compétence en administration système !
  22. #[Route('/{anything}', name: 'proxy', requirements: ['anything' => '.+'])] public function index(Request

    $request, HttpClientInterface $httpClient): Response { $originResponse = $httpClient->request($request->getMethod(), $request->getRequestUri()); return new Response( $originResponse->getContent(false), $originResponse->getStatusCode(false), [ 'content-type' => $originResponse->getHeaders(false)['content-type'], ] ); }
  23. # ça proxifie, maintenant, ajoutons du monitoring clever env set

    NEWRELIC_APPNAME "prod - api proxy php" clever env set NEWRELIC_LICENSE xxxxx
  24. # imaginez la discussion avec l'infogérant pour # lui dire

    de downgrade PHP. Mieux comme ça non ? clever env set CC_PHP_VERSION 8.0 clever restart
  25. // on n'oublie pas les tests, pas grand chose, mais

    on itérera au besoin public function testProxyGet() { $client = static::createClient(); $crawler = $client->request('GET', '/secretUrl'); $response = $client->getResponse(); $data = json_decode($response->getContent()); $headers = $response->headers; $this->assertIsArray($data); $this->assertTrue($response->isCacheable()); }
  26. public function index(Request $request, HttpClientInterface $httpClient): Response { // ...

    $response->setPublic(); $response->setSharedMaxAge(3600); return $response; }
  27. Et le build ??? Clever Cloud lance tout seul un

    composer install s’il détecte un composer.json
  28. // le code n'étant pas structuré (une action répond à

    100% des appels), New Relic // regroupe toutes les transactions sous /index.php, on corrige ça $action = parse_url($request->getRequestUri(), PHP_URL_PATH); if (extension_loaded('newrelic')) { newrelic_name_transaction($action . ' - ' . $request->query->get('client')); }
  29. # Hit rate trop faible vu avec varnishstat -1 |

    grep MAIN.n_lru_nuked # on augmente sa taille allouée (1go par défaut) # cette variable d'environnement a été créée exprès pour moi, merci Clever <3 clever env set CC_VARNISH_STORAGE_SIZE "13G" # fuite mémoire car métadonnées sur un trop grand nombre d'objets # on passe d'une instance nano (512M) à S (2go) clever scale --flavor S
  30. API www Clients apps BDD Tout sur un serveur Users

    Contributors backoffice Proxy cache Infrastructure Clever Cloud
  31. # Mise en ligne du site front git clone [email protected]:pouet.git

    clever create -t php "front" -o "Conf AFUP" clever env set CC_PHP_VERSION 8.0 clever env set APP_ENV prod clever env set NEWRELIC_APPNAME "prod - front php" clever env set NEWRELIC_LICENSE xxxxx clever env set API_URL https://... clever domain add www.j-ai-signé-un-nda.com clever deploy
  32. # nginx != apache, .htaccess… 🤦 composer require symfony/apache-pack git

    add . git commit -m "Fix apache config" clever deploy
  33. # ESI (Edge Side Include), merci Varnish {# base.html.twig #}

    {{ render_esi( controller( 'App\\Controller\\MenuController::index', {'_locale': app.request.get('_locale')} ) ) }}
  34. /** * @Cache(smaxage="3600", public=true) */ class MenuController extends AbstractController {

    public function index() { // les gros calculs étaient dans du routing return $this->render('_menu.html.twig'); } }
  35. /** * @Route("/media/{anything}", name="media_proxy", methods={"GET"}, requirements={"anything":".+"}) */ public function proxy(Request

    $request, HttpClientInterface $httpClient): Response { $originalResponse = $httpClient->request($request->getMethod(), $request->getRequestUri()); $response = new Response( $originalResponse->getContent(), $originalResponse->getStatusCode(), ['content-type' => $originalResponse->getHeaders()['content-type']] ); $response->setPublic(); $response->setSharedMaxAge(3600); return $response; }
  36. API www Clients apps BDD Un serveur Users Contributors backoffice

    Proxy cache Infrastructure Clever Cloud BDD jetable API test
  37. # nginx != apache, .htaccess… 🤦 composer require symfony/apache-pack (et

    non, legacy…) touch .htaccess git add . git commit -m "Fix apache config" clever deploy
  38. Performance SQL ? - Malgré des ajouts d’index… Performances horribles

    comparées au legacy - Dans notre bonheur, j’étais passé direct de MySQL 5.7 à MySQL 8, mais PERTE DES QUERY CACHE. - Legacy qui fait 500x la même requête SQL dans une boucle => on va éviter de fixer le code, on fixe MySQL - => on jette l’instance v8 et on lance v5.7
  39. www Clients apps One server Users Contributors backoffice Proxy cache

    Infrastructure Clever Cloud BDD API KTHXBYE Uploaded data
  40. Bug marrant 1/2 Constat : des énormes pics bases de

    données sans cause visible dans l’APM API. Que faut-il faire ? augmenter la puissance BDD ? Sont nuls ces serveurs, on va repasser sur un dédié
  41. Bug marrant 2/2 On regardait la mauvaise application… Un contributeur

    ouvrait 40 onglets d’un coup 404 favicon.ico => chargement par défaut de la page d'accueil du BO Page d’accueil avec plein de métriques, plein de calculs : écroulement de la BDD Solution : ajouter un favicon 🙄
  42. PaaS : gestion des fichiers contribués Pas de stockage local

    sur du cloud, car les machines meurent 💀. Deux solutions : stockage objet “S3” (cellar) ou point de montage distant “NFS” (fsbucket)
  43. PaaS : gestion des mails - SMTP local ne fonctionne

    évidemment pas - On peut utiliser un SMTP distant en configurant des variables d'environnement (mais ça ne fonctionne pas) - On utilise symfony/mailer
  44. PaaS : et si on veut quand même scripter ?

    C’est documenté https://www.clever-cloud.com/doc/develop/build-hooks/ - hooks sur le déploiement : Avant / après build, avant lancement, lancement ok, lancement planté - déclaration par… variable d’environnement
  45. Différence sur le déploiement ? Avant ? - SSH sur

    la machine - Lancement commande inconnue - Pull du code - Composer install - Npm build - Pendant ce temps là le site est down Après ? $ clever deploy Une nouvelle instance se lance quand le build est prêt. 0 downtime, 0 code custom
  46. Tout n’est pas magique : pas libre de tout faire…

    - RabbitMQ, Cassandra ? => demander au support - Extension Apache ou PHP exotique ? => demander au support - Réplication SQL ? => demander au support - DataDog à la place New Relic ? ben non ! Mais tu peux tester Elastic APM - https://redirection.io/ ? ben non (enfin si, en hackant beaucoup, article à venir) - Un mauvais signal : zone New Yorkaise qui ferme 10j après que je l’utilise
  47. Tout n’est pas magique :( - Pas de support d’HTTP/2

    => faut demander un accès béta un comble quand on sait que le CEO en parlait en conférence en 2014 - Pas de réseau privé par organisation (ça arrive) - Pas de healthcheck applicatif (je fais du lobying) - Vim a le mouse support activé. Mais qui fait ça ?
  48. Cependant <3… rétrospective - Soucis de version de PHP :

    changer une variable d’environnement - Soucis de MySQL trop lent : lancer les deux versions et comparer - Vous avez souvent eu ce degré de liberté / réactivité avec vos scripts ansible / bash / infogérant ? - Grande agilité => on peut TESTER des choses sans un gros investissement
  49. - Le client a la main sur tout : il

    peut vous donner les mêmes accès que moi - Depuis la console PaaS : identifier 4 applications PHP, une base MySQL et 2 dossiers partagés (fsbucket). - Dans chaque app : identifier les contrats (les variables d'environnements) - Déployer: clever deploy - Ça ralentit ou ça plante ? regarder New Relic ou clever logs C’est bon vous pouvez me virer
  50. > Quelques bons chiffres pour vous illustrer les avancées toujours

    positives de notre projet. > +70% par rapport à la même période l'année précédente > et le tout SANS NUITS BLANCHES liées aux serveurs !
  51. Conclusion - Architecture moins chère, scalable et évolutive. - Déploiement

    standardisé et sans code custom. - Applications bien cloisonnées sans container ni VM à gérer. - Pas nécessaire d’avoir de connaissances en administration système. - C’est souvent plus simple et moins coûteux de se faire accompagner par un expert. - J’ai mis plus de temps à préparer cette présentation qu’à effectuer cette migration