Rakenna CI-putkesi käyttäen Azure Pipelines YAMLia

Pasi Huuhka | 21.01.2020
Lukuaika 7 min

Väsyttääkö kliksuttelu Azure DevOpsin portaalissa? Ärsyttääkö yksittäisten muutosten teko erikseen jokaista ympäristöä kohden? Olen itse törmännyt vastaaviin tuntemuksiin, mutta onneksi näihinkin ongelmiin on löytynyt ratkaisu Microsoftin Azure DevOps-palvelusta!

Tässä blogipostauksessa opimme, mikä Azure Pipelines YAML on, miksi sitä pitäisi käyttää, ja miten päästä parhaiten alkuun sen hyödyntämisessä.

Mikä ihmeen YAML?

Viime kuukausiin saakka Microsoftin oma DevOps-tuote – sopivasti nimeltään Azure DevOps – on markkinoinut pääasiassa graafiseen käyttöliittymään perustuvia ”Classic”-build ja release-putkia.

Jollain tasolla tämä on aivan ymmärrettävää, sillä käyttöliittymäpohjaisia putkia on helppo ymmärtää, ja niiden kautta itse alustan toimintaa on yksinkertaista kuvata. Kuitenkin todella nopeasti ympäristöjen ja vaatimusten muuttuessa monimutkaisemmaksi, isot hankaluudet putkien kehityksen kanssa nostavat päätään. Kopiointi toiseen projektiin on häsläyksen takana, templatejen luonti useaa ympäristöä varten on hankalampaa kuin kuuluisi ja jos satut omistamaan useamman eri ympäristön sovelluksestasi, saatat joutua tekemään saman muutoksen useaan kertaan. Tämä on ongelma etenkin, jos julkaisujen haarat eroavat vaatimuksiltaan kehityshaaraan, esimerkiksi putkessa annettavien parametrien osalta: voit päivittää tuotannon putken vasta kun se voi ottaa kyseisen parametrin vastaan.

Pinnan alla on kuitenkin jo kuplinut pitkään. Kilpailevilla CI/CD-tuotteilla on ollut ratkaisunsa näihin ongelmiin jo kauan, ja myös Microsoftin vastaus – YAML-skeemaan perustuvat putket – on vihdoin saavuttamassa pariteettia Classic-tyylisten putkien kanssa. Mielestäni nyt on viimeistään oikea hetki tutustua näiden tuomiin mahdollisuuksiin. Mitä ne siis ovat?

Pähkinänkuoressa ne ovat julkaisuputken logiikan säilyttämistä koodina suoraan repositoriossa sovelluksesi koodin vierellä. Samoin kuin infrastruktuuri koodina-ajattelun nousu, ”julkaisuputket koodina” on seuraava askel sovelluksen kokonaisuuden hallinnan parantamisessa. Tämä avaa samalla lukuisia uusia mahdollisuuksia siihen, miten yrityksesi tekemistä standardisoidaan, ja miten työtavat virtaviivaistuvat.

Kolme mielestäni mieleenpainuvinta etua YAML-skeeman käytössä Azure Pipelines-putkissa ovat:

  • Putket ovat repositoriossasi – Saat siis kaikki git-prosessien hyödyt, kuten Pull Requestit, versiohistorian, haaroituksen, ym. Tämän myötä ei ikinä tarvitse pelätä rikkovansa putkea muille, sillä kehittäjä voi tehdä siihen muutoksia omassa kehityshaarassaan. Voit olla myös varma siitä, että julkaisuhaarasi build & release-putket toimivat vielä myöhemminkin, jos niihin täytyy jostain syystä palata jälkikäteen. Koodin ja putkien tila vastaa toisiaan, ja tämä voi parhaimmillaan säästää useita tunteja selvitystyötä.
  • Koodin uudelleenhyödyntäminen – YAML-putket tukevat template-rakenteiden käyttöä ja niiden parametrisointia – jopa erillisistä repositorioista, antaen mahdollisuuksia luoda standardisoituja rakennuspalikoita, joita kaikki yrityksesi projektit voivat käyttää. Vaikka vastaava toiminnallisuus löytyykin Classic-puolelta, YAML vie tämän seuraavalle tasolle käytännöllisyydellään.
  • Putkien eri osia on paljon yksinkertaisempaa ajaa samanaikaisesti – Classic-putkilla ainoa yhteisajomahdollisuus on release-tyyppisten putkien Stage-tasoissa. Tämä johtaa usein siihen, että releaset jaettiin pieniin stageihin, joka taas tekee yleisnäkymän historiatiedot lähes hyödyttömiksi.

