Cześć wszystkim! W jego
początek
Wszystko zaczęło się pewnego deszczowego wrześniowego wieczoru, kiedy czyściłem maszynę wypożyczoną za 5 dolarów w Digital Ocean, która została zamrożona, ponieważ Docker zapełnił swoimi obrazami i kontenerami wszystkie 24 gigabajty dostępnego miejsca na dysku. Ironią losu było to, że wszystkie te obrazy i kontenery były tymczasowe i potrzebne tylko do testowania wydajności mojej aplikacji za każdym razem, gdy wydawana była nowa wersja biblioteki lub frameworka. Próbowałem pisać skrypty powłoki i konfigurować harmonogram cron do czyszczenia śmieci, ale to nie pomogło: za każdym razem kończyło się to nieuchronnie zajęciem miejsca na dysku mojego serwera i zawieszaniem się serwera (w najlepszym wypadku). W pewnym momencie natknąłem się na artykuł o tym, jak uruchomić Jenkinsa w kontenerze oraz jak może on tworzyć i usuwać potoki kompilacji za pośrednictwem przekazanego do niego gniazda demona dokującego. Podobał mi się ten pomysł, ale zdecydowałem się pójść dalej i spróbować poeksperymentować z bezpośrednim uruchamianiem Dockera w Dockerze. W tamtym czasie całkowicie logicznym rozwiązaniem wydawało mi się pobieranie obrazów Dockera i tworzenie kontenerów dla wszystkich aplikacji, które potrzebowałem do testowania w innym kontenerze (nazwijmy to kontenerem pomostowym). Pomysł polegał na uruchomieniu kontenera pomostowego z flagą -rm, która po zatrzymaniu automatycznie usuwa cały kontener i całą jego zawartość. Majstrowałem przy obrazie Dockera z samego Dockera (
Ćwiczyć. Szyszki
Postanowiłem sprawić, że pojemnik będzie działał tak, jak potrzebowałem, i kontynuowałem eksperymenty, które zaowocowały niezliczoną ilością pąków. Efektem moich samotortur był następujący algorytm:
-
Uruchamiamy kontener Docker w trybie interaktywnym.
docker run --privileged -it docker:18.09.6
Zwróć uwagę na wersję pojemnika, wykonaj krok w prawo lub w lewo, a Twój DinD zamieni się w dynię. W rzeczywistości rzeczy często się psują, gdy wydawana jest nowa wersja.
Musimy natychmiast dostać się do skorupy. -
Próbujemy dowiedzieć się, które kontenery są uruchomione (odpowiedź: żaden), ale mimo to uruchommy polecenie:
docker ps
Będziesz trochę zaskoczony, ale okaże się, że demon Dockera nawet nie działa:
error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 192.168.65.1:53: no such host
-
Uruchommy to sami:
dockerd &
Kolejna nieprzyjemna niespodzianka:
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: Iptables not found
-
Zainstaluj pakiety iptables i bash (w bash wszystko jest przyjemniejsze niż w sh):
apk add --no-cache iptables bash
-
Uruchommy basha. Wreszcie wracamy do zwykłej powłoki
-
Spróbujmy ponownie uruchomić Dockera:
dockerd &
Powinniśmy zobaczyć długi arkusz dzienników kończący się słowami:
INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sock
-
Naciśnij enter. Wracamy do bash'a.
Od tej chwili możemy próbować uruchamiać inne kontenery w naszym kontenerze Docker, ale co jeśli będziemy chcieli uruchomić kolejny kontener Docker w naszym kontenerze Docker lub coś pójdzie nie tak i kontener ulegnie awarii? Zacznij od początku.
Własny kontener DinD i nowe eksperymenty
Aby uniknąć ciągłego powtarzania powyższych kroków, stworzyłem własny kontener DinD:
Działające rozwiązanie DinD umożliwiło mi rekursywne uruchamianie Dockera w Dockerze i przeprowadzanie bardziej ryzykownych eksperymentów.
Opiszę teraz jeden z takich (udanych) eksperymentów z uruchomieniem MySQL i Nodejs.
Najbardziej niecierpliwi mogą zobaczyć jak było tutaj
Zacznijmy:
-
Uruchamiamy DinD w trybie interaktywnym. W tej wersji DinD musimy ręcznie zmapować wszystkie porty, z których mogą korzystać nasze kontenery podrzędne (już nad tym pracuję)
docker run --privileged -it -p 80:8080 -p 3306:3306 alekslitvinenk/dind
Przechodzimy do basha, skąd możemy od razu przystąpić do uruchamiania kontenerów podrzędnych.
-
Uruchom MySQL'a:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql
-
Z bazą danych łączymy się w taki sam sposób, jak łączylibyśmy się z nią lokalnie. Upewnijmy się, że wszystko działa.
-
Uruchom drugi kontener:
docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server
Należy pamiętać, że mapowanie portów będzie dokładne 8080:8080, ponieważ zmapowaliśmy już port 80 z hosta do kontenera nadrzędnego na port 8080.
-
Wchodzimy do localhost w przeglądarce, upewniamy się, że serwer odpowiada „Hello World!”
W moim przypadku eksperyment z zagnieżdżonymi kontenerami Dockera wypadł całkiem pozytywnie i będę dalej rozwijać projekt i wykorzystywać go do stagingu. Wydaje mi się, że jest to dużo lżejsze rozwiązanie niż Kubernetes i Jenkins X. Ale to jest moja subiektywna opinia.
Myślę, że to wszystko w dzisiejszym artykule. W następnym artykule opiszę bardziej szczegółowo eksperymenty z rekurencyjnym uruchamianiem Dockera w Dockerze i montowaniem katalogów głęboko w zagnieżdżonych kontenerach.
PS Jeśli uznasz ten projekt za przydatny, daj mu gwiazdkę na GitHubie, rozwidl go i powiedz znajomym.
Edit1 Poprawione błędy, skupiono się na 2 filmach
Źródło: www.habr.com