{"id":5104,"date":"2022-10-28T09:15:00","date_gmt":"2022-10-28T07:15:00","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=5104"},"modified":"2022-10-27T15:34:44","modified_gmt":"2022-10-27T13:34:44","slug":"nightmare-infrastructures-come-sopravvivere-a-unapocalisse-zombie-sul-cloud","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/nightmare-infrastructures-come-sopravvivere-a-unapocalisse-zombie-sul-cloud\/","title":{"rendered":"Nightmare Infrastructures: come sopravvivere a un\u2019apocalisse zombie sul Cloud"},"content":{"rendered":"\n

Jack Skeleton, in “The Nightmare Before Christmas”, cantava: “Cos’\u00e8? Cos’\u00e8? Ma che colore \u00e8?”<\/p>\n\n\n\n

E di fronte a certe infrastrutture, \u00e8 capitato di dirlo anche a noi.<\/p>\n\n\n\n

<\/p>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

Potreste gi\u00e0 aver capito che, in questo articolo, andremo a descrivere alcune strane infrastrutture con cui abbiamo avuto a che fare nel passato, raccontando storie spaventose su pattern e pratiche per nulla appropriati per il cloud e che, a lungo andare, hanno trasformato innocue infrastrutture in Zombie assetati di cervelli, pronti ad invadere il Cloud.<\/p>\n\n\n\n

Non \u00e8 nostra intenzione puntare il dito e deridere nessun design in particolare: i requisiti e le condizioni al contorno possono far s\u00ec che alcune soluzioni siano pressoch\u00e9 obbligatorie; il nostro intento \u00e8 farvi fare una risata: il mondo l\u00e0 fuori \u00e8 gi\u00e0 abbastanza spaventoso! <\/p>\n\n\n\n

(Se siete nostri clienti, state leggendo questa storia e vi riconoscete: si, stiamo parlando di voi ! :D) <\/em><\/p>\n\n\n\n

Non vi resta che andare a prendere i pop corn e la vostra coperta preferita: stiamo per iniziare i nostri racconti horror! <\/p>\n\n\n\n

<\/p>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

TestProdDev<\/h2>\n\n\n\n

“La strada per l’inferno \u00e8 lastricata di buone intenzioni”<\/em><\/p>\n\n\n\n

<\/p>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

Cosa c’\u00e8 di male nell’applicare un piccolo fix direttamente in produzione perch\u00e9 non c’\u00e8 tempo di provarlo nell’ambiente di dev o di test ? <\/p>\n\n\n\n

Ovviamente la patch rimarr\u00e0 solamente in produzione, facendo in modo che gli altri ambienti siano disallineati. Dopo qualche tempo, tutti si saranno dimenticati di quel piccolo, insignificante pezzo di codice, che rimarr\u00e0 in silenzio ad aspettare il momento giusto per gustarsi la vendetta: al rilascio di una nuova funzionalit\u00e0 sicuramente emerger\u00e0 un bug solo nell’ambiente di produzione causato dalla modifica (la legge di Murphy \u00e8 sempre valida).<\/p>\n\n\n\n

Siccome si tratta dell’ambiente di produzione, un altro “piccolo” fix sar\u00e0 rilasciato, aumentando il disallineamento. <\/p>\n\n\n\n

La storia si ripeter\u00e0 fino a che ogni nuovo sviluppo sar\u00e0 applicato direttamente all’ambiente di produzione perch\u00e9 non ci sar\u00e0 modo di essere sicuri che il software possa essere provato in modo affidabile negli altri ambienti. Siamo “finalmente” arrivati all’ambiente di testproddev.<\/strong><\/p>\n\n\n\n

Il vero incubo \u00e8 riuscire a capire dove le cose smettono di funzionare e perch\u00e9 a volte funzionano! In altri casi esistono ambienti di test, ma che non sono propriamente di test. <\/p>\n\n\n\n

Parafrasando Boskov: “Produzione \u00e8 quando cliente urla<\/em>“<\/p>\n\n\n\n

Tutto ha inizio un Marted\u00ec mattina, con un drift nell’ambiente di test. Dopo aver valutato come risolvere il disallineamento ed aver applicato le modifiche su CloudFormation, si \u00e8 materializzato l’incubo “Update Rollback Failed”. Una ulteriore analisi ci ha fatto scoprire il problema alla base di tutto: qualcuno ha cancellato una task definition di un container Fargate ECS, che \u00e8 stato poi aggiornato da CloudFormation. In questi casi l’unica soluzione possibile \u00e8 cancellare l’intero stack e ricrearlo da zero. <\/p>\n\n\n\n

\u201cNessun problema\u201d, abbiamo pensato: per fortuna siamo nell’ambiente di test e stiamo usando IAC, cosa mai potrebbe andare male? <\/p>\n\n\n\n

Cinque minuti dopo aver cancellato lo stack, i nostri Slack in ufficio hanno cominciato  a suonare all’unisono: l’ambiente di “Test” era usato per ospitare servizi usati da partner del cliente. In questo caso la fortuna ci ha aiutato: tutti i dati erano salvati nei backup e in soli 15 minuti l’infrastruttura \u00e8 stata ripristinata da zero.<\/p>\n\n\n\n

Cosa abbiamo imparato? Mai fidarsi di qualcosa che ha “test” nel nome.<\/p>\n\n\n\n

In qualsiasi caso: se un ambiente \u00e8 essenziale per il business \u00e8 sempre meglio considerarlo tale usando nomi come \u201cproduzione\u201d, \u201cproduction\u201d, \u201cprod\u201d o qualcosa che comunque significhi: “Maneggiare con cura, attenzione!”<\/p>\n\n\n\n

Il Cloud semplifica il deploy delle infrastrutture: usiamo questa caratteristica a nostro vantaggio! <\/p>\n\n\n\n

Tutto pu\u00f2 essere automatizzato usando IAC, i costi diventano un problema marginale: con il modello di pagamento on-demand si possono fare esperimenti e cancellare tutto alla fine dei test, minimizzando le spese. Usare delle pipeline per Continuous Integration e Continuous Deployment fa in modo che tutto sia sincronizzato.<\/p>\n\n\n\n

AWS CloudFormation, CodeBuild, CodePipeline e CodeDeploy sono servizi chiave per fare s\u00ec che tutto sia aggiornato e coerente in ambienti differenti. <\/p>\n\n\n\n

Microservizi… giganti<\/h2>\n\n\n\n

Se affermo che la mia immaginazione, alquanto stravagante, produsse le<\/em><\/p>

visioni simultanee di un polipo, di un drago e di una caricatura umana, non<\/em><\/p>

sar\u00f2 infedele allo spirito della cosa. Una testa polposa, tentacolare,<\/em><\/p>

sormontava un corpo grottesco e squamoso, munito di ali rudimentali; ma<\/em><\/p>

era il profilo generale del tutto che lo rendeva sconvolgente e spaventoso<\/em><\/p>

in massimo grado. Alle spalle della figura si intuiva vagamente uno sfondoarchitettonico di dimensioni ciclopiche. – <\/em>H.P. Lovecraft – Il richiamo di Chtulu<\/p><\/blockquote>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

Un microservizio \u00e8, per definizione, codice che funziona in modo cooperativo con altri elementi, permettendo ai team di sviluppo di concentrarsi maggiormente su singoli problemi. Ad esempio, un microservizio pu\u00f2 occuparsi dell’invio di email ai clienti, mentre un’altro far\u00e0 s\u00ec che l’inventario sia aggiornato a fronte di un pagamento andato a buon fine. <\/p>\n\n\n\n

Un design a microservizi fa s\u00ec che il software sia facilmente manutenibile ed occupi poche risorse computazionali. <\/strong><\/p>\n\n\n\n

Ci \u00e8 capitato di trovare un container Docker con allocati 8 gigabyte di ram e 4 cpu: il tutto per far funzionare una applicazione Liferay usata come CRM, gestore di pagamenti con relativo invio di mail. In questo caso non si trattava di un microservizio, ma di un elefante che tentava di guidare una 500! <\/p>\n\n\n\n

Alcuni framework enterprise tendono ad essere per loro natura monolitici. Se necessitate di tecnologie di questo genere non fatevi indurre nella tentazione di usare container solamente per avere una strategia di deploy pi\u00f9 semplice: non \u00e8 cos\u00ec. Le istanze EC2 con Autoscaling Group non sono alla moda come i container Docker e le Lambda, ma possono essere la soluzione migliore in casi analoghi.<\/p>\n\n\n\n

Per citare il Tenente Combo: “un’ultima cosa”: no, usare un cluster EKS o, peggio ancora, un cluster Kubernetes su EC2 non fa s\u00ec che si stiano usando i microservizi.<\/strong> State “semplicemente” aggiungendo complessit\u00e0 e costi alla vostra infrastruttura.<\/p>\n\n\n\n

Essere “Cloud-native” \u00e8 pi\u00f9 semplice quando si sviluppa qualcosa da zero. Trasferire una applicazione su AWS con un lift and shift senza adattarla al paradigma cloud non rende il software cloud-ready, scalabile, n\u00e9 altamente affidabile.<\/p>\n\n\n\n

Istanze EC2 per contenuti web statici<\/h2>\n\n\n\n

“Abominevole! Ahah! Non \u00e8 incredibile? A voi io sembro “abominevole”? E perch\u00e9 non potevano chiamarmi “l’adorabile” uomo delle nevi o “il simpatico” uomo delle nevi, per la miseria! Io sono un tipo socievole!”<\/em><\/p>\n\n\n\n

<\/p>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

Ammettiamolo: a volte la tentazione di usare una tecnologia che gi\u00e0 padroneggiamo al posto di servizi gestiti meno conosciuti \u00e8 forte. Un esempio tipico \u00e8 un server Apache per ospitare un sito web statico. <\/p>\n\n\n\n

Questo approccio, per\u00f2, fa crescere la manutenzione ed anche la bolletta AWS mensile, anche senza usare un Autoscaling Group ed un Load Balancer per rendere la soluzione altamente affidabile.<\/p>\n\n\n\n

Ci \u00e8 capitato di dover fare modifiche alla configurazione di due webserver Apache che si occupavano di servire pagine statiche.<\/p>\n\n\n\n

I due server, per ragioni storiche e di SEO, avevano una configurazione con 60.000 regole di rewrite, combinate con 13.000 condizioni. Una quantit\u00e0 enorme di regole era ovviamente ridondante e interferiva con le altre. A seconda della pagina la risposta poteva richiedere anche 5 secondi prima di essere servita, nonostante le istanze EC2 utilizzate fossero due m5.2xlarge. Quando qualcosa andava storto, abilitare il log generava circa 2.000 righe la cui analisi non era semplice.<\/p>\n\n\n\n

Usando CloudFront ed S3 il risparmio sarebbe stato considerevole, con il vantaggio di avere a disposizione una Content Distribution Network globale. Per la gestione dei redirect sono sufficienti una Lambda@edge ed una tabella Dynamo.<\/p>\n\n\n\n

Contenuto statico generato sul backend (con finale a sorpresa)<\/h2>\n\n\n\n

“Niente lacrime per favore; non si deve sprecare cos\u00ec la sofferenza.” – <\/em>PinHead, Hellraiser.<\/p>\n\n\n\n

<\/p>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

Quando il backend genera pagine statiche, sprechiamo cicli ci CPU, soldi ed energia. Per ridurre il carico di un application server monolitico, si pu\u00f2 provare ad usare CloudFront. <\/p>\n\n\n\n

Una cosa che non ci stancheremo mai di dire: per favore, fate in modo che script e utility (o anche rotte applicative) non siano messe in sottocartelle che potrebbero essere raggiunte ed indicizzate per sbaglio dai motori di ricerca (anche configurare robots.txt in modo che siano esclusi spesso non \u00e8 una soluzione). <\/p>\n\n\n\n

Abbiamo ricevuto la telefonata di un cliente finito nel panico perch\u00e9 la notte il database di produzione era stato cancellato. <\/p>\n\n\n\n

Dopo aver investigato, abbiamo notato l’esistenza di uno script PHP (utility.php) usato dagli sviluppatori per resettare velocemente l’ambiente di sviluppo locale. Per rendere le cose pi\u00f9 veloci, era in una directory il cui contenuto era visualizzabile e, per attivarlo, bastava una semplice GET.<\/p>\n\n\n\n

Il deploy dell’applicazione era fatto a mano copiando i file sul server, per cui una svista ha fatto s\u00ec che la cartella con le utility finisse online. Quando un motore di ricerca ha scoperto il nuovo percorso, ovviamente, ha richiesto il file utility.php con una GET e… Il database di produzione ha smesso di esistere!<\/p>\n\n\n\n

Igor in Frankenstein Junior avrebbe detto:  “Potrebbe essere peggio, potrebbe piovere!”<\/em><\/p>\n\n\n\n

Servizi unmanaged: lo stateless stateful<\/h2>\n\n\n\n

“Si paga per quel che si ottiene, si ottiene ci\u00f2 per cui si paga\u2026 e prima o poi quel che ti appartiene torna a te.” <\/em>– Stephen King, It<\/p>\n\n\n\n

<\/p>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

Una installazione MySQL su Docker sembra una buona idea per gestire gli aggiornamenti e tenere allineate le versioni fra l’ambiente locale (gestito con docker-compose) e l’ambiente di produzione. <\/p>\n\n\n\n

Cosa c’\u00e8 di meglio di una istanza EC2 con Docker a bordo per semplificarci la vita? <\/p>\n\n\n\n

Un container, per definizione, \u00e8 stateless. Quindi, per conservare i dati, dovremo definire dei volumi. Ovviamente i dati devono essere salvati, quindi occorre un sistema di backup consistente (che non pu\u00f2 quindi essere un semplice snapshot). A questo punto dovremo iniziare a sviluppare script di backup e ad usare job di cron per la pianificazione.<\/p>\n\n\n\n

In breve tempo ci ritroveremo a spendere pi\u00f9 tempo per gestire la nostra installazione: ad ogni cambio di versione di mysql andr\u00e0 fatto l’aggiornamento delle tabelle avviando le utility all’interno del container con docker exec, lo spazio su disco andr\u00e0 aumentato, i limit dei container andranno adattati…  <\/p>\n\n\n\n

Se calcoliamo il Total Cost of Ownership (TCO) ci rendiamo conto che un database Aurora RDS in configurazione Multi-AZ \u00e8 molto pi\u00f9 conveniente! <\/p>\n\n\n\n

A questo proposito, il nostro Alessio ha scritto un ottimo articolo su servizi stateful e stateless<\/a>.<\/p>\n\n\n\n

Lo stateless stateful: il ritorno. <\/h2>\n\n\n\n

“Errare humanum est, perseverare autem diabolicum” <\/em>– Sant’ Agostino<\/p>\n\n\n\n

<\/p>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

<\/p>\n\n\n\n

Ok, metteremo i dati su un filesystem condiviso! EFS \u00e8 una buona soluzione, pu\u00f2 scalare, ha i backup integrati ed ha un modello di pagamento a consumo. <\/p>\n\n\n\n

In questo caso, abbiamo visto girare una applicazione PHP su container Docker in istanze ECS (in autoscaling group) con tutto il codice applicativo ospitato su EFS.<\/p>\n\n\n\n

Sappiamo che a volte un filesystem condiviso \u00e8 necessario per ospitare dati condivisi (come ad esempio in questo caso<\/a>.<\/p>\n\n\n\n

Una applicazione PHP, anche se piccola, non pu\u00f2 per\u00f2 essere ospitata su EFS a causa del modo in cui l’interprete interagisce con il filesystem (e perch\u00e9 le IOPs saranno molto minori rispetto ad un disco EBS).<\/p>\n\n\n\n

Questi consigli da parte di AWS possono aiutare, ma i risultati non sono garantiti: <\/p>\n\n\n\n