Kaikki ei kuitenkaan ole ruusuilla tanssimista. Kuten minkä tahansa uuden teknologian oppimisessa, kuluu putkien rakentamiseen tekijän omaksuessa uusia työtapoja huomattavasti enemmän aikaa kuin Classic-tyylillä. Samalla etenkin monimutkaisemmissa toteutuksissa on vielä joitakin toiminnallisuuksia (esim. post release gatet), jotka eivät ole vielä tuettuja YAML-putkilla. Asiakkaalle on myös pystyttävä perustelemaan niihin kuluva työmäärä, ja hänen on ymmärrettävä niistä koituvat hyödyt pitkässä juoksussa, jolloin panostus maksaa itsensä takaisin moninkertaisena.

Tällä hetkellä ainoa oletuksena aktivoitu YAML vaihtoehto on luoda yksinkertaisia build-putkia, ja ne ovat tämän postauksen pääosassa. Suosittelen kuitenkin, että myös preview-ominaisuus ”multi-stage pipelines” kytketään päälle, sillä se mahdollistaa myös monimutkaisempien build ja release-putkien rakennuksen, ja on myös todella lähellä siirtymistä opt-out-tyyliseksi ominaisuudeksi.

YAML-putken rakennuspalikat

Päältäpäin YAML-putken rakenne on hyvin samanlainen kuin sen Classic-veljienkin:

  • Staget ovat isoja putken jakolinjoja: ”rakenna sovelluspaketti”, ”aja nämä testit”, ”julkaise sovellus tuotantoon”. Näitä käytetään Classic release-putkien luonnissa, ja myös build-putket perustuvat pinnan alla näihin, joskin ne ovat vain yhden Stage-tason objektin sisällön kuvaus. Jokainen Stage voi sisältää yhden tai useampia Job-osia
  • Jobit ovat kokonaisuuksia, jotka osoitetaan yhdelle agenttikoneelle tietyssä joukossa agentteja (agent pool). Sekä Stage, että Job voidaan järjestää sisältämään riippuvuuksia toiseen samantasoiseen osaan, tai ajamaan yhtäaikaisesti toisten kanssa. YAMLin uutuus on deployment-tyylinen Job, jotka osoittavat tiettyyn sovellusympäristöön ja määrittävät tietynlaisen julkaisustrategian.
  • Stepit ovat lineaarinen yhdistelmä erinäisiä toimintoja, kuten skriptin tai taskin ajoa, juuri kuten Classic-versioissakin. YAML tarjoaa useita eri avainsanoja, jolla yleisimmät asiat (kuten powershell tai bash skriptin ajo tai artifaktien lataus) voidaan määrittää nopeasti. Näihin kuuluvat esimerkiksi ”download” ja ”script”, ja niiden käyttö voi joskus aiheuttaa ylimääräistä selvitystä nykyisen dokumentaation tason vuoksi.

Tyypillinen YAML-putki voisi näyttää jotakuinkin tältä:

trigger:
- master

stages: 
- stage: stage1
  jobs:
  - job: job1
    pool:
      vmImage: 'windows-latest'
    steps:
    - task: NuGetToolInstaller@1
    - task: NuGetCommand@2
      inputs:
        restoreSolution: 'mysolution.sln'
    - script: echo Hello, world!
      displayName: 'Run a one-line script'

- stage: stage2
  jobs:
  - job: importantjob
    pool:
      vmImage: 'windows-latest'
    steps:
      - pwsh: 'write-output "I do nothing"'

Kaikki mainituista rakennuspalikoista voivat myös käyttää template-rakenteita parametreineen.

Templaten kutsuja:

trigger:
- master

stages: 
- template: template-stage.yaml
  parameters:
    stagename: 'MyStage1'
    vmImage: 'windows-latest'
    restoreSolution: 'mysolution.sln'

Templaten sisältö:

parameters:
  stageName: ''       # should fail if not given
  vmImage: 'windows-2019'  # default values if not given in caller
  restoreSolution: ''

stages: 
- stage: ${{ parameters.stageName }}
  pool:
    vmImage: ${{ parameters.vmImage }}
  jobs:
  - job: job1
    steps:
    - task: NuGetToolInstaller@1
    - task: NuGetCommand@2
      inputs:
        restoreSolution: '${{ parameters.restoreSolution }}'
    - script: echo Hello, world!
      displayName: 'Run a one-line script'

Kaikkia näitä ei kuitenkaan tarvita toimivaan putkeen, vaan yksinkertaisemmat putket voivat hyvin rakentua vain listasta steppejä. Kun pääset syventymään tarkemmin eri palikoihin, tutustu jokaisen omaan dokumentaatiosivuun, josta löytyy paljon lisätietoja konfigurointia varten.

Okei, mistä voin aloittaa?

