Bitbucket pipeline z własnym Docker Image

Programowanie, nawet te dla zabawy, służy rozwiązywaniu problemów. Klepanie kodu dla klepania kodu jest nudne i frustrujące. Zatem jaki ciekawy problem trafił się tym razem?

Jest sobie grupka na fejsbooku, „Wiating”. Służy ona do dzielenia się miejscami odpoczynku na szlakach turystycznych itp. punktami POI. Punktem centralnym jest współdzielona mapa na Google Maps. Sama mapa jest publiczna. Jak ludzie mogą ją edytować, to i mogą przy okazji coś zepsuć, mniej lub bardziej specjalnie. Na usługach Google jest niby jakaś kontrola wersji, ale powodzenia, aby ręcznie porównywać, co się zmieniło. Może zatem robić backup w normalnej kontroli wersji, np. w systemie git?

Atlassian, jakiś czas temu w chmurowej wersji Bitbucket wprowadził usługę „Pipelines”. Jest to bardzo podobne rozwiązanie do Jenkins Pipelines. W repozytorium dodajemy plik, który opisuje budowanie kodu. Można ustawić sobie akcje do wykonania, a potem wywoływać to w cronie (można ustawić sobie dzienny/tygodniowy/miesięczny cykl). Aby zrobić backup publicznej mapy, wystarczy coś takiego:

pipelines:
  custom:
    staging:
    - step:
        script:
        - curl -o map.kmz https://mapsengine.google.com/map/kml?mid={id_mapy}
        - unzip -o map.kmz
        - set +e
        - git add doc.kml
        - git commit -m "Updating repo"
        - git push
        - echo "done"

Flow bardzo prosty, ściągamy plik (KMZ), rozpakowujemy, w środku jest XML w formacie KML. Dodajemy do repo zmiany, koniec.
Set +e jest po to, aby pipeline nie wywalił się, gdy nie ma nic do commitowania (bo np. tego dnia nie było żadnej zmiany na mapie)

Bitbucket oferuje w darmowym planie 50min. miesięcznie na pipelines. Task wykonuje się około 10 sek. Także styknie na kilka buildów na dzień.

No dobrze, mamy backup. Ale w zasadzie czym są te polecenia i czemu mam dostęp do curla, unzipa i gita? Otóż wszystkie polecenia są wykonywane w kontekście obrazu dockerowego, domyślnie Ubuntu z dodanymi paroma programami. No dobrze, a czy można użyć własnego obrazu docker? Oczywiście!

Mapę i tak co jakiś czas konwertuje na format zgodny z naręcznym GPS Garmina. Jeśli robię to ręcznie, to czemu nie podpiąć tego pod automat? Egzotyczny format GPI, w programie GPSBabel jest jego obsługa. Dochodzi jeden problem. Parę lat temu, program okrojono o obsługę kodowań, więc polskich znaczków w pliku GPI nie zobaczymy. Twórcy nie kwapią się z przywróceniem ich obsługi. Na szczęście, w świecie Opensource, gdy nie zgadzamy się z decyzjami projektowymi, robimy forka.

A pomysł na obraz? Wziąłem go stąd i ulepszyłem.

FROM alpine:latest

RUN	apk add --no-cache \
	--update \
	alpine-sdk \
	sed \
	gperf \
	qt5-qtbase \
	qt5-qttools-dev \
	git \
	&& git clone https://github.com/globalbus/gpsbabel.git gpsbabel \
	&& cd gpsbabel \
	&& ./configure --disable-shapefile \
	&& make \
    && make install \
    && cd .. \
    && rm -rf /gpsbabel \
	&& apk del alpine-sdk sed gperf qt5-qttools-dev git
RUN	apk add --no-cache \
	--update \
	git \
	curl
ENTRYPOINT	["/usr/local/bin/gpsbabel"]

Względem pierwowzoru, okroiłem zależności qt5, dodałem klonowanie z własnego forka, a następnie czyszczenie źródeł po zbudowaniu binarki. Zostawianie źródeł programu w obrazach dockerowych jest niestety nagminne. Na koniec musiałem dodać gita i curla, potrzebne mi do reszty funkcjonalności Pipelines.

Takiego Dockerfile nie musimy budować na swoim komputerze! Wystarczy podpiąć repozytorium do konta na DockerHub, a zostanie automatycznie zbudowany i opublikowany. Nice.

Finalnie plik pipelines wygląda tak:

image: jfilipski/gpsbabel:latest

pipelines:
  custom:
    staging:
    - step:
        name: Download and update
        script:
        - curl -o map.kmz https://mapsengine.google.com/map/kml?mid={id_mapy}
        - unzip -o map.kmz
        - set +e
        - git add doc.kml
        - git commit -m "Updating repo"
        - git push
        - echo "done"
    - step:
        name: Update downloads section
        script:
        - gpsbabel -i kml -o gpx doc.kml map.gpx
        - gpsbabel -w -i kml -f doc.kml -o garmin_gpi,bitmap=wiatki.bmp,category="Wiating",descr=0,position=0,unique=1,writecodec=windows-1250 -F map.gpi
        - curl -X POST "https://${BB_AUTH_STRING}@api.bitbucket.org/2.0/repositories/globalbus/wiating/downloads" -F files=@"map.gpx"
        - curl -X POST "https://${BB_AUTH_STRING}@api.bitbucket.org/2.0/repositories/globalbus/wiating/downloads" -F files=@"map.gpi"

Dodała się pierwsza linijka, został wybrany mój obraz z DockerHub, w kontekście którego, zostaną wykonane pozostałe polecenia.
Gpsbabel jest w /usr/local/bin, więc jest dostępny w PATH.
Po zbudowaniu, oba pliki (GPX i GPI) zostają wgrane do sekcji Downloads w repozytorium przez REST API Bitbucketa.

To, co kiedyś wymagało dłubaniny na własnym hostingu, dziś jest dostępne w ledwie kilkunastu linijkach. Dziś nawet do abstrakcyjnie prostych rzeczy, budowanie automatu na narzędziach CI jest bardzo proste. Oczywiście ten PoC nie jest doskonały, pliki wgrywają się niezależnie od tego, czy są zmiany w KML, czy też nie. Można by też tagować je wersjami itd.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *