Контейнер Docker

Решение для виртуализации Docker за последнее десятилетие кардинально изменило способы создания, распространения и эксплуатации программного обеспечения. В отличие от своих предшественников — виртуальных машин (VM) — Docker виртуализирует отдельные приложения. Таким образом, контейнер Docker — это контейнер приложения или программного обеспечения.

Термин «программный контейнер» основан на физических контейнерах, таких как те, что используются на кораблях. В логистике контейнеры как стандартизированные единицы — это то, что сделало возможными современные розничные сети. Таким образом, контейнер можно перевозить на любом судне, грузовике или поезде, предназначенном для этих целей. Это работает в значительной степени независимо от содержимого контейнера. Снаружи контейнер оснащен стандартизированными интерфейсами. Это очень похоже на то, как работают контейнеры Docker.

Что такое контейнер Docker?

Итак, что именно представляет собой контейнер Docker? Давайте передадим микрофон разработчикам Docker:

Цитата

«Контейнеры — это стандартизированная единица программного обеспечения.

которая позволяет разработчикам изолировать свое приложение от окружающей среды». — Источник: www.docker.com/why-docker

В отличие от физического контейнера, контейнер Docker существует в виртуальной среде. Физический контейнер собирается на основе стандартизированной спецификации. Мы видим нечто подобное с виртуальными контейнерами. Контейнер Docker создается на основе неизменяемого шаблона, называемого «образом». Образ Docker содержит зависимости и параметры конфигурации, необходимые для создания контейнера.

Подобно тому, как множество физических контейнеров может быть создано на основе одной спецификации, любое количество контейнеров Docker может быть создано на основе одного образа. Таким образом, контейнеры Docker формируют основу для масштабируемых сервисов и воспроизводимых сред приложений. Мы можем создать контейнер из образа, а также сохранить существующий контейнер в новом образе. Внутри контейнера можно запускать, приостанавливать и останавливать процессы.

В отличие от виртуализации виртуальных машин (ВМ), контейнер Docker не содержит собственной операционной системы (ОС). Вместо этого все контейнеры, запущенные на хосте Docker, обращаются к одному и тому же ядру ОС. Если Docker развернут на хосте Linux, используется существующее ядро Linux. Если программное обеспечение Docker работает на системе, отличной от Linux, используется минимальный образ системы Linux через гипервизор или виртуальную машину.

При выполнении каждому контейнеру выделяется определенное количество системных ресурсов. Сюда входят оперативная память, ядра процессора, устройства хранения данных и (виртуальные) сетевые устройства. Технически, «cgroups» (сокращение от «control groups») ограничивают доступ контейнера Docker к системным ресурсам. «Пространства имен ядра» используются для разделения ресурсов ядра и отличия процессов друг от друга.

Внешне контейнеры Docker взаимодействуют по сети. Для этого определенные службы прослушивают открытые порты. Обычно это веб-серверы или серверы баз данных. Сами контейнеры управляются на соответствующем хосте Docker с помощью Docker API. Контейнеры можно запускать, останавливать и удалять. Клиент Docker предоставляет интерфейс командной строки (CLI) с соответствующими командами.

Что отличает контейнеры Docker от образов Docker?

Два термина «контейнер Docker» и «образ Docker» часто вызывают путаницу. Это неудивительно, поскольку это своего рода дилемма «курица или яйцо». Контейнер создается из образа; однако контейнер также может быть сохранен как новый образ. Давайте рассмотрим различия между этими двумя понятиями подробнее.

Образ Docker — это инертный шаблон. Образ только занимает место на жестком диске и больше ничего не делает. В отличие от него, контейнер Docker — это «живой» экземпляр. Работающий контейнер Docker имеет поведение; он взаимодействует с окружающей средой. Более того, у контейнера есть состояние, которое меняется со временем, используя переменный объем оперативной памяти.

Возможно, вы знакомы с понятиями «класс» и «объект» из объектно-ориентированного программирования (ООП). Отношения между контейнером Docker и образом Docker похожи на отношения между объектом и связанным с ним классом. Класс существует только один раз; на его основе можно создать несколько похожих объектов. Сам класс загружается из файла исходного кода. Во вселенной Docker существует похожая схема. Шаблон создается из исходного блока, «Dockerfile», который, в свою очередь, создает множество экземпляров:

  Исходный текст Шаблон Экземпляр
Концепция Docker Dockerfile образ Docker Контейнер Docker
Аналогия в программировании Исходный код класса загруженный класс инстанцированный объект
Совет

Мы называем контейнер Docker «запущенным экземпляром» соответствующего образа. Термины «экземпляр» и «инстанцировать» сейчас абстрактны. Если вы не совсем поняли их, давайте воспользуемся мнемоническим приемом. Мысленно замените «инстанцировать» на «вырезать». Даже если между этими словами нет никакой связи, между их значениями в терминах информатики существует сильное соответствие. Подумайте об этом принципе следующим образом: Точно так же, как мы используем нож для печенья, чтобы вырезать много одинаковых печений из пласта теста, мы инстанцируем много одинаковых объектов из шаблона. Таким образом, инстанцирование — это когда шаблон создает объект.

