Как пуснах Docker в Docker и какво излезе от това

Здравейте всички! В неговия предишна статия, обещах да говоря за стартирането на Docker в Docker и практическите аспекти на използването на този урок. Време е да спазиш обещанието си. Опитен devopser вероятно ще възрази, че тези, които се нуждаят от Docker вътре в Docker, просто препращат сокета на Docker daemon от хоста в контейнера и това ще бъде достатъчно в 99% от случаите. Но не бързайте да ми хвърляте бисквитки, защото ще говорим за действително стартиране на Docker в Docker. Това решение има много възможни приложения и тази статия е за едно от тях, така че седнете и изпънете ръцете си пред себе си.

Как пуснах Docker в Docker и какво излезе от това

Начало

Всичко започна в една дъждовна септемврийска вечер, когато почиствах машината, която наех за $5 в Digital Ocean, която беше замразена поради факта, че Docker беше запълнил всичките 24 гигабайта налично дисково пространство със своите изображения и контейнери. Иронията беше, че всички тези изображения и контейнери бяха преходни и бяха необходими само за тестване на производителността на моето приложение всеки път, когато бъде пусната нова версия на библиотека или рамка. Опитах се да напиша шел скриптове и да настроя график на cron за почистване на боклука, но не помогна: всеки път неизбежно завършваше с изяждане на дисковото пространство на сървъра ми и сървърът висеше (в най-добрия случай). В някакъв момент попаднах на статия за това как да стартирам Jenkins в контейнер и как може да създава и изтрива конвейери за изграждане чрез сокет на докер демон, препратен в него. Хареса ми идеята, но реших да отида по-далеч и да опитам да експериментирам с директно стартиране на Docker в Docker. По това време ми изглеждаше напълно логично решение да изтегля Docker изображения и да създавам контейнери за всички приложения, които са ми необходими за тестване в друг контейнер (нека го наречем етапен контейнер). Идеята беше да се стартира етапен контейнер с флага -rm, който автоматично изтрива целия контейнер и цялото му съдържание, когато бъде спрян. Бръкнах с изображението на Docker от самия Docker (https://hub.docker.com/_/docker), но се оказа твърде тромаво и така и не успях да го накарам да работи така, както ми трябваше, и исках сам да извървя целия път.

Практикувайте. Шишарки

Реших да накарам контейнера да работи така, както ми трябваше, и продължих експериментите си, което доведе до безброй пъпки. Резултатът от моето самоизтезание беше следният алгоритъм:

  1. Стартираме Docker контейнера в интерактивен режим.

    docker run --privileged -it docker:18.09.6

    Обърнете внимание на версията на контейнера, стъпете надясно или наляво и вашият DinD се превръща в тиква. Всъщност нещата доста често се повреждат, когато се пусне нова версия.
    Трябва незабавно да влезем в черупката.

  2. Опитваме се да разберем кои контейнери се изпълняват (Отговор: няма), но нека все пак изпълним командата:

    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

  3. Нека го стартираме сами:

    dockerd &

    Още една неприятна изненада:

    failed to start daemon: Error initializing network controller: error obtaining controller instance: failed 
    to create NAT chain DOCKER: Iptables not found

  4. Инсталирайте пакетите iptables и bash (всичко е по-приятно за работа в bash, отколкото в sh):

    apk add --no-cache iptables bash

  5. Да стартираме bash. Най-накрая се върнахме в обичайната черупка

  6. Нека се опитаме да стартираме 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

  7. Натиснете Enter. Върнахме се в баша.

Отсега нататък можем да опитаме да стартираме други контейнери в нашия Docker контейнер, но какво ще стане, ако искаме да стартираме друг Docker контейнер в нашия Docker контейнер или нещо се обърка и контейнерът се срине? Започнете всичко отначало.

Собствен контейнер DinD и нови експерименти

Как пуснах Docker в Docker и какво излезе от това
За да избегна повтарянето на горните стъпки отново и отново, създадох свой собствен DinD контейнер:

https://github.com/alekslitvinenk/dind

Работещото DinD решение ми даде възможност да стартирам Docker вътре в Docker рекурсивно и да правя по-приключенски експерименти.
Сега ще опиша един такъв (успешен) експеримент с стартиране на MySQL и Nodejs.
Най-нетърпеливите могат да видят как беше тук

Затова нека започнем:

  1. Стартираме DinD в интерактивен режим. В тази версия на DinD трябва ръчно да картографираме всички портове, които нашите дъщерни контейнери могат да използват (вече работя върху това)

    docker run --privileged -it 
    -p 80:8080 
    -p 3306:3306 
    alekslitvinenk/dind

    Влизаме в bash, откъдето веднага можем да започнем да стартираме дъщерни контейнери.

  2. Стартирайте MySQL:

    docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql

  3. Свързваме се с базата данни по същия начин, както бихме се свързали с нея локално. Нека се уверим, че всичко работи.

  4. Стартирайте втория контейнер:

    docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server

    Моля, имайте предвид, че картографирането на портовете ще бъде точно 8080:8080, тъй като вече сме картографирали порт 80 от хоста към родителския контейнер към порт 8080.

  5. Отиваме на localhost в браузъра, уверете се, че сървърът отговаря „Hello World!“

В моя случай експериментът с вложени Docker контейнери се оказа доста положителен и ще продължа да развивам проекта и да го използвам за постановка. Струва ми се, че това е много по-леко решение от Kubernetes и Jenkins X. Но това е моето субективно мнение.

Мисля, че това е всичко за днешната статия. В следващата статия ще опиша по-подробно експерименти с изпълнение на Docker рекурсивно в Docker и монтиране на директории дълбоко във вложени контейнери.

PS Ако намирате този проект за полезен, моля, дайте му звезда в GitHub, разклонете го и кажете на приятелите си.

Edit1 Коригирани грешки, фокусирани върху 2 видеоклипа

Източник: www.habr.com

Добавяне на нов коментар