Niedawno wspomniałem jak refaktoryzowałem skrypt który utrzymywał mój profil GitHub aktualne. Od Geecon Prague jestem również szczęśliwym posiadaczem Raspberry Pi:
Chociaż obecna konfiguracja działa bezbłędnie – i jest darmowa, chciałem poeksperymentować z samodzielnie hostowanymi runnerami. Oto moje odkrycia.
Kontekst
GitHub oferuje duże bezpłatne korzystanie z GitHub Actions:
Korzystanie z GitHub Actions jest bezpłatne dla standardowych runnerów hostowanych przez GitHub w repozytoriach publicznych oraz dla runnerów hostowanych samodzielnie. W przypadku repozytoriów prywatnych każde konto GitHub otrzymuje określoną ilość bezpłatnych minut i przestrzeni dyskowej do wykorzystania z runnerami hostowanymi przez GitHub, w zależności od planu konta. Wszelkie użycie wykraczające poza uwzględnione kwoty jest kontrolowane przez limity wydatków.
Jednak polityka ta może łatwo zmienić się jutro. Polityka bezpłatnego poziomu wykazuje regularną tendencję do zmniejszania się, gdy:
- Wystarczająco duży odsetek użytkowników korzysta z produktu, lock-in
- Akcjonariusze chcą większych przychodów
- Nowy dyrektor finansowy postanawia obniżyć koszty
- Globalna gospodarka kurczy się
- Połączenie powyższych czynników
Ostrzeżony jest uzbrojony. Lubię wypróbować różne opcje, zanim będę musiał wybrać jedną z nich. Przykład: co jeśli będę musiał przeprowadzić migrację?
Teoria
Akcje GitHub składają się z dwóch komponentów:
- Sama infrastruktura GitHub Actions.
Obsługuje harmonogram zadań. - Biegacze, którzy uruchamiają zadania
Domyślnie zadania są uruchamiane na serwerach GitHub. Możliwe jest jednak skonfigurowanie zadania tak, aby działało na innych serwerach, zarówno lokalnych, jak i w chmurze: są one nazywane self-hosted runners.
The dokumentacja dotycząca tworzenia samodzielnie hostowanych runnerów zawiera wszystkie niezbędne informacje do ich zbudowania, więc nie będę jej parafrazował.
Zauważyłem jednak dwa nietrywialne problemy. Po pierwsze, jeśli mają Państwo zadania w różnych repozytoriach, to proszę skonfigurować zadanie dla każdego repozytorium. Grupy runnerów są dostępne tylko dla repozytoriów organizacji. Ponieważ większość moich repozytoriów zależy od mojego zwykłego konta, nie mogę używać grup. W związku z tym należy zduplikować pakiet każdego repozytorium na Pi runnera.
Ponadto nie ma dedykowanego pakietu: trzeba rozpakować archiwum. Oznacza to, że nie ma możliwości łatwej aktualizacji wersji runnera.
Biorąc to pod uwagę, spodziewałem się, że migracja będzie trwała jedną linię:
jobs:
update:
#runs-on: ubuntu-latest
runs-on: self-hosted
Jest to jednak nieco bardziej skomplikowane. Proszę opisać, jakie kroki musiałem podjąć w moim repozytorium, aby zadanie zadziałało.
Praktyka
GitHub Akcje zależą od Dockera zainstalowanego na runnerze. Z tego powodu myślałem, że zadania działają na dedykowanym obrazie: to po prostu błąd. Cokolwiek skryptuje się w zadaniu, dzieje się w uruchomionym systemie. Przykładowo, początkowy skrypt zainstalował Pythona i Poezję.
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Set up Python 3.x
uses: actions/setup-python@v5
with:
python-version: 3.12
- name: Set up Poetry
uses: abatilo/actions-poetry@v2
with:
poetry-version: 1.7.1
W kontekście tymczasowego kontenera tworzonego podczas każdego uruchomienia ma to sens; w kontekście stabilnego, długo działającego systemu – nie.
Raspbian, domyślny system operacyjny Raspberry, ma już zainstalowany Python 3.11. Dlatego musiałem obniżyć wersję skonfigurowaną w Poezji. To nic wielkiego, ponieważ nie używam żadnej konkretnej funkcji Pythona 3.12.
[tool.poetry.dependencies]
python = "^3.11"
Raspbian zabrania instalacji jakichkolwiek zależności Pythona w środowisku podstawowym, co jest bardzo rozsądnym domyślnym rozwiązaniem. Aby zainstalować Poezję, użyłem zwykłego menedżera pakietów APT:
sudo apt-get install python-poetry
Następnym krokiem była obsługa sekretów. Na GitHubie ustawia się sekrety w GUI i odwołuje się do nich w skryptach za pomocą zmiennych środowiskowych:
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Update README
run: poetry run python src/main.py --live
env:
BLOG_REPO_TOKEN: ${{ secrets.BLOG_REPO_TOKEN }}
YOUTUBE_API_KEY: ${{ secrets.YOUTUBE_API_KEY }}
Pozwala to na segregację poszczególnych kroków, tak aby krok miał dostęp tylko do potrzebnych mu zmiennych środowiskowych. W przypadku samodzielnie hostowanych programów uruchamiających, ustawiają Państwo zmienne środowiskowe w istniejącym pliku .env
wewnątrz folderu.
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Update README
run: poetry run python src/main.py --live
Jeśli chcą Państwo bezpieczniejszej konfiguracji, proszę działać na własną rękę.
Wreszcie, architektura jest oparta na modelu pull. Runner stale sprawdza, czy zadanie jest zaplanowane. Aby uczynić runner usługą, musimy użyć gotowych skryptów wewnątrz folderu runner:
sudo ./svc.sh install
sudo ./svc.sh start
Skrypt używa systemd
pod spodem.
Wnioski
Migracja z runnera GitHub do runnera self-hosted nie jest dużym problemem, ale wymaga zmiany niektórych elementów. Co najważniejsze, należy zrozumieć, że skrypt działa na maszynie. Oznacza to konieczność zautomatyzowania provisioningu nowej maszyny w przypadku awarii. Rozważam korzyści płynące z uruchomienia runnera wewnątrz kontenera na Pi, aby powrócić do poprzednich kroków. Chętnie dowiem się, czy znalazł Pan i wykorzystał takie rozwiązanie. W każdym razie, na razie nie migruję więcej zadań do self-hosted.