Github Action Runners
Sjekk Github's dokumentasjon for Github Actions: https://docs.github.com/en/actions/about-github-actions/understanding-github-actions
Før bestilling
Når man bestiller en runner for en organisasjon under UiO-IT er det krav til alle brukere må signere commits med en personlig SSH eller GPG-nøkkel. Merk at GPG-signering via web-interfacet til Github er ikke mulig, da vi har slått av muligheten for at Github-serveren kan signere vår kode.
For hvordan du setter opp 2-faktor og GPG/SSH-signering se dokumentasjonen her: Github for IT-ansatte
Bestilling av server til å kjøre github runnere
Om man jobber på UiO-IT så kan man bestille egen server i virtprov, Den skal ha navn gh-runner-$RUNNERSERVER.uio.no. hvor $RUNNERSERVER er organisasjonsnavn og ev. et tall. Når det er på plass, sender man en epost til github-support@usit.uio.no med navn på den nye serveren, og hvilken organisasjonen den skal legges inn, så tar vi oss av resten av oppsettet. Om man har spesielle behov, som at flere organisasjoner skal ha tilgang til runneren, at det ikke skal være krav om signering av commits, e.l. så er det greit å spesifisere dette. github-support vil vurdere hvorvidt vi mener at dette er unntak som kan gjøres fra vårt ordinære opplegg.
Om man ikke har tilgang til virtprov kan man bestille en server til dette formålet via dette nettskjemaet Virtuell Server
Legge til nøkler på en Github Actions runner-server
På våre Github Actions runnere, er det satt opp et script som sjekker hvorvidt en commit er signert med en kjent og gyldig SSH/GPG-nøkkel før Actions-jobber kjører. Om jobben ikke er signert med en kjent SSH/GPG-nøkkel, vil den feile. Løsningen da er at man importerer inn ens public SSH/GPG-nøkkel på runnerns SSH/GPG-store.
Legge til SSH-nøkler til Github Actions runners
Nøklene blir lagret i fila gh-runner-$RUNNERSERVER.uio.no:/opt/gh-runner-gpg/ssh_allowed_signers. Alle eiere av en slik runner har tilgang til serveren med deres driftsbruker, og kan importere inn de SSH-nøklene som trengs.
Først kopier ut din public key delen av din SSH-nøkkel til github actions runner serveren:
cat ~/.ssh/id_ed25519.pub | ssh bruker-drift@gh-runner-$RUNNERSERVER.uio.no "cat >> /tmp/brukernanv.pub"
Deretter logg på serveren med din driftsbruker og kjør følgende kommando for å importere inn nøkkelen du nå har og legg til epost som du har satt i din gitconfig:
sudo /opt/gh-runner-scripts/ssh-key-import.sh /tmp/brukernavn.pub dinbruker@uio.no
Du skal nå være klar for å bruke commits signert med ditt SSH-nøkkelpar.
Legge til GPG-nøkler til Github Actions runners
Nøklene ligger lagret under gh-runner-$RUNNERSERVER.uio.no:/opt/gh-runner-gpg/pubring.kbx. Alle eiere av en slik runner har tilgang til serveren med deres driftsbruker, og kan importere inn de GPG-nøklene som trengs.
Først hent ut og last opp GPG-nøkkelen:
gpg --armor --export dinepost@usit.uio.no| ssh -J bruker@login.uio.no bruker-drift@gh-runner-$RUNNERSERVER.uio.no "cat > ~/brukernavn.asc"
Deretter logg på serveren med din driftsbruker og kjør følgende kommando for å imnportere inn nøkkelen du nå har lastet opp:
ssh -J bruker@login.uio.no bruker-drift@gh-runner-$RUNNERSERVER.uio.no
sudo /opt/gh-runner-scripts/gpg-key-import.sh ~/brukernavn.asc
Etter dette kan du enten lage en ny commit, eller trigge en re-run av jobben i Github Actions-fanen tilhørende repoet ditt.
Hvordan bruke Github Actions
Github Actions består av to komponenter som spiller sammen. Den første brikken er at man trenger en runner som skal utføre jobbene, den andre er en eller flere workflow-filer som beskriver hva jobbene skal gjøre. Runneren kjører under en vanlig bruker uten sudo-rettigheter på din RHEL9-VM, som betyr at om du trenger noen pakker installert fra Yum, så bør det utføres med root på maskina, evt med din driftsbruker om den har sudo-rettigheter.
Workflow-filene skrives i YAML, og en helt enkel workflow ser slik ut:
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: [ self-hosted ]
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
# Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world!
# Runs a set of commands using the runners shell
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.
For de fleste bruksområder så holder det å sjekke ut filene i et repo, og så utføre noe arbeid på filene som blir sjekket ut, og det gjør man som beskrevet over med en action kalt checkout. Github sin offisielle dokumentasjon innholder en god del tutorials for hvordan man både skriver workflows og eksempler på hvordan man bruker actions for kompilering av kode etc. Se her for mer informasjon:
Quickstart for GitHub Actions
Use cases and examples
Det er verdt å merke seg et par viktige begrensinger når man følger guider fra nettet, og det er at for det første så vil kun actions som er tilgjengelig i våre interne Github fungere med github.uio.no.[1] Årsaken til dette er at de forutsetter at man både har internett og at runneren kjører på Ubuntu. Da alle våre runners kjører på RHEL og ligger på et nett uten tilgang til internett, så vil disse feile. Og man bør alltid sette runs-on til å være lik enten self-hosted, eller et av labels som er satt for ens runner. For nesten alle organisasjoner så er det følgende labels som er tilgjengelig:
self-hosted
Linux
X64
I tillegg kan man bruke navnet på runneren, om man f.eks har konfigurert flere runners på flere VMer, og det er forskjellige utvalg av verktøy, så kan det være lurt å "hardkode" til en gitt runner.
Unngå å bruk Docker i workflows, da det kun er Podman som er installert på våre runners, og Github Actions per nå støtter ikke Podman. Så hvis du finner et eksempel som bruker syntaksen container: så vil det feile, fordi Docker ikke er tilgjengelig. Det finnes en workaround for å få dette til å fungere med Podman, men det er nok bedre å heller bruke Podman direkte med Run-kommandoen, se eksempel nedenfor for hvordan man gjør det.
[1] Hvis man besøker [actions org] (https://github.uio.no/actions) så vil man se listen over hvilke som er tilgjengelig. Og innenfor disse så funker alle bortsett fra følgende:
- setup-python
- setup-go
- setup-node
- setup-java
- setup-dotnet
I tillegg har vil en liste med egenutvikla actions under IT-GITHUB-ACTIONS, og det er også mulig å skrive egne actions som man kan tilgjengeligjøre innenfor egen organisasjon, og om man vil, for hele github.uio.no. Se følgende lenke for hvordan man utvikler egne actions: Create an action
Og sist men ikke minst, våre runners er lengekjørende, så miljøet blir ikke nullstilt etter en jobb, så unngå å gjøre endringer på OS/mapper utenfor arbeidsområdet til en workflow job, da de endringene fortsatt vil være der neste gang en jobb kjører. Om du trenger å gjøre den type endringer, er det nok best å kjøre testene dine i en container som du starter via Workflow-filen. Se eksempel under for hvordan man bruker Podman.
Hvordan håndtere hemmeligheter
Hvis man har en workflow som trenger hemmeligheter, så skal man ikke bruke Github Secrets. Istedenfor bruker man en action kalt Uio Secrets Action. Se repoet til actionen for hvordan man tar den i bruk. Den forutsetter at man har lagret ens hemmeligheter i en JSON-strukturert fil under /etc/uio-gh-runner/secrets.json.
Hvordan bruke Podman i workflows
Hvis man f.eks skal bygge et container image, og man har en Containerfile-fil i repoet som man vil bygge fra, så kan man bruke podman i en workflow-fil slik:
- name: Set build tag
id: tag
run: echo "value=${GITHUB_REPOSITORY#*/}_${{ github.sha }}_${{ github.run_id }}_${{ github.run_attempt }}" >> $GITHUB_OUTPUT
- name: Build container image
run: >
podman build
--file Containerfile
--tag "${{ steps.tag.outputs.value }}"
.
Dette vil starte en byggejobb, og tagge den med en rekke verdier satt i Set build tag-jobben, som kjører før imaget blir bygget.
Merk at man bør ha en ukentlig cronjobb som kjører og pruner eksisterende images, så ikke hjemmeområdet til runneren fyller seg opp og går fullt. Se eksmepel under her for hvordan det kan gjøres:
name: Container cleanup
on:
schedule:
- cron: "01 00 * * 0" # Sundays at 00:01
jobs:
cleanup:
name: Clean the GitHub Runner's containers store
runs-on: self-hosted
steps:
- name: "Buildah: Remove working containers"
run: buildah rm --all
if: ${{ !cancelled() }}
- name: "Podman: remove all unused pods, containers, images and networks"
run: podman system prune --filter=until=24h --all --force
if: ${{ !cancelled() }}
- name: "Prune podman volumes"
run: podman volume prune -f
if: ${{ !cancelled() }}
continue-on-error: true