Здравейте всички! В неговия
Начало
Всичко започна в една дъждовна септемврийска вечер, когато почиствах машината, която наех за $5 в Digital Ocean, която беше замразена поради факта, че Docker беше запълнил всичките 24 гигабайта налично дисково пространство със своите изображения и контейнери. Иронията беше, че всички тези изображения и контейнери бяха преходни и бяха необходими само за тестване на производителността на моето приложение всеки път, когато бъде пусната нова версия на библиотека или рамка. Опитах се да напиша шел скриптове и да настроя график на cron за почистване на боклука, но не помогна: всеки път неизбежно завършваше с изяждане на дисковото пространство на сървъра ми и сървърът висеше (в най-добрия случай). В някакъв момент попаднах на статия за това как да стартирам Jenkins в контейнер и как може да създава и изтрива конвейери за изграждане чрез сокет на докер демон, препратен в него. Хареса ми идеята, но реших да отида по-далеч и да опитам да експериментирам с директно стартиране на Docker в Docker. По това време ми изглеждаше напълно логично решение да изтегля Docker изображения и да създавам контейнери за всички приложения, които са ми необходими за тестване в друг контейнер (нека го наречем етапен контейнер). Идеята беше да се стартира етапен контейнер с флага -rm, който автоматично изтрива целия контейнер и цялото му съдържание, когато бъде спрян. Бръкнах с изображението на Docker от самия Docker (
Практикувайте. Шишарки
Реших да накарам контейнера да работи така, както ми трябваше, и продължих експериментите си, което доведе до безброй пъпки. Резултатът от моето самоизтезание беше следният алгоритъм:
-
Стартираме Docker контейнера в интерактивен режим.
docker run --privileged -it docker:18.09.6
Обърнете внимание на версията на контейнера, стъпете надясно или наляво и вашият DinD се превръща в тиква. Всъщност нещата доста често се повреждат, когато се пусне нова версия.
Трябва незабавно да влезем в черупката. -
Опитваме се да разберем кои контейнери се изпълняват (Отговор: няма), но нека все пак изпълним командата:
docker ps
Ще бъдете малко изненадани, но се оказва, че демонът Docker дори не работи:
error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 192.168.65.1:53: no such host
-
Нека го стартираме сами:
dockerd &
Още една неприятна изненада:
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: Iptables not found
-
Инсталирайте пакетите iptables и bash (всичко е по-приятно за работа в bash, отколкото в sh):
apk add --no-cache iptables bash
-
Да стартираме bash. Най-накрая се върнахме в обичайната черупка
-
Нека се опитаме да стартираме Docker отново:
dockerd &
Трябва да видим дълъг лист от регистрационни файлове, завършващ с:
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
-
Натиснете Enter. Върнахме се в баша.
Отсега нататък можем да опитаме да стартираме други контейнери в нашия Docker контейнер, но какво ще стане, ако искаме да стартираме друг Docker контейнер в нашия Docker контейнер или нещо се обърка и контейнерът се срине? Започнете всичко отначало.
Собствен контейнер DinD и нови експерименти
За да избегна повтарянето на горните стъпки отново и отново, създадох свой собствен DinD контейнер:
Работещото DinD решение ми даде възможност да стартирам Docker вътре в Docker рекурсивно и да правя по-приключенски експерименти.
Сега ще опиша един такъв (успешен) експеримент с стартиране на MySQL и Nodejs.
Най-нетърпеливите могат да видят как беше тук
Затова нека започнем:
-
Стартираме DinD в интерактивен режим. В тази версия на DinD трябва ръчно да картографираме всички портове, които нашите дъщерни контейнери могат да използват (вече работя върху това)
docker run --privileged -it -p 80:8080 -p 3306:3306 alekslitvinenk/dind
Влизаме в bash, откъдето веднага можем да започнем да стартираме дъщерни контейнери.
-
Стартирайте MySQL:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql
-
Свързваме се с базата данни по същия начин, както бихме се свързали с нея локално. Нека се уверим, че всичко работи.
-
Стартирайте втория контейнер:
docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server
Моля, имайте предвид, че картографирането на портовете ще бъде точно 8080:8080, тъй като вече сме картографирали порт 80 от хоста към родителския контейнер към порт 8080.
-
Отиваме на localhost в браузъра, уверете се, че сървърът отговаря „Hello World!“
В моя случай експериментът с вложени Docker контейнери се оказа доста положителен и ще продължа да развивам проекта и да го използвам за постановка. Струва ми се, че това е много по-леко решение от Kubernetes и Jenkins X. Но това е моето субективно мнение.
Мисля, че това е всичко за днешната статия. В следващата статия ще опиша по-подробно експерименти с изпълнение на Docker рекурсивно в Docker и монтиране на директории дълбоко във вложени контейнери.
PS Ако намирате този проект за полезен, моля, дайте му звезда в GitHub, разклонете го и кажете на приятелите си.
Edit1 Коригирани грешки, фокусирани върху 2 видеоклипа
Източник: www.habr.com