План
1) Введение
2) Что такое docker и для чего он мне нужен
3) Что у меня получилось в результате изучения docker
4) Мои конфигурационные файлы docker и docker-compose
5) Выводы
Введение
Всем привет, меня зовут Александр, я являюсь фронтенд разработчиком более 4-х лет. В этой статье хочу поделится своим опытом знакомства с docker и docker-compose. Перед началом основной части хочу отступить и сделать небольшую предисторию: почему мне понадобилось изучить эту технологию? Также, эта статья не является очередным пособием к обучению docker, а всего лишь показывает, что вы получите в результате обучения данной технологии.
Очень долго избегал ее изучения, потому что не понимал зачем она мне нужна, если в основном работаю с одним стеком, который у меня настроен на моей локальной машине, а настраивал его с нуля очень редко. В те годы, а это было в конце 2019 года, я был еще молод и только заходил в it, многого не понимал. Шли годы, я поменял стек с php на js и переехал с бекенда на юай, но все-равно не видел причины для себя, чтобы изучить докера. Так продолжалось до тех пор, пока я не начал вести блог и несколько проектов на основной работе. На всех трех были разные требования. На работе нужно было две версии ноды, а в домашних проектах помимо нее еще нужно разворачивать базу данных. В этот момент я задумался, что пора изучить docker, лучшего момента уже не придумаешь.
Что такое docker и для чего он мне нужен
Давайте для начала вспомним, что такое докер? Докер — это технология, которая позволяет запускать различные образы и среды разработки в контейнере, при этом сама рабочая среда на физической машине может отсутствовать. Теперь давайте обсудим зачем мне нужна данная технология? Ранее я упоминал косвенные причины зачем мне нужен был docker, теперь давайте погрузимся в них глубже. В своем домашнем проекте я использую nodejs и монго. Постоянно настраивать на домашнем компьютере рабочее пространство уже надоело, да и времени сейчас часто не хватает, просто хочется сесть за машину, запустить пару команд и начать работать - это первая причина. Едем дальше, у меня есть стенд с моим блогом, который вы сейчас читаете в данный момент времени, на нем, также, необходимо развернуть рабочую среду, чтобы этот сайт работал. В начале это тоже делал руками, но теперь могу поставить настройку на докер, чтобы на сайте и домашнем компьютере были аналогичные условия работы сайта, а не приближенные — это вторая причина, по которой мне понадобился докер, но не последняя. На работе участвую в командной разработке и у меня уже не раз возникала ситуация, когда необходимо помочь коллегам бекам установить рабочий юай, чтобы они могли тестировать программу. Также бывают ситуации, когда мне нужен рабочий бек или стенд с ним, а т. к. стендом пользуется много людей параллельно — это часто бывает накладывает определенные ограничения и все должны ждать — неудобно. Вот здесь во всей красе и выходит докер, где можно у каждого локально запустить свой экземпляр рабочей версии бека и далее спокойно работать — эта третья и самая главная причина, по которой я решил изучить docker.
Что у меня получилось в результате изучения docker
Когда я ставил себе конечную цель, которая скажет, что я продвинулся достаточно в изучении докера, то мне на глаза попалась следующее умозаключение: основа контейнера докера — это как можно маленькие контейнеры, как можно меньший образ; он должен работать только с одной программой, для которой он предназначен. Она помогла мне понять, что конечной целью изучения докера должна быть работа трех контейнеров, в которых будут работать отдельно юай, бекенд и база данных, и они смогут между собой общаться.
В результате изучения docker у меня получилось настроить работу в режиме разработки двух моих основных домашних проектов. Они запускаются в одном пространстве, могут общаться друг с другом и параллельно можно вести разработку, чтобы каждый раз не пересобирать контейнеры, то есть у меня получилось достичь поставленной цели. Далее хочу поделится тем, с какими проблемами я столкнулся, когда после теории начал настраивать для себя рабочую инфраструктуру на контейнерах.
Самое главное — это проблема с сетями в docker, то есть у меня не было изначально понимания, как общаются между собой запущенные контейнеры. Оказывается, у docker есть три типа сетей: bridge, host, none. Подробно в это не буду погружаться, нас здесь интересует тип bridge, более подробную информацию можно найти в интернете. В docker можно создать отдельную сеть bridge в рамках которой могут работать все запущенные docker контейнеры. В ее пределах контейнеры могут общаться между собой, а отдельный тип был создан, чтобы запущенные контейнеры изолировать от других, чтобы не было влияния посторонних программ. Когда я вдоволь наигрался и понял как работают сети, то начал тестировать, каким образом можно соединить мои собственные контейнеры.
Подключение контейнера с базой данных на стороне бекенда
На изображении «Подключение контейнера с базой данных на стороне бекенда» в примере видно, что вместо localhost после обратного слеша используется имя контейнера, в данном примере — это mongodb, то есть здесь получилось обратится к контейнеру через dns. А вот с подключением бекенда к юаю так не получилось сделать, когда прописал название контейнера, в котором работал бекенд — у меня вызов на сторону бекенда не приходил. В итоге пришлось прописать ip контейнера с беком, чтобы подружить юай и бекенд.
Подключение контейнера с бекендом на стороне юая
На изображении «Подключение контейнера с бекендом на стороне юая» в примере показано, что вместо localhost, как было ранее, прописан ip адрес контейнера с бекендом. Вот таким неоднозначным образом у меня получилось связать три контейнера между собой.
Также необходимо упомянуть еще одного героя, который позволяет автоматизировать управление вышеупомянутыми тремя контейнерами, - docker-compose. Благодаря ему можно двумя командами up и build запустить контейнеры и одной командой stop остановить это все и почистить остатки мусора, который оставляет за собой обычный docker.
В сухом остатке имеем, что для настройки разработки бека с юаем необходимо сделать следующее:
- создать локальную сеть, в рамках которой контейнеры смогут общаться между собой;
- прописать правильные доменные имена/ip адреса, чтобы контейнеры могли общаться между собой;
- запустить все три контейнера в рамках одной локальной сети вручную или через docker-compose.
Также вы меня можете спросить, как узнать ip адрес контейнера, чтобы к нему подключится и проверить есть ли связь между контейнерами? Давайте начнем с первого, ip адрес можно узнать из настроек сети docker, более подробную работу с ними можно найти в интернете. А вот проверить связь между контейнерами — это хороший вопрос. Я его решил следующим алгоритмом действий:
- зайти в bash консоль контейнера, это можно сделать следующей командой: docker exec -it b5d116ad83cc bash, где b5d116ad83cc — это id или имя контейнера;
- проверить наличие программы для прослушивания контейнера по ip или имени контейнера, который нужен для работы. Например, есть два контейнера с бекендом и базой данных для него и контейнер с бекенодом от него зависит. В этом случае контейнер с бекендом должен смочь прослушивать контейнер с базой данных;
- если программы по прослушиванию ip нет, то ее можно установить через apt-get менеджер и повторить вышеописанный пункт;
Если вышеописанный алгоритм не помог, то значит вы допустили где-то ошибку, либо я с таким сценарием не сталкивался и его нужно разбирать отдельно.
Но это не все проблемы, которые у меня возникли, вторая из них, но не менее важная — это как сохранить данные в контейнере с базой данных, делать дамп и вносить данные в базу данных? Здесь у меня нашелся ответ через нативную команду docker — exec. Выполнив эту команду можно сделать дамп или восстановить базу данных.
Команды для выполнения дампа или восстановления базы данных в докере
На изображении «Команды для выполнения дампа или восстановления базы данных в докере» приводится пример выполнения работы с контейнером, в котором крутится база данных, в данном примере используется база данных mongo, на других базах данных должен применяться тот же принцип, что и для нее. Первая команда выполняет создание дампа, вторая — применения дампа в базу данных. Из нюансов работы, я бы отметил, что необходимо использовать целостный файл для работы. Дело в том, что mongo может создать отдельный дамп из коллекции базы данных и поместить его в отдельный файл. Так работать не получится, необходимо применять целостный файл, который содержит в себе всю базу данных. Не знаю на сколько это актуально для баз данных mysql и т. п., но упомянуть этот нюанс посчитал нужным.
Мои конфигурационные файлы docker и docker-compose
В качестве примера настройки я приведу свои конфигурационные файлы, который мною используются, чтобы работать с докером.
Файл докер на стороне юая
Файл докер на стороне бекенда
На изображениях «Файл докер на стороне юая» и «Файл докер на стороне бекенда» приведены примеры конфигурационных файлов, которые используются для создания образов юай и бекенд частей моего интернет приложения. Давайте разберем общие команды:
- from — указывает образ, на базе которого будет собран текущий образ;
- workdir — указывается рабочая папка, так до конца и не понял зачем ее указывать, если и без нее все работает, но на всякий случай оставил, чтобы в дальнейшем не было проблем;
- copy — копирует файлы с физической машины в образ, первым аргуметом принимает путь откуда нужно копировать, вторым — куда в контейнере вставить;
- run — запускает комманду, которая будет запускаться, когда создается контейнер от образа;
- cmd — команда, которая запускается при каждом старте контейнера.
Версия и настройка сети в docker-compose
Настройка сервиса для frontend приложения
Настройка сервиса для backend приложения
Настройка сервиса для базы данных mongo приложения
Выводы
В этой статье я поделился своими мыслями почему ранее мне, как специалисту, не нужно было использование docker и почему он мне понадобился в данный момент времени; с какими трудностями столкнулся и как их решил, что было сделано для этого, какие алгоритмы использовал; привел пример конфигурационных файлов, которые используются в моих проектах. Надеюсь, что мой пример и пояснения помогли вам понять в освоении и понимании зачем нужен docker.