Teoria – Szkoła Dockera https://szkoladockera.pl Najlepsze miejsce dla entuzjastów konteneryzacji i Dockera Thu, 22 Oct 2020 06:29:54 +0000 pl-PL hourly 1 https://wordpress.org/?v=5.7.13 https://szkoladockera.pl/wp-content/uploads/2019/07/cropped-Shelftons-5-32x32.png Teoria – Szkoła Dockera https://szkoladockera.pl 32 32 Open Container Initiative (OCI) – standard dla obrazów i kontenerów https://szkoladockera.pl/open-container-initiative-oci-standard-docker-image-i-kontenerow/ https://szkoladockera.pl/open-container-initiative-oci-standard-docker-image-i-kontenerow/#comments Thu, 22 Oct 2020 06:28:38 +0000 https://szkoladockera.pl/?p=2188 Docker (jako firma) w 2015 roku dołączył do OCI (Open Container Initative), tym samym znacznie otwierając się na współpracę z innymi firmami w rozwoju konteneryzacji. Był to jeden z przełomowych momentów (również dla nas – użytkowników) i spora zmiana polityki firmy. Powiem tylko tyle, albo aż tyle: Ten wpis powinien Więcej…

Artykuł Open Container Initiative (OCI) – standard dla obrazów i kontenerów pochodzi z serwisu Szkoła Dockera.

]]>
Docker (jako firma) w 2015 roku dołączył do OCI (Open Container Initative), tym samym znacznie otwierając się na współpracę z innymi firmami w rozwoju konteneryzacji. Był to jeden z przełomowych momentów (również dla nas – użytkowników) i spora zmiana polityki firmy.

Powiem tylko tyle, albo aż tyle:

Ten wpis powinien przeczytać każdy, kto myśli na poważnie o stosowaniu konteneryzacji.

Gwarantuję – nie pożałujesz. Przejdźmy więc do sedna – czego się dowiesz?


Czego się dowiesz

  • Czym jest organizacja Open Container Initiative i dlaczego powstało
  • Jakie standardy wprowadza OCI
  • Co z pozostałymi narzędziami takimi jak Kubernetes, Podman?
  • Jak obrazy dockerowe mogą działać w Kubernetes?
  • Czy obraz zbudowany w wersji Dockera 17.03 będzie działać na wersji 19.03?


Open Container Initiative (OCI) – co to jest?

Jeśli pracowałeś w większej firmie, to pewnie możesz kojarzyć coś takiego jak ISO. Jest to organizacja zajmująca się „standardyzacją” – przykład: bezpieczeństwo (bhp), zarządzanie jakością (ISO 9001).

Open Container Initiative również możemy określić jako organizację zajmującą się standaryzacją. Zadaniem OCI jest – jak łatwo się domyślić – utrzymanie standardów konteneryzacji.

Organizacja została założona w 2015 roku przez firmy Docker oraz CoreOS (twórcy świetnych narzędzi takich jak Prometheus, Clair czy Quay.io). Z czasem do projektu dołączały inni giganci z doliny krzemowej, min. Google, Amazon, Redhat, czy Microsoft (i wiele wiele innych).

Jakie standardy wyznacza OCI

OCI skupia się na dwóch ważnych sprawach:

Zarówno OCI Image Format jak i OCI Runtime odbiły się sporym echem i miały znaczny wpływ na dalszy rozwój konteneryzacji. W kolejnym akapicie dowiesz się, co dzięki temu my – użytkownicy na tym zyskujemy.


OCI Image Format – czyli specyfikacja obrazów

Skoro tu jesteś, to wiesz czym jest Docker (a jeśli nie wiesz – jest genialnym narzędziem).

Teraz może Cię trochę zaskoczę, ale jak to zwykle w świecie bywa – Docker nie ma już monopolu i doczekał się konkurencji. Nie mam jednak zamiaru dzisiaj o tym mówić, na przykład – jaka jest przyszłość Dockera, albo czy konkurencja go wyprzedzi. To nie jest temat na dziś, ale możesz być spokojny – warto inwestować czas w Dockera. Mówię to naprawdę z czystym sumieniem („a co miałbyś powiedzieć” – pewnie pomyślałeś – „skoro promujesz się jako ekspert dockerowy”).

Jeśli moje słowa Cię nie przekonują, zerknij na Stack Overlow Survey 2020.

TLDR; Docker zajął drugie miejsce w kategorii Most Loved Platforms. Wyprzedził min. Kubernetes oraz chmurę AWS.

OK — pora wrócić do tematu.

Skupmy się na specyfikacji obrazów (OCI Image Format).

Źródło: https://coreos.com/blog/oci-image-specification.html

Łatwo zauważyć, że przed erą OCI mieliśmy dysproporcję pomiędzy standardem obrazów dla Docker i RKT (pierwsza konkurencja dla Dockera?).

Oznaczało to, że obraz zbudowany za pomocą Dockera oraz obraz zbudowany przez RKT – to były dwie podobne, ale jednak inne rzeczy. Ba, nawet sam docker image V1 nie był kompatybilny z docker image v2.2 – tym samym nie było to zgodne z różnymi wersjami Docker Registry.

OCI Image Format wprowadził pełną kompatybilność pomiędzy Dockerem a RKT (na początku) jeśli chodzi o strukturę obrazów, a z czasem dołączyły do tego nowo-powstałe narzędzia – na przykład Podman czy Buildah.

Poniższe polecenie to potwierdzają.

Pobieranie obrazu
$ docker pull dnaprawa/hello-world
$ podman pull dnaprawa/hello-world
$ buildah pull dnaprawa/hello-world
Wypchnięcie obrazu do repozytorium
$ docker push dnaprawa/hello-world
$ podman push dnaprawa/hello-world

A teraz mała uwaga.

OCI Image Format to nie tylko to, co widzisz powyżej – czyli podobieństwo poleceń docker pull image i podman pull image.

To przede wszystkim wspólny standard struktury obrazu (od strony technicznej). Mam nadzieję, że jest już to zrozumiałe. Lećmy dalej. Czas na OCI Runtime.


OCI Runtime – czyli standard uruchamiania kontenerów

OCI Image Format był przełomowy, ale bez standaryzacji runtime’u byłby znacznie mniej użyteczny.

Nadszedł rok 2017 i celebracja powstania pierwszej wersji Open Container Initivative Specification 1.0.

Dzięki temu firmy takie, jak Docker, CoreOs, czy RedHat mogły rozwijać autorskie narzędzia, ale już nie po swojemu, ale według odgórnie ustalonego STANDARDU. My jako użytkownicy zyskaliśmy na tym wiele. Zyskaliśmy pełną dowolność jeśli chodzi o wybór narzędzi do pracy z kontenerami jak również kompatybilność przy wdrażaniu na produkcję.

  • Po pierwsze: do budowania obrazów (Docker)
  • Po drugie: wybierania środowiska uruchomieniowego.

Jak już wcześniej wspominałem, Docker nie jest już jedyną opcją jeśli chodzi o runtime kontenerów. Sama roadmapa na rok 2020 to potwierdza. Docker obecnie skupia się na rozwiązaniach dla programistów – czyli zapewnienie jak najlepszego ekosystemu do codziennej pracy z kontenerami lokalnie, jak również tworzenia i dystrybucji obrazów.

Kilka alternatyw dla Dockera:

  • CRI-O (stworzony z myślą o Kubernetes)
  • ContainerD (stworzony przez Dockera i udostępniony jako open-source, wykrzystywany również przez k8s)
  • Podman (chyba największa „konkurencja” dla Dockera)

To oznacza, że obrazy zgodne z OCI będą działać dla każdego runtime’u kontenerów, który będzie zgodny OCI runtime.


Obraz zgodny z formatem OCI

Obraz zbudowany przy pomocy Dockera jest artefaktem – zgodnym z formatem OCI. Dzięki temu nie jesteśmy całkowicie uzależnieni od ekosystemu Dockera. Naszym wyborem wcale nie musi być Docker Hub jeśli chodzi o repozytorium obrazów.

Nie muszę też przypominać, że obecnie na rynku można dowolnie przebierać w prywatnych Docker Registry. Kilka najpopularniejszych to:

  • Azure Container Registry (ACR)
  • Elastic Container Registry (ECR)
  • Google Container Registry (GCR)
  • Gitlab Container Registry
  • Canister.io

Można by wymieniać prawie bez końca. Nowe rejestry obrazów powstają jak grzyby po deszczu. Co to oznacza?

Zwyczajnie jest na to zapotrzebowanie na rynku. Coraz więcej firm decyduje się na migrację do kontenerów i potrzebuje gdzieś te komercyjne obrazy przechowywać.


