Docker для фронтендера. Часть 1. Зачем?

Привет, Хабр!


Несколько месяцев назад я выступал на конференции FrontendConf 2019 с докладом Docker для фронтендера и хотел бы сделать небольшую расшифровку доклада для тех, кто больше любит читать, а не слушать.



Приглашаю под кат всех веб-разработчиков, особенно фронтендеров.


Содержание


  1. Docker для фронтендера. Часть 1. Зачем?
  2. Docker для фронтендера. Часть 2. Что ты такое?
  3. Docker для фронтендера. Часть 3. Немного рецептов

Восхождение Docker


Docker инструмент не новый, он впервые был опубликован ещё в марте 2013 года и с тех пор его популярность только растёт.



Тут мы видим, что частота запросов по Node.js достигла плато и никуда не двигается, а запросов про Docker продолжает увеличиваться.



Вот такая игрушка была на конференции РИТ++ 2019 в рамках DevOps-секции. И по моему опыту ни одна конференция по DevOps не проходит без докладов про Docker, так же, как и фронтендерские конференции не проходят без докладов про сравнение фреймворков, настройку вебпака и профессиональное выгорание.


Давайте и мы во фронтенд-тусовке тоже начнём говорить про эту технологию.



Это дорожная карта веб-разработчика. Слева изображены навыки, обязательные для любого пути развития. Действительно, сложно представить хорошего веб-разработчика, который не умеет в Git, терминал или не знает HTTP. 


Docker тут тоже присутствует, но где в недрах ветки развития DevOps'а в блоке Infrastructure as a code -> Containers.


Но мы знаем, что Docker — это ещё и отличный инструмент для разработки, а не только для эксплуатации. И, по моему мнению, он имеет все шансы через некоторое время попасть в секцию Required for any path и стать обязательным требованием во многих вакансиях фронтенд-разработчиков.


Можно сказать, что мы сейчас живём в Эру Docker. Поэтому, если вы фронтенд-разработчик и ещё с ним не познакомились, то я расскажу, почему это стОит сделать.


Зачем?


Кейс 1. Поднимаем backend


Первый и самый полезный кейс, который мы можем рассмотреть — это запуск API на своём уютном макбуке. Да, мы отлично знаем наши технологии, но разворачивать что-то стороннее всегда испытание не из лёгких.


На одном из наших проектов фронтенд-разработчику нужно было поставить на компьютер вот такой набор, чтобы API заработал:


* go1.11
* MySQL
* Redis
* Elasticsearch
* Capistrano
* syslog
* PostgreSQL

К счастью, у нас были инструкции по развёртыванию проекта в README-файлах. Они выглядели примерно так:


