Для чего используют docker

Docker. Зачем и как

Есть множество прекрасных публикаций для тех, кто уже пользуется docker-ом. Есть хорошие статьи для тех, кто хочет этому научиться. Я пишу для тех, кто не только не знает, что такое docker, но и не уверен стоит ли ему это знать.

Я сознательно опускаю некоторые технические подробности, а кое где допускаю упрощения. Если вы увидите, что docker – то, что вам нужно, вы легко найдете более полную и точную информацию в других статьях.

Начну я с описания нескольких типичных проблем.

Проблемы

Первая проблема — как передать продукт клиенту.

Предположим у вас есть серверный проект, который вы закончили и теперь его необходимо передать пользователю. Вы готовите много разных файликов, скриптов и пишите инструкцию по установке. А потом тратите уйму времени на решения проблем клиента вроде: «у меня ничего не работает», «ваш скрипт упал на середине — что теперь делать», «я перепутал порядок шагов в инструкции и теперь не могу идти дальше» и т. п.

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

Вторая проблема — тиражируемость. Пусть вам нужно поднять 5 (или 50) почти одинаковых серверов. Делать это вручную долго, дорого и подвержено ошибкам.

Наконец, третья проблема — переиспользуемость. Предположим у вас есть отдел, который делает браузерные игры. Предположим, что их у вас уже несколько. И все они используют один и тот же технологический стэк (например — java-tomcat-nginx-postgre). Но при этом, чтобы поставить новую игру вы вынуждены заново подготавливать на новом сервере почти одинаковую конфигурацию. Вы не можете просто так взять и сказать — «хочу сервер, как в игре странники но только с другим веб архивом»

Обычные решения

Как обычно решаются эти проблемы.

Установочный скрипт

Первый подход я уже упомянул — вы можете написать скрипт, который установит всё, что вам нужно и запускать его на всех нужных серверах. ( Скрипт может быть как простым sh файлом, так и чем-то сложным, созданным с использованием специальных инструментов).

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

Облачные сервисы

Второй подход — использование облачных сервисов. Вы вручную устанавливаете на виртуальный сервер всё, что вам нужно. Затем делаете его image. И далее клонируете его столько раз, сколько вам надо.

Недостатка здесь два. Во-первых, vendor-lock-in. Вы не можете запускать свое решение вне выбранного облака, что не всегда удобно и может привести к потерям несогласных с этим выбором клиентов. Во-вторых, облака медленны. Виртуальные (и даже «bare-metal») сервера предоставляемые облаками на сегодняшний день сильно уступают по производительности dedicated серверам.

Виртуальные машины

Третий подход — использование виртуальных машин. Здесь тоже есть недостатки:

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

Сложное управление совместным использованием серверных ресурсов — не все виртуальные машины вообще поддерживают совместное использование памяти или CPU. Те что поддерживают, требуют тонкой настройки.

Подход докера — контейнеризация

И вот тут появляется docker, в котором

Как работает docker

Создание образа

Сначала создается docker image (или образ). Он создается при помощи скрипта, который вы для этого пишете.
Образы наследуются и, обычно, для создания своего первого образа мы берём готовый образ и наследуемся от него.
Чаще всего мы берем образ в котором содержится та или иная версия linux. Скрипт тогда начинается как-то так:

Кроме этого, мы можем копировать в наш образ любые локальные файлы при помощи директивы COPY.

Докер поддерживает гораздо больше различных директив. Например, директива USER roman говорит докеру что все следующие директивы нужно выполнять из под пользователя roman. А директива ENTRYPOINT [“/opt/tomcat/catalina.sh”] задает исполняемый файл, который будет запускаться при старте.

Я не буду перечислять все остальные директивы — в этом нет смысла. Здесь главное — принцип: вы создаёте вот такой скрипт, называете его Dockerfile и запускаете команду docker build, docker выполняет скрипт и создает image.