Czy obraz zbudowany na wersji Dockera 17.03 będzie działać na nowszej wersji?

Załóżmy, że zaadaptowaliśmy Dockera i kontenery jakiś czas temu, gdy najnowszą wersją Dockera była 17.03. Aplikacja działała przez te wszystkie lata stabilnie, ale chcemy się zmigrować do najnowszej wersji Dockera, albo przejść na Kubernetes. Może pojawić się pytanie:

Czy to będzie działać?

Zacznijmy od tego co się zmieniło w Dockerze na przestrzeni lat. W starszych wersjach, obraz po pobraniu (docker image pull) był inaczej reprezentowany na dysku. Za tę kwestię odpowiedzialny jest storage driver.

Jeżeli jesteś zainteresowany szczegółami działania najnowszego i zarazem rekomendowanego storage drivera – overlay2 – to zajrzyj TUTAJ. W tym filmie dość szczegółowo omawiam jego działanie. Jeżeli z kolei jesteś już na pokładzie mojego programu Docker Maestro, to również znajdziesz tam lekcję o tej tematyce (Moduł: Docker Advanced, lekcja „Przechowywanie warstw obrazu na dysku”)

Może pojawić się pytanie?

Generalnie będzie działać (bo obraz zbudowany na wersji Docker 17.03 jest już zgodny z OCI Image Format), ale mogą być drobne różnicę w działaniu „pod spodem” (głównie w/w storage driver). Więcej na ten temat znajdziesz w „breaking changes”: https://docs.docker.com/engine/breaking_changes/

Docker – kluczowe zmiany

Jak widać dotyczą one Dockera w wersji 1.10. Warto zwrócić uwagę na to zdanie: 

Every Engine release strives to be backward compatible with its predecessors, and interface stability is always a priority at Docker

Tutaj też lista wszystkich starszych realease’ów oraz lista wprowadzonych zmian względem poprzedniej wersji: https://docs.docker.com/engine/release-notes/17.03/


Co dalej?

Mam nadzieję, że ten post pomógł Ci zrozumieć czym jest OCI oraz rozwiał Twoje wątpliwości w kwestii kompatybilności obrazów, a różnymi wersjami Dockera oraz pozostałymi narzędziami takimi jak Kubernetes czy Podman.

Jeżeli masz jakieś dodatkowe pytania – śmiało pisz w komentarzu.

Będę również niezmiernie wdzięczny ??, jeśli podzielisz się tym postem z kolegą albo w Social Media. Możesz również zapisać się do newslettera poniżej i być na bieżąco z kolejnymi wpisami.

Dzięki i do usłyszenia wkrótce!
– Damian

Artykuł Open Container Initiative (OCI) – standard dla obrazów i kontenerów pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/open-container-initiative-oci-standard-docker-image-i-kontenerow/feed/ 2
Konteneryzacja – fakty i mity związane z Dockerem https://szkoladockera.pl/konteneryzacja-fakty-i-mity/ https://szkoladockera.pl/konteneryzacja-fakty-i-mity/#respond Tue, 18 Aug 2020 05:45:33 +0000 https://szkoladockera.pl/?p=2144 Aplikacja w kontenerze – fakty i mity związane z Dockerem „Uruchomimy bazę danych w kontenerze i znikną nam wszystkie problemy” – czyli fakty i mity na temat konteneryzacji i Dockera.

Artykuł Konteneryzacja – fakty i mity związane z Dockerem pochodzi z serwisu Szkoła Dockera.

]]>
Aplikacja w kontenerze – fakty i mity związane z Dockerem

„Uruchomimy bazę danych w kontenerze i znikną nam wszystkie problemy” – czyli fakty i mity na temat konteneryzacji i Dockera.



Artykuł Konteneryzacja – fakty i mity związane z Dockerem pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/konteneryzacja-fakty-i-mity/feed/ 0
Docker dla programistów – kiedy i jak może się przydać https://szkoladockera.pl/docker-dla-programistow-kiedy-i-jak-moze-sie-przydac/ https://szkoladockera.pl/docker-dla-programistow-kiedy-i-jak-moze-sie-przydac/#respond Mon, 10 Aug 2020 05:45:14 +0000 https://szkoladockera.pl/?p=2107 Docker dla programistów – kiedy i jak może się przydać Czas na kolejne wideo, w którym opowiadam – jak Docker może ułatwić życie PROGRAMISTOM! Jeżeli dopiero zaczynasz swoją przygodę z Dockerem => zajrzyj TUTAJ.

Artykuł Docker dla programistów – kiedy i jak może się przydać pochodzi z serwisu Szkoła Dockera.

]]>
Docker dla programistów – kiedy i jak może się przydać

Czas na kolejne wideo, w którym opowiadam – jak Docker może ułatwić życie PROGRAMISTOM!

Jeżeli dopiero zaczynasz swoją przygodę z Dockerem => zajrzyj TUTAJ.



Artykuł Docker dla programistów – kiedy i jak może się przydać pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/docker-dla-programistow-kiedy-i-jak-moze-sie-przydac/feed/ 0
Komunikacja kontenerów – sieć typu bridge https://szkoladockera.pl/komunikacja-kontenerow-siec-typu-bridge/ https://szkoladockera.pl/komunikacja-kontenerow-siec-typu-bridge/#respond Wed, 24 Jun 2020 08:12:18 +0000 https://szkoladockera.pl/?p=1921 Komunikacja kontenerów Podstawowa rzecz, z jaką prędzej czy później musimy się zmierzyć, to komunikacja między kontenerami. Najprostszy przykład, jaki nasuwa mi się na myśl, to komunikacji kontenera zawierającego frontend z kontenerem zawierającym backend aplikacji. Kolejny przykład – komunikacja backendu z usługami typu Redis czy Elasticsearch. Takich przykładów może być zdecydowanie Więcej…

Artykuł Komunikacja kontenerów – sieć typu bridge pochodzi z serwisu Szkoła Dockera.

]]>
Komunikacja kontenerów

Podstawowa rzecz, z jaką prędzej czy później musimy się zmierzyć, to komunikacja między kontenerami. Najprostszy przykład, jaki nasuwa mi się na myśl, to komunikacji kontenera zawierającego frontend z kontenerem zawierającym backend aplikacji.

Kolejny przykład – komunikacja backendu z usługami typu Redis czy Elasticsearch. Takich przykładów może być zdecydowanie więcej. Wszystko zależy od naszych potrzeb i rodzaju wykorzystywanych w projekcie technologii.

Żeby dokładnie zrozumieć, w jaki sposób Docker na to zezwala, trzeba zacząć od podstaw, czyli od tego jak działa sieć typu bridge.

Można śmiało powiedzieć, że jest to najczęściej stosowany sterownik sieciowy — bridge.

Wynika to z tego, że można go wykorzystywać zarówno do celów developerskich, jak również uruchamiając projekt na środowiskach testowych czy produkcyjnych.

Czego się dowiem?


Po pierwsze, poznasz różnicę pomiędzy DOMYŚLNĄ siecią typu bridge (tworzoną przez Dockera po zainstalowaniu) oraz manualnie tworzonymi sieciami.

Po drugie, zobaczysz w praktyce jak tworzyć własne sieci i podpinać do nich kontenery

Po trzecie, zrozumiesz działanie sieci typu bridge

Jest to jedna z lekcji mojego kursu online Docker Maestro.

Łącznie cały kurs to blisko 13 godzin materiału.

Sprawdź agendę i listę wszystkich lekcji na http://dockermaestro.pl



Artykuł Komunikacja kontenerów – sieć typu bridge pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/komunikacja-kontenerow-siec-typu-bridge/feed/ 0
Kontener na produkcji puchnie – czyli problem z miejscem na dysku https://szkoladockera.pl/kontener-mi-puchnie-czyli-problem-z-miejscem-na-dysku/ https://szkoladockera.pl/kontener-mi-puchnie-czyli-problem-z-miejscem-na-dysku/#respond Fri, 19 Jun 2020 07:22:23 +0000 https://szkoladockera.pl/?p=1883 Prędzej czy później możemy natknąć się na sytuację, gdzie kontener na produkcji po jakimś czasie puchnie. Inaczej mówiąc, z czasem jego rozmiar na dysku jest coraz to większy i większy. Przyjrzymy się dzisiaj temu problemowi oraz pokażę potencjalne miejsca, które mogą być tego powodem. Problem puchnięcia kontenera (jak i sposób Więcej…

