Должен ли каждый образ Docker содержать JDK?

Итак, я новичок в Docker. Позвольте мне объяснить контекст вопроса.

  1. У меня есть 10-20 приложений микросервисов Spring Boot, каждое из которых работает на разных портах на моем локальном компьютере.

  2. Но для перехода на Docker, исходя из моих знаний, каждая из служб должна находиться в другом контейнере Docker, чтобы можно было быстро развертывать или создавать копии.

  3. Для каждого контейнера Docker нам нужно создать новый образ Docker.

  4. Каждый образ Docker должен содержать JRE для запуска приложения Spring Boot. Это максимум около 200 MB. Это означает, что размер каждого образа докера составляет, скажем, максимум 350 MB. С другой стороны, на моем локальном ПК у меня есть только одна JRE размером 200 MB, и каждое приложение занимает всего несколько МБ места.

  5. Исходя из этого, мне потребуется 600 MB в моей локальной системе, но для всех образов Docker потребуется 7 GB.

Это правильный подход? Следует ли добавлять «OpenJDK» из DockerHub в каждый образ?

Почему размер изображения большой, даже если на целевом ПК уже есть JDK?

Кажется, вы говорите о JDK и JRE - в идеале вам следует избегать создания образов с помощью JDK, поскольку он вам нужен только во время сборки, и просто иметь JRE в производственном образе. Обратите внимание, что у вас есть несколько FROM в Dockerfile, поэтому вы можете создавать с JDK, а затем упаковывать только с JRE.

mcfedr 17.10.2018 14:57

Действительно. Взгляните на многоступенчатые сборки. Это позволяет выполнять сборку с помощью JDK в одном образе, а затем копировать созданные артефакты в более легкий образ времени выполнения.

spender 17.10.2018 17:14
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
23
2
5 432
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Ваше понимание неверно.

Образы Docker состоят из слоев; см. следующую схему:

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

Но если все ваши контейнеры основаны на одном и том же образе и добавляют разные вещи, говорит ваше другое приложение микросервисов к тонкому слою R / W, все контейнеры будут совместно использовать 91e54dfb1179, поэтому это не будет n * m отношение.

Вам нужно обратить внимание на использование одного и того же базового образа для всех приложений Java, насколько это возможно, и добавить разные вещи в тонкий слой R / W.

Enter image description here

Хороший ответ, но у меня есть еще одно сомнение. Предположим, образы докеров построены в разных системах? Скажем, каждый микросервис создается отдельной командой в другом географическом регионе? Это совместное использование существующего jre с идентификатором не будет работать, не так ли?

SamwellTarly 17.10.2018 15:10

@SamwellTarly Используйте хорошее обычное базовое изображение, когда это уместно - это базовое изображение должно содержать тяжелые общие части.

Christian Sauer 17.10.2018 15:28

@SamwellTarly Вам необходимо выровнять базовое изображение с большинством обычных вещей вместе, по крайней мере, с одним настраиваемым базовым изображением, которое вас больше всего интересует. И предложите использовать dockerhub или частную регистрацию докеров, чтобы поделиться им. Затем каждая сервисная команда могла бы добавлять вещи на основе этого базового образа.

atline 17.10.2018 15:37

Вам следует рассмотреть возможность использования OpenJDK в качестве базового образа.

JimmyJames 17.10.2018 15:45

Ответ Лагома великолепен, но я хотел бы добавить, что размер контейнеров Docker должен быть как можно меньше, чтобы упростить передачу и хранение.

Следовательно, существует множество контейнеров на основе дистрибутива Alpine Linux, которые действительно малы. По возможности постарайтесь их использовать.

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

Не только wget, конечно - я видел производственные образы Docker со всевозможными глупостями внутри, вплоть до полного дистрибутива GCC (в приложении PHP).

Sebastian Lenartowicz 17.10.2018 13:42

@SebastianLenartowicz Забавно! Почему? Должен быть материал, который я видел, для тестирования или сборки пакета python. Большинство людей склонны не использовать многослойные изображения, которые могли бы предотвратить эту конкретную проблему.

Christian Sauer 17.10.2018 13:48

Понял. Столь прочный дизайн с максимальной степенью наследования.

SamwellTarly 17.10.2018 15:13

@ChristianSauer Потому что образы Docker были созданы людьми с неполным пониманием их предназначения. Они вообразили, что им нужна целая система Unix-y внутри, чтобы они могли изменять и администрировать ее во время ее работы (я знаю, я знаю).

Sebastian Lenartowicz 17.10.2018 15:16

@SamwellTarly ВНИМАНИЕ! Это зависит! Слишком большое количество наследований делает весь ваш проект громоздким. Например. если у вас развернуто несколько микросервисов, может быть полезно иметь разные версии jave - например, потому что в одном пакете есть ошибка, которая не позволяет ему работать с версией, которую вы предпочитаете для всех других служб. Подводить баланс! Время разработки также является важным фактором - заставить работать образы alpine может быть непросто, если вам нужно установить deps.

