Darmowy Continuous Deployment dla Haskella
Po zakończeniu pisania pierwszej aplikacji w Haskellu nadszedł czas na przygotowanie automatyzacji budowania i publikowania jej kolejnych wersji. Po zapoznaniu się z dostępnymi możliwościami postanowiłem postawić na tandem składający się z GitLaba oraz nieznanej mi wcześniej platformy Fly.io. Był to strzał w dziesiątkę, szczególnie że dla mniejszych, hobbistycznych projektów jest to zupełnie darmowe.
Co dostajemy w wersji darmowej?
Zanim przejdziesz dalej, warto sprawdzić, czy te narzędzia spełniają twoje wymagania. Oto krótkie podsumowanie kwestii istotnych dla tego artykułu:
- GitLab (link do szczegółów) - rozbudowana platforma przeznaczona do rozwoju oprogramowania. Pozwala na założenie nieograniczonej liczby publicznych oraz prywatnych repozytoriów. Wersja darmowa umożliwia uruchomienie zadań CI/CD trwających do 2000 minut na miesiąc.
- Fly.io (link do szczegółów) - platforma umożliwiająca uruchamianie aplikacji jak najbliżej użytkownika końcowego (tzw. location-smart). Każde konto dostaje co miesiąc 10 dolarów, które można wykorzystać na dowolne usługi. Jest to kwota, która pozwala uruchamiać i utrzymywać przy działaniu małe aplikacje.
Przygotowanie Dockerfile
Aby opublikować naszą aplikację, musimy ją zdokeryzować. W tym celu utworzmy plik Dockerfile
. Całość zbudujemy na podstawie obrazu phadej/ghc, który zawiera już w sobie GHC oraz cabala. Do wyboru dostajemy obrazy oparte na Debianie lub Ubuntu wraz z różnymi wersjami GHC. Mam sentyment do Debiana, więc wybrałem obraz na podstawie jego stabilnej, odchudzonej wersji (ok. 300 MB) - phadej/ghc:8.10.2-buster-slim
. Zakładając, że nasza aplikacja nazywa się foobar
oraz nasłuchuje na porcie 8080
, całość będzie wyglądać następująco:
FROM phadej/ghc:8.10.2-buster-slim
WORKDIR /usr/src/app
COPY . .
RUN cabal update
RUN cabal build foobar
EXPOSE 8080
CMD ["cabal", "run", "foobar"]
Konfiguracja Fly.io
Żeby rozpocząć naszą przygodę z platformą Fly.io potrzebne będzie nam narzędzie flyctl
. Jego instalacja jest banalna i sprowadza się do uruchomienia jednej komendy, niezależnie od systemu operacyjnego. Listę tych komend znajdziesz w oficjalnej dokumentacji.
Po zainstalowaniu flyctl
należy założyć konto
flyctl auth signup
lub zalogować się za pomocą komendy
flyctl auth login
Następnie przechodzimy do katalogu z naszym projektem. Aby dodać nową aplikację do Fly.io oraz wygenerować plik fly.toml
wystarczy wykonać polecenie:
flyctl auth init
Na początku flyctl
zada nam dwa pytania: o nazwę aplikacji oraz grupę, do której ma należeć (domyślnie zaznaczona jest nasza “prywatna grupa”). Następnie będziemy mogli wybrać builder. Niestety żadna z opcji nie pozwala na zbudowanie aplikacji napisanej w Haskellu, więc zostawiamy None (Do not set a builder). Ostatnie pytanie dotyczy portu, na którym nasłuchuje nasza aplikacja. To właśnie na ten port kierowany będzie ruch z zewnątrz.
? App Name (leave blank to use an auto-generated name)
? Select organization: Wojciech Sołtysiak (wojciech-soltysiak)
? Select builder: None
(Do not set a builder)
? Select Internal Port: 8080
New app created
Name = foobar
Owner = wojciech-soltysiak
Version = 0
Status =
Hostname = <empty>
Przygotowanie .gitlab-ci.yml
Nadszedł czas na przygotowanie konfiguracji dla GitLaba. Żeby poprawnie umieścić naszą aplikację na platformie Fly.io, nasz runner musi:
- Pobrać i uruchomić narzędzie
flyctl
. Aby to zrobić, wystarczy doinstalowanie zwykłegocurla
. - Zbudować obraz. W tym celu nasz pipeline uruchomimy na obrazie
docker:stable
wraz z usługądocker:dind
(przy okazji polecam ten artykuł wyjaśniąjący działanie Docker in Docker).
Konfiguracja dla automatycznego deploya na Fly.io dla każdej zmiany na branchu master wygląda następująco:
image: docker:stable
services:
- docker:dind
stages:
- deploy
fly_deploy:
stage: deploy
before_script:
- apk add curl
- curl -L https://fly.io/install.sh | sh
- export FLYCTL_INSTALL="/root/.fly"
- export PATH="$FLYCTL_INSTALL/bin:$PATH"
script:
- flyctl deploy
only:
- /^master$/
Pozyskanie tokena i wstawienie go do GitLaba
Ostatnim krokiem jest pozyskanie tokena potrzebnego do uwierzytelnienia podczas wywołania flyctl deploy
na runnerze. Wystarczy wykonać następującą komendę:
flyctl auth token
W odpowiedzi dostaniemy nasz token. Kopiujemy go i wstawiamy do GitLaba (Nasz projekt → Settings → CI/CD → Variables) pod nazwą FLY_API_TOKEN
. Warto go zabezpieczyć i zaznaczyć opcje Protect variable oraz Mask variable. Dzięki temu mamy pewność, że token nie wycieknie w logach oraz pojawi się tylko na tagach i branchach oznaczonych jako protected.
Podsumowanie
Opisana wyżej konfiguracja CD została już kilkukrotnie przetestowana w boju i sprawdza się bardzo dobrze. Jedynym minusem (niezależnym od GitLaba i Fly.io) jest długi czas budowania aplikacji. Od wrzucenia zmian na mastera do odpowiadającej aplikacji mija czasami nawet 35 minut. Ponoć przejście na stacka potrafi znacząco skrócić czas budowania aplikacji, ale jeszcze nie miałem okazji tego sprawdzić. Mam nadzieję, że połączenie GitLaba z Fly.io Cię zainteresowało i wykorzystasz je przy swoim kolejnym projekcie.