Artykuł Kontener na produkcji puchnie – czyli problem z miejscem na dysku pochodzi z serwisu Szkoła Dockera.

]]>
Prędzej czy później możemy natknąć się na sytuację, gdzie kontener na produkcji po jakimś czasie puchnie. Inaczej mówiąc, z czasem jego rozmiar na dysku jest coraz to większy i większy. Przyjrzymy się dzisiaj temu problemowi oraz pokażę potencjalne miejsca, które mogą być tego powodem.

Problem puchnięcia kontenera (jak i sposób jak tego uniknąć) jest na tyle uniwersalny, że przedstawione w tym artykule praktyki śmiało możesz od razu wdrożyć u siebie.

Gdzie kontener domyślnie zapisuje dane?

Żeby móc zrozumieć gdzie tkwi problem, zaczniemy od podstaw – czyli od tego gdzie domyślnie kontener zapisuje swoje dane.

Po uruchomieniu dowolnego kontenera tworzy nam się minimum jeden proces.

Każdy taki proces ma prawo do modyfikacji systemu plików kontenera. Gdzie zatem zapisywane są te zmiany?

Domyślnym katalogiem, gdzie Docker przechowuje warstwy obrazów jest /var/lib/docker/overlay2. Więcej na ten temat możesz znaleźć TUTAJ.

**Mowa tutaj o kontenerach odpalonych za pomocą Dockera

Oprócz warstw obrazu, na podstawie którego tworzony jest kontener, dodatkowo tworzy się warstwa – writeable layer. Służy ona do przechowywania zmian zachodzących w kontenerze.

Warstwa writeable

Warto jeszcze wspomnieć, że warstwa writeable istnieje do momentu usunięcia kontenera. Chcąc zapisać naniesione w kontenerze zmiany, możemy to zrobić za pomocą polecenia docker container commit <nazwa_lub_id_kontenera> <nowy_obraz:tag>.

To polecenie jest odpowiedzialne za utworzenie nowego obrazu na podstawie kontenera, uwzględniając wszystkie zmiany, jakie zaszły w warstwie writeable.


Co może powodować, że kontener puchnie?

Wiemy już, gdzie kontener zapisuje dane. Teraz czas na przedstawienie dwóch najczęstszych błędów w podejściu do konteneryzacji.

Jak to kiedyś ktoś fajnie powiedział:

„Żyj krótko, umieraj młodo”

Po pierwsze – kontenery zostały stworzone dla aplikacji BEZSTANOWYCH.

Oznacza to, że stan kontenera powinien być wyniesiony na zewnątrz. Jednym z powodów przyrostu miejsca na dysku może być przechowywanie stanu aplikacji w systemie plików kontenera.

Sprawdź, czy i jakie pliki są tworzone podczas działania kontenera

Po drugie – zapisywanie logów aplikacji do pliku

To podejście doskonale znamy z ery przed Dockerem i konteneryzacją. Powiedziałbym, że nadal coś takiego ma miejsce dla aplikacji hostowanych na VM-kach (szczególnie windowsowych).

Sprawdź, gdzie przechowane są logi aplikacji lub usługi uruchomionej w kontenerze

Mam tutaj na myśli logowania do pliku tekstowego (.log). Zaraz po przechowywaniu stanu, jest to najczęstszy powód puchnięcia kontenera.


Jak sprawdzić jakie zmiany zaszły w kontenerze?

Wiemy już, co może być przyczyną puchnięcia kontenera. Jak zatem upewnić się i dokładnie zidentyfikować problem?

Rozważmy to na poniższym przykładzie:

docker container run -it --name mydebian debian:stretch bash
echo 'Tekst, tekst, tekst' > tekst.txt
exit

Co się stało powyżej? Odpalony został kontener o nazwie mydebian, wewnątrz którego stworzony został plik text.txt. Polecenie exit spowodowało zatrzymanie kontenera.


Sprawdzenie co zostało zmienione za pomocą poniższej instrukcji:

docker container diff mydebian
A /tekst.txt
C /root
A /root/.bash_history

Instrukcja docker container diff zwraca to, co zostało zmienione w systemie plików kontenera względem obrazu. Inaczej mówiąc, zwraca to, co zostało zapisane w warstwie writeable.

Docker Maestro – najbardziej obszerny kurs online Dockera po polsku

Poruszana tematyka:

  • Tworzenie własnych obrazów
  • narzędzia wspomagające pracę z Dockerem
  • bezpieczeństwo,
  • orkiestracja
  • zagadnienia DevOps
  • …i wiele, wiele więcej

Sprawdź na http://dockermaestro.pl


Jak sprawdzić ile miejsca na dysku zajmują zmiany?

Pomocne tutaj będzie kolejne polecenie (które częściowo już napewno znasz). Tym poleceniem jest docker container ls (lub docker ps) rozbudowane o dodatkowy parametr -s.

Sprawdźmy całość na poniższym przykładzie:

docker container ls -as

CONTAINER ID    IMAGE            STATUS                        NAMES       SIZE
5ce9595d1e76    debian:stretch   Exited (0) 10 minutes ago     mydebian    70B (virtual 101MB)

Zwróć uwagę na ostatnią kolumne SIZE.

Wartość przed nawiasem, to ilość miejsca na dysku po zmianach zachodzących w kontenerze.

Jeżeli chcemy wyświetlić, ile miejsca zajmują również zatrzymane kontenery, do docker container ls dorzucamy parametr -as.


Rozwiązanie problemu

Mierząc się z problemem puchnięcia danych, zacząłbym od dwóch czynności:

  1. Stan aplikacji nie powinien zostać zapisywany w systemie plików kontenera
  2. Logi kontenera powinny zostać wyniesione do zewnętrznej usługi lub do STDOUT/STDERR

Z reguły są to dwie najczęstsze przyczyn.

Artykuł Kontener na produkcji puchnie – czyli problem z miejscem na dysku pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/kontener-mi-puchnie-czyli-problem-z-miejscem-na-dysku/feed/ 0
Docker vs LXC – czym to się różni? https://szkoladockera.pl/czym-rozni-sie-docker-od-lxc/ https://szkoladockera.pl/czym-rozni-sie-docker-od-lxc/#comments Thu, 02 Apr 2020 06:08:35 +0000 https://szkoladockera.pl/?p=1551 Docker vs LXC – czym to się różni? Na przebiegu kilku ostatnich lat, rosnąca popularność Dockera wprowadziła podział na jego zwolenników, jak i przeciwników. Osoba „bezstronna”, na samym początku może szukać odpowiedzi na kilka pytań: Dlaczego Docker? Dlaczego nie wykorzystać czegoś, co było od dawna — LXC? Jaka jest różnica między LXC a Dockerem? Kiedy wybrać kontenery LXC, a kiedy kontenery Dockerowe? W Więcej…

Artykuł Docker vs LXC – czym to się różni? pochodzi z serwisu Szkoła Dockera.

]]>
Docker vs LXC – czym to się różni?

Na przebiegu kilku ostatnich lat, rosnąca popularność Dockera wprowadziła podział na jego zwolenników, jak i przeciwników. Osoba „bezstronna”, na samym początku może szukać odpowiedzi na kilka pytań: Dlaczego Docker? Dlaczego nie wykorzystać czegoś, co było od dawna — LXC? Jaka jest różnica między LXC a Dockerem? Kiedy wybrać kontenery LXC, a kiedy kontenery Dockerowe?

W tym artykule postaram się rozwiać wszystkie te wątpliwości i odpowiedzieć na pytania osoby „bezstronnej”.


Historia konteneryzacji i LXC

Konteneryzacja sama w sobie ma dość długą historię. Pierwsze próby stworzenia czegoś, co mogłoby przypominać dzisiejsze kontenery, podjęto już w roku 2000. Twórcy systemu FreeBSD (system operacyjny z rodziny UNIX) wprowadzili polecenie jail (więzienie).

Docker vs LXC
Zródło: https://unsplash.com

Dzięki jail otrzymywaliśmy możliwość izolowania systemu plików, użytkowników oraz sieci.
Dodatkowo jail wprowadziło możliwość przypisania adresu IP czy konfigurowanie niestandardowych instalacji pakietów i bibliotek. Główną ideą jail, było odizolowanie aplikacji działających na hoście. Jak na rok 2000, pomysł był bardzo dobry, aczkolwiek nie obyło się bez problemów. Aplikacje w obrębie jail miały ograniczoną funkcjonalności i finalnie to rozwiązanie nie przyjęło się na większą skalę.

Przełom nastąpił w 2006 roku, gdy inżynierowie firmy Google zaprezentowali światu mechanizm przeznaczony do izolowania procesów oraz ograniczania zużycia zasobów (CPU, pamięć, dysk, sieć) przez proces. W 2007 roku mechanizm ten został określony jako Control Groups (cgroups). Rok później, cgroups zostało przyłączone do jądra Linuksa 2.6.24, co doprowadziło do powstania projektu znanego teraz jako LXC — Linux Containers.


Idea kontenerów LXC

Główną zaletą LXC jest możliwość uruchomienia pełnoprawnego systemu operacyjnego w kontenerze, który uruchamiany jest na współdzielonym jądrze systemu hosta. Jeśli chodzi o zasadę działania, LXC jest bardziej „zbliżone” do maszyn wirtualnych.

Na oficjalnej stronie ubuntu, o kontenerach LXC możemy przeczytać:

Containers are a lightweight virtualization technology.
They are more akin to an enhanced chroot than to full virtualization like Qemu or VMware, both because they do not emulate hardware and because containers share the same operating system as the host.

O kontenerach LXC możemy myśleć jako czymś zbliżonym do tego, za co w systemie Linux odpowiedzialne jest polecenie chroot. Chroot to polecenie uniksowe, pozwalające uruchomić dany program ze zmienionym korzeniem (root) – katalogiem głównym systemu plików


Docker vs LXC – czyli inne typy kontenerów

Zanim przejdziemy do omawiania różnic, warto wspomnieć o tym, co było kiedyś. Mianowicie, na samym początku (rok 2013) Docker korzystał z rozwiązań kontenerów LXC. Z czasem jednak, przedstawiciele Dockera doszli do wniosku, że błędy w LXC mają bezpośredni wpływ na działanie Dockera. Jako że LXC było rozwijane przez społeczność, Docker nie miał nad tym pełnej kontroli.

W 2014 roku Docker stworzył i zaczął wykorzystywać własne narzędzie do uruchamiania kontenerów o nazwie libcontainer.


Inne podejście do kontenerów

Podstawowa różnica pomiędzy Dockerem a kontenerami LXC to podejście do tworzenia kontenerów.

Kontenery LXC zostały stworzone z myślą uruchomienia pełnoprawnego systemu operacyjnego, zawierającym wszystko to, co moglibyśmy mieć w wirtualnej maszynie. Różnica pomiędzy wirtualną maszyną a kontenerami LXC polega na tym, że system operacyjny wewnątrz kontenerów LXC nie posiada własnego jądra (kernela) i działa bezpośrednio na jądrze systemu hosta.

Docker z kolei zaadoptował całkiem inne podejście. Zamiast uruchamiać cały system operacyjny wraz ze wszystkimi jego komponentami, takimi jak: syslog, cron, czy systemd — Docker został zaprojektowany do uruchamiania JEDNEJ aplikacji per kontener.


Pojedynczy proces vs wiele procesów

Opierając się na zasadzie SRP (Single Responsible Principle), każdy kontener dockerowy powinien mieć jedną odpowiedzialność. W Dockerfile definiujemy główny proces startowy kontenera, za pomocą instrukcji CMD lub ENTRYPOINT.

W przypadku Dockera, niezalecane jest tworzenie kontenerów, wewnątrz których działają dwa, niezależne od siebie procesy. Oczywiście, jak to zwykle bywa, istnieją pewne wyjątki, gdzie zachodzi potrzeba uruchomienia więcej niż jednego procesu. W takich sytuacjach kluczowa kwestia to moment, w którym jeden proces nagle kończy swoje działanie. Sami musimy zarządzić tym, co ma się wtedy wydarzyć.  Czy kontener powinien się wtedy „wysypać”? Czy działać dalej? – na to pytanie musisz sobie odpowiedzieć.

Z kolei wewnątrz kontenera LXC, działa wiele procesów. Wynika to z tego, że na starcie uruchamiany jest cały system operacyjny.

Idąc dalej, można by posunąć się o stwierdzenie, że kontenery LXC zostały stworzone z myślą o administratorach a kontenery dockerowe z myślą o developerach. Oczywiście trzeba to traktować nieco z przymrużeniem oka (sys-admini też korzystają z Dockera), aczkolwiek jest w tym trochę prawdy.


Wbudowane mechanizmy

Docker zawiera w sobie niemal wszystkie niezbędne mechanizmy służące do spakowania aplikacji do obrazu, dystrybucję obrazów, aż do uruchomienia kontenera:

  • Dockerfile, dzięki któremu możemy określić zachowanie kontenera
  • Docker Hub, dzięki któremu nie musimy tworzyć obrazów „od zera”
  • Mechanizm do budowania i dystrybucji obrazów (docker build, docker push/pull)
  • Mechanizm uruchamiania kontenerów na podstawie wcześniej zbudowanego obrazu (docker run)

LXC z kolei jest rozdzielone na kilka aplikacji/komponentów. Przykładowo, aby móc zbudować własny obraz, potrzebne jest nam narzędzie distrobuilder.

Definicję obrazu tworzymy za pomocą pliku .yaml. Przykład takiego pliku znajdziesz TUTAJ. Co można o tym powiedzieć? Mechanizm ten wydaje się nieco bardziej skomplikowany niż jego odpowiednik — plik Dockerfile.

Może to wynikać z tego, że definicja pozwala naprawdę na wiele. Wewnątrz niej możemy określić nawet listę repozytoriów dla managera pakietów (apt) oraz listę paczek, która ma być zainstalowana (np. openssh-client, curl, git itp.).


Docker vs LXC – cechy wspólne


Cgroups

Bez tego mechanizmu pewnie w ogóle nie było by kontenerów. Mowa tutaj o Control Groups (cgroups), które zapoczątkowało narodziny LXC. Zarówno Docker jak i LXC wykorzystują ten mechanizm. 

Namespace

Drugi obok cgroups kluczowy mechanizm wykorzystywany przez kontenery. Wyróżniamy następujące typy namespace’ów

  • Process ID (pid) – każdy kontener posiada własne drzewo procesów (proces w kontenerze A, nie wie nic o istnieniu procesu w kontenerze B)
  • Network (net) – czyli IP routing table
  • Mounts (mnt) – montuje system plików
  • Inter-proc comms (ipc) – pozwala procesom wewnątrz kontenera na dostęp to tej samej współdzielonej pamięci, ale rozdziela pamięć od innych procesów z innych kontenerów
  • UTS (uts) – nadaje każdemu kontenerowi hostname
  • User (user) – pozwala na zmapowanie kont wewnątrz kontenera na konta na hoście. Przykład: root w kontenerze zmapowany na readonly user na hoście
Root w kontenerze

Domyślnie zarówno kontenery dockerowe jak i kontenery LXC startują w trybie root’a. Oznacza to, root w kontenerze jest mapowany na root’a na hoście. Ma to oczywiście zły wpływ na bezpieczeństwo. Gdyby atakującemu udało by się wyjść „z kontenera”, może skończyć się to przejęciem całego hosta.

Mamy jednak możliwość re-mapowania roota w kontenerze na użytkownika nieuprzywilejowanego na hoście. Zarówno Docker jak i LXC posiadają taki mechanizm, który wykorzystuje user namespace.


LXC szybki start

Aby skorzystać z LXC na dystrybucjach pochodnych od Debiana, potrzebujemy doinstalować pakiet o nazwie lxc-utils.

Kontenery LXC działają również na innych dystrybucjach takich jak CentOS. Jednak “ojczystą” dystrybucją omawianego rozwiązania jest Ubuntu.

$ apt install lxc-utils

Tworzenie kontenerów LXC

Po zainstalowaniu niezbędnych pakietów, możemy przystąpić do tworzenia kontenerów LXC. Pierwsza możliwość to stworzenie kontenera w trybie interaktywnym. Po wpisaniu poniższego polecenia, zostaniemy poproszeni o wskazanie:

  • Dystrybucji
  • Wersji
  • Architektury

W moim przypadku było to kolejno: ubuntu, bionic, amd64

$ sudo lxc-create --template download --name u1

Distribution:
ubuntu
Release:
bionic
Architecture:
amd64

Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs

---
You just created an Ubuntu bionic amd64 (20200328_07:42) container.

Właśnie utworzyliśmy kontener o nazwie u1, bazujący na ubuntu w wersji bionic i architekturze amd64.

Ten sam efekt możemy uzyskać jednym poleceniem:

$ lxc-create -t download -n u1 -- --dist ubuntu --release bionic --arch amd64

Do wyświetlanie kontenerów służy polecenie lxc-ls

$ lxc-ls --fancy
NAME STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
u1   STOPPED 0         -      -    -    false

