Przegląd Sealious i propozycje zmian

Podjąłem próbę ustawienia na swoim laptopie środowiska do rozwijania Sealious, aby mieć miejsce do weryfikowania swoich zmian i udzielania przeglądów kodu. Wszystkie opisane tu czynności wykonywałem na systemie:

  • Debian 9.3 Stretch
  • Docker w wersji 17.05.0-ce, build 89658be z repozytorium oryginalnego dostawcy
  • GNU Make w wersji 4.1
  • Repozytorium Sealious Archive ustawione na wersji 3e3b0e3f7068b5249339a7e21bb1967367dfc53b (najświeższa gałąź alpha)

1. Makefile

Brakuje mi szybkiej i opisanej metody żeby maksymalnie dwoma komendami przejść do rozwoju Sealious. Aktualny Makefile wymaga własnego przeanalizowania, aby wpaść na metodę ustawienia środowiska. Wywołanie make ustawia jedynie bazę danych. Samo make test zwraca:

$ make test
./npm.sh run test            
Starting sealiousarchive_mailcatcher_1 ... done       
Starting sealiousarchive_db_1          ... done                              
                                                                 
> sealious@0.8.0 test /opt/sealious                  
> mocha setup-test.js lib/**/*.test.js
                                 
sh: mocha: not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! sealious@0.8.0 test: `mocha setup-test.js lib/**/*.test.js`
npm ERR! spawn ENOENT
npm ERR!
npm ERR! Failed at the sealious@0.8.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm WARN Local package.json exists, but node_modules missing, did you mean to install?

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/node/.npm/_logs/2018-04-06T22_05_07_142Z-debug.log
Makefile:9: recipe for target 'test' failed
make: *** [test] Error 1

Wykonanie make build zwraca:

$ make build
./npm.sh run build
Starting sealiousarchive_mailcatcher_1 ... done
Starting sealiousarchive_db_1          ... done
Building test
....
.... (zakończona pomyślnie budowa obrazu, którą wyciąłem dla czytelności)
....
npm ERR! missing script: build

npm ERR! A complete log of this run can be found in:
npm ERR!     /opt/sealious/.npm/_logs/2018-04-06T22_29_55_570Z-debug.log
Makefile:15: recipe for target 'build' failed
make: *** [build] Error 1

Ponadto w Makefile znajdują się zwracające błąd lub nic nie robiące targety:

  • watch
  • test-nginx

Drogą eksperymentów doszedłem, że do uzyskania gotowego do przeprowadzenia testów środowiska wymagane są komendy:

  • make install
  • make test

Propozycje

Usuńmy nadmiarowe targety z Makefile i przygotujmy krótką instrukcję uzyskiwania gotowego do działania środowiska deweloperskiego.

2. Nieudane testy

Uruchomienie testów jeszcze bez zmieniania niczego w kodzie kończy się licznymi błędami. Ze względu na długi output załączam go w pliku error.log (8,8 KB)
Proszę o informację czy jest to zamierzony stan rzeczy. Podczas rozmowy z @bartosz-gordon i @kuba-orlik padło przypuszczenie, że niektóre testy kończą się niepowodzeniem z powodu zbyt długiego czasu wykonywania. W logu rzeczywiście jest parę timeoutów. Czy bylibyśmy w stanie pozbyć się ograniczeń czasowych lub włączać je tylko określoną flagą/zmienną środowiskową, np. podczas testowania wydajności docelowego hardware-u pod aplikację przed wdrożeniem?

3. Środowisko tworzy pliki z obcymi uprawnieniami

Kontener MongoDB binduje katalogi db i configdb z katalogu z kodem wykorzystując użytkownika i grupę inną niż użytkownik uruchamiający środowisko. Powoduje to, że użytkownik pod którym rozwijamy kod nie ma uprawnień żeby je posprzątać, np.:

sealious-archive$ rm db/ -rf                            
rm: cannot remove 'db/collection-46--5284711994617411567.wt': Permission denied
rm: cannot remove 'db/index-24--5284711994617411567.wt': Permission denied
rm: cannot remove 'db/journal/WiredTigerPreplog.0000000001': Permission denied
rm: cannot remove 'db/journal/WiredTigerPreplog.0000000002': Permission denied
rm: cannot remove 'db/journal/WiredTigerLog.0000000001': Permission denied

Propozycje

Nie widzę powodu żeby binarne pliki bazy danych były w katalogu z kodem. Proponuję przenieść je do woluminów zarządzanych przez Docker. Takie podejście jest stosowane, np. tutaj.

4. Brakuje domyślnych konfiguracji

Uruchomienie Sealious z przykładową aplikacją wymaga posiadania jej konfiguracji, manifestu oraz prostego hello world do działania. Aktualnie w repozytorium jest jedynie przykładowy plik konfiguracyjny. Same automatyczne testy kodu nie pozwalają uruchomić aplikacji, w której można by manualnie testować zmiany(poprawcie mnie, jeśli się tu mylę i gdzieś są przykładowe hello world).

Propozycje

Stwórzmy prosty szablon startowy od którego będzie można zacząć rozwój Sealious.

5. Brak serwera HTTP w środowisku testowym

Mam tu na myśli reverse-proxy w postaci Nginx, za którym się zawsze wdraża aplikacje webowe. Spotykałem już przypadki, gdy w projektach nie brano pod uwagi środowiska produkcyjnego gdzie będzie uruchamiany kod. Takie różnice między testami a produkcją kończyły się czasami problemami przed samym wdrożeniem.

Propozycje

