សួស្តីអ្នកទាំងអស់គ្នា! នៅក្នុងរបស់គាត់។
Начало
Все началось дождливым сентябрьским вечером, когда я чистил арендованную за $5 машинку на Digital Ocean, которая намертво повисла из-за того что Докер заполонил своими образами и контейнерами все 24 гигабайта доступного дискового пространства. Ирония была в том, что все эти образы и контейнеры были транзиентными и нужны были лишь для того чтобы тестировать работоспособность моего приложения каждый раз когда выходила новая версия какой-либо библиотеки или фреймворка. Я пробовал писать шелл-сркипты и настраивать расписание крон для очистки мусора, но это не спасло: каждый раз все неминуемо заканчивалось тем, что дисковое пространство моего сервера оказывалось съеденным а сервер зависшим (в лучшем случае). В какой-то момент я наткнулся на статью про то как запускать Jenkins в контейнере и как он может создавать и удалять сборочные конвееры через проброшенный в него сокет докер демона. Идея мне приглянулась, но я решил пойти дальше и попробовать поэкспериментировать с непосредственным запуском Докера внутри Докера. Мне тогда казалось вполне логичным решением выкачивать докер образы и создавать контейнеры всех приложений которые мне нужны для тестирования внутри другого контейнера (давайте назовем его staging контейнер). Идея заключалась в том, чтобы запускать staging контейнер с флагом -rm, что автоматически удаляет весь контейнер со всем его содержимым при его остановке. Я покопался с докер образом от самого Докера (
Практика. Шишки
Я задался целью заставить контейнер работать так как мне было нужно и продолжал свои эксперименты, результатом которых стало несметное количество шишек. Итогом моего самоистязания стала следующий алгоритм:
-
Запускаем Докер контейнер в интерактивном режиме.
docker run --privileged -it docker:18.09.6
Обратите внимание на версию контейнера, шаг вправо или в лево и ваш ДинД превращается в тыкву. На самом деле, все ломается довольно часто с выходом новой версии.
Мы должны сразу попасть в шелл. -
Пробуем узнать, какие контейнеры запущены (Ответ: никакие), но давайте выполним команду все-равно:
docker ps
Вы будете немного удивлены, но оказывается Докер демон даже не запущен:
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 (в баше всяко работать приятнее чем в sh):
apk add --no-cache iptables bash
-
Запускаем bash. Наконец-то мы снова в привычном шелле
-
попробуем запустить Докер еще раз:
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. Мы снова в баше.
Начиная с этого момента мы можем пробовать запускать другие контейнеры внутри нашего Докер контейнера, но что если мы хотим поднять еще один Докер контейнер внутри нашего Докер контейнера или что-то пойдет не так и контейнер «вылетит»? Начинать все с начала.
Собственный DinD контейнер и новые эксперименты
Чтобы не повторять вышеописанные шаги снова и снова я создал собственный DinD контейнер:
Рабочее DinD решение дало мне возможность запускать Докер внутри Докера рекурсивно и проводить более смелые эксперименты.
Один такой (удачный) эксперимент с запуском MySQL и Nodejs я собираюсь сейчас описать.
Самые нетерпеливые могут посмотреть как это было здесь
ដូច្នេះសូមចាប់ផ្តើម៖
-
Запускаем DinD в интерактивном режиме. В данной версии DinD нам нужно вручную замапить все порты которые могут использовать наши дочерние контейнеры (я над этим уже работаю)
docker run --privileged -it -p 80:8080 -p 3306:3306 alekslitvinenk/dind
Мы попадаем в баш, откуда можем сразу приступать к запуску дочерних контейнеров.
-
Запускаем 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!».
В моем случае эксперимент с вложенными Докер контейнерами оказался довольно положительным и я продолжу развивать проект и использовать его для стейджинга. Мне кажется, что это гораздо более легковесное решение чем тот же Kubernetes и Jenkins X. Но это мое субъективное мнение.
Я думаю, что для сегодняшней статьи — это все. В следующей статье я более подробно опишу эксперименты с рекурсивным запуском Докера в Докере и монтирование директорий вглубь вложенных контейнеров.
PS Если вы считаете данный проект полезным, то пожалуйста поставьте ему звездочку на ГитХабе, сделайте форк и расскажите друзьям.
កែសម្រួល 1 Исправил ошибки, сделал фокус на 2 видео
ប្រភព: www.habr.com