Christian Sauer 17.10.2018 15:27

Другие ответы довольно хорошо охватывают наслоение Docker, поэтому я просто хочу добавить подробности для ваших вопросов.

Это правильный подход? Следует ли добавлять «OpenJDK» из DockerHub в каждый образ?

да. Если его нет на изображении, его не будет в контейнере. Вы можете сэкономить место на диске, повторно используя как можно больше слоев. Так что попробуйте записать свой Dockerfile с «С меньшей вероятностью изменится» на «Скорее всего, изменится». Поэтому, когда вы создаете свой образ, чем чаще вы видите «Использование кеша», тем лучше.

Почему размер изображения большой, даже если на целевом ПК уже есть JDK?

Докер хочет как можно меньше иметь дело с хостом. Докер даже не хочет иметь дело с хостом. Первое, что он делает, - это создает виртуальную машину, в которой можно спрятаться. Образы Docker предполагают, что единственное, что выдаст хост, - это пустая оперативная память, диск и процессоры. Таким образом, каждый образ Docker должен также содержать собственную ОС / ядро. (Это то, что делает ваш начальный FROM, выбирая базовый образ ОС для использования). Итак, ваш окончательный размер образа на самом деле равен OS + tools + app. Размер изображения немного вводит в заблуждение, так как это сумма всех слоев, которые повторно используются в изображениях.

(Подразумевается) Должно ли каждое приложение / микросервис находиться в собственном контейнере?

В идеале да. Преобразование вашего приложения в изолированный модуль упрощает замену / балансировку нагрузки этого модуля.

На практике, возможно, нет (для вас). Spring Boot - это не легкий фреймворк. Фактически, это структура для модулирования вашего кода (эффективного запуска системы управления модулями внутри системы управления модулями). А теперь вы хотите разместить у себя 10-20 из них? Это, вероятно, не сможет работать на одном сервере. Docker заставит Spring загрузиться в память на приложение; а объекты не могут быть повторно использованы в модулях сейчас, поэтому их тоже нужно создавать с несколькими экземплярами! А если вы ограничены одним рабочим сервером, горизонтальное масштабирование не подходит. (Вам понадобится ~ 1 ГБ HEAP (RAM) для каждой загрузки Spring, мой пробег основан на вашем коде). А с 10-20 приложениями рефакторинг, чтобы облегчить приложение для развертывания Docker, может оказаться невыполнимым / в рамках бюджета. Не говоря уже о том, что если вы не можете запустить минимальную настройку локально для тестирования (недостаток ОЗУ), усилия по разработке будут гораздо более «веселыми».

Докер - это не золотой молоток. Попробуйте, оцените все за и против и решите, стоят ли плюсы минусов для вас и вашей команды.

Мне нравится ваш ответ, но в то же время он наводит на размышления. Какую альтернативу вы бы предложили каждому микросервису, запускаемому как приложение весенней загрузки. Это обеспечивает очень слабую связь и отсутствие этапа развертывания, как в более старых более крупных приложениях Spring. Микросервисы могут общаться между собой. Итак, в этом случае, наконец, на машине, на которой запущен образ докера, не все ли они будут использовать одну и ту же JRE и не устранят ли необходимость в куче размером 1 ГБ на контейнер?

SamwellTarly 18.10.2018 09:11

@SamwellTarly Контейнеры будут совместно использовать (большую часть) базового образа, но их оперативная память (слой R + W и ОЗУ) изолирована для каждого контейнера. Таким образом, JVM каждого контейнера должна загружать ресурсы, которые она использует, в память (а Spring Boot использует МНОГО ресурсов). Docker фактически основан на философии дизайна 12-факторное приложение, которая предполагает, что ваши микросервисы предназначены для работы на отдельных виртуальных машинах / машинах. Хотя одним из компромиссов было бы сначала построить все это на одном контейнере Docker, а затем создать больше по мере рефакторинга для более легкого развертывания.

Tezra 18.10.2018 14:52

