GitHub Actions i Package Registry do nauki i projektów

Github dorobił się dwóch istotnych produktów: Actions oraz Package Registry. Actions to wbudowany w Github CI/CD na bazie Azure DevOps. Package Registry to za to rejestr paczek JavaScript (dla npm), Java (Maven), Ruby (RubyGems), .NET (NuGet) oraz Docker images

Do nauki ten zestaw jest przydatny, a do pobocznych projektów wręcz idealny!

Jeśli chcesz się nauczyć Kubernetes od zera, to zapraszam Cię do szkolenia online Poznaj Kubernetes. Można do niego dołączyć do niego tylko od 4 do 15 listopada!

Przejdźmy do praktyki. Skupię się we wpisie na wykorzystaniu aplikacji .NET Core budowanej i hostowanej w kontenerze. Tak naprawdę w tym scenariuszu, można wymienić .NET Core na każdy inny język, z którym można zrobić multi-stage build w Docker np. w golang albo node.js (na koniec wkleję przykłady do tych języków).

Oprócz aplikacji potrzebujemy dwóch plików w repozytorium: Dockerfile oraz definicji w YAML dla Github Actions.

Cały opisywany kod znajduję się w moim repozytorium kaluzaaa/sample-net-core-docker-actions-package-registry.

Dockerfile jak każdy widzi.

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "sample-net-core-docker-actions-package-registry.dll"]

Składa się on z dwóch części. Pierwszy FROM (Build-env) to środowisko odpowiedzialne za budowę aplikacji. Korzysta z ciężkiego obrazu z całym SDK. Za to druga część to lżejszy runtime, do którego jest tylko kopiowana aplikacja z wcześniejszego obrazy - COPY --from=build-env /app/out .. Kiedy budowa się zakończy, wypluty zostanie tylko drugi obraz, a po pierwszym zostaną tylko warstwy w cache.

Drugi plik to definicja w dla Github Actions jak ma zbudować aplikację. Pierwsza istotna rzeczą jest, że definicja musi się znaleźć w repozytorium w katalogu .github/workflows/.

Mój plik nazywa się main.yml i wygląda jak poniżej

name: Main CI

on: [push]

jobs:

  build:

    runs-on: ubuntu-latest
    env:
      APP_NAME: sample

    steps:
    - uses: actions/checkout@v1

    - name: Login to GitHub Package Registry
      run: echo ${{ secrets.GITHUB_TOKEN }} | docker login -u ${GITHUB_ACTOR} --password-stdin docker.pkg.github.com

    - name: Build the Docker image
      run: docker build . --file Dockerfile --tag docker.pkg.github.com/${{ github.repository }}/$APP_NAME:${GITHUB_SHA::7}

    - name: Push the Docker image
      run: docker push docker.pkg.github.com/${{ github.repository }}/$APP_NAME:${GITHUB_SHA::7}

Przejdźmy przez definicje pliku. W sekcji on definiujemy, kiedy ma być wykonywane zadania. W tym wypadku jest to przy każdym commicie. W env znajduje się zmienna APP_NAME wykorzystana do nazwania obrazu kontenera.

Teraz czas na kroki zadania (steps). Pierwszą rzeczą jest actions/checkout@v1, które jak nazwa wskazuje, robi checkout repozytorium. Kolejno potem dzieje się zalogowanie do GitHub Package Registry przez Docker, Budowa obraz oraz na koniec jego wypchnięcie do rejestru.

Do logowania się do rejestru wykorzystane są zmienne (GITHUB_ACTOR) i domyślne secrety (secrets.GITHUB_TOKEN), o których można przeczytać w dokumentacji.

Sam rejestr Docker dla repozytorium znajduję się w ściżce docker.pkg.github.com/<użytkownik Github>/<nazwa repozytorium>/nazwa aplikacji. W CI <użytkownik Github>/<nazwa repozytorium> jest zastąpiony przez już gotową zmienną ${{ github.repository }}, a nazwa aplikacji poprzez zmienną środowiskową.

Kiedy wepchniemy do repozytorium commit z Dockerfile oraz definicją Actions Github automatycznie zbuduję obraz kontenera. Jeżeli chcemy dodać na przykład testy jednostkowe, to możemy zrobić to Dockerfile, ale równie dobrze można rozszerzyć cały piepline o testowanie i budowę poza kontenera, a dopiero na sam koniec zbudować obraz.

W samym Github można zobaczyć stan Actions w portalu

lub przejrzeć dokładnie logi z zadania

Obrazy kontenerów za to można sprawdzić w code -> package

Cały opisywany kod znajduję się w moim repozytorium kaluzaaa/sample-net-core-docker-actions-package-registry.

Dodatkowo obiecane przykłady dla golang oraz node.js(tutaj trochę, więcej filozofii).

Na koniec koszty. Ile to kosztuje? Dla publicznych repozytoriów nic! Dla prywatnych repozytoriów dostajemy 2000 min Actions.

Cennik dla Package Registry jest trochę gorszy. Dla publicznych za darmo jak w Actions. W prywatnych płacimy za wielkość przechowywanych paczek oraz za transfer wychodzący z Github.

W kolejnym wpisie pokażę jak hostować taką aplikację w Kubernetes, ale w wersji do nauki i pobocznych projektów, czyli w cenie jednej lub dwóch kawy latte za miesiąc!

Jeśli chcesz się nauczyć Kubernetes od zera, to zapraszam Cię do szkolenia online Poznaj Kubernetes. Można do niego dołączyć do niego tylko od 4 do 15 listopada!