{"id":4921,"date":"2022-09-16T09:00:00","date_gmt":"2022-09-16T07:00:00","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=4921"},"modified":"2022-09-14T11:40:17","modified_gmt":"2022-09-14T09:40:17","slug":"paas-su-aws-come-implementarlo-nel-modo-migliore","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/paas-su-aws-come-implementarlo-nel-modo-migliore\/","title":{"rendered":"PaaS su AWS: come implementarlo nel modo migliore"},"content":{"rendered":"\n

Introduzione<\/h1>\n\n\n\n

Grazie agli strumenti offerti dai cloud provider, negli ultimi anni, sono diventati popolari molti prodotti PaaS, ovvero servizi che permettono di fornire e gestire piattaforme di computing complete senza doversi far carico di tutte le complessit\u00e0 legate al mantenimento dell\u2019infrastruttura sottostante. La complessit\u00e0 di queste applicazioni \u00e8 strettamente legata alla scalabilit\u00e0 e alla velocit\u00e0 dell\u2019intera soluzione. Dobbiamo quindi essere in grado di creare e rimuovere risorse in maniera fluida ed efficiente in un ambiente capace di garantire la separazione netta dell\u2019infrastruttura di un utente finale da quella di un altro.<\/p>\n\n\n\n

Un altro punto critico da analizzare nelle fasi preliminari di un progetto PaaS \u00e8 il cos\u00ec detto shared responsibility model<\/em><\/a>, un documento che definisce le responsabilit\u00e0 e i task operativi a carico del \u201cvendor\u201d e quelli in capo alll\u2019utente: chi deve occuparsi di mantenere l\u2019infrastruttura sicura dal punto di vista di accessi alle risorse e cifratura dei dati? Chi deve garantire l\u2019alta disponibilit\u00e0 della soluzione?<\/p>\n\n\n\n

Nel momento in cui decidiamo di spostare il nostro workload dall\u2019on-premise ad Amazon Web Services, stiamo accettando di delegare la gestione di alcuni aspetti architetturali al Cloud provider: in questo caso si parla di \u201csicurezza del<\/strong> cloud\u201d (a carico di AWS) contro \u201csicurezza nel<\/strong> cloud\u201d (a carico del cliente).<\/p>\n\n\n\n

In questo articolo analizzeremo i punti chiave per una corretta implementazione di un prodotto PaaS, che in questo caso consiste in virtual host dedicati che possano essere gestiti e aggiornati in autonomia tramite l\u2019utilizzo del proprio repository.<\/p>\n\n\n\n

Seguiranno altri due articoli in cui vedremo pi\u00f9 nel dettaglio le finezze tecniche e le considerazioni fatte per i singoli componenti architetturali. Rimanete quindi in ascolto\u2026 e nel frattempo: partiamo!<\/p>\n\n\n\n

Necessit\u00e0 e richieste<\/h2>\n\n\n\n

Il nostro obiettivo, come anticipato poco fa, \u00e8 quello di creare una vending machine di virtual host su Amazon EC2 su cui i nostri clienti potranno caricare il loro software personalizzato in base alle loro necessit\u00e0. Inoltre, il deploy dell’infrastruttura e del software dovranno essere automatizzati tramite pipeline CI\/CD in maniera da semplificare la gestione delle risorse che verranno fornite agli utenti.<\/p>\n\n\n\n

Abbiamo scelto di utilizzare le seguenti tecnologie e framework:<\/p>\n\n\n\n

GitLab<\/h2>\n\n\n\n

I sorgenti del nostro codice e le configurazioni delle AMI sono salvati su GitLab, una piattaforma DevOps che permette di effettuare version control<\/em> utilizzando git<\/em>. Gitlab<\/a> offre diversi piani di pagamento, dalla versione gratuita, perfetta per progetti personali o di test, ad una enterprise che aggiunge un supporto dedicato, gestione della vulnerabilit\u00e0, un maggior numero di pipeline CI\/CD, eccetera. Questo \u00e8 l’unico constraint del progetto.<\/p>\n\n\n\n

Packer<\/h2>\n\n\n\n

Packer<\/a> \u00e8 un prodotto ideato da HashiCorp che permette di automatizzare la creazione di immagini macchina utilizzando dei template scritti nel linguaggio proprietario di HashiCorp (HCL). Si integra molto bene con AWS in quanto, lanciando il comando di build, verr\u00e0 creata una nuova AMI contenente le parametrizzazioni indicate all\u2019interno del template, permettendo quindi di lanciare delle istanze EC2 preconfigurate.<\/p>\n\n\n\n

Un esempio di un file (ami-creation.pkr.hcl) di configurazione di Paker:<\/p>\n\n\n\n

variable \"region\" {\n  type = string\n  default = eu-west-1\n}\n\nsource \"amazon-ebs\" \"ami-creation\" {\n  Ami_name = \u201cNOME DELLA AMI FINALE\"\n  Ami_description = \"DESCRIZIONE DELLA AMI\"\n  Vpc_id = \"VPC IN CUI PACKER CREER\u00c0 LA EC2 DA CUI GENERARE LA AMI\"\n  Subnet_id = \"SUBNET IN CUI PACKER CREER\u00c0 LA EC2 DA CUI GENERARE LA AMI\"\n  Security_group_id = \"SECURITY GROUP PER LA EC2\"\n  Instance_type = \"DIMENSIONE DELLA EC2\"\n  Region = \"REGION IN CUI VIENE CREATA LA EC2 E LA AMI\"\n  Source_ami = \"ID AMI DI PARTENZA\"\n  Ssh_username = \"ubuntu\"\n  Communicator = \"ssh\"\n  Iam_instance_profile = \"PROFILO PER LA GESTIONE DELLA EC2\"\n\n  launch_block_device_mappings {\n    Device_name = \"\/dev\/sda1\"\n    Volume_size = 16\n    Volume_type = \"gp3\"\n    delete_on_termination = true\n  }\n\n  run_tags = {\n    Name = \"NOME DELLA EC2 IN FASE DI BUILD DA PACKER\"\n  }\n\n  tags = {\n    TAGS PER LA AMI RISULTANTE\n  }\n}\n\nbuild {\n  sources = [\"source.amazon-ebs.ami-creation\"]\n\n  provisioner \"file\" {\n    destination = \".\/install.sh\"\n    source      = \"install.sh\"\n  }\n\n  provisioner \"shell\" {\n    inline = [\n      \"sudo chmod +x preInstall.sh && sudo .\/preInstall.sh\",\n      \"sudo -E .\/install.sh\"      \n    ]\n  }\n}\n<\/code><\/pre>\n\n\n\n

Scelto per la sua versatilit\u00e0 e velocit\u00e0 di esecuzione rispetto ad altri competitor, l\u00fanica pecca riscontrata \u00e8 nella criptatura della AMI in quanto aumenta notevolmente (dai 5 agli 8 minuti in pi\u00f9 per esecuzione)<\/p>\n\n\n\n

RDS<\/h2>\n\n\n\n

RDS (Relational Database Service)<\/a> \u00e8 un servizio AWS completamente gestito che permette di creare e gestire Database Server selezionando uno dei vari DB engine offerti. Nel nostro caso abbiamo scelto MySQL. RDS ci permette di scalare il nostro data layer in maniera pi\u00f9 fluida rispetto ad una implementazione tramite istanze EC2.
Scelto per la sua versatilit\u00e0 e scalabilit\u00e0 in quanto non sempre \u00e8 prevedibile il volume di traffico che i clienti svilupperanno.<\/p>\n\n\n\n

S3<\/h2>\n\n\n\n

S3 (Simple Storage Service)<\/a> \u00e8 un servizio completamente serverless che ci permette di salvare file utilizzando uno spazio di archiviazione virtualmente illimitato a basso costo e accessibile tramite chiamate API. Offre numerose funzionalit\u00e0, tra cui encryption-at-rest<\/em>, classi di storage (utili quando si vuole ridurre i costi legati allo storage di dati poco frequentemente acceduti), gestione degli accessi e replica cross-region per ridurre la probabilit\u00e0 di perdita dei dati.<\/p>\n\n\n\n

EC2<\/h2>\n\n\n\n

EC2 (Elastic Compute Cloud)<\/a> \u00e8 un servizio che permette di creare una macchina virtuale partendo dalla scelta della configurazione \u201chardware\u201d (offre pi\u00f9 di 500 combinazioni) passando per il dimensionamento e il numero dei dischi agganciati alla scelta del sistema operativo preinstallato. Per la versatilit\u00e0 e potenza del servizio si possono eseguire anche workload HPC. Abbiamo scelto questo servizio per la sua elasticit\u00e0 nella customizzazione del sistema operativo e dei requisiti necessari all\u2019esecuzione del software.<\/p>\n\n\n\n

CodeBuild, CodeDeploy & CodePipeline<\/h2>\n\n\n\n

Abbiamo deciso di affidarci a CodeBuild, CodeDeploy e CodePipeline per la creazione della nostra pipeline CI\/CD. CodeBuild<\/a> permette di creare sistemi di compilazione, unit e integration test orchestrati dalla nostra pipeline CodePipeline<\/a> in maniera gestita e scalabile. Tra le numerose funzionalit\u00e0 di CodePipeline troviamo la possibilit\u00e0 di aggiungere degli step di Manual Approval<\/em> (ossia uno step che mette in pausa l\u2019esecuzione della nostra pipeline che pu\u00f2 essere ripresa dopo un intervento umano), integrazione diretta con altri servizi come CloudFormation, CodeDeploy, eccetera.<\/p>\n\n\n\n

Tecnologie e setup del progetto<\/h2>\n\n\n\n

Per distribuire le nostre risorse infrastrutturali, abbiamo deciso di utilizzare il servizio CloudFormation, facendoci aiutare da AWS CDK.<\/p>\n\n\n\n

CDK (Cloud Development Kit) \u00e8 un framework ufficiale sviluppato da Amazon Web Services per creare Infrastructure as Code (IaC). \u00c8 compatibile con diversi linguaggi di programmazione (Typescript, Javascript, Python, Java e C#) e permette, tramite i suoi costrutti, di definire le risorse infrastrutturali del nostro progetto (Bucket S3, Application Load Balancer, VPC, Database, ecc.) in maniera programmatica. Il nostro progetto scritto con CDK, una volta \u201ccompilato\u201d, generer\u00e0 un template CloudFormation in formato json distribuibile tramite l\u2019omonimo servizio. Il principale vantaggio che si ottiene utilizzando CDK rispetto ad altri framework IaC deriva dal fatto che, scrivendo l\u2019infrastruttura utilizzando un linguaggio di programmazione, possiamo approfittare dei costrutti e delle astrazioni specifici del linguaggio (iterazioni, condizioni, oggetti, funzioni, ecc.) per rendere il nostro template pi\u00f9 facilmente interpretabile riducendo i copia\/incolla e quindi le righe di codice da gestire.<\/p>\n\n\n\n

Per quanto riguarda GitLab si \u00e8 optato per creare un API gateway con un API REST per intercettare i webhook lanciati da GitLab in base ai push e utilizzare il servizio di AWS CodePipeline per la gestione del deploy del software nella EC2 dedicata.<\/p>\n\n\n\n

Abbiamo deciso di dividere il progetto in 3 macro aree, ognuna delle quali fa riferimento ad uno specifico layer infrastrutturale. Ogni macro area corrisponde ad un repository git con uno stack CDK dedicato. Questa soluzione ci permette di separare le aree di competenza e assegnare ciascuna di esse ad un team dedicato di sviluppatori.<\/p>\n\n\n\n

  1. Global infrastructure<\/li>
  2. Infrastructure pipeline<\/li>
  3. Software pipeline<\/li><\/ol>\n\n\n\n

    1. Global infrastructure<\/h3>\n\n\n\n

    Il repo Global Infrastructure<\/strong> contiene tutti gli stack che servono a deployare i servizi infrastrutturali condivisi suddivisi per l\u2019ambiente in cui vengono rilasciati.<\/p>\n\n\n\n

    Questi sono i servizi condivisi gestiti dal committente che gestiscono tutto il primo layer, dai ruoli al network alle chiavi di cifratura al load balancer condiviso:<\/p>\n\n\n\n