Onneksemme Microsoft tarjoaa hieman hämmennystä herättävän läjän dokumentaatiota, jota voimme hyödyntää. Tämän lisäksi saatavilla on myös aloitustemplateja, ja VS Coden lisäosa auttamaan kehityksessä. Mielestäni kuitenkin paras työkalu aloittelijalle on Azure DevOpsin portaalin editori ja sieltä löytyvä todella hyödyllinen task assistant-ominaisuus, joka auttaa yksittäisten steppien konfiguroimisessa.

Näillä askelilla pääset alkuun:

  • Luo build-putki juuri niin kuin ennenkin. Kerro mistä koodisi löytyy.
  • Azure DevOps analysoi koodisi ja ehdottaa jotain yksinkertaisia templateja, joista voit aloittaa sen perusteella, mitä repositoriostasi löytyy.
  • Valitse haluamasi template (tai jo valmiiksi luomasi YAML-tiedosto).
  • Muuta tiedoston nimeä ja määritä sen paikka repossa.

Tässä aloitin ASP.NET templatella, sillä se sisälsi jo joitakin haluamiani variableja. Myös trigger oli valmiiksi määritetty käynnistämään putki aina kun master-haarani päivittyy. En kuitenkaan halunnut käyttää valmiina olevia taskeja, joten poistin ne ja käytin assistant-toimintoa konfiguroimaan dotnet core-komentorivityökalun vastaavia toiminnallisuuksia. Samalla määritin myös agenttikoneen windows-2019 -ryhmästä, ja lisäsin jokaiseen taskiin myös displayname kentän, joka selventää logeja myöhemmin. Vielä lopuksi käytin uutta PublishPipelineArtifact taskia julkaistakseni pakatut projektini valmiina release-putken käyttöön.

Tässä vielä putkeni lopullinen koodi:

trigger:
- master

pool:
  vmImage: 'windows-2019'

variables:
  buildConfiguration: 'Release'

steps:
- task: DotNetCoreCLI@2
  displayName: "Dotnet Restore"
  inputs:
    command: 'restore'
    projects: '**/*.csproj'
    feedsToUse: 'select'
- task: DotNetCoreCLI@2
  displayName: "Dotnet Build"
  inputs:
    command: 'build'
    projects: '**/*.csproj'
    arguments: '--no-restore --configuration $(buildConfiguration)'
- task: DotNetCoreCLI@2
  displayName: "Dotnet Publish"
  inputs:
    command: 'publish'
    publishWebProjects: true
    arguments: '-o $(Pipeline.Workspace)/publish --no-build'
- task: PublishPipelineArtifact@1
  displayName: "Publish Artifacts"
  inputs:
    targetPath: '$(Pipeline.Workspace)/publish'
    artifact: 'web'
    publishLocation: 'pipeline'

Voisit halutessasi myös käyttää Variables-nappulaa oikeassa yläkulmassa. Tätä kautta voit luoda ajoa ennen määritettäviä variableja, joita käytetään putkessa samaan tapaan kuin ennenkin. Dialogi antaa myös lisää esimerkkejä näiden käytölle. Itse yritän pitää mahdollisimman paljon logiikasta kuitenkin kirjattuna YAML-tiedostoon.

Tämän jälkeen voit tallentaa putken, ja valita, haluatko tehdä commitin suoraan valitsemaasi haaraan vaiko luoda uuden haaran. Valinta riippuu omasta git prosessistasi, mutta vahva suositukseni on tehdä uusi haara ja tuoda tiedosto Pull Requestin kautta master-haaraan.

Lokien seuraaminen on yhtä helppoa kuin ennenkin, ja tarjoaa samat ominaisuudet kuin Classic-puolella.

Matka altaan syvään päähän

Vaikka yllä olevat esimerkit ovatkin todella yksinkertaisia, ja sisältävät vain perusasiat, on niistä kuitenkin helppo jatkaa omien putkiesi rakennusta.

Jos sinulla on jo valmiita putkia, nopein tapa muuntaa ne YAMLiksi on käyttää ”View Yaml”-nappulaa, jonka löydät jokaisen build-putken Jobin, ja jokaisen release ja build-putken yksittäisen taskin kohdalta. Job-tason toiminnallisuus on erityisen hyödyllinen, sillä sitä hyödyntäen voi muunnon tehdä todella pienellä työmäärällä muutamassa minuutissa.

 

Jos haluat oppia lisää, alla on lista toiminnallisuuksia joihin suosittelen tutustumaan. Ne tulevat vastaan todella pian kun siirryt monimutkaisempien putkien rakennukseen, etenkin silloin kun alat rakentaa release-putkia YAMLin avulla.