Harjoitusprojekti: Go, Docker ja CircleCI -tuotantoputki

Uusi ohjelmistoprojekti edessä — ja samalla myös joukko uutta teknologiaa pitäisi opetella. Miten saada nopeasti luotua itselle kokonaiskuva tulossa olevasta työmaasta ja tuntumaa uusiin työkaluihin? Yksinkertaisen, mutta kaikki työvaiheet kattavan harjoitusprojektin avulla on mahdollista nopeasti oppia perusteet monestakin teknologiasta yhtä aikaa.

Dokumentoin tässä oppimisprojektin ja siihen liittyvän teknologian yleisellä tasolla. Teknisiä yksityiskohtia ja lähdekoodia varten projekti löytyy GitHubista. Docker-image on saatavilla Docker Hubissa, ja tuotannossa oleva sovellus itse löytyy osoitteesta https://anttihalla.fi/golang-docker-circleci-example

Harjoitusprojektin määrittely

Tällä kertaa tarkoitus oli opetella perusteet kolmesta työkalusta: ohjelmointikieli Go, virtualisointityökalu Docker ja jatkuvan integraation palvelu CircleCI.

Miten nopeasti saada pohjaosaaminen näistä kaikista kolmesta? Yritänkö tehdä projektin joka yhdistää nämä kaikki kolme, vai olisiko siinä liikaa opittavaa kerralla? Toinen vaihtoehto olisi ensin siirtää vanhoja projekteja Dockeriin ja/tai CircleCI:hin. Tällä tavalla saisi oppimisen määrää ja uusia tuntemattomia minimoitua.

Annoin ajatuksen hautua sen aikaa, kun kävin googlettamassa perustietoja aiheesta. Naputtelin Go-tutorialin, lueskelin CircleCI:n dokumentaatiota, katselin YouTubesta Dockerin perusteita. Näitä haudutellessa päädyin lopulta siihen, että yritän tehdä suoraan yhden projektin, joka yhdistää nämä kolme asiaa. Pitäisi vain suunnitella etenemisaskeleet siten, että joudun opettelemaan vain yhden uuden asian kerrallaan.

Alustava suunnitelma oli lyhyesti:

  • lue perusteita dokumentaatiosta, katsele pari videota YouTubesta
  • asenna Docker engine omalle koneelle
  • asenna Golang -dockerkontin avulla Go-ohjelmointiympäristö
  • luo projekti GitHubiin
  • kirjoita Go Hello World -sovellus
  • kirjoita sovellukselle yksikkötesti
  • liitä GitHub-projekti CircleCI:hin ja aja yksikkötesti siellä automaattisesti

Olen liian monta kertaa kehitellyt pöytälaatikkoprojekteja vain huomatakseni, että tuotantoon viemisessä onkin monta mutkaa vielä matkassa. Nyt halusin välttää sen harjoittelemalla myös julkaisun tuotantopalvelimelle. Toki tuotantokoodia pitää myös osata päivittää, joten automaattinen testien ajo ja tuotantoversion päivityksen sujuvuus pitää myös varmistaa.

Monet ohjelmointikielten oppikirjat eivät ole yksinään riittäviä tietolähteitä käytännön ohjelmistoprojektia varten samasta syystä: kirjat keskittyvät itse kielen ominaisuuksiin, esimerkiksi juuri tuotantoonvientiin liittyvien toimintojen jäädessä sivuseikoiksi, mikäli niitä edes käsitellään.

Ohjelma itse saa olla simppeli, mutta koko tuotantoketju pitää testata, mukaan lukien kehitysyökalut ja tekstieditorien kielituet. Tämän vuoksi suunnitelmaan piti lisätä vielä muutama askel:

  • määrittele jatkuvan integroinnin ketju tuotantoon asti
  • julkaise projekti tuotantopalvelimella julkisessa internetissä
  • tee muutoksia koodiin ja varmista että muutokset näkyvät tuotantopalvelimella

Suunnitelma kuulosti toteutettavissa olevalta ja riittävän pieneltä, jotta saan sen myös tehtyä. Tavoite oli saada homma tehtyä vähitellen yhden viikon aikana, pari tuntia päivässä tehden ja opiskellen.