Если в процессе возникают какие-то ошибки, докер о них сообщает и вы их исправляете. То есть исправление скрипта происходит на этапе создания image. На этапе установки скрипт уже не используется.

Создание контейнера

Когда у вас уже есть docker image вы можете создать из него контейнер на любом физическом сервере, где установлен докер. Если image – это тиражируемый образ некоторой «машины», то container это уже сама «машина», которую можно запускать и останавливать.

Важный момент — при создании контейнера из image, его можно параметризовать. Вы можете передавать докеру переменные окружения, которые он использует при создании контейнера из image. Так вы сможете создавать немного разные машины из одного образа. Например, передать образу web-сервера его доменное имя.

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

Union filesystem

Ок — память и процессор используется эффективно. А как насчёт файловой системы? Ведь если у каждого контейнера докера своя собственная копия операционной системы, то мы получим ту же проблему, что и с виртуальными машинами — тяжеловесные образы, которые содержат одно и тоже.

На самом деле в докере это не так. Если вы используете 100500 контейнеров, основанных на одном и том же образе операционной системы, то файлы этой системы будут скачаны докером ровно один раз. Это достигается за счёт использования докером union file system.

Union file system состоит из слоёв (layers). Слои как бы наложены друг на друга. Некоторые слои защищены от записи. Например, все наши контейнеры используют общие защищенные от записи слои, в которых находятся неизменяемые файлы операционной системы.

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

Container registry

Получается, что docker image состоит из слоёв. И хорошо было бы уметь скачивать на наш сервер только те слои, которых на нём пока нет. Иначе для установки 100 контейнеров, основанных на Ubuntu мы скачаем Ubuntu внутри их образов 100 раз. Зачем?

Хорошая новость в том, что докер решает эту проблему. Докер предоставляет специальный сервис, называемый docker registry. Docker registry предназначен для хранения и дистрибуции готовых образов. Собрав новый образ (или новую версию образа) вы можете закачать его в docker registry. Соответственно, потом его можно скачать оттуда на любой сервер. Главная фишка здесь в том, что физически качаться будут только те слои, которые нужны.

Например, если вы создали новую версию образа, в котором поменяли несколько файлов, то в registry будут отправлены только слои, содержащие эти файлы.

Аналогично, если сервер качает из registry какой-то образ, скачаны будут только слои, отсутствующие на сервере.
Docker registry существует и как общедоступный сервис и как open source проект, доступный для скачивания и установки на собственной инфрастуктуре.

Использование контейнеров

Созданные контейнеры можно запускать, останавливать, проверять их статус и т д. При создании контейнера можно дополнительно передать докеру некоторые параметры. Например, попросить докер автоматически рестартовать контейнер, если тот упадёт.

Взаимодействие между контейнерами

Если контейнеров на сервере несколько, управлять ими вручную становится проблематично. Для этого есть технология docker compose. Она существует поверх докера и просто позволяет управлять контейнерами на основе единого конфигурационного файла, в котором описаны контейнеры, их параметры и их взаимосвязи (например контейнер A имеет право соединяться с портом 5432 контейнера B)

Выводы

Таким образом докер очень хорошо подходит для решения перечисленных выше задач:

Источник

Как и для чего использовать Docker

Для чего используют docker. Смотреть фото Для чего используют docker. Смотреть картинку Для чего используют docker. Картинка про Для чего используют docker. Фото Для чего используют docker

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

(В статье намеренно опущены многие детали, чтобы не грузить информацией, которая не нужна для ознакомления).

Установка

Чтобы начать пользоваться Докером, необходимо установить движок — Docker Engine. На странице https://docs.docker.com/engine/install/ доступны ссылки для скачивания под все популярные платформы. Выберите вашу и установите Докер.

Проверить успешность установки можно командой docker info :

Она выдаёт довольно много информации о конфигурации самого Докера и статистику работы.

Запуск

На этом этапе команды на выполнение даются “как есть” без объяснения деталей. Подробнее о том, как их формировать и что в них входит разбирается позже.

