Web-sovellus pilvessä data edellä - Tekninen toteutus
Posted 20.01.2019 04.11.2019 Mikael Ahonen
Toteutin harrasteprojektina sekä tietokoneelle että mobiililaitteille taipuvan web-sovelluksen, jossa tärkeänä kriteerinä oli kyvykkyys hyödyntää dataa monipuolisesti esimerkiksi koneoppimisen, rajapintojen ja visualisointien muodossa.
Otin ensimmäiseksi käyttökohteekseni punttisalikäyntieni tallentamisen ja seuraamisen.
Nyt kerron web-sovelluksen teknisestä toteutuksesta ja mitä asioita tekisin ensi kerralla toisin.
Johdannoksi voit lukea web-sovelluksen esittelyn.
Blogi ei ole sponsoroitu.
Web-sovellus pilvialustalle – Ensimmäiset teknologiavalinnat
Web-sovellus vs Natiivi mobiilisovellus. Valitsin web-sovelluksen käyttöjärjestelmä- ja laite riippumattomuuden vuoksi.
Pilvi-alusta. Ensimmäiset testailuversion sovelluksestani tein Herokussa kohtuullisella vaivalla.
Taustajärjestelmä. Pythonin Django vaikutti taustajärjestelmään (back end) hyvältä vaihtoehdolta, koska se on vakaa, sillä on aktiivnen kehittäjäyhteisö ja suosion myötä kattava dokumentaatio. Päädyin Pythoniin data-kirjastovalikoiman vuoksi. R ei soveltunut järjestelmien rakentamiseen yhtä hyvin.
Tietokanta. Web-sovelluksen tietokannan pystyi tekemään Herokuun. Valitsin PostgreSQL-kannan, koska jututtamieni kehittäjien mielestä se oli MySQL:ää ”ammattimaisempi valinta”.
Käyttöliittymä. Aluksi tein käyttöliittymän Djangon HTML-pohjia hyödyntäen, koska se oli helppo tapa aloittaa.
Versionhallinta. Käytin Git-versionhallintaa. Säilöin koodini julkiselle GitHub-tilillleni.
Tietomallinnus luo sovellukselle pohjan
Ensiksi kirjasin sovellukseen liittyviä käsitteitä: Harjoitus, sarja, lihasryhmä, liike, harjoitusrutiini ja niin edelleen. Piirsin jokaisesta käsitteestä laatikon ja yhdistin laatikot toisiinsa viivoilla.
Tietomallinnus ei ollut kattava, koska sen tarkoitus oli vain hahmottaa tietokannan rakennetta itselleni.
Web-sovelluksen tietomalli oli hyvin yksinkertainen. Tietommallissa kuvattiin vain käsitteet ja niiden väliset suhteet. Esimerkiksi harjoituksella (workout) oli useita sarjoja (set).
Taustajärjestelmän ja käyttöliittymän erottaminen – Django Rest Framework
Melko varhaisessa vaiheessa oli selvää, että saatuani jotain näkyvää aikaiseksi Djangolla, haluaisin erottaa käyttöliittymän (front end) ja taustajärjestelmän (back end) toisistaan. Tämä vaikutti olevan web-kehityksen trendi, joka mahdollistaa kokonaisuuden pilkkomisen itsenäisiin, skaalautuviin ja suorituskykyisiin kokonaisuuksiin.
Jatkoin taustajärjestelmän kehittämistä Djangolla, johon asensin Django Rest Framework-paketin.
Käyttöliittymän valitseminen – React ja Bootstrap
Käyttöliittymäksi valitsin Reactin, koska siihen olin törmännyt useimmin keskusteluissa ja blogeissa. React ei ollut minulle tuttu, joten aloitin perusteiden opiskelun Code Academyssa. Varsinkin aloittelijalle suosittelen create-react-app pakettia päästäksesi nopeasti alkuun.
Jälkikäteen olen ollut tyytyväinen valintaan. Dokumentaatiota ja keskustelua Reactista löytyy runsaasti.
Kakkosvaihtoehtona oli Vue. Angularin toimintalogiikka on hieman erilainen, enkä edes harkinnut sen käyttämistä.
Hyödynsin käyttöliittymän elementteihin entuudestaan tuttua Bootstrap-pakettia. Nyt saattaisin kokeilla myös material-ui:ta.
Taustajärjestelmän siirtäminen Herokusta AWS:ään
Pian halusin siirtää toteutukseni Herokusta AWS:ään. AWS tarjoaisi laajemman palveluvalikoiman ja enemmän hallintaa. AWS oli kerennyt tulla tutuksi työskennellessäni Solitalla.
AWS:ssä hyödynsin Elastic Beanstalk-palvelua, joka toimi melko samalla tavalla kuin Heroku. Ideana on, että koodi ladataan Beanstalkiin ZIP-pakettina ja web-sovelluksen muutokset astuvat välittömästi voimaan, mikäli virheitä ei havaita. Palvelu takaa muutosten tekemisen minimivaivalla ilman syvällistä ymmärrystä taustalla toimivan palvelimen toiminnasta.
Elastic Beanstalkia vastaava palvelu olisi Microsoftin Azuresssa App Service ja Google Cloudilla App Engine.
Muutosten vieminen palveluun olikin helppoa, mutta ensimmäinen käyttöönotto ja asetustiedostojen säätäminen vei hyvän tovin.
Tietokannan yhdistäminen Beanstalk-sovellukseen tapahtui suhteellisen kätevästi valikoiden kautta. Tietokanta pyöri AWS RDS-palvelussa.
Käyttöliittymän jakelu AWS:stä
Tallensin Reactilla toteutetun koodin AWS S3-palveluun, jota käytetään tiedostojen varastointiin.
Reactin käyttöliittymätiedostojen jakelun hoidin Amazon CloudFrontin kautta, joka mahdollistaa tiedostojen tehokkaan jakelun, salatun HTTPS-liikenteen ja oman verkko-osoitteen käyttämisen.
SSL-sertifikaatin HTTPS-yhteyttä varten sai vaivattomasti AWS Certificate manager-palvelusta huterillakin pohjatiedoilla.
Oman verkko-osoitteen käyttäminen
Verkko-osoitteeni mikaelahonen.com on hankittu näitäkin verkkosivuja isännöivän web-hotellin kautta. Web-hotellini hallintapaneelista loin aliverkkotunnukset app.mikaelahonen.com käyttöliittymälle ja api.mikaelahonen.com Djangolla toteutetulle rajapinnalle.
Tein Amazon Route 53-palvelun ohjeiden mukaiset valmistelut sekä CloudFrontia että Beanstalkia varten. Sen jälkeen syötin Route 53:n antamat verkko-osoiteet web-hotellini DNS-hallintapaneelista aliverkkotunnusten NS-tietuille.
Koodin siirtäminen automaattisesti GitHubista AWS:ään
Olin tehnyt omat GitHub-arkistonsa React-käyttöliittymälle ja Django-rajapinnalle. Testattuani muutokset omalla tietokoneellani latasin käyttökelpoiseksi todetun koodin GitHubiin.
GitHubiin siirretyt muutokset päivittyivät automaattisesti AWS:ään, koska tein Amazon EC2-virtuaalikoneen, johon asensin Jenkinsin kyselemään GitHub muutoksia minuutin välein. Tämän jälkeen Jenkins vei tiedostot joko S3:een (React) tai Beanstalkiin (Django).
Myöhemmin ajastin Jenkins-palvelimen Amazon Cloudwatch-palvelusta käynnistymään vain kerran päivässä lyhyeksi aikaa kulujen minimoiseksi. Jenkins-toteutus on jälkikäteen ajateltuna hieman raskas ja nyt toteuttaisin sen todennäköisesti AWS Lambda-funktioilla, jotka toimivat käyttäjän näkökulmasta ilman palvelimia.
Käyttöliittymän tiedostot täytyy jakaa käyttäjille julkisesti, joten ne eivät saa sisältää salaista tietoa. Djangolla toteutettu taustajärjestelmä sen sijaan tarvitsee esimerkiksi tietokannan salasanan toimiakseen. Salasanoja en tallentanut GitHubiin julkaistavaan koodiin, vaan koodi poimi salasanat järjestelmämuuttujista, joita pystyi syöttämään Beanstalkissa käsin.
Datan visualisointi web-sovelluksessa – Plotly ja D3
Tein päätöksen visualisoida data käyttöliittymässä. Javascript-kirjastot mahdollistavat kuvaajien interaktiivisuuden, eikä käyttöliittymän piirtämissä kuvaajissa tarvitse kuljettaa ylimääräisiä bittejä verkon yli.
Aloitin kuvaajien tekemisen plotly-kirjastolla, koska sillä peruskuvaajien tekeminen on todella helppoa. D3-kirjastoon kannattaa siirtyä siinä vaiheessa, kun tarvitsee räätälöityjä visualisointeja.
Graafista haluaisin nähdä jatkossa kehityskäyräni valitsemani liikkeen osalta.
Kun harjoituksesta klikkaa haluamaansa sarjaa, pääsee muokkaamaan toistomäärää ja käytettyä painoa. Testimielessä tehdyn kuvaajan tilalle on tarkoitus tehdä käyrä, josta voi seurata kehitystä.
Vei melko kauan, että sain React-käyttöliittymän ja Djangon REST-rajapinnan juttelemaan keskenään luotettavasti. HTTP-protokolla tuli erittäin tutuksi.
Web-sovelluksen pilvipalvelinkustannukset
Toteutukseni kulut muodostuivat pilvilaskentakapasiteetin ostamisesta AWS:ltä, sillä käyttämäni avoimen lähdekoodin kirjastot ja ohjelmistot eivät vaadi lisenssimaksuja.
Suurimman kuluerän muodostivat RDS-palvelun tietokanta ja Elastic Beanstalkin käyttämä EC2-virtuaalipalvelin. Normaalihinnoilla kustannus on kevyimmillä vaihtoehdoilla yhteensä noin 20 euroa kuukaudessa. Käyttöliittymän jakelun ja tiedostojen varastoinnin kustannukset ovat ainakin harrastekäytössä mitättömiä.
AWS:n lähettämien laskujen mukaan RDS ja EC2 kustannukseni menevät kuukausittain ilmaiseen kiintiöön. Olin luullut, että ilmaisia resursseja saa vain 12 ensimmäistä kuukautta.
Esimerkki AWS-kustannuksista yhdeltä kuukaudelta. Kuukausittainen ilmainen kokeilu kattaa RDS-palvelun ja Elastic Beanstalkin virtuaalikoneen kustannukset. GitHub-arkistojen siirtämiseen käytetty virtuaalikone aiheuttaa nimellisiä kustannuksia. Kahden alidomainin ohjaaminen Route 53-palvelun kautta maksaa dollarin kuussa.
Web-sovelluksen arkkitehtuuri ja ihannetoteutus
Millaisen sovelluksen tekeisin nykyisellä kokemuksellani?
Djangossa kaikki on paketoitu sisään: tietomalli, toimintalogiikka, käyttöliittymä ja käyttäjänhallinta jne. Jatkossa tulen käyttämään projekteissani Flask-pakettia, joka toimii sovelluksen aivoina.
Flask-sovelluksen paketointi Docker-konttiin mahdollistaa samanlaiset testi- ja tuotantoympäristön, sekä sovelluksen siirtämisen muille pilvialustoille.
Harkitsin taustajärjestelmän rajapinnan luomiseen AWS Api Gateway-palvelua, mutta muutamien kokeilujen jälkeen totesin rajapinnan tekemisen hoituvan pienessä projektissa joustavammin Flaskilla.
Iso osa tilastollisesta laskennasta onnistuisi Flaskilla HTTP-pyynnön prosessoinnin yhteydessä. Koneoppimismalleja pystyisi opettamaan etukäteen ja tallentamaan S3:een python objekteina. Isomman mittaluokan laskentaan Flask voisi kutsua valmiita AWS-palveluita, kuten SageMaker (koneoppiminen) tai Rekognition (kuvantunnistus).
Tunnistautumiseen valitsisin Amazon Cogniton. Ensin käyttäjä tunnistautuu käyttöliittymässä Cognitoon ja saa käyttäjätunnuksia vastaan tunnistautumisavaimen. Avain lähetetään taustajärjestelmälle jokaisessa käyttöliittymän tekemässä kutsussa. Flask tarkistaa avaimen Cognitosta aina ennen vastauksen antamista käyttöliittymälle.
Kehittämiseen käytin Windows-läppäriäni, johon oli asennettu Ubuntu Subsystem for Linux Linux-käytön mahdollistamiseksi. Harrasteprojektissa en näe GitHub-automaatiota tarpeellisena.
Web-sovellukseni ihannearkkitehtuuri. Teknisestä kuvauksesta näkee, kuinka eri palvelut liittyvät toisiinsa.
apiawsazuredata science ja analytiikkadatalla ennustaminendatan visualisointijavascriptkäyttöliittymäsuunnittelukoneoppiminenmobiili-sovelluspilvipythonrtietokanta ja sqlweb frameworkweb-sovellus
⟵Web-sovellus pilvessä data edellä – Sovelluksen esittely
Kokemuksia tekstianalytiikasta rahoitushakemuksien luokittelussa⟶