w Praktyce
4 godz. 33 min · Docker · Full-stack i Programowanie
Wojciech PołowniakSr. Fullstack EngineerW początkowych sekcjach kursu, zrozumiesz czym jest Docker i jakie ma zalety wobec rozwiązań oferujących pracę z serwerami lokalnymi, np. XAMPP - poznasz jego architekturę, założenia oraz najważniejsze pojęcia, których nieznajomość często spędza sen z powiek nawet doświadczonym programistom.
Jako że Docker jest to narzędzie dla programistów i administratorów systemów operacyjnych, lwia część pracy z tym narzędziem odbywa się w konsoli. Przedstawię Ci najważniejsze polecenia powiązane z tą technologią oraz zestaw dobrych praktyk i protipów które zawstydzą niejednego inżyniera oprogramowania.
W tej sekcji tego kursu przejdziemy przez najważniejsze punkty tworzenia skonteneryzowanych aplikacji z perspektywy programisty aplikacji internetowych - jeśli chcesz szybko rozpocząć swoją przygodę z Dockerem, ponieważ znasz już podstawy teorii i czujesz się wystarczająco pewnie - możesz zacząć z tego miejsca! A jeśli tempo będzie zbyt szybkie - zawsze możesz wrócić do części teoretycznej pracy z Dockerem
Przebudowywanie zasobów na żywo, dynamiczne odczytywanie zawartości plików... To podstawowe koncepty które współcześni programiści sieci web biorą za pewnik. Przy nieznajomości Dockera, łatwo jest strzelić sobie w stopę i utrudnić swoją pracę, zabierając sobie możliwość korzystania z powyższych funkcjonalności. W tym kursie, pokażę Ci jak wygodnie pracować z Dockerem w środowisku developerskim.
Jedną z wielu zalet Dockera jest niewątpliwie proste przenoszenie zmian konfiguracji i infrastruktury ze środowiska developerskiego na produkcyjne. W tym kursie, poza przyswojeniem podstawowej wiedzy na temat Dockera poznasz szereg dobrych praktyk w kontekście bezpieczeństwa oraz przygotowywania Twoich aplikacji pod środowisko, na którym będzie uruchomiona Twoja aplikacja gdy uznasz że jest gotowa by ujrzeć światło dzienne.
Ten kurs to zestaw kompleksowej wiedzy dzięki której dowiesz się jak od zera, na żywo, stworzyć aplikację na Twoim lokalnym środowisku - i jakie kroki należy podjąć, aby móc zobaczyć ją w internecie - wszystko w kontekście Dockera, wysokiej skalowalności i bezpieczeństwa. W jednej z ostatnich lekcji kursu zobaczysz jak robię deploy na serwery DigitalOcean by uzyskać link do swojej nowo zbudowanej aplikacji internetowej.
Ten kurs jest kierowany do webdeveloperów, bądź zaawansowanych programistów którzy nie pracowali jeszcze z Dockerem. Przydatne może być zrozumienie interfejsu linii poleceń czyli tzw. konsoli, oraz podstawowa wiedza na temat web developmentu czy systemów operacyjnych. Jeśli potrafisz korzystać z systemu kontroli wersji git, na pewno ułatwi to Tobie zrozumienie konceptu pracy z poleceniami dockera. Niemniej, każde zagadnienie staram się tłumaczyć na bieżąco.
W tej lekcji.
Posłużymy w końcu sygnały wejściowe, o których mówię już od tylu lekcji.
W tym przypadku z poziomu nauczyciela.
W związku z czym nasza aplikacja oczywiście dalej będzie serwowała nasze
statyczne pliki, tak jak miało to miejsce w poprzednich lekcjach tego kursu.
Ale aby była troszkę lepiej.
Przygotowana na środowisko produkcyjne to stworzymy sobie error handling, czyli
po prostu logikę, która powinna się wywołać w momencie, kiedy
dzieją się jakieś sygnały, że aplikacja powinna zakończyć swoje działanie.
Więc robimy sobie zmienną handler, która będzie tak naprawdę funkcją.
Może być funkcją asynchroniczne nawet.
Ściągnąłem sobie ósemkę.
I tę funkcję będziemy przekazywać.
Do odpowiedniego event Chandlera na zmiennej proces.
Jest to zmienna globalna, w której mamy dostęp do zmiennych środowiskowych.
Jesteśmy w stanie zabić procesy uczenia.
Dzięki niemu jesteśmy w stanie nasłuchiwać na różne zdarzenia.
Czyli tutaj będziemy po prostu.
Na dany event.
Wywoływać sobie.
Tą naszą logikę handler.
Czyli na przykład jeżeli byśmy mieli na agenta.
Czyli np.
kiedy zabijemy proces sygnałem numer 9, to wtedy powinien się wywołać ten handler.
I co możemy tutaj zrobić?
Oczywiście moglibyśmy tutaj wyłączać kolekcje z bazą danych.
Moglibyśmy czyścić jakiś kesz.
Moglibyśmy pisać jakieś logi do zewnętrznych miejsc albo wysyłać jakiś
monitoring, ale my po prostu zapiszemy tutaj Grey z puli szatynki down.
No i tutaj możemy wykorzystać.
Sobie piosenkę po to, żeby po prostu opóźnić to wywołanie, symulując tak
naprawdę połączenie z bazą danych czy jakieś asynchroniczne operacje.
Czyli stworzymy sobie tutaj nowy
Promise, który zostanie rozwiązany w tej samej linii.
Czyli mamy jako pierwszy parametr do Promise.
Jest to oczywiście funkcja. W której to.
Funkcji parametr resolve jest naszą funkcją, która rozwiąże tego.
To jest też bardzo ciekawa skryptowe logika.
W każdym razie to nam po prostu opóźni wywoływanie następnych linijek,
więc tutaj zrobimy resolve, który się wywoła po określonym macie.
Czyli rezultat wywołuje się po powiedzmy 300 milisekundach
i dzięki temu następna linijka wywoła się dopiero po 300 milisekundach.
Więc po prostu powiedzmy tutaj.
OK.
Czyli tutaj symuluje zapisywanie jakiejś informacji.
Następnie po określonym czasie
mówimy, że ta sytuacja się skończyła i robimy proces exit.
Jeżeli to jest cała logika, która powinna się wywołać tutaj możemy podać kod błędu
0 albo 1 0, to znaczy brak błędu 1 to jest błąd.
Czyli coś poszło nie tak w danym programie?
No i skąd mamy wziąć ten kod błędu? Niekoniecznie.
Aplikacja musiała zostać wyłączona z powodu błędu.
Mogła zostać wyłączona z powodu zmiany skalowania naszej aplikacji
powiedzmy albo zmiany lokalizacji, gdzie nasza aplikacja chodzi.
Może być z jednego serwera przeniesiona na drugi.
Nie powinniśmy tego zgadywać.
Więc tutaj do tej zmiennej.
Która jest przekazywana przez proces, on.
Przekazywany jest po prostu kod i ten kod.
Możemy w parametrze przechwycić.
I wejść tym samym kodem.
Więc jak to zapiszemy?
Zrobiłem sobie docker composer logs w polu.
To faktycznie zobaczymy, że to nam się
tutaj już zaatakowało i jeśli byśmy spróbowali
otworzyć nowy terminal, może tak przede wszystkim pół na pół.
A właśnie w ten.
Sposób to przechodząc do katalogu.
14.
Robiąc docker composer albo po prostu kilka bezpośrednio.
Docker kill id kontenera.
To widzimy, że on się wyłączył kodem 137, ale to przez to prawdopodobnie, że on
próbuje robić nam tutaj light reload, Więc jeżeli byśmy spróbowali.
Po prostu pozbyć się tego.
Likwidował to przynajmniej na chwilę.
Takie pisanie po prostu zapisać.
I teraz musimy zrobić dokładnie kompost,
a żeby to się startowało to widzimy, że faktycznie.
Teraz to zajęło. Troszkę krócej.
Nasza aplikacja wystartowała.
No i jeśli sobie zrobiłem ponownie docker ps.
Do KIR.
Ten sam serwer.
Dalej mamy kod 137.
Zrobiliśmy apkę,
zapisaliśmy zmianę, więc on nam już tego na podmianę nie powinien uruchamiać.
W związku z czym możemy zrobić.
To też tak, że po prostu.
Zrobią composer i wejdziemy sobie na ten kontener Docker vs Jacek Bash.
Zobaczymy co jest w naszym sorcie index 200.
Nasze zmiany powinny zostać tutaj zaaplikowane.
Ale być może akurat kill nie robi tutaj gwinta.
Jest bardzo dużo różnych wydarzeń, które powinniśmy obsługiwać.
Nie jest to oczywiście tylko i wyłącznie timing, więc po prostu to zrobimy.
Event, które powinniśmy obsłużyć ma być może to jest po prostu problem.
Więc tutaj po prostu wypisujemy wszystkie.
Potencjalne zdarzenia, które mogą się wydarzyć.
Czy to będą wszystkie?
Nie wiem, ale na pewno są to wszystkie najbardziej popularne,
z których ja pamiętam, że muszę po prostu korzystać.
Jeszcze może z gwinta dodamy.
No i teraz po prostu zamiast robić pojedynczego.
Procesu, możemy zrobić event for i event.
Po prostu tutaj process on event i robimy handler.
Zapiszmy.
Zobaczmy tego loga sformułowaniem.
Pytałem się czy faktycznie już nie chodzi.
Wydaje mi się, że nie.
Także zobaczmy jak wyjdziemy stąd.
Nawet teraz możemy spróbować docker composer down to widzimy, że aplikacja.
Nam się wywróciła.
App error command failed signal a powinniśmy tutaj dodać i ona.
Nie pokazała nam.
Tych informacji o
tych danych, więc może po prostu zróbmy docker composer
app ponownie i za chwilę znowu zrobimy down albo po prostu command.
Tak jak widzieliście tutaj pojawiło się Grey i Pink.
Tylko czemu jest stopień, a nie rating D?
To jest dobre pytanie skąd indziej te informacje?
Ale zobaczmy jeszcze raz pakiet not.
Zrobimy docker composite docker composite down.
I tutaj dostajemy błąd o tym, że.
Uruchamiany jest.
OK, wydaje mi się, że to co byśmy musieli
ewentualnie jeszcze zrobić to po prostu to też w ramach przygotowania
do naszego uruchamiania aplikacji produkcyjnie zamiast uruchamiać tego przez
NPM, a po prostu Node App Source index możemy zrobić.
Wtedy mamy pewność, że żaden dodatkowy
proces nie jest jeszcze przed tym modem i ponownie musimy zrobić komponent App.
Tutaj włączymy logi.
Nie ma nic w logach.
I teraz Composition.
I faktycznie widzimy grey sharing down
i drugi raz Grey swój sharing dając się nam uruchomiła.
Ponieważ nie mamy tutaj wyłączonego eventy, czyli w momencie, gdy
wychodzimy faktycznie z procesu, ten handler jeszcze raz się wywołuje.
Oczywiście można to obsłużyć.
Natomiast jak teraz zobaczymy docker ps.
Ten kontener już nie stoi.
Wyłączył się i on się wyłączył w bardzo szybkim czasie.
Zobaczmy.
3 sekundy czy setne sekundy zamiast tych 10 sekund?
W związku z czym to jest taki przykładowy.
Proces Terminator.
Można to nazwać.
Do naszych aplikacji webowych i to.
Co po prostu warto.
Pamiętać to że jest taka metoda na zmiennej process aby nasłuchiwać na
zdarzenia systemowe, że możemy wyłączyć process poprzez process.
Exit i że te.
Wszystkie zdarzenia które z dockera wysyłamy czy poprzez control.
Jeżeli np. uruchamiam bez flagi
no to w taki sposób jesteśmy zatrzymać nasz kontener i wtedy on będzie się
wyłączał z gracją, niezależnie od tego jaki był powód wyłączenia tego kontenera.
Oczywiście dla każdego z tych sygnałów powinna być inna logika, może inne
logowanie, ale idea tego jak to obsłużyć jest właśnie taka.
index.js · 8 min
const express = require('express');
const app = express();
const port = 8080;
app.use(express.static('src/static'));
app.get('/hello', (req, res) => {
res.send('Hello world from my API!');
});
app.listen(port);
const handler = async (code) => {
console.log('Gracefully shutting down...');
await new Promise(resolve => setTimeout(resolve, 300));
console.log('Ok, bye!');
process.exit(code);
};
const events = ['exit', 'SIGINT', 'SIGTERM', 'SIGQUIT'];
events.forEach(event => {
process.on(event, handler);
});