Начнем с самого простого варианта:

При первом вызове данная команда начнет скачивать образ (image) nginx, поэтому придется немного подождать. После того, как образ скачается, запустится bash, и вы окажетесь внутри контейнера (container).

Команда выполняется практически мгновенно, так как образ уже загружен. В отличие от предыдущего старта, где запускается баш и начинается интерактивная сессия внутри контейнера, запуск команды cat /etc/nginx/nginx.conf для образа nginx выведет на экран содержимое указанного файла (взяв его из файловой системы запущенного контейнера) и вернет управление в то место, где вы были. Вы не окажетесь внутри контейнера.

Последний вариант запуска будет таким:

Несмотря на то, что все запуски выполнялись по-разному и приводили к разным результатам, общая схема их работы — одна. Докер при необходимости автоматически скачивает образ (первый аргумент после docker run ) и на основе него стартует контейнер с указанной командой.

Образ — самостоятельная файловая система. Пока мы используем готовые образы, но потом научимся создавать их самостоятельно.

Контейнер — запущенный процесс операционной системы в изолированном окружении с подключенной файловой системой из образа.

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

Зачем все это?

Докер — универсальный способ доставки приложений на машины (локальный компьютер или удаленные сервера) и их запуска в изолированном окружении.

Вспомните, когда вам приходилось собирать программы из исходников. Этот процесс включает в себя следующие шаги:

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

Докер позволяет упростить эту процедуру до запуска одной команды причем с почти 100% гарантией успеха. Посмотрите на вымышленный пример, в котором происходит установка программы Tunnel на локальный компьютер в директорию /usr/local/bin используя образ tunnel:

Запуск этой команды приводит к тому, что в основной системе в директории /usr/local/bin оказывается исполняемый файл программы, находящейся внутри образа tunnel. Команда docker run запускает контейнер из образа tunnel, внутри происходит компиляция программы и, в конечном итоге, она оказывается в директории /usr/local/bin основной файловой системы. Теперь можно стартовать программу, просто набрав tunnel в терминале.

А что если программа, которую мы устанавливаем таким способом, имеет зависимости? Весь фокус в том, что образ, из которого был запущен контейнер, полностью укомплектован. Внутри него установлены все необходимые зависимости, и его запуск практически гарантирует 100% работоспособность независимо от состояния основной ОС.

Часто даже не обязательно копировать программу из контейнера на вашу основную систему. Достаточно запускать сам контейнер, когда в этом возникнет необходимость. Предположим, что мы решили разработать статический сайт на основе Jekyll. Jekyll — популярный генератор статических сайтов, написанный на Ruby. Например, гайд который вы читаете прямо сейчас, находится на статическом сайте, сгенерированном с его помощью. И при его генерации использовался Докер (об этом можно прочитать в гайде: как делать блог на Jekyll).

Старый способ использования Jekyll требовал установки на вашу основную систему как минимум Ruby и самого Jekyll в виде гема (gem — название пакетов в Ruby). Причем, как и всегда в подобных вещах, Jekyll работает только с определенными версиями Ruby, что вносит свои проблемы при настройке.

С Докером запуск Jekyll сводится к одной команде, выполняемой в директории с блогом (подробнее можно посмотреть в репозитории наших гайдов):

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

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

Для чего используют docker. Смотреть фото Для чего используют docker. Смотреть картинку Для чего используют docker. Картинка про Для чего используют docker. Фото Для чего используют docker

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

Но в какой-то момент все изменилось. Картинка стоит тысячи слов:

Для чего используют docker. Смотреть фото Для чего используют docker. Смотреть картинку Для чего используют docker. Картинка про Для чего используют docker. Фото Для чего используют docker

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