Как создается контейнер Docker?

Чтобы понять, как создается контейнер Docker, следует обратиться к методологии «Двенадцатифакторного приложения». Это собрание двенадцати фундаментальных принципов построения и эксплуатации сервис-ориентированного программного обеспечения. И Docker, и двенадцатифакторное приложение появились еще в 2011 году. Двенадцатифакторная методология помогает разработчикам проектировать программное обеспечение как услугу в соответствии с определенными стандартами. К ним относятся:

  • Использование декларативных форматов для автоматизации настройки, чтобы минимизировать время и затраты для новых разработчиков, присоединяющихся к проекту;
  • Наличие чистого контракта с базовой операционной системой, обеспечивающего максимальную переносимость между средами исполнения;
  • возможность развертывания на современных облачных платформах, что избавляет от необходимости использования серверов и системного администрирования;
  • Минимизация расхождений между разработкой и производством, обеспечивающая непрерывное развертывание для максимальной гибкости;
  • возможность масштабирования без существенных изменений в инструментарии, архитектуре или практике разработки.

Структура контейнера Docker основана на этих принципах. Контейнер Docker включает в себя следующие компоненты, которые мы подробно рассмотрим ниже:

  1. Операционная система контейнера и объединенная файловая система
  2. Программные компоненты и конфигурация
  3. Переменные окружения и конфигурация времени выполнения
  4. Порты и тома
  5. Процессы и журналы

Операционная система контейнера и объединенная файловая система

В отличие от виртуальной машины, контейнер Docker не содержит собственной операционной системы. Вместо этого все контейнеры, запущенные на хосте Docker, обращаются к общему ядру Linux. В контейнер включается только минимальный уровень исполнения. Обычно он включает реализацию стандартной библиотеки C и оболочку Linux для запуска процессов. Ниже приведен обзор компонентов официального образа «Alpine Linux»:

ядро Linux стандартная библиотека C Unix-команды
от хоста musl libc BusyBox

Образ Docker состоит из стека слоев файловой системы, доступных только для чтения. Слой описывает изменения файловой системы в слое под ним. С помощью специальной объединенной файловой системы, такой как overlay2, слои накладываются друг на друга и объединяются в единый интерфейс. При создании контейнера Docker из образа к слоям, доступным только для чтения, добавляется еще один слой, доступный для записи. Все изменения, внесенные в файловую систему, включаются в записываемый слой с помощью метода «копирование при записи».

Программные компоненты и конфигурация

На основе минимальной операционной системы контейнера в контейнер Docker устанавливаются дополнительные программные компоненты. За этим обычно следуют дальнейшие шаги по установке и настройке. Для установки используются стандартные методы:

  • через системный менеджер пакетов, такой как apt, apk, yum, brew и т.д.
  • через менеджер пакетов для языков программирования, например pip, npm, composer, gem, cargo и т.д.
  • путем компиляции в контейнере с помощью make, mvn и т.д.

Вот несколько примеров программных компонентов, обычно используемых в контейнерах Docker:

Область приложений Программные компоненты
Языки программирования PHP, Python, Ruby, Java, JavaScript
Инструменты разработки node/npm, React, Laravel
Системы баз данных MySQL, Postgres, MongoDB, Redis
Веб-серверы Apache, nginx, lighttpd
Кэши и прокси-серверы Varnish, Squid
Системы управления контентом WordPress, Magento, Ruby on Rails

Переменные окружения и конфигурация времени выполнения

Следуя методологии двенадцатифакторного приложения, конфигурация контейнера Docker хранится в переменных окружения, называемых «Env-Vars». Здесь мы понимаем под конфигурацией все значения, которые меняются между различными окружениями, например, между системой разработки и производственной системой. Сюда часто входят имена хостов и учетные данные баз данных.

Значения переменных окружения влияют на поведение контейнера. Для того чтобы сделать переменные окружения доступными в контейнере, используются два основных метода:

1. Определение в Dockerfile

Оператор ENV объявляет переменную окружения в Dockerfile. Ей может быть присвоено необязательное значение по умолчанию. Оно вступает в силу, если при запуске контейнера переменная окружения пуста.

2. Передается при запуске контейнера

Чтобы получить доступ к переменной окружения в контейнере, которая не была объявлена в Dockerfile, мы передаем переменную при запуске контейнера. Это работает для отдельных переменных через параметры командной строки. Кроме того, можно передать «env-файл», который определяет несколько переменных окружения вместе с их значениями.

Вот как передать переменную окружения при запуске контейнера:

 

docker run --env <env-var> <image-id></image-id></env-var>

Для многих переменных окружения полезно передавать env-файл:

docker run --env-file /path/to/.env <image-id></image-id>
Примечание