Po utworzeniu, kontener posiada status STOPPED. Aby go uruchomić, należy użyć polecenia lxc-start

UWAGA: Chcąc uruchomić kontener LXC, nie musimy wskazywać głównego procesu. Kontener domyślnie uruchomi polecenie /sbin/init co spowoduje uruchomienie jednocześnie wielu procesów (o czym za chwilę)

Poniższe polecenie uruchamia kontener LXC o nazwie u1, w trybie dettached (w tle).

$ lxc-start -n u1 -d

Docker vs LXC – procesy w kontenerze

Aby przenieść się do terminala kontenera używamy polecenia lxc-attach

$ lxc-attach u1 bash

Sprawdźmy teraz, jakie procesy działają wewnątrz kontenera:

root@u1:/$ ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.4 159152  8476 ?        Ss   06:31   0:00 /sbin/init
root         38  0.0  0.4  78452  9392 ?        S<s  06:31   0:00 /lib/systemd/systemd-journald
systemd+     42  0.0  0.2  80052  5368 ?        Ss   06:31   0:00 /lib/systemd/systemd-networkd
systemd+     65  0.0  0.2  70636  5112 ?        Ss   06:31   0:00 /lib/systemd/systemd-resolved
root         67  0.0  0.1  31288  3144 ?        Ss   06:31   0:00 /usr/sbin/cron -f
root         68  0.0  0.2  62024  5620 ?        Ss   06:31   0:00 /lib/systemd/systemd-logind
root         69  0.0  0.8 170376 17428 ?        Ssl  06:31   0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
message+     70  0.0  0.2  49924  4248 ?        Ss   06:31   0:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
syslog       71  0.0  0.2 263032  4252 ?        Ssl  06:31   0:00 /usr/sbin/rsyslogd -n
root         76  0.0  0.1  15952  2452 pts/2    Ss+  06:31   0:00 /sbin/agetty -o -p -- \u --noclear --keep-baud pts/2 115200,38400,9600 vt220
root         77  0.0  0.1  15952  2324 pts/1    Ss+  06:31   0:00 /sbin/agetty -o -p -- \u --noclear --keep-baud pts/1 115200,38400,9600 vt220
root         78  0.0  0.1  15952  2324 pts/3    Ss+  06:31   0:00 /sbin/agetty -o -p -- \u --noclear --keep-baud pts/3 115200,38400,9600 vt220
root         79  0.0  0.1  15952  2316 pts/1    Ss+  06:31   0:00 /sbin/agetty -o -p -- \u --noclear --keep-baud console 115200,38400,9600 vt220
root         80  0.0  0.1  15952  2236 pts/0    Ss+  06:31   0:00 /sbin/agetty -o -p -- \u --noclear --keep-baud pts/0 115200,38400,9600 vt220
root         88  0.0  0.1  23188  3836 pts/2    Ss   06:34   0:00 bash
root        100  0.0  0.1  39084  3408 pts/2    R+   06:34   0:00 ps aux

I co widzimy? Wewnątrz kontenera działa wiele procesów, min. Systemd czy Cron.

Dla porównania uruchomimy teraz kontener dockerowy, również na podstawie ubuntu, wskazując główny proces kontenera jako bash, po to, by następnie wyświetlić listę procesów.

$ docker run -it ubuntu /bin/bash
root@997e7a66b371:/$ ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.3  0.1  18504  3344 pts/0    Ss   06:38   0:00 /bin/bash
root         10  0.0  0.1  34400  2808 pts/0    R+   06:39   0:00 ps aux

Jak łatwo zauważyć w obrębie kontenera dockerowego działa tylko proces /bin/bash oraz proces, który służy do wyświetlania procesów (ps aux).


Docker vs LXC – zużycie zasobów przez kontener

Porównamy teraz, ile zasobów sprzętowych potrzebują oba typy kontenerów. Na początku sprawdźmy kontener LXC. Służy do tego polecenie lxc-info

$ lxc-info -n u1 -S
CPU use:        2.16 seconds
BlkIO use:      161.71 MiB
Memory use:     257.47 MiB
KMem use:       9.54 MiB
Link:           veth22ME4X
 TX bytes:      2.17 KiB
 RX bytes:      2.97 KiB
 Total bytes:   5.14 KiB

Sprawdźmy teraz jak to wygląda w przypadku kontenera dockerowego. W tym celu użyjemy polecenia docker stats.

$ docker stats ubuntu-docker --no-stream
CONTAINER ID   NAME            CPU %    MEM USAGE / LIMIT     MEM %   NET I/O    BLOCK I/O   PIDS
b1cb60de4b1a   ubuntu-docker   0.00%    1.234MiB / 1.861GiB   0.06%   906B / 0B  0B / 0B     1


Jak można łatwo zauważyć, kontener LXC potrzebuje o wiele więcej zasobów niż kontener dockerowy. Wynika to z jego „budowy” – czyli uruchomienia pełnoprawnego systemu operacyjnego. W kontenerze dockerowym, działa tylko jeden proces – /bin/bash. W związku z tym ilość potrzebnych zasobów do wykonania tego procesu jest znikoma.


LXD – czyli turbodoładowane LXC

Projekt pod nazwą LXD został uruchomiony w roku 2015, używając tych samych komponentów co LXC. Celem LXD było stworzenie przyjaźniejszego w użyciu ekosystemu. Bez wątpienia, narodziny Dockera w 2013 roku i rosnąca jego popularność skłoniła twórców LXD do działania, by móc „konkurować” z Dockerem.

Pomimo, że zarówno LXC jak i LXD są stale rozwijane, dla osób które nigdy nie korzystały z LXC, istnieje rekomendacja, aby od razu zacząć od LXD.

Jeżeli chciałbyś skorzystać z kontenerów LXD, możesz to zrobić w środowisku online TUTAJ. Jest to interaktywny tutorial przedstawiający podstawowe polecenia.


LXD – jak to działa?

LXD nieco skopiowało architekturę od Dockera. Głównie mowa tutaj o daemonie, z którym możemy się komunikować za pomocą REST API. Dzięki temu nie jesteśmy uzależnieni od terminala, lecz możemy nawet samemu tworzyć aplikacje komunikujące się z daemonem.

W przeciwieństwie do LXC, używając LXD wszystkie tworzone kontenery, są uruchamiane w trybie non-root. Aby uruchomić kontener w trybie root’a, musimy jasno to określic (-c security.privileged=true)


LXD – repozytorium obrazów

LXD posiada tez własne repozytorium obrazów dostępne TUTAJ.

Znajdziemy w nim niemalże wszystkie dystrybucje systemu Linux. W przeciwieństwie do Docker Hub’a, nie ma tutaj gotowych obrazów przeznaczonych dla konkretnej technologii, tak by wykorzystać go na potrzeby danej aplikacji.

Chcąc uruchomić aplikację przy użyciu kontenerów LXD, sami musimy stworzyć obraz bazując na wybranej przez nas dystrybucji. Przykład tworzenia obrazu LXD dla aplikacji NodeJS znajdziesz TUTAJ.


Docker vs LXD – polecenia

Poniżej znajdziesz porównanie poleceń. Jak łatwo zauważyć są one bardzo podobne.

Docker LXD
docker image ls lxc image list
docker container run –name first ubuntu:18.04 lxc launch images:ubuntu/18.04 first
docker container stop first lxc stop first
docker container rm firstlxc delete first
docker container lslxc list
docker container inspect firstlxc config show first
docker exec -it first /bin/bashlxc exec first — /bin/bash


Podsumowanie

Kontenery LXC mogą być swiętną alternatywą dla wirtualnej maszyny. Przede wszystkim są lżejsze, gdyż korzystają z kernela systemu hosta, jednocześnie zapewniając nam działania pełnoprawnego systemu operacyjnego.

Idea używania Dockera jest zupełnie inna. Od samego początku, jego głównym przeznaczeniem jest możliwość uruchomienia pojedynczej APLIKACJI w kontenerze, zamiast uruchamiania całego systemu operacyjnego.

Docker vs LXC – gdzie zatem stosować Dockera a gdzie LXC?

Jednym zdaniem – Docker do uruchamiania aplikacji, LXC (LXD) – tam, gdzie chcę wykorzystać zalety wirtualnej maszyny, ale aż tak bardzo nie potrzebuję pełnej wirtualizacji.


