/ 18.11.2024
Dynamiczny rozwój urządzeń IoT dzisiaj nikogo nie dziwi, jednak wraz z nim wzrasta zapotrzebowanie na wydajne i niezawodne oprogramowanie. W tym celu niezbędne jest posiadanie sprawnego procesu rozwoju, który umożliwi szybsze wprowadzenie produktu na rynek i zapewnienie mu wysokiej jakości. Jak to uzyskać? Odpowiedzią jest Yocto Project i konteneryzacja w Docker.
Linux obecnie jest popularnym wyborem dla systemów wbudowanych ze względu na wysoką niezawodność i dostępność kodu źródłowego. Jednak rozwój takiego systemu okazuje się prawdziwym wyzwaniem ze względu na ograniczone zasoby, wymagania optymalizacyjne oraz trudny próg wejścia.
Doświadczeni programiści pracujący w ramach rozwoju systemów wbudowanych nie tylko muszą dogłębnie rozumieć jądro Linux’a, sterowniki urządzeń i programowanie niskopoziomowe, ale także posiadać wiedzę na temat architektury sprzętu i systemów operacyjnych czasu rzeczywistego. Ta wszechstronna wiedza pozwala im radzić sobie z wyzwaniami związanymi z tworzeniem oprogramowania dla urządzeń o ograniczonych zasobach.
Spis treści
Dlaczego rozwój oprogramowania do systemów wbudowanych jest wyzwaniem?
Jednym z kluczowych aspektów usprawniania procesów rozwoju jest efektywne wykorzystanie dostępnych zasobów. Ponieważ systemy wbudowane często mają ograniczone zasoby pamięci, mocy obliczeniowej, programiści muszą starannie zarządzać pamięcią, wykorzystaniem procesora i zużyciem energii. Wiąże się to z optymalizacją kodu, wykorzystaniem wydajnych algorytmów i technik akceleracji sprzętowej. Usprawniając te procesy, deweloperzy mogą wydatnie zwiększyć wydajność swojego oprogramowania przy jednoczesnym zminimalizowaniu wykorzystania zasobów.
Kolejnym ważnym aspektem usprawniania procesów deweloperskich jest odpowiednie wykorzystanie systemów kontroli wersji i narzędzi do współpracy. Narzędzia te umożliwiają deweloperom płynną współpracę, śledzenie zmian i skuteczne rozwiązywanie konfliktów. Przyjmując najlepsze praktyki w zakresie kontroli wersji i współpracy, zespoły programistyczne mogą zapewnić płynną koordynację i zminimalizować ryzyko błędów lub konfliktów kodu.
W tym artykule omówimy jeden ze sposobów usprawnienia rozwoju systemu wbudowanego przy użyciu YP i kontenerów Docker.
Czym jest Yocto Project?
Yocto Project to projekt współpracy typu open-source, który zapewnia szablony, narzędzia i metody do tworzenia niestandardowych dystrybucji Linuksa dla systemów wbudowanych takich jak urządzenia IoT, smartfony, tablety, urządzenia oparte na ekranach dotykowych itp. niezależnie od architektury sprzętowej. Zazwyczaj możesz stworzyć dystrybucję dla swojego Raspberry Pi, nawet dla Arduino UNO.
Według niedawnej ankiety przeprowadzonej przez Eclipse Foundation, z Yocto korzysta71% respondentów, którzy stosują go budowaniu customowych dystrybucji dla systemów wbudowanych.
Dzięki Yocto Project programisci maja dostep do recept ktore to z kolei umozliwiaja w latwy i szybki sposob instalacje oprogramowania w stworzonej przez nas dystrybucji. Malo tego, pisanie recept jest tak trywialne ze bardzo latwo sie dodaje nowe oprogramowanie. które umożliwiają im tworzenie dedykowanych dystrybucji Linux’a, zoptymalizowanych pod kątem docelowego sprzętu. Niezależnie od tego, czy jest to małe urządzenie IoT, czy złożony przemysłowy system sterowania, projekt Yocto zapewnia elastyczność i skalowalność potrzebną do spełnienia unikalnych wymagań każdego systemu wbudowanego.
Korzyści stosowania Yocto w systemach wbudowanych Linuxa
Yocto upraszcza proces tworzenia i utrzymywania dystrybucji Linuksa dostosowanych specjalnie do systemów wbudowanych.
Do głównych zalet Yocto należy kilka czynników, m.in.:
1. Yocto umożliwia programistom tworzenie ustandaryzowanego i powtarzalnego środowiska kompilacji, zapewniając spójne wyniki na różnych platformach sprzętowych
Yocto używa framework Openembedded jako swojego systemu cross-kompilacji.
Jest on oparty o BitBake’a , który funkcjonuje jak menadżer pakietów, czyli czyta recepty i zajmuje się instalacja pakietów. Pozwala programistom zdefiniować komponenty oprogramowania i konfiguracje wymagane dla ich wbudowanej dystrybucji Linuksa. Automatycznie pobiera niezbędny kod źródłowy, stosuje poprawki i kompiluje oprogramowanie, w wyniku czego powstaje kompletny obraz Linuksa gotowy do wdrożenia na docelowym sprzęcie. Jest to szczególnie ważne w dziedzinie systemów wbudowanych, gdzie konfiguracje sprzętowe mogą się znacznie różnić.
2. Yocto zapewnia architekturę opartą na warstwach (meta layers), która pozwala na łatwe dostosowywanie i integrację komponentów oprogramowania.
Programiści mogą dodawać lub usuwać warstwy w celu włączenia lub wyłączenia określonych funkcji, co ułatwia dostosowanie dystrybucji Linuksa do wymagań systemu docelowego. Ta elastyczność zapewnia, że wynikowy system jest zoptymalizowany.
3. Oferuje szeroką gamę gotowych receptur, znacznie skracając czas i wysiłek wymagany do integracji oprogramowania.
Receptury, które są przepisami na instalacje pakietów, są utrzymywane przez społeczność projektu YP i obejmują wiele komponentów oprogramowania powszechnie stosowanych w systemach wbudowanych. Narzędzia te obejmują menedżera pakietów do zarządzania komponentami oprogramowania, zestaw programistyczny (SDK) do wzajemnej kompilacji aplikacji oraz środowisko uruchomieniowe do testowania i debugowania systemu.
Programiści mogą wykorzystać te zasoby, aby szybko dodać funkcjonalność do swojej dystrybucji Linuksa, oszczędzając cenny czas na rozwój.
Czym są kontenery Docker?
Konteneryzacja to technika, która pozwala programistom spakować aplikację i jej zależności do jednego kontenera, zapewniając, że aplikacja będzie działać w ten sam sposób w każdym środowisku, w którym zostanie wdrożona. Technologia Dockera jest wyjątkowa, ponieważ skupia się na wymaganiach programistów i operatorów systemów, aby oddzielić zależności aplikacji od infrastruktury. Pozwala to na spójne i przewidywalne wdrażanie na różnych platformach i środowiskach, zmniejszając ryzyko błędów i przestojów
Kontenery Docker oferują kilka korzyści dla rozwoju oprogramowania:
1. Zapewniają spójne i powtarzalne środowisko
Kontenery Docker eliminują problem „to działa tylko na moim sprzęcie”. Programiści mogą utworzyć obraz kontenera, który zawiera całe środowisko programistyczne, w tym biblioteki, narzędzia i zależności. Obraz ten może być udostępniany innym członkom zespołu, zapewniając spójność w całym cyklu rozwoju.
2. Ułatwiają współpracę między członkami zespołu
Programiści mogą udostępniać obrazy kontenerów za pośrednictwem rejestru kontenerów, umożliwiając innym szybkie replikowanie środowiska programistycznego. Promuje to kulturę DevOps, w której rozwój, testowanie i wdrażanie odbywają się płynnie.
Połączenie Yocto i Docker’a – dlaczego świetnie się sprawdza?
Używanie Dockera do budowania wlasnych dystrybucji przy uzyciu YP przynosi wiele korzyści. Dzięki hermetyzacji środowiska kompilacji w kontenerze Docker, deweloperzy mogą zapewnić powtarzalność na różnych maszynach i systemach operacyjnych. Eliminuje to potrzebę ręcznego konfigurowania środowiska kompilacji i zmniejsza ryzyko niespójności i błędów.
Jak Docker rozwiązuje problemy tradycyjnego podejścia?
Zamiast dokumentu instalacyjnego możemy przekazać obraz Dockera naszym współpracownikom. Budując główny system plików tzw. rotfs (root file system), uruchamiamy kontener dockerowy (docker-composer), a w nim dopiero uruchamiamy bitbake. Kontener dockerowy gwarantuje, że kompilacje naszej dystrybucji przy użyciu YP będą wykonywane przez wszystkich w dokładnie tym samym środowisku wykonawczym. YP ma posiada reproducibility tests mające na celu stworzenie całkowicie powtarzalnych wersji. Oznacza to, jeśli uruchomisz kompilację dzisiaj, a następnie uruchomisz tę samą konfigurację X razy w przyszłości, pliki binarne, które otrzymasz z kompilacji, powinny być binarnie identyczne. Przeprowadzając upstream w celu zachowania powtarzalności po każdej zmianie te testów, bez względu na to jakie patche dodasz do kodu BitBake lub warstwy OpenEmbedded czy innych pomniejszych warstw jak meta-python, za każdym razem otrzymasz taki sam wynik kompilacji.
Dzięki zastosowaniu YP sytuacja nie zmieni się nawet za kilka lat, kiedy na naszych komputerach będziemy mieli nowsze wersje Linuksa lub kiedy z zespołu odejdą eksperci od kompilacji, będziemy w stanie odtworzyć dokładnie ten sam obraz Linuksa, który zbudowaliśmy trzy lub pięć lat wcześniej.
Jest to możliwe, ponieważ Docker umożliwia powrót do wcześniej zamrożonego kodu i gdy okaże się, że na nowych wersjach bibliotek już się nie skompiluje, to wtedy konteneryzacja zapewnia ta właśnie możliwość skompilowania naszego kodu na starych wersjach bibliotek.
Docker sprawia, że konserwacja urządzeń o długiej żywotności produktów jest o wiele łatwiejsza niż przy tradycyjnym podejściu, ponieważ znacząco przyspiesza rozwiązywanie błędów kompilacji.
Najlepsze praktyki wykorzystywane do efektywnego zarządzania kompilacjami YP & Docker
Kluczowe jest przestrzeganie najlepszych praktyk i zachowanie czujności w związku z wersjonowaniem i debugowaniem w środowiskach kontenerowych. Najlepiej korzystać z systemu kontroli wersji i dokładnego testowania.
Poniżej omawiamy kilka przydatnych wskazówek, które wpłyną na skuteczność zarządzania kompilacjami YP & Docker:
1. Stosuj główne zasady konteneryzacji
Zacznij od oficjalnych i minimalnych obrazów bazowych, aby zmniejszyć niepotrzebne koszty ogólne. Wykorzystaj również wieloetapowe kompilacje Docker, aby utrzymać ostateczny rozmiar obrazu na minimalnym poziomie.
2. Wykorzystuj najlepsze praktyki Yocto Project
- Efektywnie organizuj warstwy Yocto oraz regularnie aktualizuj warstwy, aby być na bieżąco z najnowszymi ulepszeniami i poprawkami błędów.
Każda warstwa w YP ma swój odpowiednik dla danej wersji Yocto. Np. Jeśli pracujemy w YP w wersji tag: yocto-4.0.13, tag: 2022-04.13-kirkstone, tag: 2022-04.13 oznacza, że jest to kirkstone w wersji 4.0.13 uruchamiany na obrazie dockerowym . Każda warstwa począwszy od najwazniejszej czyli openembedded-core po pomniejsze jak meta-python itd. musi byc w wersji kirkstone. Natomiast bitbake musi byc w wersji przypisanej do wydania yocto.
- dobrą praktyką w zarządzaniu warstwami jest użycie plików .bbappend, Jeśli pojawia się jakiś błąd w warstwie z zewnątrz, to nie trzeba wstawić zmian w danej warstwie, ale korzystać z bbappend.
3. Buforuj obrazy Docker
Wykorzystuj mechanizm buforowania warstw Docker w celu przyspieszenia kolejnych kompilacji poprzez ponowne wykorzystanie warstw pośrednich (Leverage Docker Layer Caching). Każda z zależności powinna być buforowana oddzielnie, aby uniknąć niepotrzebnego ponownego pobierania i przebudowywania podczas iteracyjnego rozwoju.
4. Optymalizuj Yocto
- Dostosuj liczbę równoległych zadań kompilacji (np. make -jX) w oparciu o dostępne zasoby systemowe, aby przyspieszyć kompilacje Yocto.
- SSTATE Cache: Skonfiguruj i wykorzystaj pamięć podręczną stanu współdzielonego (SSTATE) do przechowywania pośrednich artefaktów kompilacji dzięki czemu przyśpieszysz znacznie proces.
5. Twórz obrazy wybiórczo
W przypadku opracowywania określonego celu, buduj selektywnie tylko te obrazy i komponenty, które są niezbędne, aby zaoszczędzić czas i zasoby. Wykorzystaj zmienne środowiskowe BitBake do kontrolowania, jakie paczki mają się zainstalować na naszym obrazie naszej dystrybucji.
6. Dbaj o monitorowanie i rejestrowanie
Regularne profilowanie i monitorowanie czasu kompilacji jest niezbędne w celu identyfikacji wąskich gardeł i optymalizacji zadań wymagających dużej ilości zasobów. Istotne jest również szczegółowe rejestrowanie podczas procesu kompilacji, aby pomóc w debugowaniu i identyfikowaniu problemów.
7. Integracja kontroli wersji
Jeśli używasz warstw Yocto z repozytoriów Git, rozważ użycie submodułów Git, aby efektywniej zarządzać zależnościami. Przechowuj również konfiguracje środowiska Yocto w systemie kontroli wersji, aby zapewnić powtarzalność w różnych środowiskach programistycznych.
Potencjalne wyzwania podczas kompilacji Yocto z Dockerem
Chociaż połączenie Yocto i Dockera oferuje znaczące korzyści, istnieją również wyzwania, przed którymi mogą stanąć deweloperzy. Jednym z typowych wyzwań jest rozmiar wynikowego obrazu Docker, który może być dość duży ze względu na włączenie zależności, sam proces kompilacji już powoduje olbrzymi narzut. Przykładowo mały program, którego kod zajmuje 10 MiB może utworzyć kod przejściowy dla linkera, czyli tzw. object file itd. który zajmie 500 MB, aby potem plik wykonywalny zajął 1 MB. Można jednak temu zaradzić, stosując wieloetapowe kompilacje i techniki optymalizacji obrazu w celu zmniejszenia ostatecznego rozmiaru obrazu Docker.
Do innych wyzwań należą m.in:
- Konflikty między recepturami, które mogą spowodować niepowodzenie kompilacji.
- Upewnienie się, że plik Dockerfile jest zoptymalizowany pod kątem wydajności i wykorzystania zasobów.
- Zarządzanie zależnościami i integracją warstw w kontenerach Docker podczas pracy z Yocto może być trudne.
- Zadbanie o powtarzalność i spójności kompilacji Yocto w różnych środowiskach.
Aby sprostać tym wyzwaniom, ważne jest, aby wybrać kompatybilny obraz bazowy oraz bezpiecznie instalować wymagane pakiety, dodawać warstwy Yocto i ostrożnie korzystać z równoległych i przyrostowych kompilacji. Ponadto ważne jest, aby podczas developmentu przestrzegać najlepszych praktyk zarządzania zależnościami i integracją warstw w kontenerach Docker.
Podsumowanie
W przypadku rozwoju wbudowanego systemu Linux, aby skutecznie zapewnić powtarzalne kompilacje i konfiguracje najlepiej używać w pełni konteneryzowanego środowiska programistycznego. Dzięki temu możesz równolegle pracować nad wieloma projektami o różnych wymaganiach konfiguracyjnych na tej samej maszynie. Ponadto dockeryzacja środowiska programistycznego pozwala nam utrzymać czystość w systemie i nie obciążać go pakietami specyficznymi dla danego projektu.
Jeśli chciałbyś porozmawiać o doświadczeniu specjalistów w VM.PL w projektach systemów wbudowanych, skontaktuj się z nami. Chętnie doradzimy w doborze odpowiednich rozwiązań.
Źródła: