Tech stackia valitessaan startupit etsivät kustannustehokkaita ja skaalautuvia ratkaisuja. Serverless voi olla erinomainen vaihtoehto, mutta miten sen käytössä pääsee alkuun?
Severi Haverila
Severi works as a DevOps consultant by day, and runs a startup company at night. His main interests are working with state-of-the-art technologies and solving problems for the customers in a pragmatic way.
Mitä alkuvaiheen startupeilta puuttuu? Aivan, palvelimia! Anteeksi, tarkoitin rahaa, minkä vuoksi palvelimet kannattaa unohtaa ja käynnistää liiketoiminta serverless-ratkaisulla. Eikä palvelimilla tarkoiteta vain vanhentuneita palvelinräkkejä tai LAMP-pinoasi ajavia EC2-instansseja, vaan myös hienoja GKE Kubernetes -klustereitasi. Voit toki maksaa ylimääräiset 50 dollaria minimaalisesta Kubernetes-klusterista, joka palvelee vain frontendiasi ja muutamaa NodeJS-mikropalvelua harvakseltaan tulevalla liikenteellä. Mutta miksi tekisit niin, kun voit toteuttaa kaiken tämän murto-osalla kustannuksista ja vähentää ylläpitotyötä?
Tässä blogikirjoituksessa näytän, kuinka pääset alkuun kaiken tämän kanssa 10 minuutissa. Tarkemmin sanottuna keskitymme siihen, että sinä ja muut kehittäjät pääsette kehittämään yhdessä maailmaa muuttavaa tuotettanne. Kirjoituksen lopussa sinulla on repositorio, joka sisältää AWS:ssä toimivan serverless API:n ja API:a hyödyntävän React-frontendin.
Serverless Framework
Käytämme Serverless Frameworkia serverless API:mme luomiseen AWS:ään. Serverless Framework ei ole sidottu pelkästään AWS:ään, sillä se tukee kaikkia suurimpia pilvipalveluntarjoajia sekä pilvipalveluntarjoajista riippumattomia teknologioita, kuten Kubelessia.
AWS:n kanssa Serverless Framework käyttää taustalla CloudFormationia serverless-pinomme määrittämiseen. Serverless Frameworkilla on helppo lisätä mukautettuja CloudFormation-resursseja serverless-deploymentiin. Voisimme esimerkiksi luoda CloudFormation-templaten, joka luo DynamoDB-taulun Lambda-funktioidemme käyttöön, ja ottaa sen käyttöön Lambda-funktioiden kanssa ajamalla vain yhden serverless deploy -komennon.
Puhe riittää, laitetaan Lambda-funktiot käyntiin!
Aloitetaan
Projekti on määritetty niin, että muiden kanssa on helppo tehdä yhteistyötä. Käytännössä tämä tarkoittaa, että voit helposti luoda omia kopioita serverless API:sta, kehittää sille uusia ominaisuuksia ja määrittää frontendin automaattisesti hyödyntämään omaa serverless REST API:asi.
Kloonaa tämä repositorio: https://github.com/severi/serverless-react-getting-started
ja checkouttaa tagi step1
Repositoriossa on frontendia varten perusmuotoinen create-react-app-boilerplate-projekti (frontend-kansio) ja backendiä varten yksinkertainen serverless-framework-esimerkki (api-kansio).
Frontend-osa luotiin ajamalla (lisätietoja):
Frontendin käynnistäminen
Varmistetaan ensin, että frontend toimii oikein. Aja sitä varten seuraavat komennot:
Ja kaikki on valmista! Nyt kun frontend pyörii onnistuneesti, voit pysäyttää sen – ellet halua ihailla mahtavaa create-react-app-aloitussivua vielä hetken. Keskitymme serverless-osaan ja palaamme frontendiin myöhemmin.
Serverless API:n käyttöönotto
Seuraavaksi tarvitsemme työkalut käyttöön. Asenna Serverless Frameworkin CLI
Meidän on määritettävä AWS-tunnistetietomme ja luotava AWS-tili, jos sinulla ei vielä ole sellaista. Onneksi serverless.com tarjoaa tähän kattavat ohjeet, joten niitä ei tarvitse kopioida tänne. Seuraa tätä linkkiä ja palaa, kun olet valmis.
Funktion käyttöönotto
Aja api-kansiosta sls deploy, jotta funktiomme saadaan käyttöön AWS:ssä. Tulosteen pitäisi näyttää tältä:
Nyt kun funktiomme toimii AWS:ssä, voimme kokeilla sen käynnistämistä. Käytämme siihen curlia. Funktion URL-osoite löytyy komennon sls deploy tulosteesta. Tarkista endpoints:-osio. Kuten näemme, se todella toimii:
Mitä tässä tapahtuu?
API:n rakenne on yksinkertainen:
Kiinnostavat osat ovat tiedostot serverless.yml ja functions/myFunction.js. Seuraavissa osioissa kuvaamme molemmat yksityiskohtaisesti.
serverless.yml
serverless.yml-tiedostomme koostuu kolmesta osiosta:
service – määrittää serverless-stackimme nimen
provider – AWS:ään liittyvät asetukset
functions – serverless-funktiomme, jotka haluamme ottaa käyttöön
Otamme käyttöön yhden funktion nimeltä myFunction. Handler-osio määrittää, mistä kyseisen funktion koodi löytyy. Se tarkoittaa funktiota main tiedostossa functions/myFunction.js.
functions/myFunction.js
Käyttöön otettava funktio on yksinkertainen. Se palauttaa vain { hello: "world" } JSON-objektin.
Events-aliosiossa määritämme lisäksi, että myFunction vastaa HTTP GET -pyyntöihin seuraavassa polussa: /myfunction.
Muistutuksena: näin testaamme funktiotamme. Huomaa, miten URL-osoite päättyy:
Provider-osiossa määritämme myös oletusvaiheeksi “dev”.
Sen voi ylikirjoittaa lisäämällä --stage stagename -valitsimen sls deploy -komentoon.
Vaiheiden avulla voit luoda erillisiä kehitys- tai testiympäristöjä. Katso tästä täydellinen serverless.yml-viite.
AWS
Mitä AWS:n puolella sitten tapahtuu? Serverless Framework käyttää taustalla Cloudformationia serverless-stackimme käyttöönottoon. Voit varmistaa tämän avaamalla Cloudformation-osion AWS:n web-käyttöliittymässä: https://eu-north-1.console.aws.amazon.com/cloudformation/home
Huomaatko, miten serverless luo Cloudformation-stackin antamiemme service- ja stage-nimien perusteella?
Kun siirryt juuri luodun Cloudformation-stackimme Resources-välilehdelle, näet, millaisia AWS-resursseja käyttöönoton aikana luotiin.
Näitä resursseja ovat:
ServerlessDeploymentBucket
API Gateway
IAM Role
MyFunctionLambdaFunction
S3 Bucket, johon lambda-koodimme kopioidaan
tähän lambda-URL-osoitteemme https://XXXXXXXX.execute-api.eu-north-1.amazonaws.com/ -osa viittaa
Sallii lambda-funktiomme kirjoittaa lokinsa CloudWatchiin
Lambda-funktio itse
Yhtenäinen koodaustyyli
Yksi Node.js:n käytön eduista on, että voimme hyödyntää samaa ohjelmointikieltä ja samoja kirjastoja sekä sovelluksemme frontendissä että backendissä. Frontendimme käyttää jo uusimpia ES6-JavaScript-ominaisuuksia. Jotta voimme hyödyntää samoja ominaisuuksia backend-palveluissa ja tehdä koodaustyylistämme yhtenäisen frontendin ja backend-funktioiden välillä, meidän on lisättävä ensimmäinen plugin serverless.yml-tiedostoomme: serverless-bundle. Lisätietoa ES6:n JavaScript-syntaksiin tuomista muutoksista löydät täältä.
serverless-bundlen kehittäjien omassa serverless-oppaassa antaman suosituksen mukaisesti otamme käyttöön myös funktioiden erillisen paketoinnin.
Kun otamme erillisen paketoinnin käyttöön yhdessä serverless-bundle-pluginin kanssa, voimme luoda jokaiselle funktiolle oman optimoidun paketin – tosin tällä hetkellä funktioita on vain yksi, mutta todellisessa sovelluksessa niitä olisi useita.
Voimme nyt muuntaa myFunction.js-tiedostomme hyödyntämään ES6-syntaksia. Koska esimerkkifunktiomme on melko yksinkertainen, ero ES5- ja ES6-toteutusten välillä rajoittuu funktion määrittelytapaan. Suuremmassa koodikannassa vaikutus olisi luonnollisesti suurempi.
Otetaan funktio uudelleen käyttöön:
serverless-bundle ottaa muun muassa käyttöön eslintin serverless-projektissamme. Voit testata tätä poistamalla funktion lopusta puolipisteen ja yrittämällä sitten ottaa sen uudelleen käyttöön. Näet jotain tämän kaltaista:
Mikä on paras tapa korjata nämä ongelmat? Voisimme toki korjata ne käsin, mutta pidemmän päälle se voi käydä työlääksi. Haluamme ehdottomasti korjata nämä ongelmat automaattisesti, jos mahdollista.
Valitettavasti en ole löytänyt tapaa:
näyttää linting-virheet Visual Studio Codessa
ajaa eslint --fix-lipulla suoraan serverless-bundlen käyttöön ottamia eslint-määrityksiä käyttäen.
Kiertotapana olen tehnyt seuraavaa:
ja lisännyt seuraavat skriptit APIn package.json-tiedostoon
Tämä korvaa eslint-määritykset samalla määrityksellä, jota plugin käyttää. Koska .eslintrc.json-tiedosto sijaitsee api-kansion juuressa, linting toimii sekä CLI:n että VSCoden kautta.
Voimme nyt korjata automaattisesti korjattavat linting-ongelmat suorittamalla:
Käytännössä linting kannattaa standardoida niin, että sekä frontend- että serverless-koodi lintataan samoilla asetuksilla. Näin saat yhtenäisen koodaustyylin kaikkiin JavaScript-tiedostoihisi.
Tämän vaiheen täydellisen ratkaisun löydät tagista step2
Serverless-funktion kutsuminen verkkosivustoltamme
Muokataan frontendin `App.js`-tiedostoa ja lisätään koodi, joka kutsuu lambdaamme.
Tämä ei yksin riitä, sillä saamme CORS-virheen – kokeile klikata painiketta, avaa selaimesi konsoli ja näet virheilmoituksen. CORS tulee sanoista ”Cross-Origin Resource Sharing”, ja sen avulla voidaan tehdä pyyntöjä muille domaineille kuin sille, jossa verkkosivustosi toimii. Voit lukea lisää CORSista täältä.
Kun tarkastelemme https://serverless.com/framework/docs/providers/aws/guide/serverless.yml/-sivuston serverless.yml-viitettä, näemme, että voimme lisätä funktioomme seuraavan asetuksen:
Kommenttien mukaisesti meidän on muokattava myös vastaustamme. Tämän otsakkeen lisääminen tarkoittaa, että voimme tehdä kehityksen aikana cross-origin-pyyntöjä mahtavasta verkkosovelluksestamme eli osoitteesta http://localhost:3000.
Ota funktio uudelleen käyttöön. Nyt painikkeen klikkauksen pitäisi tulostaa vastaus oikein selaimen konsoliin.
Vähemmän kovakoodausta, enemmän yhteistyötä
APIn URL-osoitteen kovakoodaus frontend-koodiimme ei ole optimaalista. Sovelluksesi tuotantoversiossa haluat kohdistaa pyynnöt APIn tuotantoversioon. Kehityksessä sinun ja kollegojesi tulisi käyttää kukin omia versioitanne.
Otetaan tämä käyttöön siirtämällä koodiin kovakoodattu URL-osoite ympäristömuuttujaan muuttamalla App.js-tiedostomme fetch-rivi seuraavaan muotoon:
Kuten osa teistä on ehkä huomannut, käytämme create-react-appin tarjoamaa mukautettujen ympäristömuuttujien toimintoa palvelumme päätepisteen upottamiseen ympäristömuuttujaksi build-vaiheessa (lisätietoja).
Määritellään seuraavaksi REACT_APP_ServiceEndpoint-muuttuja. Käytämme tähän .env.development.local-tiedostoa (lisätietoja eri .env-tiedostoista ja niiden prioriteeteista täällä).
Voimme luoda tiedoston manuaalisesti ja lisätä siihen seuraavan rivin
Tämä toimii, kun kehittäjiä on vain yksi ja ympäristömuuttujia vain yksi, mutta entä jos tarvitsemme myöhemmin frontendissä lisää tietoa AWS-stackistamme? Haluaisit ehkä antaa käyttäjien ladata tiedostoja S3:een suoraan selaimesta ilman lambda-funktioiden kutsumista. Miten myös viestimme näistä manuaalisista vaiheista muille kehittäjille, jotta he voivat määrittää omat kehitysympäristönsä?
Onneksi env-tiedoston luominen voidaan automatisoida.
Automatisointiin käytämme mukautettua forkia lisäosasta nimeltä "Serverless Stack Output Plugin". Lisäosan README-tiedoston mukaan se tekee seuraavaa:
tallentaa AWS CloudFormation Stackin tulosteen JSON/YAML/TOML-tiedostoihin tai välittää tulosteen JavaScript-funktiolle jatkokäsittelyä varten.
Lisäosan fork-versiomme avulla voimme luoda create-react-appin ympäristötiedostot automaattisesti serverless-stackimme deployment-vaiheen aikana.
Asennetaan serverless-stack-lisäosan mukautettu versiomme suorittamalla
ja muokkaamalla serverless.yml-tiedostoamme näin:
Jos otamme APIn uudelleen käyttöön komennolla sls deploy, huomaat, että saamme myös tiedoston nimeltä .stack.dev.react_app. Kopioidaan se frontend-hakemistoon ja nimetään se uudelleen
ja valmista tuli!
Käynnistä frontend uudelleen ja tarkista, että se tulostaa edelleen hello-world-objektin konsoliin. Tällä tavalla yksittäisen kehittäjän on helppo luoda uusi serverless-ympäristö määrittämällä deploymentin aikana oma stage (esim. sls deploy --stage myenv), käyttämällä luotua tiedostoa frontendin ympäristömuuttujien määrittämiseen ja yhdistämällä se uuteen serverless-backendiin. Tämä ei rajoitu vain serverless-funktioihin ja niiden API Gateway -URL-osoitteeseen, vaan koskee myös muita serverless-frameworkilla luotuja AWS-resursseja.
Tuotantobuildia varten ympäristömuuttujat voidaan sijoittaa .env.production-tiedostoon ja tallentaa versionhallintaan.
Katso tämän vaiheen täydellinen ratkaisu tagista step3:
Poista serverless-stack AWS:stä suorittamalla:
Jos haluat varmistaa asian huolellisesti, tarkista AWS-konsolin CloudFormation-sivu ja varmista, että kaikki serverless-frameworkin luomat stackit on poistettu.
Yhteenveto
Serverless-kehityksen aloittamisen ei tarvitse olla vaikeaa. Kyseessä on edelleen uusi alue, joten siihen liittyvä teknologia ja parhaat käytännöt kehittyvät jatkuvasti. Toivottavasti tämä opas on tehnyt serverless-matkastasi hieman ymmärrettävämmän ja pystyt nyt käynnistämään uusia serverless-projekteja sekä kehittämään niitä yhdessä kollegoidesi kanssa.
Tekninen velka on todellisuutta jokaisessa yrityksessä. Vaikka se ei ole maailmanloppu, päätös sen ottamisesta pitäisi aina tehdä harkiten. Infrastruktuuri koodina ja käyttöönottojen automatisointi kannattaa nostaa tehtävälistan kärkeen jo varhaisessa vaiheessa. Onneksi serverless framework ja CloudFormation auttavat meitä tässä.
Serverless on erinomainen työkalu kehittäjän työkaluketjussa, mutta se ei aina ole kustannustehokkain ratkaisu (lisätietoja tästä blogista ja tästä serverlessiin siirtymistä käsittelevästä blogista). Oikeisiin käyttötarkoituksiin käytettynä sen avulla voidaan kuitenkin luoda kustannustehokkaita ja automaattisesti skaalautuvia palveluita. Kuten tässä blogikirjoituksessa näit, alkuun pääseminen on varsin suoraviivaista.
Jos haluat oppia aiheesta lisää, tässä on erinomainen opas, josta aloittaa. Käsittelemme ehkä myös muita serverless-kehityksen näkökulmia tulevissa blogikirjoituksissa. Sillä välin on aika lopettaa rahan tuhlaaminen vajaakäytöllä oleviin palvelimiin ja aloittaa serverless-matkasi!
- Pilvi
Subscribe to our newsletter
Related blogs