Команда «docker inspect» может быть использована для отображения переменных окружения, присутствующих в контейнере, вместе с их значениями. Поэтому следует быть осторожным при использовании конфиденциальных данных в переменных окружения.

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

Выделить ядро процессора и 10 мегабайт оперативной памяти для контейнера Docker при запуске:

docker run --cpus="1" --memory="10m" <image-id></image-id>

Открывать порты, определенные в Dockerfile, при запуске контейнера:

docker run -P <image-id></image-id>

Сопоставить TCP-порт 80 хоста Docker с портом 80 контейнера Docker:

docker run -p 80:80/tcp <image-id></image-id>

Порты и объемы

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

Связь с процессами, запущенными в контейнере, извне осуществляется через открытые сетевые порты. При этом используются стандартные протоколы TCP и UDP. Например, представим себе контейнер Docker, содержащий веб-сервер; он прослушивает TCP-порт 8080. Docker-файл образа Docker также содержит строку «EXPOSE 8080/tcp». Мы запускаем контейнер командой «docker run -P» и получаем доступ к веб-серверу по адресу «http://localhost:8080».

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

  • Именованный том — рекомендуется
  • Анонимные тома — теряются при удалении контейнера
  • Bind mounts — исторические и не рекомендуемые; производительные
  • Tmpfs mounts — расположен в оперативной памяти; только в Linux.

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

Процессы и журналы

Контейнер Docker обычно инкапсулирует приложение или сервис. Программное обеспечение, выполняемое внутри контейнера, образует набор запущенных процессов. Процессы в контейнере Docker изолированы от процессов в других контейнерах или в основной системе. Процессы можно запускать, останавливать и перечислять внутри контейнера Docker. Управление осуществляется через командную строку или через API Docker.

Запущенные процессы постоянно выводят информацию о состоянии. В соответствии с двенадцатифакторной методологией приложений, для вывода используются стандартные потоки данных STDOUT и STDERR. Вывод этих двух потоков данных можно прочитать с помощью команды «docker logs». Также можно использовать так называемый «драйвер протоколирования». Драйвер протоколирования по умолчанию записывает журналы в формате JSON.

Как и где используются контейнеры Docker?

В настоящее время Docker используется на всех этапах жизненного цикла программного обеспечения. Это включает в себя разработку, тестирование и эксплуатацию. Контейнеры, запущенные на хосте Docker, управляются с помощью API Docker. Клиент Docker принимает команды в командной строке; для управления кластерами контейнеров Docker используются специальные инструменты оркестровки.

Базовая схема развертывания контейнеров Docker выглядит следующим образом:

  1. Docker-хост загружает образ Docker из реестра.
  2. Из образа создается и запускается Docker-контейнер.
  3. Приложение в контейнере работает до тех пор, пока контейнер не будет остановлен или удален.

Давайте рассмотрим два примера развертывания контейнеров Docker:

Развертывание контейнеров Docker в локальной среде разработки

Использование контейнеров Docker особенно популярно в разработке программного обеспечения. Обычно программное обеспечение разрабатывается командой специалистов. Для этого используется набор инструментов разработки, известный как инструментарий. Каждый инструмент имеет определенную версию, и вся цепочка работает только в том случае, если версии совместимы друг с другом. Кроме того, инструменты должны быть правильно настроены.

Чтобы обеспечить постоянство среды разработки, разработчики используют Docker. Образ Docker создается один раз и содержит весь правильно сконфигурированный набор инструментов. Каждый разработчик в команде переносит образ Docker на свою локальную машину и запускает из него контейнер. Затем разработка ведется в контейнере. При изменении набора инструментов образ обновляется централизованно.

Развертывание контейнеров Docker в оркестрованных кластерах

В центрах обработки данных хостинг-провайдеров и поставщиков услуг «платформа как услуга» (PaaS) используются кластеры контейнеров Docker. Каждый сервис (балансировщик нагрузки, веб-сервер, сервер баз данных и т.д.) работает в собственном контейнере Docker. При этом один контейнер может выдержать только определенную нагрузку. Программное обеспечение для оркестровки отслеживает контейнеры, их нагрузку и состояние. Оркестрант запускает дополнительные контейнеры, когда нагрузка увеличивается. Такой подход позволяет сервисам быстро масштабироваться в ответ на изменение условий.

Преимущества и недостатки виртуализации контейнеров Docker

Преимущества виртуализации с помощью Docker проявляются, в частности, в отношении использования виртуальных машин (ВМ). Контейнеры Docker намного легче, чем виртуальные машины. Они запускаются быстрее и потребляют меньше ресурсов. Образы, лежащие в основе контейнеров Docker, также меньше на несколько порядков. Если размер образов ВМ обычно составляет от сотен МБ до нескольких ГБ, то размер образов Docker начинается всего с нескольких МБ.

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

Оцените статью
cdelat.ru
Добавить комментарий