@SamwellTarly Чем меньше ваше окончательное изображение и чем меньше объем оперативной памяти, тем быстрее вы сможете запускать контейнеры (что будет иметь большое значение, если вы захотите воспользоваться преимуществами масштабирования / балансировки нагрузки Docker-контейнера. Даже если вы используйте только 1 контейнер, он решает проблему "работает на моей машине" (в основном). Для более целенаправленного ответа вам было бы лучше задать другой вопрос о том, как решить любую проблему, которую вы пытаетесь решить, переключившись на Docker .

Tezra 18.10.2018 14:58

Да, я понимаю, что использование контейнера, включая ОЗУ, должно быть минимальным. Однако в самом облачном руководстве Amazon каждый микросервис используется как приложение для весенней загрузки. Базовая JVM запросит отображение RAM размером 2 ГБ. Однако каждый микросервис использует очень мало оперативной памяти (10 МБ) на моем локальном ПК. Если ему нужно больше ОЗУ, разве диспетчер кластера не справится с этим? Можете ли вы указать мне свой источник, в котором говорится, что загрузка Spring тяжелая и требует много оперативной памяти в облачной платформе?

SamwellTarly 19.10.2018 15:29

@SamwellTarly Если Ram не проблема, то, очевидно, это не проблема. Если у вас есть конечный предел ресурсов сервера, то менеджер кластера не может выделить больше ресурсов, чем имеется в кластере. Конечно, ваша первая серьезная проблема с контейнерами Java + (если вы не используете 11+) заключается в том, что Java чрезмерно выделяет кучу из кластера. Я не могу указать вам на точные цифры о том, что Spring тяжелый, потому что в любом блоге о нем есть поверхностные тесты, которые просто доказывают, что «Spring - это не так просто на бумаге», но я видел на практике, что Spring может добавить потрясающий запуск и запуск. накладные расходы. (до X5)

Tezra 19.10.2018 15:57

@SamwellTarly Но это не совсем вина Спрингса. Как я уже сказал, это во многом будет зависеть от того, как была разработана ваша кодовая база. Если все сделано «правильно», загрузка Spring может использоваться с минимальными накладными расходами, если все сделано неправильно, это усугубит все, что не так в вашей кодовой базе. Вот почему я говорю: попробуйте сами, но не думайте, что Docker все решит за вас. Это может усугубить ситуацию. Вы можете настраивать различные вещи, чтобы компенсировать это, но эти процессы настройки не всегда в бюджете. Но это решать только вам.

Tezra 19.10.2018 16:01

Based on this, I would need 600 MB on my local system, yet need 7 GB for all Docker images.

Is this approach correct? Should "OpenJDK" from DockerHub be added to each image?

Это правильно. Хотя вы можете задаться вопросом, недостаточно ли JRE.

Why is the size of the image large even if the target PC may already have the JDK?

Вы сравниваете несопоставимые вещи: среда местный (это все, кроме производственной машины) VS интеграция / производство среды.

В среде интеграции / производства нагрузка на ваши приложения может быть высокой, и обычно рекомендуется изоляция между приложениями. Итак, здесь вы хотите разместить минимальное количество приложений (ui / services) на машине (голой, виртуальной машине или контейнере), чтобы предотвратить побочные эффекты между приложениями: несовместимость общих библиотек, побочные эффекты обновления программного обеспечения, нехватка ресурсов, связанные сбои между приложениями. ..

В локальной среде нагрузка на ваши приложения довольно низкая, и изоляция между приложениями, как правило, не является серьезной проблемой. Таким образом, здесь вы можете разместить несколько приложений (ui / services) на вашем локальном компьютере, а также поделиться некоторыми общими библиотеками / зависимостями, предоставляемыми ОС. Хотя вы можете это сделать, действительно ли хорошая практика - смешивать и делиться всем на местном уровне? Не думаю, потому что:
1) локальная машина не является корзиной: вы работаете над этим целый день. Чем больше чистоты, тем эффективнее ваша разработка. Например: JDK / JRE может различаться между приложениями, размещенными локально, некоторые папки, используемые приложением, могут иметь одно и то же расположение, версия базы данных может отличаться, приложения могут иметь другой установленный сервер Java (Tomcat, Netty, Weblogic) и / или с разными версии ...
Благодаря контейнеру это не проблема: все устанавливается и удаляется в соответствии с вашими требованиями.

2) среды (от локальной до производственной) должны быть как можно ближе, чтобы упростить всю цепочку интеграции-развертывания и выявлять проблемы на раннем этапе, а не только в производственной среде.

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


У всего есть своя цена, но на самом деле это не так дорого

Помимо изоляции (аппаратные и программные ресурсы), контейнеры обладают и другими преимуществами, такими как быстрое развертывание / удаление, масштабируемость и отказоустойчивость (например: Kubernetes полагается на контейнер). Изоляция, быстрота, масштабируемость и надежность имеют свою цену: физически не разделять какие-либо ресурсы между контейнерами (ОС, библиотеки, JVM, ...).

Это означает, что даже если вы используете точную ОС, библиотеки, JVM в своих приложениях, каждое приложение должно будет включить их в свой образ. Это дорого ? Не совсем: официальные образы часто полагаются на Alpine (легкая ОС Linux с ограничениями, но настраиваемая при необходимости) и что представляют собой образ размером 350 МБ (указанное вами значение соответствует действительности) с точки зрения стоимости?
На самом деле это действительно дешево. При интеграции / производстве все ваши службы, скорее всего, не будут размещаться на одном компьютере, поэтому сравните 350 МБ для контейнера с ресурсами, используемыми в традиционных виртуальных машинах для интеграции / производства, которые содержат полную ОС с несколькими установленными дополнительными программами. Вы понимаете, что ресурсоемкость контейнеров не проблема. Это даже считается преимуществом за пределами местных условий.

Другие вопросы по теме