То же самое произошло и в разработке ПО. Docker стал универсальным средством доставки софта независимо от его структуры, зависимостей и способа установки. Всё, что нужно программам, распространяемым через Докер, находится внутри образа и не пересекается с основной системой и другими контейнерами. Важность этого факта невозможно переоценить. Теперь обновление версий программ никак не задействует ни саму систему, ни другие программы. Сломаться больше ничего не может. Всё, что нужно сделать, это скачать новый образ той программы, которую требуется обновить. Другими словами, Докер убрал проблему dependency hell и сделал инфраструктуру immutable (неизменяемой).

Больше всего Docker повлиял именно на серверную инфраструктуру. До эры Докера управление серверами было очень болезненным мероприятием даже несмотря на наличие программ по управлению конфигурацией (chef, puppet, ansible). Основная причина всех проблем — изменяемое состояние. Программы ставятся, обновляются, удаляются. Происходит это в разное время на разных серверах и немного по-разному. Например, обновить версию таких языков, как PHP, Ruby или Python могло стать целым приключением с потерей работоспособности. Проще поставить рядом новый сервер и переключиться на него. Идейно Докер позволяет сделать именно такое переключение. Забыть про старое и поставить новое, ведь каждый запущенный контейнер живет в своем окружении. Причем, откат в такой системе тривиален: всё что нужно — остановить новый контейнер и поднять старый, на базе предыдущего образа.

Приложение в контейнере

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

На практике все преимущества Docker достигаются только со вторым подходом. Во-первых, сервисы, как правило, разнесены по разным машинам и нередко перемещаются по ним (например, в случае выхода из строя сервера), во-вторых, обновление одного сервиса не должно приводить к остановке остальных.

Первый подход крайне редко, но бывает нужен. Например, Хекслет работает в двух режимах. Сам сайт с его сервисами использует вторую модель, когда каждый сервис отдельно, но вот практика, выполняемая в браузере, стартует по принципу “один пользователь — один контейнер”. Внутри контейнера может оказаться всё что угодно в зависимости от практики. Как минимум, там всегда стартует сама среда Хекслет IDE, а она в свою очередь порождает терминалы (процессы). В курсе по базам данных в этом же контейнере стартует и база данных, в курсе, связанном с вебом, стартует веб-сервер. Такой подход позволяет создать иллюзию работы на настоящей машине и резко снижает сложность в поддержке упражнений. Повторюсь, что такой вариант использования очень специфичен и вам вряд ли понадобится.

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

Работа с образами

Docker — больше, чем просто программа. Это целая экосистема со множеством проектов и сервисов. Главный сервис, с которым вам придется иметь дело — Registry. Хранилище образов.

Концептуально оно работает так же, как и репозиторий пакетов любого пакетного менеджера. Посмотреть его содержимое можно на сайте https://hub.docker.com/, кликнув по ссылке Explore.

Разберемся с тем, как формируется имя образа, и что оно в себя включает.

Важно понимать, что это всего лишь соглашение, а не правило. Конкретный образ вообще может не иметь тега latest, либо иметь, но он не будет содержать последние изменения, просто потому, что никто их не публикует. Впрочем, популярные образы следуют соглашению. Как понятно из контекста, теги в Докере изменяемы, другими словами, вам никто не гарантирует, что скачав образ с одним и тем же тегом на разных компьютерах в разное время вы получите одно и то же. Такой подход может показаться странным и ненадежным, ведь нет гарантий, но на практике есть определенные соглашения, которым следуют все популярные образы. Тег latest действительно всегда содержит последнюю версию и постоянно обновляется, но кроме этого тега активно используется семантическое версионирование. Рассмотрим https://hub.docker.com/_/nginx

Теги, в которых присутствует полная семантическая версия (x.x.x) всегда неизменяемы, даже если в них встречается что-то еще, например, 1.12.2-alphine. Такую версию смело нужно брать для продакшен-окружения. Теги, подобные такому 1.12, обновляются при изменении path версии. То есть внутри образа может оказаться и версия 1.12.2, и в будущем 1.12.8. Точно такая же схема и с версиями, в которых указана только мажорная версия, например, 1. Только в данном случае обновление идет не только по патчу, но и по минорной версии.