1. Установить GVM (https://github.com/moovweb/gvm)
2. `gvm install go1.11.13 --binary`
3. `gvm use go1.11.13 --default`
4. В папке с проектом создать ссылку на golang (`gvm linkthis`)
5. Установить `gb` `go get github.com/constabulary/gb/...`
6. Настроить авторизацию `git config --global url."git@git.example.com:".insteadOf "https://git.example.com/"`
7. Установить зависимости `gb vendor restore`
8. Поднять БД
9. Собрать ассеты `npm run build` (`npm run build:dev` для разработки)
10. Запустить сервер `npm start`

И вот так:


## Elasticsearch
1. Скачать и установить Elasticsearch `brew install elasticsearch` - macOS (предложит установить дистрибутив java)
2. Установка плагина
* выбери в https://github.com/imotov/elasticsearch-analysis-morphology из списка подходящий к твоей версии плагин, и запусти
`/usr/local/Cellar/elasticsearch/2.3.3/libexec/bin/plugin install http://dl.bintray.com/content/imotov/elasticsearch-plugins/org/elasticsearch/elasticsearch-analysis-morphology/2.3.3/elasticsearch-analysis-morphology-2.3.3.zip` - пример
* потом перезапусти эластик `brew services restart elasticsearch`
3. в проекте админки
`rake environment elasticsearch:import:model CLASS='Tag' FORCE=y `
`rake environment elasticsearch:import:model CLASS='Post' FORCE=y`
индексировать будет долго, но пользоваться можно сразу

## Postgres comments db
1. `psql -U postgres -h localhost`
2. `create database comments_dev;`

## Redis install and start
1. `brew install redis`
2. Перед запуском `brew services start redis`

Как вы думаете, сколько времени требовалось начинающему разработчику, чтобы развернуть у себя проект и начать делать задачи?


Около недели.


Естественно, не все команды терминала проходили с первого раза, довольно часто инструкция устаревала.


Это считалось нормальным и всех устраивало. То есть, чтобы сделать фичу в 1 час работы, требовалось сначала потратить 40 часов на разворачивание всех компонент локально.


Сейчас разворачивание проекта со всеми сервисами для разработки выглядит вот так и при холодном старте занимает около 10 минут.


$ docker-compose up api
...
Listening localhost:8080

Все команды разворачивания сервисов выполняются во время сборки Docker образов. Они автоматизированы и не могут устареть.


Кейс 2. Устойчивость


Второй кейс — устойчивость системы нашего рабочего компьютера.


Кому нравится ставить на свой любимый компьютер какой-то сторонний софт? Кому нравится устанавливать несколько разных баз данных, новые компиляторы, интерпретаторы?


А это приходится делать, когда мы разворачивает локально сторонний API.


Более того, вы можете сломать вашу систему и потратить несколько часов на её восстановление.



Использование Docker для разработки достаточно хорошо справляет с этой проблемой. Весь сторонний софт крутится в изолированных контейнерах и при необходимости легко удаляется.


$ docker rm --volumes api
$ docker system prune --all

Кейс 3. Контролируем эксплуатацию


И третий кейс, про который бы я хотел рассказать — это возможность фронтенд-разработчику контролировать эксплуатацию своего сервиса. Самому решать, как его сервис будет работать в продакшене.


Я знаю, что передача проекта в эксплуатация довольно часто выглядит следующим образом.


Фронт: Ребят, я всё сделал. Код в репе. Выкатите, плиз!
Админ: Как оно выкатывается?
Фронт: Собираешь нодой и раздаёшь статику веб-сервером из папки /build
Админ: Какой версией ноды собирать? Какая команда сборки? Каким веб-сервером раздавать?


В итоге для админа развёртывание вашего проекта превращается в не менее увлекательный квест, как для вас развёртывание API на локальной машине из предыдущих кейсов.


Даже если проект будет работать у вас на компьютере, совсем не обязательно, что всё так же будет работать на продакшене. И мы получаем классическую проблему "это работает на моей машине".



Docker помогает нам и с этим. Решение простое, если мы запаковали наш проект в Docker, тем самым автоматизировав его сборку и настроив запуск, то он будет одинаково работать на всех серверах, которые поддерживают Docker.



А инструкция для админов сведётся к:


Фронт: Ребят, я всё сделал. Собрал для вас Docker-образ. Выкатите, плиз!
Админ: Ок


Уж с чем, а с Docker-образами админы точно должны уметь работать. Не то, что с нашей нодой.


Что же такое Docker?


Надеюсь, я смог объяснить, почему стоит присмотреться к этой технологии, если вы фронтенд-разработчик и до сих пор её не знаете. Но я так и не рассказал, что это такое.



Планирую написать про это в следующих частях статьи и дать немного полезных рецептов для фронтенд-разработчиков.


Updated


Поддержать автора
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 26

    0
    docker-compose up api


    Как просто!

    Кроме API нужно ещё поднять конейнер с elastic, mongo запихать данные в mongo и проиндексировать их эластиком. Причём пихать данные нужно только когда у вас подымутся Mongo и эластик. А их ещё надо и сконфигурить.
      0
      Делается преднастроеный докерок эластика с данными и всё вместе линкуется одним компоузом. И индексировать эластиком монго… Это как?
        0
        docker-compose не ждёт когда подымется mongo или elastic, он знает только запущен конейнер или нет. docker-compose для такой цели можно написать и решить всё через, но он будет довольно сложной штукой с кучей логики в entrypoint.sh
        Для таких целей должно быть что-то более умное, чем docker-compose.
          0
          ну так и апликуха не должна насмерть валиться от кратковременного офлайна эластика
            0
            Это да, но чтобы заполнить эластик вам нужны данные в монге, те дождаться, когда отработают все mongorestore.
            Чтобы начать заполнять монгу через mongorstore вам нужно знать, что mongo поднялась (ей на это время нужно). Чтобы заполнять эластик вам нужно тоже дождаться, пока подымется эластик. Сам docker-compose всё это не умеет. Те поднять всё одной командой docker-compose up api без вороха sh-скриптов не выйдет.

            И индексировать эластиком монго… Это как?

            Это использовать эластик как полнотекстовый поиск, а документы хранить в mongo/postgresql.
              0
              Зачем весь этот рестор, если можно иметь докера с уже проиндексированными данными? Оно ведь для разработки. Достаточно иметь плюс минус актуальный снэпшот.
                0
                Так для разработки и нужно, чтобы каждое добавление поля в базу бэкендером сразу же было доступно фронтам. Причём чем интенсивнее разработка, тем быстрее должно обновляться API и база.
                Иметь образа с данными можно, но строить такие образы намного сложнее. По мне пока самый простой способ, это делать образ уже запущенного и модифицированного контейнера. Те я не знаю, как описать рестор данных в рамках Dockerfile.
                Потом для автоматического построения всех этих образов нужна инфраструктура, причём она должна куда-то публиковать образа. А образа должны быть специфичны для веток в которых идёт разработка. Ведь в разных ветках могут быть разные поля в базе. Ну и операция переключения между ветками для фронта будет тоже не такой тривиальной.
                  0
                  Мы используем локальный гитлаб, там вся необходимая инфраструктура встроена. Да, время вложить в «поразбираться» придётся, но где это сейчас не требуется? Я это к тому, что проблемы как таковой нет, при наличии правильного инструментария и процессов.
        0
        Отличное замечание, я про это не рассказал.

        Действительно, полностью избавиться от инструкций и команд не получается.

        Мы делаем вот так:

        1. docker-compose up api собирает связанные через depends_on образы и запускает их.
        2. Все команды на запущенных контейнерах стараемся убирать в Makefile.

        Что-то вроде:

        # Makefile
        migrate:
          docker-compose run api bundle exec rake db:migrate
        
          +3
          depends_on не делает liveness-readiness проверок, просто проверяет состояние контейнера. Лучше уж сказать, чтобы сделал
          docker-compose up -d backend frontend elastic redis postgres
          и увидел заветную запись в логах, если надо что-то сделать. Еще есть костыли типа wait-for-it.sh.

          Команды в Makefile поддерживаю, главное чтобы они не расползались по другим местам :)
        +5

        На прошлой работе также было, дерьма с этим хлебнул знатно. Сейчас же все запросы к апи проксирую через Nginx на стейджовый сервер, проблем не знаю и рекомендую всем сделать также и закопать, наконец, эту стюардессу

          +2
          После доклада меня спрашивали несколько раз про этот подход, когда фронтенд-разработчик всё запускает не локально, а использует отдельный staging- или dev-сервер для разработки.

          Этот способ работает и имеет свои плюсы, но не лишен и недостатков.

          Вот некоторые из них:

          1. Невозможность работать офлайн или при плохом Интернете. Многие любят работать из дома, деревни или в дороге.
          2. Необходимость делить один и тот же ресурс с другими разработчиками и тестировщиками. У нас были случаи, когда приходилось создавать необходимую для разработки сущность новости с названием «НЕ УДАЛЯТЬ!», чтобы кто-то её случайно не грохнул. Но, всё равно это периодически случалось.
          3. Такой сервер достаточно хрупкий. Было несколько ситуаций, когда бекенд-разработчики или эскплуатация начинали шатать сервак. Или, к примеру, накатывали туда какие-нибудь ломающие изменения. Это останавливало разработку у всей команды.
            +1
            Работаем в распредёлнной команде по такой схеме.
            Невозможность работать офлайн или при плохом Интернете.

            Хороший интернет в наше время must have. Без него вообще плохо.

            Необходимость делить один и тот же ресурс с другими разработчиками и тестировщиками.

            Почти никогда у нас это не проблема, но зависит от проекта, конечно.

            Такой сервер достаточно хрупкий.

            Да, он хрупкий (хотя перед выкладкой прогоняются тесты), но понять почему у фронта упало бекендерам сильно проще, потому что обший сервер пишет логи.

            Есть более важная проблема при таком подходе: очень сложно иметь по серверу на фиче-ветку. Можно сделать front-ветку на каждого фронта и если фронту нужно переключиться на какую-то фиче ветку, то то эту ветку мерджат в front-ветку и CI/CD её строит. Однако это запарано, потому народ всё льёт в master.
              0
              Да, кстати, об это я не подумал. Хороший кейс.

              Локальное разворачивание позволяет развернуть у себя любую ветку API.

              Например, вот так:

              cd api
              git checkout feature/branch
              docker-compose build api
              make migrate
              docker-compose up api
              
                0
                Мы в итоге, к тому же и пришли. Только у нас не make migrate, а большой скрипт, который инициализирует окружение. Только вот для запуска этого скрипта надо локально установить кучу всего, например, чтобы сделать mongorestore нужно поставить mongo-tools, чтобы проиндексировать эластик, надо собрать соответствующий кусок приложухи, для сборки которого нужно поставить SDK. Так что да, вынести сервера бд в отдельные контейнеры можно, но SDK всё равно надо будет ставить и настраивать.
                  0
                  Не уверен, но, думаю, можно попробовать сделать образ с SDK, который при старте инициализирует окружение.
          +1
          * go1.11
          * MySQL
          * Redis
          * Elasticsearch
          * Capistrano
          * syslog
          * PostgreSQL


          Сколько памяти отъест виртуалка на MacOS/windows чтобы гонять это всё в контейнерах?

            +2
            на 16 можно жить.
              +1
              Нельзя. Буквально вчера развернул себе бекенд на 12 (!) контейнерах, запустил фронт, IDE, Skype, Firefox, AIMP… и память всё, кончилась. Хорошо что вся эта требуха докерная сама спрятана в виртуалку, сегодня буду её на отдельную тачку выносить.
              0
              Оно всё достаточно легковесное, в этом и прелесть Docker. Вот пример вывода docker stats.

              CONTAINER ID        NAME                                   MEM USAGE
              e4941ea92ce7        nginx_1                                3.16MiB
              1b023bfff38f        api_1                                  351.5MiB
              e07c6958e378        pg_1                                   18.64MiB
              1fa783f5fdbc        terminal-front_1                       14.89MiB
              72e9dfa0805a        adminer_1                              11.19MiB
              e9ce9f965867        admin-front_1                          1.312MiB
              3edacc59a77b        certbot_1                              1.547MiB
              

              Видим, что БД заняла 19 МБ, а API на Java — 352 МБ.

              У нас у разработчиков от 8 до 16 ГБ оперативной памяти. Обычно, этого хватает.

              По личному опыту, большую часть оперативной памяти во время разработки съедает IDE, Chrome, Telegram, Slack, а не запущенные docker-контейнеры.
                0
                Но ведь вопрос не в том, сколько памяти потребляет контейнер, вопрос в том, сколько ест виртуалка без которой вы на MacOS или Win ничего не сможете сделать. Docker build выполняется именно на виртуалке, и если сама апа ест 14 мегабайт, то вопрос в том, сколько будет жрать ресурсов docker build.
                  0
                  Да, Вы правы. Плюс ещё примерно 4 ГБ на виртуалку на MacOS.

                    +1
                    А какая разница, сколько ест docker build? Он выполняется в общем случае на произвольной машине, не совпадающей с сервером и один раз. А все занимаемое время уже сбилженный контейнер просто работает.
                +1
                Респект автору!
                  +1
                  Крутой доклад, спасибо :-)
                    +1

                    Надо попробовать, жду второй доклад :)

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое