{"id":5152,"date":"2022-11-11T07:14:46","date_gmt":"2022-11-11T06:14:46","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=5152"},"modified":"2022-11-09T10:43:00","modified_gmt":"2022-11-09T09:43:00","slug":"paas-su-aws-come-implementarlo-nel-modo-migliore-parte-iii","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/paas-su-aws-come-implementarlo-nel-modo-migliore-parte-iii\/","title":{"rendered":"PaaS su AWS: come implementarlo nel modo migliore \u2013 Parte III"},"content":{"rendered":"\n
Bentornati alla nostra serie di articoli sul Platform-as-a-Service su Amazon Web Service.<\/p>\n\n\n\n
Abbiamo iniziato introducendo i fondamentali per un corretto approccio al PaaS su AWS<\/a> preseguendo poi analizzando i servizi condivisi alla base del funzionamento della nostra vending machine<\/a>.<\/p>\n\n\n\n \u00c8 il momento di focalizzarci sui servizi dedicati agli utenti finali.<\/p>\n\n\n\n Per comodit\u00e0 abbiamo diviso i servizi in due repository e, come accennato nel primo articolo, al loro interno troviamo gli stack:<\/p>\n\n\n\n La pipeline infrastrutturale eseguir\u00e0 i seguenti step:<\/p>\n\n\n\n Il file paker-customer-environment.pkr.hcl viene generato dal deploy di CDK utilizzando dei dati recuperati dal commit. Viene validato ed eseguito<\/p>\n\n\n\n Per il solo ambiente di produzione si \u00e8 scelto di aggiungere uno stage che impedisce di rilasciare modifiche non volute per errore:<\/p>\n\n\n\n Nel momento in cui la pipeline arriva a questo step, viene inviata una mail agli indirizzi precedenetemente indicati (nell\u2019esempio sopra sono indicati nella configurazione approvalEmails). La persona che si occuper\u00e0 di verificare l\u2019aggiornamento richiesto potr\u00e0 permettere l\u2019esecuzione della pipeline, oppure bloccarla per correggere eventuali errori.<\/p>\n\n\n\n Lo stage configura le credenziali di git e clona il repository; effettua poi una chiamata al ALB condiviso per calcolare la priorit\u00e0 della regola da applicare al listener. Se si tratta di un aggiornamento ad una regola gi\u00e0 esistente, la priorit\u00e0 non verr\u00e0 modificata.<\/p>\n\n\n\n In caso di dominio custom e ambiente di produzione verr\u00e0 deployato un Application Load Balancer nominale con due listener (porta 80 http e porta 443 https)<\/p>\n\n\n\n E agganciato il certificato dell\u2019utente<\/p>\n\n\n\n Viene creato un database RDS, le parametrizzazioni sono definite all\u2019interno di un file di configurazione. Tra questi parametri troviamo:<\/p>\n\n\n\n Grazie al servizio AWS Autoscaling possiamo configurare delle soglie che, una volta superate, scateneranno la creazione di una nuova istanza che potr\u00e0 gestire parte del traffico.<\/p>\n\n\n\n Per poter configurare un Autoscaling group \u00e8 necessario fornire un Launch Template (preferito da AWS) oppure un Launch Configuration (che sta cadendo in disuso). Per qualche motivo il costrutto AutoScaling fornito da AWS CDK utilizza di default il Launch Configuration, ma ci aspettiamo che nelle versioni future della classe venga implementato l\u2019utilizzo del Launch Template!<\/p>\n\n\n\n Viene creato il target group utilizzando le configurazioni fornite dall\u2019utente (dal file di config) per gestire gli health check con cui verificare l\u2019integrit\u00e0 delle risorse di destinazione. Questo target group verr\u00e0 associato poi all\u2019Application Load Balancer.<\/p>\n\n\n\n La destinazione finale\u2026<\/p>\n\n\n\n Questa \u00e8 la pipeline che realmente effettua il deploy del software del cliente all\u2019interno del gruppo di istanze EC2 dedicate, ed \u00e8 suddivisa nei seguenti stage.<\/p>\n\n\n\n Effettua dei test sul codice e per farlo utilizza la funzionalit\u00e0 messa a disposizione da CodeBuild tramite l\u2019utilizzo del file buildSpec.yaml e un\u2019immagine personalizzata su cui fare i test scaricata direttamente dal servizio ECR.<\/p>\n\n\n\n Il buildSpec file \u00e8 un file YAML che racchiude le configurazioni necessarie al progetto di CodeBuild:<\/p>\n\n\n\n Permette di dare piena autonomia al cliente sui comandi che devono essere eseguiti dal job di build divisi per sezione.<\/p>\n\n\n\n Come per la pipeline infrastrutturale vogliamo proteggerci da aggiornamenti non voluti che potrebbero causare down-time nell\u2019applicazione. Per questo motivo ogni rilascio in produzione deve essere confermato da un essere umano.<\/p>\n\n\n\n Utilizzando il servizio CodeDeploy possiamo automatizzare l\u2019aggiornamento delle nostre virtual machine e il deploy del codice appena approvato.<\/p>\n\n\n\n Anche per questo servizio la funzionalit\u00e0 di gestione dei comandi da file viene in nostro aiuto, il file da mettere nella root del repository software si chiama appspec.yaml.<\/p>\n\n\n\n Quando vediamo l\u2019iconica scritta Succeeded con il flag verde in corrispondenza della pipeline software avremo completato tutto il percorso e saremo in possesso del parco macchine con il nostro software installato pronto per essere usato.<\/p>\n\n\n\n Quando un cliente ci chieder\u00e0 un parco macchine potremo tranquillamente creare il file di configurazione dedicato e lanciare il deploy degli stack di infrastruttura (il primo repository analizzato in questo articolo) e la \u201cmagia\u201d dello IAC far\u00e0 il resto permettendo anche di concentrare gli sforzi dell\u2019utente finale solo sullo sviluppo e mantenimento del proprio software.<\/p>\n\n\n\n
<\/li><\/ul><\/li>
<\/li><\/ul><\/li><\/ul>\n\n\n\nRepository infrastrutturale<\/h2>\n\n\n\n
Pipeline infrastrutturale<\/h3>\n\n\n\n
Creazione AMI con Packer<\/h3>\n\n\n\n
source .\/configFile.sh\nAMI_DESCRIPTION=\\\"commit id: $COMMIT_ID\\\\n time stamp: $COMMIT_TIME\\\\n commit by: $COMMIT_AUTHOR_NAME\\\\n message: $COMMIT_MESSAGE\\\"\nsed -i s\/PLACE_CODEBUILD_BUILD_ID\/$CODEBUILD_BUILD_NUMBER\/g packer-CUSTOMER-$ENVIRONMENT.pkr.hcl\npacker validate packer-$CUSTOMER-$ENVIRONMENT.pkr.hcl\npacker build packer-$CUSTOMER-$ENVIRONMENT.pkr.hcl\nexport AMI_ID=$(cat manifest-$CUSTOMER-$ENVIRONMENT.json | grep artifact_id | cut -d \":\" -f3 | cut -d '\\\"' -f1)\nexport AMI_NAME=ami-$CUSTOMER-$ENVIRONMENT-$CODEBUILD_BUILD_NUMBER\nexport INSTANCE_NAME=$CUSTOMER-$ENVIRONMENT-$CODEBUILD_BUILD_NUMBER<\/code><\/pre>\n\n\n\n
Approvazione manuale<\/h3>\n\n\n\n
myPipeline.addStage({\nstageName: 'approve',\nplacement: {\njustAfter: myPipeline.stages[1],\n}\n}).addAction( new aws_codepipeline_actions.ManualApprovalAction({\nactionName: `${process.env.CUSTOMER}-approve`,\nnotificationTopic: new Topic(this, `${process.env.CUSTOMER}-${process.env.ENVIRONMENT}-software-sh-pipeline`),\nnotifyEmails: configFile.approvalEmails,\nadditionalInformation: `${process.env.CUSTOMER} deploy to ${process.env.ENVIRONMENT}`\n})\n)\n}<\/code><\/pre>\n\n\n\n
Deploy repository software pipeline<\/h3>\n\n\n\n
Repository pipeline software<\/h2>\n\n\n\n
Application load balancer<\/h3>\n\n\n\n
myCustomAppLoadBalancer.addListener(`App-80-Listener`, {\nport: 80,\ndefaultAction: elbv2.ListenerAction.redirect({\npermanent: true,\nport: '443',\nprotocol: 'HTTPS',\n})\n})\nconst myCustom443ApplicationListener =\n myCustomAppLoadBalancer.addListener(`App-443-Listener`, {\nport: 443,\ndefaultAction: elbv2.ListenerAction.fixedResponse(503, {\ncontentType: `text\/plain`,\nmessageBody: 'host not found',\n})\n})<\/code><\/pre>\n\n\n\n
const wildcardListenerCertificate = elbv2.ListenerCertificate.fromArn(`${configFile.customer.certificate.arn}`)\nmyCustom443ApplicationListener.addCertificates(`Wildcard-${localUpperCustomer}-Cert`, [wildcardListenerCertificate])<\/code><\/pre>\n\n\n\n
Database RDS<\/h3>\n\n\n\n
Autoscaling Group<\/h3>\n\n\n\n
Target group<\/h3>\n\n\n\n
Pipeline software<\/h3>\n\n\n\n
Build<\/h3>\n\n\n\n
version: 0.2\nphases:\n install:\n commands:\n - echo Entered the install phase...\n finally:\n - echo This always runs even if the update or install command fails\n pre_build:\n commands:\n - echo Entered the pre_build phase...\n finally:\n - echo This always runs even if the login command fails\n build:\n commands:\n - echo Entered the build phase...\n finally:\n - echo This always runs even if the install command fails\n post_build:\n commands:\n - echo Entered the post_build phase...\n - echo Build completed on `date`\nartifacts:\n files:\n - location\n - location\n name: artifact-name<\/code><\/pre>\n\n\n\n
Approvazione manuale<\/h3>\n\n\n\n
Deploy <\/h3>\n\n\n\n
new codedeploy.ServerDeploymentGroup(this, `Deployment-Group-${localUpperCustomer}-${localUpperEnvironment}`, {\ndeploymentGroupName: `${process.env.CUSTOMER}-${process.env.ENVIRONMENT}-deploy-group`,\nloadBalancer: codedeploy.LoadBalancer.application(props.targetGroup),\nautoScalingGroups: [props.asg],\nrole: softwarePipelineRole,\napplication: deployApp,\ndeploymentConfig: codedeploy.ServerDeploymentConfig.ONE_AT_A_TIME,\ninstallAgent: true,\nautoRollback: {\nfailedDeployment: true,\nstoppedDeployment: true\n}\n})<\/code><\/pre>\n\n\n\n
version: 0.0\nos: linux\nfiles:\n - source: \/\n destination: \/var\/www\/html\nhooks:\n BeforeInstall: # You can use this deployment lifecycle event for preinstall tasks, such as decrypting files and creating a backup of the current version\n - location: deployScript\/beforeInstall.sh\n timeout: 300\n runas: root\n\n# INSTALL \u2013 During this deployment lifecycle event, the CodeDeploy agent copies the revision files from the temporary location to the final destination folder. This event is reserved for the CodeDeploy agent and cannot be used to run scripts.\n\n AfterInstall: # You can use this deployment lifecycle event for tasks such as configuring your application or changing file permissions\n - location: deployScript\/afterInstall.sh\n timeout: 300\n runas: root\n\n ApplicationStart: # You typically use this deployment lifecycle event to restart services that were stopped during ApplicationStop\n - location: deployScript\/applicationStart.sh\n timeout: 300\n runas: root\n\n ValidateService: # This is the last deployment lifecycle event. It is used to verify the deployment was completed successfully.\n - location: deployScript\/validateService.sh\n timeout: 300\n runas: root<\/code><\/pre>\n\n\n\n
Conclusione<\/h2>\n\n\n\n
\n\n\n\nAbout Proud2beCloud<\/h4>\n\n\n\n