Artykuł Docker vs LXC – czym to się różni? pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/czym-rozni-sie-docker-od-lxc/feed/ 10
Zmienne środowiskowe w Dockerze https://szkoladockera.pl/zmienne-srodowiskowe-w-dockerze/ https://szkoladockera.pl/zmienne-srodowiskowe-w-dockerze/#respond Thu, 19 Mar 2020 07:08:15 +0000 https://szkoladockera.pl/?p=1508 Przeglądając grupy tematyczne związane z Dockerem, zauważyłem, że wiele osób ma problem z zrozumieniem, w jaki sposób można przekazywać zmienne środowiskowe do obrazu i do kontenera. Zmotywowało mnie to do stworzenia tego artykułu. Z artykułu dowiesz się WSZYSTKO na temat zmiennych środowiskowych w Dockerze. Oczywiście wszystko na przykładach, tak by Więcej…

Artykuł Zmienne środowiskowe w Dockerze pochodzi z serwisu Szkoła Dockera.

]]>
Przeglądając grupy tematyczne związane z Dockerem, zauważyłem, że wiele osób ma problem z zrozumieniem, w jaki sposób można przekazywać zmienne środowiskowe do obrazu i do kontenera. Zmotywowało mnie to do stworzenia tego artykułu.

Z artykułu dowiesz się WSZYSTKO na temat zmiennych środowiskowych w Dockerze. Oczywiście wszystko na przykładach, tak by łatwiej było zrozumieć, a następnie móc zastosować u siebie.

Post ten jest kontynuacją serii, w której opisują poszczególne instrukcje Dockerfile. Jeżeli jeszcze nie widziałeś, koniecznie sprawdź COPY vs ADD oraz CMD vs ENTRYPOINT.


Zastosowania instrukcji ENV

Wewnątrz pliku Dockerfile, instrukcja ENV służy do tworzenia zmiennych środowiskowych. Podczas uruchamiania kontenera na podstawie obrazu, możemy nadpisać ich wartość. Taka praktyka jest bardzo często stosowana.

Do czego mogą służyć zmienne środowiskowe? Niemal każda aplikacja ma jakąś konfigurację.

Przykłady:

  • adres IP do bazy danych
  • adres IP do innych usług (Elasticsearch, Vault etc.)
  • zmienne związane z technologią (NODE_ENV, JAVA_VERSION etc)
  • zmienne związane z logiką biznesową


Sposoby na przekazywanie zmiennych środowiskowych

1. Uruchamianie kontenera z terminala

Jeżeli tworzysz kontener korzystając z terminala, do nadpisania lub ustawienia zmiennej środowiskowej służy argument -e KLUCZ=WARTOŚĆ. Poniżej tworzymy kontener WordPressa, przekazując w zmiennych środowiskowych połączenie do bazy danych.

docker run -e WORDPRESS_DB_HOST=10.1.2.3:3306 \
    -e WORDPRESS_DB_USER=user \
    -e WORDPRESS_DB_PASSWORD=somepassword \
    -d wordpress

2. Uruchamianie z pomocą docker-compose

Ten sam efekt możesz uzyskać wewnątrz pliku docker-compose.yml

version: '3.1'

services:

  wordpress:
    image: wordpress
    environment:
       - WORDPRESS_DB_HOST: 10.1.2.3:3306
       - WORDPRESS_DB_USER: user 
       - WORDPRESS_DB_PASSWORD: somepassword
       - WORDPRESS_DB_NAME: exampledb

3. Bezpośrednio w Dockerfile

Istnieją pewne przypadki, dla których na stałe chcemy ustawić zmienną środowiskową. Jak już wyżej wspominałem, może dotyczyć to technologii, w której tworzymy aplikację. Przykładowo, chcemy na stałe ustawić zmienną środowiskową NODE_VERSION. Przykład poniżej.

FROM scratch

# set up node
ENV NODE_VERSION 8.9.4
ENV NODE_DOWNLOAD_SHA 21fb4690e349f82d708ae766def01d7fec1b085ce1f5ab30d9bda8ee126ca8fc
RUN curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \
    && echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \
    && tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \
    && rm nodejs.tar.gz \
    && ln -s /usr/local/bin/node /usr/local//nodejs


Stosowanie plików .env

Istnieje możliwość stworzenia pliku o nazwie .env. Zawartość tego pliku może posłużyć do nadpisania wartości znajdujących się w pliku docker-compose.yml. Warto zaznaczyć, że oba pliki muszą znajdować się w tym samym katalogu.

Zawartość pliku .env defniujemy za pomocą schematu klucz=wartość

DB_PORT=5434
DB_USER=myuser

Przykład pliku docker-compose, gdzie to zadziała. Zwróć uwagę w jaki sposób określamy, że zmienna ma zostać podstawiona. Jest to składnia ${DB_PORT} oraz ${DB_USER}

version: '3.2'

services:
  postgres:
    image: postgres:9.6
    ports:
      - ${DB_PORT}:5432
    environment:
        POSTGRES_PASSWORD: secretpassword
        POSTGRES_USER: ${DB_USER}

Aby upewnić się, że wartości są podstawiane prawidłowo wystarczy użyć komendy docker-compose config

$ docker-compose config                  
services:                                
  postgres:                              
    environment:                         
      POSTGRES_PASSWORD: secretpassword  
      POSTGRES_USER: myuser              
    image: postgres:9.6                  
    ports:                               
    - published: 5434                    
      target: 5432                       
version: '3.2'

W miejsce ${DB_USER} została podstawiona wartość myuser, a w miejsce ${DB_PORT} wartość 5434. Wartości te pochodzą z pliku .env. Warto podkreślić, że oba pliki muszą znajdować się w tym samym katalogu.

Gdzie takie podejście może mieć zastosowanie?

Plik docker-compose.yml jest dodawany do kontroli wersji, natomiast plik .env już nie. Dzięki temu, każdy z członków zespołu może mieć inną zawartość pliku .env według własnych potrzeb, co nie będzie powodować żadnych zmian w repozytorium.


Zmienne środowiskowe na hoście nadpisują wpisy w pliku .env

Jeżeli na hoście istnieje zmienna o takiej samej nazwie jak wewnątrz pliku .env, wartość zostanie pobrana z zmiennej środowiskowej hosta! Sprawdźmy to na przykładzie. Na hoście ustawiłem wartość zmiennej środowiskowej JAVA_HOME na C:\Program Files\Java\jdk1.8.0_221

Mamy następujące plik docker-compose.yml, w którym odwołujemy się do ${JAVA_HOME}

version: '3.2'

services:
  myapp:
    image: openjdk:7
    environment:
        JAVA_DIRECTORY: ${JAVA_HOME}

W tym samym katalogu znajduje się również plik .env zawierający zmienną JAVA_HOME=D:/java

JAVA_HOME=D:/java

Teraz pozostaje sprawdzić całość za pomocą polecenia docker-compose config

$ docker-compose config
services:
  myapp:
    environment:
      JAVA_DIRECTORY: C:\Program Files\Java\jdk1.8.0_221
    image: openjdk:7
version: '3.2'

Rezulat? Zamiast wartości zdefiniowanej w pliku .env, została podstawiona wartość zmiennej środowiskowej z hosta! (C:\Program Files\Java\jdk1.8.0_221)


Zmienne w terminalu nadpisują wszystko

Nie można było o tym nie wspomnieć. Definiując zmienną środowiskową wewnątrz terminala, ma ona najwyższy priorytet.

Ustawiamy zmienną środowiskową (system Windows):

$ set JAVA_HOME=D:\shell_variable_path

Obecny stan zmiennych o nazwie JAVA_HOME:

  • na hoście: C:\Program Files\Java\jdk1.8.0_221
  • w pliku .env:  D:\java
  • w terminalu: D:\shell_variable_path

Tradycyjnie sprawdzamy rezultat poleceniem docker-compose config

$ docker-compose config
services:
  myapp:
    environment:
      JAVA_DIRECTORY: D:\shell_variable_path
    image: openjdk:7
version: '3.2'

Tym sposobem mamy potwierdzenie, iż zmienne środowiskowe zdefiniowane w terminalu mają najwyższy priorytet!

UWAGA: Plik .env nie ma nic wspólnego z instrukcjami ENV wewnątrz Dockerfile oraz argumentem `-e` w terminalu!  Oznacza to, że wartości zdefiniowane w pliku .env, NIE trafią bezpośrednio do kontenera, a służą tylko do podstawiania wartości w pliku docker-compose.yml


Inne sposoby na przekazywanie zmiennych środowiskowych do kontenera

Po zbudowaniu obrazu, możemy uruchamiać kontenery i przekazywać do nich zmienne środowiskowe na kilka sposobów. W każdym przypadku, spowoduje to nadpisanie domyślnych wartości zdefiniowanych w Dockerfile.