Управление контейнерами

Для чего используют docker. Смотреть фото Для чего используют docker. Смотреть картинку Для чего используют docker. Картинка про Для чего используют docker. Фото Для чего используют docker

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

Теперь выведем информацию о запущенных контейнерах командой docker ps :

(Команда docker stats выводит информацию о том, сколько ресурсов потребляют запущенные контейнеры).

Теперь попробуем остановить контейнер. Выполним команду:

Здесь как раз два последних наших запуска. Если посмотреть на колонку STATUS, то видно, что оба контейнера находятся в состоянии Exited. То есть запущенная команда внутри них выполнилась, и они остановились. Разница лишь в том, что один завершился успешно (0), а второй с ошибкой (127). После остановки контейнер можно даже перезапустить:

Взаимодействие с другими частями системы

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

Interactive mode

Самый простой вариант использования Докера, как мы уже убедились — поднять контейнер и выполнить внутри него какую-либо команду:

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

Ports

Volumes

Другая частая задача связана с доступом к основной файловой системе. Например, при старте nginx-контейнера ему можно указать конфигурацию, лежащую на основной фс. Докер прокинет её во внутреннюю фс, и nginx сможет её читать и использовать.

При работе с Volumes есть несколько важных правил, которые надо знать:

Кроме пробрасывания части фс снаружи, Докер предоставляет еще несколько вариантов создания и использования Volumes. Подробнее — в официальной документации.

Переменные окружения

Конфигурирование приложения внутри контейнера, как правило, осуществляется с помощью переменных окружения в соответствии с 12factors. Существует два способа их установки:

Подготовка собственного образа

Создание и публикация собственного образа не сложнее его использования. Весь процесс делится на три шага:

Рассмотрим процесс создания образа на примере упаковки линтера eslint (не забудьте повторить его самостоятельно). В результате сборки, мы получим образ, который можно использовать так:

То есть достаточно запустить контейнер из этого образа, подключив каталог с файлами js для проверки как Volume во внутреннюю директорию /app.

1. Конечная структура директории, на основе файлов которой соберется образ, выглядит так:

Файл eslintrc.yml содержит конфигурацию линтера. Он автоматически прочитывается, если лежит в домашней директории под именем .eslintrc.yml. То есть этот файл должен попасть под таким именем в директорию /root внутрь образа.

2. Создание Dockerfile

Dockerfile имеет довольно простой формат. На каждой строчке указывается инструкция (директива) и её описание.

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

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

Технически образ Докера — это не один файл, а набор так называемых слоев. Каждый вызов RUN формирует новый слой, который можно представить как набор файлов, созданных и измененных (в том числе удаленных) командой, указанной в RUN. Такой подход позволяет значительно улучшить производительность системы, задействовав кеширование слоев, которые не поменялись. С другой стороны, Докер переиспользует слои в разных образах если они идентичны, что сокращает и скорость загрузки и занимаемое пространство на диске. Тема кеширования слоев довольно важная при активном использовании Докера. Для её эффективной работы нужно понимать как она устроена и как правильно описывать инструкции RUN для максимальной утилизации.

В соответствии со своим названием команда COPY берет файл или директорию из основной файловой системы и копирует её внутрь образа. У команды есть ограничение. То, что копируется, должно лежать в той же директории, где и Dockerfile. Именно эту команду используют при разработке когда необходимо упаковать приложение внутрь образа.

WORKDIR

3. Сборка

4. Публикация

Для успешного выполнения публикации нужно соблюсти два условия:

Docker Compose

Docker Compose — продукт, позволяющий разрабатывать проект локально, используя Докер. По решаемым задачам его можно сравнивать с Vagrant.

В бою

При использовании Докера настройка машин проекта, как правило, сводится к установке Докера. Дальше нужно только деплоить. Простейший процесс выкладки выглядит так:

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

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

Докер под капотом

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

Источник

Добавить комментарий

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