Continous
deployment
til
Azure
App
Service
med
Github
Actions!

14.09.21

Introduksjon

GitHub Actions gjør det enkelt å lage egendefinerte arbeidsflyter for å gjøre utviklingshverdagen enklere. En arbeidsflyt kan i teorien være hva som helst ettersom alt er event-drevet, og ved hjelp av en YAML-fil definerer du enkelt et sett med commands du vil kjøre når en spesifikk event har inntruffet. I denne artikkelen ser vi på hvordan vi kan legge til en CI/CD-pipeline direkte i et GitHub-repository.

For å gjennomføre alle stegene i denne artikkelen forventes det at du allerede har et GitHub-repository og en Azure-konto, i tillegg til å ha installert .NET 5 og Azure-CLI.

.NET 5 app

Vi begynner med å lage et lite Web-API. Kjør følgende kommandoer fra din foretrukne terminal. Kommandoene lager en solution-fil, legger til et web api prosjekt, og kjører applikasjonen.

$ dotnet new sln$ dotnet new webapi -o <navn>$ dotnet sln add <navn>$ cd <navn>$ dotnet run

Jeg har brukt navnet MyAzureSampleApi. Etter å ha kjørt kommandoene kan du se APIet på https://localhost:5001/swagger.

For å se Swagger i Azure gå inn i Startup.cs og gjør Swagger tilgjengelig i alle miljø ved å fjerne IsDevelopment sjekken hvor Swagger registreres.

Azure App Service

For å opprette en "App Service"-instans i Azure gjør vi følgende fra en terminal:

Log in på din Azure-konto:

$ az login

List alle tilgjengelig Azure lokasjoner:

$ az account list-locations -o table

Opprett en Resource Group. Vi bruker lokasjonen "norwayeast" i dette tilfellet og oppretter en Resource Group med navnet "AzureSamplesResourceGroup".

$ az group create --name AzureSamplesResourceGroup --location norwayeast

For å slippe å skrive inn Resource Group parameteren i de resterende kommandoene kan man gjøre følgende:

$ az configure --defaults group=AzureSamplesResourceGroup location=norwayeast

Alle applikasjoner i Azure trenger en App Service Plan, og her oppretter vi en som er gratis:

$ az appservice plan create --name AzureSamplesPlan --sku FREE

Nå kan vi opprette selve "App Service"-instansen. Her har vi spesifisert at den skal hete "MyAzureSampleApi" og kjøre på planen "AzureSamplesPlan" som vi opprettet i forrige steg. Videre har vi spesifisert runtime til .NET 5. For å se en liste av tilgjengelige runtimes kan man også kjøre følgende kommando:

$ az webapp list-runtimes$ az webapp create --name MyAzureSampleApi --plan AzureSamplesPlan --runtime "DOTNET|5.0"

Til slutt setter vi opp en Service Principal som har tilgang til å deploye til vår App Service. En Service Principal er en Active Directory Identity som brukes i automasjonscenarioer, som f.eks GitHub Actions.

$ az ad sp create-for-rbac --name "<appservice-name>" --role contributor --scopes /subscriptions/{sub-id}/resourceGroups/{resource-group} --sdk-auth

Output av kommandoen ovenfor legges inn i GitHub Secrets under nøkkelen AZURE_CREDENTIALS og brukes i YAML-filen vi setter opp senere.

{
  "clientId": "<GUID>",
  "clientSecret": "<GUID>",
  "subscriptionId": "<GUID>",
  "tenantId": "<GUID>"
}

Et alternativ til å opprette en Service Principal er å hente ut hele Publishing Profilen som ligger i Azure og legge den inn i GitHub Secrets isteden.

GitHub Actions

For å få en starter-template for ditt GitHub-repository kan man navigere til Actions. Her vil GitHub foreslå forskjellige templates basert på ditt repository. Disse templatene ligger selvfølgelig også tilgjengelig i et eget GitHub-repository, actions/starter-workflows. Eksempelet vi bruker i denne artikkelen er basert på .NET templaten:

name: Build and deploy a .NET 5 app to Azure App Service
on: [push]
env:
  AZURE_WEBAPP_NAME: 'MyAzureSampleApi'
  AZURE_WEBAPP_PACKAGE_PATH: '.'
  DOTNET_VERSION: '5.0.x'
jobs: 
  build: 
    runs-on: windows-latest 
    steps:
      # Check out the repository
      - uses: actions/checkout@v2
      - uses: azure/login@v1 
        with: 
          creds: ${{ secrets.AZURE_CREDENTIALS }}
       
      # Setup .NET SDK
      - name: Setup .NET
        uses: actions/setup-dotnet@v1 
        with: 
          dotnet-version: ${{ env.DOTNET_VERSION }} 
       
      # Run dotnet build and publish
      - name: dotnet restore, build, and publish 
        run: | 
          dotnet restore 
          dotnet build --configuration Release 
          dotnet publish -c Release -o '$/myapp'  
           
      # Deploy to Azure Web apps 
      - name: Run Azure webapp deploy action using azure credentials
        uses: azure/webapps-deploy@v2 
        with:  
          app-name: ${{ env.AZURE_WEBAPP_NAME }} 
          package: '$/myapp' 
       
      - name: logout 
        run: | 
          az logout

La oss gå igjennom de forskjellige stegene.

  • Først gir vi prosessen et navn og under on bestemmer vi hva triggeren er. I dette tilfellet starter vi byggprosessen på alle commits som blir pushet til repositoryet, uavhengig av hvilken branch du er på. Her kan man også f.eks konfigurere det slik at kun push til master skal trigge bygg.
  • env spesifiserer miljøvariabler som er tilgjengelige til alle stegene som kommer senere i workflowen. Her kan man også sette opp variabelbytter til f.eks appsettings.json om man ønsker det.
  • I jobs steget definerer vi selve byggprosessen. Hver workflow kan bestå av en eller flere jobs. I tillegg har hver job et eller flere steps. Under steps sjekker vi først ut koden og logger inn i Azure ved å bruke secreten vi la inn i GitHub tidligere. Deretter spesifiserer vi hvilken .NET version appen skal kjøre på før vi kaller på de vanlige dotnet kommandoene for restore, build og publish.
  • Til slutt deployer vi artifakten fra forrige steg til Azure.

For mer info, sjekk ut dokumentasjonen til Github Actions her.

Applikasjonen kjører nå i Azure og kan finnes under https://myazuresampleapi.azurewebsites.net/weatherforecast og https://myazuresampleapi.azurewebsites.net/swagger.

Slack varsel

En av fordelene ved å bruke GitHub Actions er at det finnes et hav av av Actions man kan benytte seg av på GitHub sitt marketplace. I dette tilfellet har jeg, litt tilfeldig, prøvd simple-slack-notfiy. For å poste til Slack kreves det i tillegg at du har opprettet og installert din egen Slack App på et workspace. For å lære hvordan du lager din egen Slack App finner du en fin oversikt i Slack sin offisielle dokumentasjon. I dette tilfellet har jeg brukt en eksisterende app, derav det ikke helt passende app-navnet.

Det eneste som kreves for å poste til Slack når du har gjort dette er å kopiere ut noe Slack kaller en incoming webhook url. Simple-slack-notify forventer å kunne lese denne fra en miljøvariabel under navnet SLACK_WEBHOOK_URL. I vårt tilfelle legger vi den inn som en secret vi refererer i vår action script.

Helt til slutt legger vi til et nytt step som spesifiserer hvilken Action vi bruker, i tillegg til hvordan meldingene skal se ut på Slack.

env:
...
  SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
...
# Notify on slack
- name: Deploy notification
  if: always()
  uses: adamkdean/simple-slack-notify@master
  with:
    status: ${{ job.status }}
    success_text: 'Deployment (#${env.GITHUB_RUN_NUMBER}) of ${env.AZURE_WEBAPP_NAME} completed successfully'
    failure_text: 'Deployment (#${env.GITHUB_RUN_NUMBER}) of ${env.AZURE_WEBAPP_NAME} failed'
    cancelled_text: 'Deployment (#${env.GITHUB_RUN_NUMBER}) of ${env.AZURE_WEBAPP_NAME} was cancelled'
    fields: |
      [{ "title": "Actor", "value": "${env.GITHUB_ACTOR}"},
      { "title": "Action URL", "value": "${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}"}]

🎉

I denne artikkelen har vi lært hvordan vi kan bruke GitHub Actions til å publisere en applikasjon til Azure. I tillegg har vi sitt på mulighetene GitHub Actions Marketplace gir oss til å bygge på CI/CD pipelinen vår.