1. Zmienne środowiskowe z hosta

Jak to działa? Standardowo korzystamy z argumentu -e, ale z małą różnicą. Podajemy tylko nazwę zmiennej, bez wartości. W ten sposób docker pobiera zmienną środowiskową zdefiniowaną w terminalu (jeżeli istnieje) lub w systemie hosta.

Obecnie w terminalu wartość zmiennej JAVA_HOME=D:\shell_variable_path

Uruchamiamy kontener w trybie interaktywnym z konsolą, wskazując -e JAVA_HOME. Następnie wewnątrz kontenera, wyświetlamy zawartość zmiennej.

$ docker run -it -e JAVA_HOME alpine sh
/ # $JAVA_HOME 
sh: D:\shell_variable_path

Widzimy, że wewnątrz kontenera została podstawiona wartość z hosta (a dokładnie z terminala hosta).

2. Wartości z pliku (env_file)

Tworzymy plik o dowolnej nazwie, a jego zawartość powinna opierać się o wpisach typu klucz=wartość. Dla przykładu, plik ten będzie miał nazwę my_env_file (bez żadnego rozszerzenia), a jego zawartość będzie następująca:

VARIABLE_NAME=variable_value

Uruchamiamy kontener z parametrem env (spowoduje wyświetlenie wszystkich zmiennych środowiskowych) wskazując na plik my_env_file:

$ docker run --env-file=my_env_file alpine env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=77929624bad0
VARIABLE_NAME=variable_value
HOME=/root

Możemy również wykorzystać to samo podejście w pliku docker-compose.yml, dodając wpis env_file: <ścieżka_do_pliku>

version: '3.2'

services:
  alpine:
    image: alpine
    env_file: my_env_file


Podsumowanie

Stosowanie zmiennych środowiskowych w Dockerze jest czymś naturalnym i często wykorzystywanym. Na przykładzie WordPressa widzimy, że nawet oficjalne obrazy, które możemy znaleźć na Docker Hubie stosują ten mechanizm. Warto go zatem znać i rozumieć jak działa.

Mam nadzieję, że nieco pomogłem zrozumieć Ci jak działają zmienne środowiskowe w Dockerze, lub bynajmniej post ten spowodował odświeżenie Twojej dotychczasowej wiedzy. Ważne, że w razie wątpliwości można tutaj wrócić i rozwiać swoje wątpliwości, do czego gorąco zachęcam!



Artykuł Zmienne środowiskowe w Dockerze pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/zmienne-srodowiskowe-w-dockerze/feed/ 0
Dockerfile – ENTRYPOINT vs CMD https://szkoladockera.pl/dockerfile-entrypoint-vs-cmd/ https://szkoladockera.pl/dockerfile-entrypoint-vs-cmd/#comments Thu, 20 Feb 2020 05:48:01 +0000 https://szkoladockera.pl/?p=1211 Ostatnio jeden z czytelników bloga zadał mi pytanie: Co powinienem użyć w moim Dockerfile? ENTRYPOINT czy CMD? Postanowiłem, że odpowiem na to pytanie w formie artykułu – tak byś i Ty mógł/mogła z tego skorzystać. Post dołącza do serii A vs B, gdzie w jednym z poprzednich artykułów omawialiśmy różnicę pomiędzy ADD i COPY. Więcej…

Artykuł Dockerfile – ENTRYPOINT vs CMD pochodzi z serwisu Szkoła Dockera.

]]>
Ostatnio jeden z czytelników bloga zadał mi pytanie: Co powinienem użyć w moim Dockerfile? ENTRYPOINT czy CMD? Postanowiłem, że odpowiem na to pytanie w formie artykułu – tak byś i Ty mógł/mogła z tego skorzystać.

Post dołącza do serii A vs B, gdzie w jednym z poprzednich artykułów omawialiśmy różnicę pomiędzy ADD i COPY. Link do tego artykułu znajdziesz TUTAJ.

Jak sam tytuł wskazuje, dzisiaj przyjrzymy się bardziej szczegółowo instrukcjom ENTRYPOINT oraz CMD.

Wprowadzenie

Kiedy uruchamiamy kontener, uruchamiamy go na podstawie obrazu. Dzięki temu jesteśmy w stanie przenosić zachowanie kontenerów pomiędzy środowiskami. To, co znajdzie się wewnątrz obrazu oraz jak będzie się zachowywać kontener po uruchomieniu, określamy w pliku Dockerfile. Plik Dockerfile to zbiór instrukcji, gdzie zwykle każda z instrukcji dodaje kolejną warstwę do finalnego obrazu.

Z reguły w pierwszej warstwie obrazu znajdują się pliki systemowe. Kolejne polecenia takie jak RUN, COPY, ADD tworzą następne warstwy, by finalnie stworzyć kompletny obraz naszej aplikacji.

Przykładowo — nasz obraz może być zbudowany na podstawie Ubuntu (polecenie FROM). W kolejnej warstwie instalujemy dodatkowe pakiety, które są niezbędne do działa naszej aplikacji. Następnie kopiujemy artefakty aplikacji i wskazujemy proces startowy kontenera za pomocą polecenia CMD.

TL;DR;

A czy możemy użyc tutaj ENTRYPOINT zamiast CMD?

Odpowiedź brzmi: TAK, możemy. Nawet powinniśmy!

FROM ubuntu:18.04
RUN apt update && apt install python3
COPY my_script.py /
CMD ["python", "my_script.py"]

Instrukcje ENTRYPOINT oraz CMD pozwalają określić punkt startowy dla kontenera, ale istnieje znaczna różnica pomiędzy nimi. Może zatem pojawić się dylemat, którą instrukcję wybrać albo która instrukcja jest rekomendowana.


Shell vs Exec

Zarówno instrukcja CMD, jak i ENTRYPOINT mogą występować w dwóch formach. Shell oraz Exec.

Exec

Składnia formy Exec (rekomendowanej) jest następująca:

<instruction> ["executable", "param1", "param2"]

FROM ubuntu:18.04
CMD ["/bin/ping", "localhost"]

Gdy polecenie jest wykonywane, następuje odwołanie bezpośrednio do pliku wykonywalnego. W tym przypadku jest to /bin/ping localhost.

Shell

Składnia formy Shell jest następująca:

<instruction> <command>

FROM ubuntu:18.04
CMD ping localhost

Podczas wykonywania instrukcji zbudowanej w formie Shell, zamiast bezpośredniego odwołania do pliku wykonywalnego, wywoływane jest procesowanie przez shell:
/bin/sh -c 'ping localhost'

Abyś mógł lepiej zrozumieć różnicę, uruchomiłem dwa kontenery i nadałem im nazwy odpowiadające formom Shell i Exec. Całość wygląda następująco:

CONTAINER ID        COMMAND                    STATUS              NAMES
dac330dd8ff6        "/bin/sh -c 'ping lo…"     Up 30 seconds       shell-form
b83174ca6fb0        "/bin/ping localhost"      Up 40 seconds       exec-form

Jeżeli chcesz poznać najlepsze praktyki tworzenia Dockerfile, zachęcam do lektury
„10 Najlepszych Praktyk Tworzenia Dockerfile”


CMD

Instrukcja CMD pozwala na określenie domyślnego polecenia, które zostanie wykonane tylko podczas uruchamiania kontenera bez podawania dodatkowych argumentów. Jeżeli uruchomisz kontener z dodatkowym argumentem, domyślne polecenie zostanie zignorowane. Jeżeli Twój Dockerfile posiada więcej niż jedną instrukcję CMD, tylko ostatnia jest brana pod uwagę. Pozostałe są ignorowane.

CMD może występować w trzech formach:

  • CMD ["executable","param1","param2"] (forma Exec, rekomendowana)
  • CMD ["param1","param2"] (pozwala na przekazanie dodatkowych parametrów do instrukcji ENTRYPOINT)
  • CMD command param1 param2 (forma Shell)

Załóżmy następujący Dockerfile:

FROM ubuntu:18.04
CMD echo "Hello world"

Gdy uruchomimy kontener bez przekazywania dodatkowych argumentów, za pomocą polecenia:

docker run -it <image> otrzymamy następujący rezultat:

Hello world

Jeżeli natomiast dodamy dodatkowy argument /bin/bash i uruchomimy kontener za pomocą polecenia docker run -it <image> /bin/bash, polecenie echo „Hello world” zostaje zignorowane i uruchamiany jest terminal.

root@8cb0763a478d:/#


ENTRYPOINT

