Mam projekt średniej wielkości, który właśnie zbliża się do końca fazy „niechlujnych prototypów zasilanych kofeiną do pokazów klienckich” i przechodzi w fazę „pomyśl o przyszłości”. Projekt składa się z urządzeń opartych na systemie Linux z oprogramowaniem i oprogramowaniem układowym oraz centralnego administracyjnego serwera WWW. Obecnie istnieje 10 prototypów, oczekuje się, że produkcja będzie rzędu niskich 1000.
Nie będąc dobrze zaznajomionym ze sztuką automatycznych aktualizacji i mając mało czasu, szybko wdrożyłem własną strategię wdrażania / automatycznej aktualizacji oprogramowania i, szczerze mówiąc, jest do bani. Obecnie składa się z następujących elementów:
- Hostowane repozytorium git (GitLab) z gałęzią wydania produkcyjnego (zwróć uwagę, że źródło serwera WWW znajduje się również w tym samym repozytorium, a także w kilku innych rzeczach).
- Przycisk „wdróż aktualizację” w interfejsie internetowym, który:
- Pobiera najnowszą wersję z gałęzi wersji produkcyjnej do lokalnego obszaru repozytorium, a także kopiuje ją do tymczasowego obszaru przygotowywania pakietów.
- Uruchamia skrypt dezynfekujący (przechowywany w repozytorium) w obszarze testowym, aby usunąć niepowiązane pliki źródłowe (np. Źródło serwera, źródło oprogramowania układowego itp.) I pliki .git.
- Zapisuje bieżący hash git do pliku w pakiecie aktualizacji (cel zostanie wyjaśniony poniżej).
- Jeśli wszystko poszło dobrze, zgrywa go i przygotowuje do podania, zastępując poprzedni pakiet gzip plikiem plikiem o tej samej nazwie, a następnie usuwa obszar przejściowy.
- Zauważ, że na serwerze są teraz dwie kopie aktualnego oprogramowania urządzenia, które powinny być zsynchronizowane: pełne lokalne repozytorium git w najnowszej gałęzi produkcyjnej i gotowy do użycia pakiet gzip, który teraz jest reprezentowany ta sama wersja.
- Oprogramowanie na urządzeniu jest zawarte w katalogu o nazwie
/opt/example/current
, który jest dowiązaniem symbolicznym do bieżącej wersji oprogramowania. - Funkcja automatycznej aktualizacji na urządzeniu, która podczas rozruchu:
- Sprawdza obecność
do_not_update
pliku i nie podejmuje żadnych dalszych działań, jeśli istnieje (dla urządzeń deweloperskich, patrz poniżej). - Odczytuje bieżący hash zatwierdzenia z wyżej wspomnianego pliku tekstowego.
- Zgłasza żądanie HTTP do serwera z tym hashem jako parametrem zapytania. Serwer albo odpowie 304 (skrót jest aktualną wersją), albo będzie obsługiwał pakiet aktualizacji gzip.
- Instaluje pakiet aktualizacji, jeśli został odebrany, w
/opt/example
:- Wyodrębnianie zaktualizowanych informacji o oprogramowaniu w folderze o nazwie
stage
. - Uruchamianie skryptu poinstalacyjnego z pakietu aktualizacji, który wykonuje takie czynności, jak wprowadzenie niezbędnych lokalnych zmian dla tej aktualizacji itp.
- Kopiowanie bieżącego folderu głównego oprogramowania do
previous
(previous
najpierw usuwa istniejący folder , jeśli taki istnieje). - Kopiowanie
stage
folderu dolatest
(latest
najpierw usuwa istniejący , jeśli taki istnieje). - Zapewnienie
current
dowiązania symbolicznego do wskazanialatest
. - Ponowne uruchomienie urządzenia (aktualizacje oprogramowania układowego, jeśli są dostępne, są stosowane przy ponownym uruchomieniu).
- Wyodrębnianie zaktualizowanych informacji o oprogramowaniu w folderze o nazwie
- Sprawdza obecność
Istnieje również kwestia początkowego wdrożenia na nowo zbudowanych urządzeniach. Urządzenia są obecnie oparte na karcie SD (ma własny zestaw problemów, poza zakresem tutaj), więc proces ten składa się z:
- Istnieje obraz SD z pewną wcześniejszą stabilną wersją oprogramowania.
- Karta SD jest tworzona z tego obrazu.
- Przy pierwszym uruchomieniu ma miejsce inicjalizacja różnych urządzeń po raz pierwszy (na podstawie numeru seryjnego), a następnie narzędzie do automatycznej aktualizacji pobiera i instaluje najnowszą produkcyjną wersję oprogramowania, jak zwykle.
Dodatkowo potrzebowałem wsparcia dla urządzeń programistycznych. W przypadku urządzeń programistycznych:
- Na urządzeniu jest utrzymywane pełne lokalne repozytorium git.
current
Dowiązanie wskazuje na katalog rozwoju.- Istnieje
do_not_update
plik lokalny , który uniemożliwia automatycznemu aktualizatorowi usunięcie kodu programistycznego za pomocą aktualizacji produkcyjnej.
Teraz teoretycznie proces wdrożenia miał na celu:
- Gdy kod będzie gotowy do wdrożenia, wypchnij go do gałęzi wydania.
- Naciśnij przycisk „Wdróż aktualizację” na serwerze.
- Aktualizacja jest teraz aktywna, a urządzenia automatycznie zaktualizują się przy następnym sprawdzeniu.
Jednak w praktyce istnieje mnóstwo problemów:
- Kod serwera WWW znajduje się w tym samym repozytorium co kod urządzenia, a serwer ma lokalne repozytorium git, z którego wykonuję. Najnowszy kod serwera WWW nie znajduje się w tej samej gałęzi, co najnowszy kod urządzenia. Struktura katalogów jest problematyczna. Gdy przycisk „Wdróż aktualizację” pobiera najnowszą wersję z gałęzi produkcyjnej, ciągnie ją do podkatalogu kodu serwera. Oznacza to, że kiedy wdrażam od zera na serwerze, muszę ręcznie „zainicjować” ten podkatalog, chwytając do niego gałąź produkcji urządzenia, ponieważ prawdopodobnie z powodu błędu użytkownika git z mojej strony, jeśli nie wdrożę, spróbuję ściągnij kod urządzenia z gałęzi serwera WWW katalogu nadrzędnego . Myślę, że można to rozwiązać, sprawiając, że obszar przejściowy nie będzie podkatalogiem lokalnego repozytorium git serwera.
- Serwer sieciowy obecnie nie utrzymuje uporczywie skrótu git oprogramowania urządzenia. Podczas uruchamiania serwera wykonuje
git rev-parse HEAD
repozytorium oprogramowania lokalnego urządzenia, aby pobrać bieżący skrót. Z powodów, dla których nie mogę się obejść, powoduje to również mnóstwo błędów logicznych, których nie będę tutaj opisywać, wystarczy powiedzieć, że czasami restartowanie serwera psuje wszystko, szczególnie jeśli serwer jest zupełnie nowy i nie produkuje repozytorium gałęzi zostało już ściągnięte. Na żądanie chętnie udostępnię źródło tej logiki, ale ten post jest długi. - Jeśli z jakiegoś powodu skrypt dezynfekcji (po stronie serwera) zawiedzie, serwer
git rev-parse HEAD
otrzyma aktualne repozytorium, ale pakiet synchronizacji / brak aktualizacji, zwróci skrót, który nie pasuje do tego, co faktycznie jest podawane na urządzenia, a problemy tutaj muszą zostać naprawione ręcznie w wierszu polecenia serwera. Tzn. Serwer nie wie, że pakiet aktualizacji jest niepoprawny, po prostu zawsze zakłada to z czystą wiarą. W połączeniu z poprzednimi punktami serwer jest wyjątkowo kruchy w praktyce. - Jednym z największych problemów jest : Obecnie na urządzeniu nie działa osobny demon aktualizacji. Z powodu komplikacji związanych z oczekiwaniem na dostęp do Internetu Wi-Fi i niektórych hakerów w ostatniej chwili jest to główne oprogramowanie do kontroli urządzenia, które sprawdza i aktualizuje urządzenie. Oznacza to, że jeśli w jakiś sposób źle przetestowana wersja wprowadzi ją do produkcji, a oprogramowanie sterujące nie może się uruchomić, wszystkie istniejące urządzenia są zasadniczo zepsute, ponieważ nie mogą się już same aktualizować. Byłby to absolutny koszmar w produkcji. Taka sama oferta dla jednego urządzenia, jeśli straci moc w nieszczęśliwym czasie.
- Drugi poważny problem to : Brak obsługi aktualizacji przyrostowych. Jeśli urządzenie, powiedzmy, nie jest włączone przez jakiś czas, to przy następnej aktualizacji pomija kilka wersji wydań, musi być w stanie wykonać bezpośrednią aktualizację pomijającą wersję. Konsekwencją tego zaktualizowanego wdrożenia jest koszmar upewnienia się, że daną aktualizację można zastosować do dowolnej poprzedniej wersji. Ponadto, ponieważ skróty git są używane do identyfikacji wersji, a nie numerów wersji, porównanie leksykograficzne wersji w celu ułatwienia przyrostowych aktualizacji nie jest obecnie możliwe.
- Nowym wymaganiem, którego obecnie nie obsługuję, jest istnienie opcji konfiguracji dla poszczególnych urządzeń (pary klucz / wartość), które należy skonfigurować po stronie serwera administracyjnego. Nie miałbym nic przeciwko, aby w jakiś sposób udostępnić te opcje na urządzenie z powrotem do urządzenia w tym samym żądaniu HTTP, co aktualizacja oprogramowania (być może mógłbym zawrzeć je w nagłówkach / plikach cookie HTTP), chociaż nie martwię się tym zbytnio, ponieważ mogę zawsze należy ustawić osobne żądanie HTTP.
- Istnieje niewielka komplikacja z uwagi na fakt, że istnieją dwie (i więcej w przyszłości) wersje sprzętu. Bieżąca wersja sprzętu jest faktycznie przechowywana jako zmienna środowiskowa na początkowym obrazie SD (nie można ich samodzielnie zidentyfikować), a całe oprogramowanie jest zaprojektowane tak, aby było kompatybilne ze wszystkimi wersjami urządzeń. Aktualizacje oprogramowania układowego są wybierane na podstawie tej zmiennej środowiskowej, a pakiet aktualizacji zawiera oprogramowanie układowe dla wszystkich wersji sprzętu. Mogę z tym żyć, choć jest to trochę niezgrabne.
- Obecnie nie ma możliwości ręcznego przesłania aktualizacji do urządzenia (w skrócie te urządzenia mają w sobie dwa adaptery Wi-Fi, jeden do połączenia z Internetem, a drugi w trybie AP, którego użytkownik używa do konfiguracji urządzenia; w przyszłości Zamierzam dodać funkcję „aktualizacji oprogramowania” do lokalnego interfejsu internetowego urządzenia). To nie jest wielka sprawa, ale ma pewien wpływ na metodę instalacji aktualizacji.
- Kilka innych frustracji i ogólnego braku bezpieczeństwa.
Więc ... to było długie. Ale moje pytanie sprowadza się do tego:
Jak to zrobić poprawnie i bezpiecznie? Czy mogę wprowadzić niewielkie zmiany do mojego istniejącego procesu? Czy istnieje sprawdzona strategia / istniejący system, który mogę wykorzystać, aby nie musiałem uruchamiać własnego gównianego systemu aktualizacji ? Lub jeśli muszę samodzielnie wykonać, jakie są rzeczy, które muszą być prawdziwe, aby proces wdrażania / aktualizacji był bezpieczny i udany? Muszę też być w stanie włączyć do zestawu urządzenia programistyczne.
Mam nadzieję, że pytanie jest jasne. Zdaję sobie sprawę, że to trochę rozmyte, ale jestem w 100% pewien, że jest to problem, który został rozwiązany wcześniej i skutecznie rozwiązany, po prostu nie wiem, jakie są obecnie akceptowane strategie.
źródło
Odpowiedzi:
Czy możesz podać więcej informacji o używanej dystrybucji Linuksa, bootloaderze i architekturze (x86, ARM, MIPS?)
Spróbuję zgadnąć w obu kierunkach i mam nadzieję, że poprowadzę cię we właściwym kierunku.
Jeśli jest to dystrybucja oparta na Yocto z U-Bootem, polecam zajrzeć na mender.io lub swupdate . Projekty te wydają się dobrze pasować do kryteriów. Ich głównym celem jest zapewnienie aktualizacji atomowych.
Mender zapewnia mnóstwo narzędzi, w tym demona (i kilka skryptów systemowych) napisanych w Go, które odciążą cię z twoich barków. Ten projekt jest dość łatwy w użyciu z Yocto (zapewniają one meta-warstwę dla wielu urządzeń, które powinny być łatwe do dostosowania do konkretnego przypadku i układu partycji. Mają też wiele gotowych rozwiązań dla popularnych SOC) . Jeśli nie używasz Yocto, możesz zajrzeć do tego postu, który dokładnie wyjaśnia, jakie kroki musisz zrobić, aby używać go z dystrybucjami nie opartymi na Yocto.
swupdate jest również całkiem niesamowite, ale wydaje się, że to jednoosobowy wysiłek faceta z DENX (organizacji stojącej za U-Boot). Wydaje się również dość dojrzały.
Jest też Ubuntu Snappy, z którym nie mam żadnego doświadczenia i nie mogę kompetentnie komentować tego (może ktoś się do niego przyłączy). Chodzi o to, aby wysyłać Ci aplikacje w samodzielnych „snapach”. Z tego, co zrozumiałem, jest to ledwie rozwiązanie twojego problemu, choć nie jest ono systemowe.
W rzeczywistości wydaje się, że dzisiejszym trendem jest używanie Dockera (nawet w systemach wbudowanych) i znajomych w stosunku do APT / YUM. Później może bardzo utrudnić zapewnienie spójności.
źródło