Go

Go (kirjoitetaan usein Golang) on Googlella kehitetty kohtuu nuori ohjelmointikieli (1.0 versio julkaistiin vuonna 2012). Tarkoitukseni oli saada nopea kosketus kielen ominaisuuksiin ja tarjolla olevaan dokumentaatioon.

Pelkän “Hello world” -tulosteen lisäksi halusin hieman kielen ominaisuuksiakin kokeilla, joten lisäsin soppaan yksinkertaisen HTTP-palvelimen, HTTP-kutsun ulkoiseen API-rajapintaan ja sieltä saadun JSON-vastauksen parsimisen. Yksi Go:n mainostetuista vahvuuksista on rinnakkaisuus, joten halusin myös nähdä miten useampi rajapintapyyntö kerralla onnistuu asynkronisesti.

Ohjelmointikielen kirjoittamista varten tarvitaan lisäksi tietenkin editori. Pääasiallisena tekstieditorinani on viime aikoina ollut Atom. Siihen löytyi suoraan muutama Go-plugin, joiden avulla sain editoriin syntaksikorostukset, käännösvirheet ja jopa automaattiset testiajot näkymään ilman sen kummempaa vaivaa. Mahdollisesti parempiakin ratkaisuja on, mutta tämä oli enemmän kuin riittävä minulle.

Haluamani tärkeimmät toiminnallisuudet onnistuivat suuremmitta mutkitta Go:n standardikirjaston avulla esimerkkejä seuraamalla. Ainoastaan koodin automaattista uudelleen kääntämistä varten jouduin asentamaan ulkoisen kirjaston. Go-lähdekoodi käännetään binääriksi ajamista varten, joten nopeaa kehitystä varten (jotta muutokset näkyvät selaimessa koodi tallennettaessa) tarvitsin tiedostojen muuttumista tarkkailevan lisäpalikan.

Projektia varten loin julkisen projektin GitHubiin, josta ohjelmakoodi löytyy. Julkinen projekti mahdollistaa myös Docker Hubin ja CircleCI:n maksuttoman käytön. Näistä lisää alla.

Docker

Docker on lyhykäisyydessään kevyt käyttöjärjestelmän virtualisointitekniikka, jonka avulla voidaan ohjelmisto rakentaa, asentaa ja hallinnoida käyttäen toisistaan eristettyjä sovelluskontteja (container). Konttien ajamista palvelimella täytyy olla asennettuna Docker-ohjelmisto.

Ajettava kontti vaatii pohjakseen sovelluksen Docker-levykuvan (image), joka puolestaan määritellään tyypillisesti projektin lähdekoodin rinnalla Dockerfile-tiedostossa. Tiedostossa määritellään pohjana käytettävä levykuva sekä askeleet ohjelmiston koostamiseksi.

Tämän harjoitusprojektin tapauksessa tiedostoon tulee vain muutama rivi: pohjana on Go-ohjelmointikielen työkalut sisältävä levykuva, ohjelma kopioidaan konttiin, käännetään ja ajetaan.

Tuotantovalmiit levykuvat tallennetaan levykuvarekisteriin (Docker registry), josta ne voidaan ladata tuotantopalvelimelle ajettavaksi. Rekisteriä voi ylläpitää itse tai voi hyödyntää Docker Hub -palvelua. Avoimen lähdekoodin ylläpitoon Docker Hub sopii hyvin, joten työnsin levykuvan sinne.

CircleCI

Jatkuva integrointi, continuous integration (CI), lienee nykyään niin keskeinen osa ohjelmistokehitystä, että harva vähänkin kunnianhimoisempi projekti pärjää ilman. CI toimii kehitystyön selkärankana, joka mahdollistaa ohjelmiston uusien versioiden hallitun tuotantoonviennin sekä laadun jatkuvan kehittämisen.

Yksinkertaisimmillaan CI-palvelin noutaa päivittyneen ohjelmakoodin automaattisesti versionhallinnasta, ajaa nipun testejä ja ilmoittaa menivätkö ne läpi. Tämä voi vuorostaan liipaista tuotantoonvientiautomatiikan. Monivaiheiset tuotantoonvientiprosessit saattavat käsin viedä tunteja, jopa päiviä joissain ympäristöissä. Toimivan CI:n avulla tämä aika lasketaan ennemminkin minuuteissa, jos ei sekunneissa.

Ennen CircleCI:tä kokemukseni oli lähinnä itse asennetuista Jenkins-palvelimista ja odotin tuntien mittaista konfigurointiurakkaa alkuun pääsemiseksi. Sain kuitenkin yllättyä positiivisesti: 15 minuutissa olin luonut palveluun tunnuksen, liittänyt GitHub-projektin automaattista koostoa varten. Palvelu tarjosi valmiin pohjatiedoston, jonka avulla perusasennus meni kivuttomasti. Konfiguraatiotiedosto liitetään lähdekoodin rinnalle versionhallintaan.

Kyllä CircleCI:n kanssakin aikaa saa kulumaan asetusten säätämisessä. Konfiguraatio-tiedostot kun loppujenlopuksi voi testata vain ajamalla koko prosessi läpi. Tätä helpottaa kyllä komentorivityökalut, joilla tiedoston voi validoida ennen ajamista.

Netistä löytyviä ohjeita seuratessa kannatta huomata myös että CircleCI versiot 1 ja 2 eivät ole täysin yhteensopivia keskenään (ja monet ohjeet viittaavat versioon 1).

Viimeinen askel kehitysputkessa oli vielä tuotantoonvienti automaattisesti CI-palvelimelta. CircleCI tarjoaa valmiita liityntöjä palveluihin kuiten AWS, Heroku, Azure, GoogleCloud ja Firebase. Päätin kuitenkin käyttää olemassaolevaa Ubuntu-virtuaalipalvelintani.

Tuotantoonviennin säätäminen olisi saattanut mennä yksinkertaisemmin ja nopeammin ottamalla käyttöön jokin tuetuista palveluntarjoajista, mutta halusin myös selvittää miten tämä kuvio toimii perinteisen palvelimen kanssa.

Tavallinen tapa asentaa valmis Docker-levykuva on kierrättää se keskitetyn rekisterin kautta. Tällaisen voi asentaa itse tai käyttää Docker Hub -palvelua. Avoimen koodin projektiin Hub sopii hyvin, joten latasin levykuvan sinne. Tuotantopalvelimeni voi sitten noutaa uuden sovellusversion Hubista — joko CI-palvelimen liipaisemana tai ajastetusti — ja asentaa uuden kontin vanhan tilalle.

Yhteenvetoa

Kokonaisuutena näiden kolmen teknologian — Go, Docker ja CircleCI — käyttöönotto onnistui yllättävänkin sujuvasti. Yhteensä tähän käytin aikaa noin 15 tuntia. Uusiin kilkkeisiin tutustuessa on helppo uppoutua yksityiskohtiin ja käyttää loputtomasti aikaa. Materiaalin syvyyssuuntaisen läpikäynnin sijaan leveyssuuntainen läpikäynti auttaa pitämään opiskeltavan kokonaisuuden paremmin tasapainossa ja ymmärtämään miten palikat liittyvät toisiinsa. Tällä tavoin kosketus jää ehkä hieman pinnalliseksi, mutta osaamiselle muodostuu kehikko, johon syvällisempi ymmärrys on myöhemmin helppo liittää.

Minimaalisen toimivan kokonaisuuden rakentaminen estää teknisiin nippeleihin jumittumisen ja auttaa ymmärtämään miten eri työkalut toimivat yhdessä. Koko tuotantoputken rakentaminen valmiiksi ensimmäisenä työnä auttaa vähentämään piileviä teknologiariskejä ja luo uudelle ohjelmistoprojektille vahvan perustan.

Tästä onkin hyvä sitten lähteä vaikka syventymään Go-kielen saloihin.

Linkkejä

comments powered by Disqus
2017-10-16