Instrukcja ENTRYPOINT również służy do określenia głównego procesu kontenera. Wygląda bardzo podobnie do CMD, ponieważ pozwala na określenie polecenia wraz z parametrami.
Istnieje jednak znacząca różnica w działaniu ENTRYPOINT. Mianowicie, po uruchomieniu kontenera z dodatkowymi parametrami, domyślne polecenie NIE jest pomijane, jak w przypadku CMD.

ENTRYPOINT występuje w dwóch formach:

  • ENTRYPOINT ["executable", "param1", "param2"] (forma Exec)
  • ENTRYPOINT command param1 param2 (forma Shell)

Exec

Exec jest rekomendowanym podejściem. Dlaczego tak jest?

Forma exec instrukcji ENTRYPOINT pozwala na zdefiniowanie dodatkowych parametrów polecenia, które w zależności od potrzeb mogą ulec zmianie. Odbywa się to za pomocą komendy CMD.


Jak to wygląda? Argumenty zawarte w instrukcji ENTRYPOINT zawsze się wykonają. Z kolei argumenty instrukcji CMD są opcjonalne i mogą zostać nadpisane podczas uruchamiania kontenera.

ENTRYPOINT ["/bin/echo", "Hej"]
CMD ["Damian"]

Gdy uruchomimy kontener bez przekazywania dodatkowych argumentów, za pomocą polecenia:

docker run -it <image> otrzymamy następujący rezultat:

Hej Damian

Jeżeli natomiast dodamy dodatkowy argument 'Filip’ i uruchomimy kontener za pomocą polecenia docker run -it <image> Filip, otrzymamy:

Hej Filip

Shell

Postać Shell instrukcji ENTRYPOINT nie bierze pod uwagę argumentów przekazanych przez CMD.

Omówmy sobie to na tym samym przykładzie:

ENTRYPOINT echo Hej
CMD Damian

Gdy uruchomimy kontener bez przekazywania dodatkowych argumentów, za pomocą polecenia:

docker run -it <image> otrzymamy następujący rezultat:

Hej

Dodając argument 'Filip’ do polecenia docker run -it <image> Filip, otrzymamy nadal to samo:

Hej

Podsumowanie

Jeżeli masz dylemat czy użyć CMD, czy ENTRYPOINT jako punkt startowy twojego kontenera, odpowiedz sobie na następujące pytanie.

Czy zawsze moje polecenie MUSI się wykonać?

Jeśli odpowiedź brzmi tak, użyj ENTRYPOINT. Co więcej, jeśli potrzebujesz przekazać dodatkowe parametry, które mogą być nadpisane podczas uruchomienia kontenera — użyj również instrukcji CMD.


Artykuł Dockerfile – ENTRYPOINT vs CMD pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/dockerfile-entrypoint-vs-cmd/feed/ 1
Dockerfile – COPY vs ADD https://szkoladockera.pl/dockerfile-copy-vs-add/ https://szkoladockera.pl/dockerfile-copy-vs-add/#respond Fri, 03 Jan 2020 06:59:08 +0000 https://szkoladockera.pl/?p=769 Tworząc Dockerfile podstawową kwestią jest kopiowania plików, czy to kodu źródłowego aplikacji, czy plików konfiguracyjnych. Zarówno poleceniem ADD jak i COPY można skopiować pliki/katalogi do określonej lokalizacji do Docker Image. COPY Polecenie COPY pozwala TYLKO na kopiowanie plików/katalogów do określonej lokalizacji wewnątrz Docker Image. Składnia COPY jest następująca: Warto tutaj Więcej…

Artykuł Dockerfile – COPY vs ADD pochodzi z serwisu Szkoła Dockera.

]]>
Tworząc Dockerfile podstawową kwestią jest kopiowania plików, czy to kodu źródłowego aplikacji, czy plików konfiguracyjnych.

Zarówno poleceniem ADD jak i COPY można skopiować pliki/katalogi do określonej lokalizacji do Docker Image.

COPY

Polecenie COPY pozwala TYLKO na kopiowanie plików/katalogów do określonej lokalizacji wewnątrz Docker Image.

Składnia COPY jest następująca:

COPY [--chown=<user>:<group>] <src>... <dest>

Warto tutaj zwrócić uwagę na opcjonalny parametr --chown, służący do nadawania praw do kopiowanych plików/katalogów.

Domyślnie prawa do kopiowanych plików/katalogów ma użytkownik root.

Gdy użyjemy następującego polecenia:

COPY /source/file/path  /destination/path

Prawa do /destination/path zostaną nadane użytkownikowi root.

Gdy chcemy nadać prawa np. użytkownikowi patrick, polecenie będzie następujące:

COPY --chown=patrick /source/file/path  /destination/path


UWAGA: Funkcja --chown jest obsługiwana tylko do budowania kontenerów Linuxowych i nie działa w Windows Containers.


ADD

Polecenie ADD robi to samo co COPY, ale oprócz tego obsługuję dodatkowe przypadki.

Po pierwsze:

Możesz użyć adresu URL zamiast lokalnego pliku / katalogu.

ADD http://example.com/file.png /home

Po drugie:

Możesz wyodrębnić plik tar ze źródła bezpośrednio do miejsca docelowego.

ADD myfile.tar.gz /home/extracted_myfile 

Pomimo, że kopiowanie bezpośrednio z URL za pomocą ADD jest możliwe, Docker zaleca by tego NIE ROBIĆ.


O ile to możliwe, unikaj korzystania z ADD, by nie być podatnym na ataki za pośrednictwem nieporządanych URL


Jeżeli chcesz poznać najlepsze praktyki tworzenia Dockerfile, zachęcam do lektury
„10 Najlepszych Praktyk Tworzenia Dockerfile”


Rekomendowanym podejściem jest użycie komendy RUN + curl/wget.

Przykładowo, zamiast

ADD http://example.com/big.tar.xz /usr/src/things/<br>
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things<br>
RUN make -C /usr/src/things all

Należy użyć

RUN mkdir -p /usr/src/things \
     && curl -SL  http://example.com/big.tar.xz \
     | tar -xJC /usr/src/things \
     && make -C /usr/src/things all


Podsumowanie

Prawidłowym i rekomendowanym wykorzystaniem ADD jest przypadek, w którym chcemy rozpakować lokalne archiwum tar do określonego katalogu wewnątrz Docker Image. Praktycznie, ma to zastosowanie w oficjalnym obrazie alpineADD rootfs.tar.gz

Dla wszystkich przypadków gdzie nie wymagane jest automatyczne rozpakowanie pliku tar, należy używać polecenia COPY.

Artykuł Dockerfile – COPY vs ADD pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/dockerfile-copy-vs-add/feed/ 0
Jak warstwy i pliki są przechowywane na dysku? Docker Storage Drivers https://szkoladockera.pl/jak-warstwy-i-pliki-sa-przechowywane-na-dysku/ https://szkoladockera.pl/jak-warstwy-i-pliki-sa-przechowywane-na-dysku/#respond Tue, 24 Dec 2019 06:59:37 +0000 https://szkoladockera.pl/?p=721 Cześć! Publikuję trzecie video z serii „Docker Dla Zaawansowanych”. Jeżeli nie widziałeś dwóch poprzednich filmów – gorąco zachęcam 🙂 Jak zbudowany jest Docker Image – wprowadzenie TUTAJDocker Image oraz Docker Registry TUTAJ W tym video tłumaczę w jaki sposób obrazy oraz kontenery są przechowywane na dysku. Dodatkowo dowiesz się o: Więcej…

Artykuł Jak warstwy i pliki są przechowywane na dysku? Docker Storage Drivers pochodzi z serwisu Szkoła Dockera.

]]>
Cześć!

Publikuję trzecie video z serii „Docker Dla Zaawansowanych”.

Jeżeli nie widziałeś dwóch poprzednich filmów – gorąco zachęcam 🙂

Jak zbudowany jest Docker Image – wprowadzenie TUTAJ
Docker Image oraz Docker Registry TUTAJ

W tym video tłumaczę w jaki sposób obrazy oraz kontenery są przechowywane na dysku.

Dodatkowo dowiesz się o:

? przechowywaniu danych tymczasowych kontenera
? przechowywaniu warstw obrazu na dysku
? CO TO jest storage driver i PO CO?
? SZCZEGÓŁOWE omówienie storage drivera – OVERLAY2.

Artykuł Jak warstwy i pliki są przechowywane na dysku? Docker Storage Drivers pochodzi z serwisu Szkoła Dockera.

]]>
https://szkoladockera.pl/jak-warstwy-i-pliki-sa-przechowywane-na-dysku/feed/ 0