Dodajmy do standardowej konfiguracji deweloperskiej Docker Nginx skonfigurowany dla Sealious. Pozwoli nam to utrzymać aktualną i działającą konfigurację gotową do przeniesienia na serwer produkcyjny. Proponuję, tak jak tutaj, zostawić również bezpośredni dostęp do Sealious na potrzeby deweloperskie, ale zachęcać do testowania raczej w konfiguracji odzwierciedlającej przyszłą produkcję.

6. Przestarzała dyrektywa w Docker Compose

W docker-compose.yml wykorzystywana jest wycofywana już powoli opcja links.

Propozycje

W Docker Compose kontenery zachowują wzajemną widoczność(również po nazwie) w ramach konfiguracji, dlatego links nie jest potrzebne. Mam jednak obawy, że usunięcie links może popsuć zależność kontenerów(mailcatcher i db uruchamianie przed test). W razie problemów zależność możemy wymusić opcją depends_on.

2 Likes

Wielkie dzięki za wnikliwy feedback!

Założyłem taska :slight_smile: ⚓ T851 Usunąć niepotrzebne targety z Makefile

W logu widoczne są dwa typy błędów: timeout i address in use. Pewnie jest tak, że jeden test dostaje timeout, przez co jest na siłę killowany przez mocha i nie ma okazji do zamknięcia portu, na którym nasłuchuje. Następnie testy które próbują otworzyć ten port zawodzą, bo port jest wciąż zajęty.

Możesz sprawdzić tę hipotezę uruchamiając testy z flagą -t 100000? (javascript - How to increase timeout for a single test case in mocha - Stack Overflow) Flagę trzeba dodać w package.json. Wyślij proszę, jak wyglądają wtedy logi.

Wychodzi tutaj problem, który powinien być załatany inną metodą niż zwiększeniem timeoutu: testy zajmują dużo czasu:

Trzeba to zdiagnozować i naprawić:

https://hub.sealcode.org/T852

Mam złe doświadczenia z volumenami zarządzanymi przez Dockera - ich rozmiar puchł nieproporcjonalnie i pojawiały się problemy z ich montowaniem przy ponownym wstawaniu aplikacji. Przypinanie do lokalnego folderu wydaje mi się znacznie bardziej ergonomiczne… Czy nie wystarczy ustawić kontener z bazą danych tak, aby działał pod użytkownikiem z UID (tak, jak to robi aktualnie npm.sh)?

Szablon ten istnieje, ale jest nieaktualny (brakuje manifest).

Powstał już task na jego aktualizację: Login :wink:

O ile boję się, że to zaciemni trochę testy Sealiousa, ale trudno nie zgodzić mi się z motywacją dołączenia nginx-a do testów. @Jakski jako że najlepiej ogarniasz temat, założyłbyś na to taska w Sealhubie? Przypnij go proszę do projektu “Sealious (aktualna wersja)”

⚓ T854 Zmiana "links" na "depends_on" w docker_compose.yml :slight_smile:

2 Likes

Zdaje się, że masz rację. Uruchomiłem z wydzłużonym timeout i wszystkie testy przeszły. error.log (4,2 KB)

Natywna implementacja woluminów w Docker to katalogi systemowe montowane w odpowiednim punkcie w kontenerze. Można przy pomocy Docker wydobyć nawet bezpośrednią ścieżkę do katalogu, gdzie znajduje się dany wolumin, np.:

$ docker volume inspect sealiousarchive_mongo_db -f '{{.Mountpoint}}'
/var/lib/docker/volumes/sealiousarchive_mongo_db/_data

Rozmiar natywnego woluminu powinien, więc zależeć jedynie od tego jak wykorzystuje go działająca w kontenerze aplikacja - sam nic dodatkowo nie waży. Czy możesz podać przykład na odtworzenie problemu z nieproporcjonalnym puchnięciem woluminu?

Woluminy tworzone przez Docker Compose są nazywane według schematu: <projekt>_<wolumin>, gdzie <projekt> to nazwa wygenerowana na podstawie katalogu z docker-compose.yml. Np. dla projektu sealious-archive:

$ docker volume ls
DRIVER              VOLUME NAME
local               sealiousarchive_mongo_configdb
local               sealiousarchive_mongo_db

Woluminy Docker Compose standardowo przeżywają docker-compose down, dlatego jeśli chce się je permanentnie usunąć należy wykonać docker-compose down -v. Jeśli nie usuniemy ich flagą -v, to podpinają się automatycznie przy kolejnym uruchomieniu projektu z Docker Compose.

Montowanie woluminów w innych kontenerach ogranicza się do użycia opcji -v, np.:

$ docker volume ls
DRIVER              VOLUME NAME
local               sealiousarchive_mongo_configdb
local               sealiousarchive_mongo_db
$ docker run --rm -itv sealiousarchive_mongo_db:/home/db debian:9 /bin/bash
root@19bade622eeb:/# ls -alrth /home/db/
total 628K
-rw-r--r-- 1  999  999   21 Apr  7 19:34 WiredTiger.lock
-rw-r--r-- 1  999  999   49 Apr  7 19:34 WiredTiger
drwxr-xr-x 2  999  999 4.0K Apr  7 19:34 journal

lub external, jeśli chcesz wykorzystać zewnętrzny wolumin w Docker Compose.

Czy powyższe wytłumaczenie rozwiewa wątpliwości na temat zastosowania woluminów w Docker? Ustawianie UID w npm.sh będzie wymagało dopisania komendy do ustawiania odpowiedniego użytkownika lub modyfikacji docker-compose.yml i dodania tam opcji od ustawiania UID - to skomplikuje ustawianie środowiska.

https://hub.sealcode.org/T857

1 Like

Ok, czuję się przekonany! :smiley:

https://hub.sealcode.org/T858

1 Like