Как стартирах Docker в Docker и какво се случи

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

Как стартирах Docker в Docker и какво се случи

Начало

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

Практика. Уроци

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

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

    docker run --privileged -it docker:18.09.6

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

  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. Най-накрая отново сме в познатия shell.

  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. Отново сме в bash.

Започвайки от този момент, можем да опитваме да стартираме други контейнери в нашия 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

    Попаднахме в контейнер, откъдето можем незабавно да започнем стартирането на дъщерни контейнери.

  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 и монтиране на директории дълбоко в вложените контейнери.

P.S. Ако смятате, че този проект е полезен, моля дайте му звезда в GitHub, направете fork и разкажете на приятелите си.

Edit1 Поправих грешките, фокусирах се върху 2 видеа.

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

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster