Pull to refresh

Comments 4

Отличная статья!

"Для дальнейшего погружения в эту тему можно подробнее изучить Docker Compose" -> "перейти на Podman и изучить Podman Compose" :)

Довольно примитивная статья, каких много, но впрочем ладно.

Что мне тут не особо нравится:

  1. Вы не указываете явным образом пользователя, следовательно вши контейнеры запускаются от root. Учитывая то, как работает докер демон, вы можно сказать биндите хостового рута с контейнерным. Не то, чтобы я сам так не делал, просто это можно указать. Всё же юзер с UID 1000, допустим, будет безопаснее, особенно когда вы не монтируете вольюмы.

  2. Вы используете два разных варианта передачи параметров в CMD. Они оба допустимы, но вы кажется не совсем понимаете, как они работают.

  3. Директива EXPOSE это инструкция можно сказать для внутреннего фаервола контейнера, т.е. указание, какие порты контейнер должен слушать. А после вы публикуете контейнер с единственным портом и даже не переопределяете его. Так почему не использовать вместо -p 4200:4200 простой ключ -P, который публикует все порты, объявленные в EXPOSE?

  4. Вы пишите о разделении слоёв, в том числе для кэширования, но вы же понимаете, что при переходе к multistage опубликуется последний stage? Т.е. всё, что вы делали в build не закешируется, а потому особого смысла от вашего деления нет?

  5. Вы не совсем понимаете, как работает докер и его слои. А так же терминологию. Начнём со второго - вы называете образ в стейдже базовым, но это не так.

    Базовым образом является образ, который используется до внесения изменений. Промежуточный образ является build stage. И в докере даже можно билдить не всё последовательно, а до нужного build stage. Т.е. в рамках одного докерфайла можно даже делать ветвление и описывать разные сценарии, а после вызывать их через --target. И то, что вы назвали алиасом, корректно называется stage name.

  6. Почему Build stage отличен от базового образа? Потому, что инструкции пораждают новые слои, а слои это ничто иное как разница между состоянием до команды и результатом выполнения команды. Можно сказать как в гит. Т.е. если вы сделаете, например, RUN npm ci && rm -r node_modules и RUN npm ci RUN rm -r node_modules, вы получите два разных результата в конечном образе. Следовательно все изменения важны и по разному влияют. В общем-то на этом и построена система кеширования докера. А если у вас каждый раз в слоях разные изменения, итоговый образ не может быть базовым.

  7. Вы не используете корректно возможности multistage. Вообще говоря, одна из особенносте buildx в том, что стейджи можно параллелить. Т.е. если следующий стейдж не является результатом предыдущего, его команды выполнятся ассинхронно, что сэкономит время на сборку, за счёт ресурсов.

    Как пример - вы можете сделать FROM node:20-alpine as build и потом FROM build as example , тогда example будет ожидать завершения build. Но вы так же можете сделать FROM node:20 as prepare и FROM node:20 as build, раскидать команды и распараллелить их. И покопировать артифакты с них. А на самом деле можно даже не копировать, а линковать, потому что копирование не такое уж быстрое. Т.е. получив node_modules в одном слое одного стейджа, вы линкуете этот слой к другому и просто используете. Вызывается просто - COPY --link.

  8. Существует базовый образ scratch, который является пустым. Можно раздать в один стейдж копирование и получение зависимостей, во второй ассеты, необходимые для билда, а в третий, пустой, всё остальное. И оно будет исполнятся параллельно.

  9. Не очень понятно, зачем вам монтировать секрет в стейдже, который всё равно не попадёт в слои итогового образа, когда вам достаточно было бы простого BUILD_ARG? Нет, я вижу, что вы сделали правленный вариант, но что мешало сделать тоже самое без compose?

  10. Честно говоря я не знаю, что у вас за архитектура и на кой чёрт тащить в каждый контейнер по личному nginx с сертами, которые протухают (обычно хорошая практика всё же прятать приложения за балансировщиком иил reverse proxy, который на уровень выше), но всё же - а вам реально нужен такой сложный web server прямо в контейнере и ради него такой тяжелый контейнер? Не, ну серьёзно?

  11. docker compose это тоже отдельная песня. Начёнём с того, что разделитель там пропал не просто так - ранее это было отдельная утилита, а теперь он стал частью докера. Впрочем ладно, это не то, о чём я хотел сказать. А сказать я хотел вот что - зачем писать compose для сборки на лету? Почему просто не собрать и не положить образ в registry, сразу протегированный? И это даже лучше, ведь тогда можно использовать не только inline cache, но и --cache-from через манифест. Ну, как бы, аргумент про громоздкие и неудобные команды это так себе, просто потому, что потом вы предлагаете писать ещё больше команд, при этом ещё и указывете про ключик -d.

    Т.е. по суть вам бы сделать docker compose up -d, что бы контейнер висес в фоне, а не перед глазами. При этом эта команда создаст контейнер, если он не создан, но не сбилдит образ. Для билда образа подойдёт команда docker compose up -d --build, тогда поедет. А ведь есть ещё и --force-recreate, если что-то пошло не так.

  12. При этом тегая образ вы не именуете контейнер при запуске, что на самом деле немного более странно. Глобально, а смысл от такого? У вас же и тег ни о чём не говорит и следующий же билд другого фронта его потрёт. Впрочем ладно, если вы не собираетесь его версионировать, то вом было достаточно очень сложной констркции, типа "docker build . -t app_frontend && docker run -d-P -t app_fronted"

    Понимаю, для вас, наверное, это очень сложно и неудобно, но как-то всё равно проще ненужного компоуза. Хотя конечно, в моём варианте есть плохой паттерн, даже 2 - я не задал наименование контейнера, о котором сказал ранее, а -P порты опубликует, но если указанный в expose занят на хостовой машине, то контейнер поднимется с биндом на другой порт. Но в отличии от конструкции -p 4200:4200 он поднимется, а не вывалит ошибку. Но да, надо будет потратить силы и сделать docker ps, что бы узнать, какой же порт.

В общем, я надеюсь, что мой комментарий помог вам лучше понять инструмент ,с которым вы работаете и помог понять, как можно не просто сделать, но и сделать лучше.

Привет! Спасибо большое за комментарий. Поправил формулировки, которые могут ввести в заблуждение. Как вы правильно заметили, многие темы остались out of scope статьи, однако приведённые решения являются хорошими примерами для погружения в тему. Подумаю о продолжении с упором на best practises))

Если у вас есть хорошие ресурсы на эту тему, уверен, все будут рады рекомендациям.

Sign up to leave a comment.