Как установить в докер много аытоа
Перейти к содержимому

Как установить в докер много аытоа

  • автор:

Что такое Docker: для чего он нужен и где используется

Docker — один из самых известных инструментов по работе с контейнерами. В статье мы расскажем, что такое контейнеры, где они применяются и чем могут быть полезны. Managed Kubernetes помогает разворачивать контейнерные приложения в инфраструктуре Selectel. Сосредоточьтесь на разработке, а мы займемся рутинными операциями по обеспечению работы вашего кластера Kubernetes. В конце будет практическая часть: мы […]

Изображение записи

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

Managed Kubernetes помогает разворачивать контейнерные приложения в инфраструктуре Selectel. Сосредоточьтесь на разработке, а мы займемся рутинными операциями по обеспечению работы вашего кластера Kubernetes.

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

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

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

Что такое контейнеры

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

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

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

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

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

Преимущества использования контейнеров Docker

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

Docker решает проблемы зависимостей и рабочего окружения

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

Например, разработчики создают приложение в системе разработки — там все настроено, приложение работает. Когда оно готово, его нужно перенести в систему тестирования, а затем в продуктивную среду. Если в одной из них нет нужной зависимости, приложение не будет работать. Программистам придется отвлечься от разработки и совместно с командой поддержки разобраться в ситуации.

В контейнерах такой проблемы нет, так как они содержат в себе все необходимое для запуска приложения. Специалисты занимаются разработкой, а не решением инфраструктурных проблем.

Изоляция и безопасность

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

Ускорение и автоматизация развертывания приложений и масштабируемость

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

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

Контейнеры приближают к микросервисной архитектуре

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

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

Docker compose — одновременно развернуть несколько контейнеров

Docker-compose позволяет разворачивать и настраивать несколько контейнеров одновременно. Например, для веб-приложения нужно развернуть стек LAMP: Linux + Apache, MySQL, PHP. Каждое из приложений — это отдельный контейнер для ОС Linux. Но в этой ситуации нам нужны именно все контейнеры вместе, а не отдельно взятое приложение. Docker-compose позволяет развернуть и настроить все приложения одной командой, а без него пришлось бы разворачивать и настраивать каждый контейнер отдельно.

Создайте кластер любой конфигурации в несколько кликов

Упростите процесс развертывания, масштабирования и обслуживания контейнерной инфраструктуры с Managed Kubernetes.

Хранение данных в Docker

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

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

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

Тома (Docker volumes)

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

Монтирование каталога (bind mount)

В этом случае директория сначала создается на хост-машине а уже потом монтируется в контейнеры.

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

Архитектура (компоненты) Docker

Теперь расскажем подробнее про компоненты, из которых состоит Docker.

Docker daemon

Это некоторый резидентный процесс, который запущен на хост-машине постоянно. Он владеет всей инфраструктурой, а также предоставляет интерфейс взаимодействия с контейнерами, включающего создание и удаление, запуск и остановку.

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

Docker client (клиент)

Это интерфейс командной строки для управления Docker daemon. Мы пользуемся этим клиентом, когда создаем и разворачиваем контейнеры, а клиент отправляет эти запросы в Docker daemon.

Docker image (образ)

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

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

Docker container (контейнер)

Это уже развернутое из образа и работающее приложение.

Docker Registry

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

Dockerfile

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

Для примера рассмотрим Dockerfile, который мы будем использовать далее в этой статье чтобы развернуть собственное приложение:

FROM python:3 COPY main.py / CMD [ "python", "./main.py" ]

Первая строчка означает, что за основу мы берем образ с названием python версии 3 это называется базовый образ. Docker найдет его в docker registry, скачает и будет использовать за основу. Вторая строчка означает, что нужно скопировать файл main.py в корень файловой системы контейнера. Третья строчка означает, что нужно запустить python и передать ему в качестве параметра название файла main.py.

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

Все эти команды выполняются в Docker client, который отправляет их в Docker daemon:

  • Команда docker build (зеленая стрелка) читает dockerfile и собирает образ.
  • Команда docker pull (красная стрелка) скачивает образ из docker registry. По умолчанию docker скачивает образы из публичного репозитория Docker Hub. Но можно создать свой репозиторий и настроить докер, чтобы он работал с ним.
  • Команда docker run (черная стрелка) берет образ и запускает из него контейнер.

Создаем виртуальную машину для работы с Docker

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

В панели управления заходим в раздел «Облачная платформа» — «Серверы», нажимаем кнопку «Создать сервер».

На следующем экране выбираем параметры сервера: имя, регион, ОС, параметры производительности и так далее. Сейчас для нас важны параметры «Источник» — выбираем ОС Ubuntu 20.04 и «Конфигурация» — выбираем 2 vCPU и 8 ГБ оперативной памяти.

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

После этого внизу страницы нажимаем кнопку «Создать». Виртуальная машина создается за несколько минут, и после того, как она перейдет в статус ACTIVE, к ней можно подключаться по SSH.

Установка Docker

Мы рассмотрим установку докера на примере Ubuntu. Если у вас другой дистрибутив Linux или операционная система — ищите соответствующую инструкцию на официальном сайте.

Для начала синхронизируем пакетную базу apt и установим нужные зависимости:

sudo apt-get update
sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg \ lsb-release

Далее импортируем GPG-ключ для репозитория docker:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Теперь добавим новый репозиторий в список apt:

echo \ "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Теперь можно устанавливать докер:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

По умолчанию, доступ к docker daemon есть только у пользователя root. Чтобы с докером могли работать и другие пользователи, их нужно добавить в специальную группу — docker. Выполните эту команду из под обычного пользователя:

sudo usermod -aG docker $USER

После этого необходимо перелогиниться, чтобы изменение вступило в силу.

Запуск контейнера

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

docker run ubuntu echo 'hello from ubuntu'

Команда docker run создает и запускает контейнер из образа. В этом примере мы создаем контейнер из образа ubuntu, затем выполняем в нем команду echo ‘hello from ubuntu’. Но так как у нас чистая установка докера и мы не скачали ни одного образа, докер сначала найдет этот образ в публичном репозитории Docker Hub, скачает, а потом создаст из него контейнер. В следующий раз, когда нам понадобится образ ubuntu, докер уже не будет его скачивать.

После выполнения команды в терминале появится строка hello from ubuntu, и контейнер сразу остановится. Теперь выполним другую команду:

docker run -it ubuntu

Эта команда запустит контейнер в интерактивном режиме, то есть контейнер запустится и будет ждать дальнейших команд. При этом мы окажемся внутри операционной системы контейнера: запустится оболочка (bash), и мы сможем выполнять какие-то команды внутри контейнера. Чтобы выйти из контейнера, введите команду exit.

Создание собственного образа и запуск контейнера

Теперь создадим HelloWorld-приложение на Python, обернем его в образ и запустим.

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

mkdir first-docker-app
cd first-docker-app

Создадим файл main.py и запишем в него одну строчку кода:

echo 'print("Hello from python");' >> main.py

Проверим, что наша программа работает. Для этого выполним команду:

python main.py

В консоли должно выйти сообщение Hello from python. Это и есть наше простое приложение. Теперь нужно обернуть его в докер-образ. Для этого создадим файл Dockerfile и напишем в нем три строчки:

FROM python:3 COPY main.py / CMD [ "python", "./main.py" ]

В первой строке мы указываем образ, который берем за основу. Так как мы пишем приложение на Python, нужно чтобы в нашем образе он уже был установлен. Самый простой способ это сделать — использовать готовый официальный образ с Docker Hub. Цифра 3 — это тег. Он означает, что нужно использовать третью версию Python. Вместо этого можно было бы использовать тег latest, который означает самую последнюю версию, или можно было указать номер конкретной версии, например 3.8.8.

Во второй строчке мы копируем наш файл main.py в корневую директорию образа.

Третья строчка — запускаем python и передаем ему в качестве параметра имя нашего файла.

Теперь из этого докер-файла можно собирать образ. Выполним команду:

docker build -t first-docker-app .

Параметр -t обозначает имя нашего образа, мы назвали его first-docker-app.

Так как у нас еще нет скачанного образа python, то докер сам скачает его из Docker Hub и затем будет использовать его в качестве основы для создания нашего образа.

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

docker images

Мы увидим, что у нас установлено три образа:

REPOSITORY TAG IMAGE ID CREATED SIZE first-docker-app latest 649cceb4dfd2 4 seconds ago 885MB python 3 b1aa63f57d3c 2 days ago 885MB ubuntu latest 8e428cff54c8 4 days ago 72.9MB

first-docker-app — это наш образ, который мы только что создали. python — это образ python, который докер автоматически скачал чтобы собрать наш образ. ubuntu — образ, который мы пробовали для запуска готового приложения.

Теперь создадим контейнер из нашего образа и запустим его:

docker run first-docker-app

В результате нам выведется результат: Hello from python.

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

Заботимся о работе и доступности вашего кластера даже в пиковые нагрузки

Managed Kubernetes — это готовый сервис Selectel. Мы отвечаем за автоматическое обновление кластера, несем ответственность по SLA за его доступность и бесперебойную работу Control Plane.

Список полезных команд

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

Посмотреть список всех контейнеров

Эта команда выведет список всех докер контейнеров:

docker ps

Но по умолчанию выводятся только работающие контейнеры. Чтобы вывести все, в том числе и остановленные, используйте опцию -a:

docker ps -a

Остановить и удалить все докер контейнеры

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

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

Запустить контейнер с последующим удалением

По умолчанию контейнеры после завершения работы останавливаются, но не удаляются. Они сохраняют свое состояние и при необходимости их можно запустить снова. Чтобы контейнер удалялся сразу после остановки, добавьте к команде docker run параметр —rm, например:

docker run --rm ubuntu echo 'hello from ubuntu'

Посмотреть список всех скачанных образов

docker images

Удалить докер образ

docker rmi

Если у этого образа есть контейнеры, пусть даже остановленные, докер не позволит его удалить. Он выдаст сообщение:

unable to remove repository reference (must force) - container is using its

Чтобы принудительно удалить образ, добавьте флаг -f:

docker rmi -f

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

docker ps -a --filter ancestor=

Итог

В статье мы рассмотрели, что такое контейнеры и Docker, как они работают и чем отличаются от виртуализации. Также мы создали простое python-приложение, обернули его в образ и запустили контейнер.

Мы рассказали основы технологий, но не затронули более сложные темы, вроде Docker Swarm, настройку сети или настройки процессов CI/CD. Но этого вполне достаточно, чтобы погрузиться в основы технологий.

Полная автоматизация «development» среды с помощью docker-compose

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

Docker в 2017

На конференции Dockercon 2016 CEO компании Docker рассказал, что количество приложений, которые запускаются в Docker выросло на 3100% за последние два года. Боле 460 тысяч приложений по всему миру запускаются в Docker. Это невероятно!

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

Что не так?

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

Многие проекты просты в начале, но становятся больше со временем. Это приводит к увеличению внешних зависимостей, таких как базы данных, очереди. В связи с ростом популярности микросервисов, многие проекты перестают быть монолитными и разделяются на несколько небольших частей. Любое такое изменение требует внимания всей команды, так как после таких изменений, проект нужно запускать по-другому. Обычно, разработчики, занимающиеся корневыми изменениями, пишут письмо, либо создают вики страничку с описанием шагов, которые нужно сделать, чтобы проект снова запустился на рабочих окружениях. Обычно это работает, но не всегда 🙂 Однажды наша команда попала в ситуацию, когда разработчик с другого континента сделал много изменений в проекте, написал длинное письмо и ушел спать. Я полагаю, Вы знаете, что было дальше. Все верно, он забыл упомянуть несколько важных моментов. В результате, на следующий день часть команды просто не смогла запустить проект и день был потерян.

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

Быстрый старт с docker-compose

Docker-compose это простой инструмент, который позволяет настроить и запустить несколько контейнеров одной командой. До того, как мы нырнем глубже в docker-compose, нужно немного остановиться на структуре проекта. Мы используем «monorepo». Код каждого сервиса (frontend, api, worker, etc) находится в своей директории и имеет Dockerfile. Пример структуры проекта можно посмотреть здесь.

Вся конфигурация для docker-compose описывается в файле docker-compose.yml , который обычно лежит в корне проекта. Начнем с автоматизации простого Node.JS приложения, которое работает с базой данных MongoDB. Вот так будет выглядеть конфигурационный файл:

version: '2' services: web: build: context: ./web dockerfile: Dockerfile.dev volumes: - "./web/src:/web/src" ports: - "8080:8080" mongo: command: mongod image: mongo:3.2.0 ports: - "27100:27017" # map port to none standard port, to avoid conflicts with locally installed mongodb. volumes: - /var/run/docker.sock:/var/run/docker.sock

Чтобы запустить проект, нам понадобиться одна команда:

$ docker-compose up

При первом старте, все контейнеры будут построены или скачаны. Если вы работали с Docker, конфигурационный файл для docker-compose должен быть более-менее понятен, но стоит обратить внимание на несколько деталей:

  1. context: ./web — таким образом указывается путь к докер файлу сервиса внутри нашего репозитория.
  2. dockerfile: Dockerfile.dev — мы используем отдельный Dockerfile.dev для рабочих окружений. Для «production» окружений, мы копируем код в образ Docker, а на рабочих окружениях мы добавляем код как «volume». При использовании «volume» не приходится перезапускать docker-compose каждый раз после изменений в коде.
  3. volumes: — «./web/src:/web/src» — так код добавляется как «volume» в Docker.
  4. Docker-compose автоматически «связывает» контейнеры. Благодаря этому есть возможно обращаться к сервису по имени. Например, из сервиса web вы можете подключится к базе данных MongoDB: mongodb://mongo:27017
Всегда используйте —build

По умолчанию, docker-compose up не будет перестраивать контейнеры, если они уже есть на хосте. Чтобы заставить докер делать это, нужно использовать аргумент —build . Обычно это нужно, когда сторонние зависимости проекта меняются или меняется докерфайл. В нашей команде мы всегда используем docker-compose up —build . Docker умеет кэшировать слои и не будет перестраивать контэйнер, если ничего не поменялось. При использовании —build повсеместно, вы, возможно, потеряете несколько секунд при старте приложения. Но, при этом вы никогда не столкнетесь с магическими проблемами запуска новой версии приложения со старыми зависимостями.

Совет: Вы можете обернуть команду запуска проект в простой баш скрипт:

#!/bin/sh docker-compose up --build "$@"

Это даст вам возможность поменять аргументы или подход для запуска приложения в целом. Для команды это всегда будет просто как: ./bin/start.sh .

Частичный запуск

В этом примере docker-compose.yml некоторые сервисы зависят друг от друга:

 api: build: context: ./api dockerfile: Dockerfile.dev volumes: - "./api/src:/app/src" ports: - "8081:8081" depends_on: - mongo

В данном случае, api сервису необходима база данных для работы. При запуске docker-compose, вы можете передать название сервиса для того, чтобы запустить только его и все его зависимости: docker-compose up api . Эта команда запустит MongoDB и только после этого запустит api .

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

>/dev/null назойливые логи

Часто мы используем инструменты, которые генерируют много логов, тем самым отвлекая нас от полезных логов нашего приложения. Чтобы отключить логи для конкретного сервиса, нужно просто установить logging driver в none.

 mongo: command: mongod image: mongo:3.2.0 ports: - "27100:27017" volumes: - /var/run/docker.sock:/var/run/docker.sock logging: driver: none
Несколько файлов docker-compose

По умолчанию, когда вы запускаете docker-compose up , docker-compose ищет конфигурационный файл docker-compose.yml в текущей директории. В некоторых случаях (поговорим об этом через минуту), вам придется создать несколько таких конфигурационных файлов. Чтобы сделать это, вам достаточно использовать аргумент —file :

docker-compose --file docker-compose.local-tests.yml up

Так почему же вам может понадобиться несколько конфигурационных файлов? Первый вариант использования — это разбиение большого проекта на несколько более мелких. Интересно, что даже если вы запускаете несколько отдельных docker-compose, сервисы все равно смогут общаться друг с другом по имени из docker-compose. Например, вы можете разделить инфраструктурные контэйнеры (базы данных, очереди и т.д.) и контейнеры приложения в отдельные docker-compose файлы.

Запуск тестов

Наши тесты включают в себя различные типы: юнит, интеграционные, UI тестирование, проверку синтаксиса кода. У каждого сервиса свой набор тестов. Интеграционные и UI тесты требуют api и web frontend для их работы.

В самом начале нам показалось, что мы должны запускать тесты при каждом запуске docker-compose. Но очень скоро мы поняли, что это не всегда удобно и занимает слишком много времени. В каких-то случаях нам также хотелось иметь немного больше контроля над тем, какие тесты запускать. Для этого мы используем отдельный конфигурационный docker-compose файл:

version: '2' services: api-tests: image: app_api command: npm run test volumes: - "./api/src:/app/src" web-tests: image: app_web command: npm run test volumes: - "./web/src:/app/src"

Для запуска тестов необходимо, чтобы основной docker-compose был запущен. Интеграционные тесты используют рабочую версию api сервиса, а UI тесты используют web frontend сервиса. По сути тесты просто используют образы, которые собраны в основном docker-compose. Также возможен запуск тестов только для конкретного сервиса, например:

docker-compose --file docker-compose.local-tests.yml up api-tests

Данная команда запустит только тесты для api сервиса.

Префикс для контейнеров

По умолчанию, все контэйнеры, которые запускаются с помощью docker-compose, используют название текущей директории как префикс. Название этой директории может отличаться в рабочих окружениях у разных разработчиков. Этот префикс ( app_ ) используется, когда мы хотим сослаться на контейнер из основного docker-compose файла. Чтобы зафиксировать этот префикс, нужно создать файл .env рядом с конфигурационными файлами docker-compose в той директории, из которой запускается docker-compose:

COMPOSE_PROJECT_NAME=app

Таким образом, префикс будет одинаковым во всех рабочих окружениях.

Заключение

Docker-compose это очень полезный и гибкий способ автоматизации запуска проектов.

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

  1. Установить Docker и Docker-compose
  2. Склонировать репозиторий
  3. Запустить в терминале ./bin/start.sh

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

Надеемся, что статья была полезной и поможет сделать Ваш проект лучше 🙂

Версию на английском, можно почитать здесь.

Управление данными в Docker

К докер контейнерам можно подключать внешние папки. Рассматриваем основные способы.

Время чтения: больше 15 мин

Открыть/закрыть навигацию по статье

  1. Связанные папки (bind mounts)
    1. Как пользоваться
    1. Как пользоваться
    2. Использование драйверов
    3. Резервные копии
    1. Как пользоваться
    1. Игорь Коровченко советует
    1. Опишите жизненный цикл контейнера Docker

    Обновлено 17 мая 2022

    В этой статье мы поговорим про управление данными приложений в Docker. Узнать, что такое Docker, вы сможете из статьи «Что такое Docker». Также вы можете почитать о мультиконтейнерных приложениях и Docker Compose и о том, как устроен Dockerfile.

    Итак, по умолчанию все данные приложения хранятся в контейнере Docker и после остановки контейнера теряются. Но это не единственный способ работать с данными. Можно использовать оперативную память и файловую систему компьютера, на котором установлен Docker Engine. Существует несколько типов хранилищ данных:

    • связанные папки, примонтированные к контейнеру как внешние диски (bind mounts);
    • тома (volumes);
    • часть оперативной памяти для работы с данными (tmpfs mounts или npipe mounts).

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

    Наглядная схема типов управления данными в Docker:

    Наглядная схема типов управления данными в Docker.

    Рассмотрим каждый тип по отдельности.

    Связанные папки (bind mounts)

    Скопировать ссылку «Связанные папки (bind mounts)» Скопировано

    Связанные папки появились в Docker с самых первых релизов. Это удобный инструмент, но у него есть ограничения. Этот тип управления данными позволяет связать папку на компьютере пользователя (то есть хосте, на котором установлен Docker Engine) и папку в контейнере. Работать в контейнере и на хосте с такой папкой можно одновременно, все изменения будут отображаться и там, и там. Механизм bind mounts подразумевает, что данные могут быть изменены в любое время как из подключённого контейнера, так и непосредственно на хосте.

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

    Связанные папки используются:

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

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

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

    Как пользоваться

    Скопировать ссылку «Как пользоваться» Скопировано

    Чтобы связать папку на хосте с папкой внутри контейнера, можно воспользоваться флагами -v или — — mount . $ ( pwd ) в командах ниже означает, что примонтируется текущая папка на хосте.

    Пример с флагом -v :

     docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app \ node:lts docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app \ node:lts     

    Можно задать следующие опции: rprivate , private , rshared , shared , rslave , slave , ro , z и Z .

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

    Последние три параметра могут быть указаны только для флага -v . Значение ro определяет режим только для чтения. Папка на хосте не может быть изменена внутри контейнера. Значение z обозначает, что папка на хосте может быть использована несколькими контейнерами. Значение Z обозначает, что папка используется только одним контейнером. Не указывайте значение Z для системных папок, например, /usr или /home. Это приведёт к тому, что работа операционной системы на хосте будет парализована. Будьте аккуратны!

    Пример с флагом — — mount :

     docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ node:lts docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ node:lts     

    Ключ bind-propagation

    Для флага — — mount есть ключ bind — propagation , который работает только на Linux (операционные системы контейнера и хоста должны поддерживать этот режим работы).

    Представьте, есть две точки монтирования /mnt1 и /mnt2 , к которым привязана одна и та же папка на хосте. Значения ключа bind — propagation определяют, что произойдёт, если в связанной папке появятся подпапки. Что произойдёт с /mnt2 / sub при монтировании /mnt1 / sub ? Возможны следующие варианты:

    — shared указывает на то, что изменения для точки монтирования /mnt1 / sub будут в точности отражаться в /mnt2 / sub и наоборот;
    — slave указывает на то же, что shared , но только в одном направлении (изменения в первой точке монтирования будут распространяться на вторую, но не наоборот);
    — private указывает, что изменения в первой точке монтирования не будут отображаться во второй, и наоборот;
    — rshared — то же, что shared , распространяет подобное поведение на все реплики точек монтирования;
    — rslave — то же, что slave , распространяет подобное поведение на все реплики точек монтирования;
    — rprivate (значение по умолчанию) — то же, что private , распространяет подобное поведение на все реплики точек монтирования.

     docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/app/src,target=/app \ --mount type=bind,source="$(pwd)"/app/src,target=/app2,readonly,bind-propagation=rslave \ node:lts docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/app/src,target=/app \ --mount type=bind,source="$(pwd)"/app/src,target=/app2,readonly,bind-propagation=rslave \ node:lts     

    Папка /app/src на хосте дважды монтируется к разным папкам в контейнере. Вторая точка монтирования имеет дополнительные настройки:

    — приложение app2 может только читать данные из папки на хосте;
    — изменения в первой точке монтирования сразу происходят и во второй, но не наоборот.

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

    Флаг — — mount не поддерживает опции для управления метками selinux ( z и Z ).

    Проверьте корректность работы хранилища с помощью команды:

     docker inspect devtest docker inspect devtest     

    В соответствующей секции Mounts вы сможете найти исчерпывающую информацию. Например, если вы находились в папке /tmp/source/target при запуске контейнера, то в этой секции будет указана примерно следующая информация:

     "Mounts": [  "Type": "bind", "Source": "/tmp/source/target", "Destination": "/app", "Mode": "", "RW": true, "Propagation": "rprivate" >], "Mounts": [  "Type": "bind", "Source": "/tmp/source/target", "Destination": "/app", "Mode": "", "RW": true, "Propagation": "rprivate" > ],      

    Для разрыва связи между папками на хосте и в контейнере выполните команды остановки и удаления контейнера:

     docker container stop devtestdocker container rm devtest docker container stop devtest docker container rm devtest     
    1. Связанными папками нельзя управлять из Docker CLI.
    2. Абсолютные пути на разных компьютерах могут быть разными.
    3. Если в контейнере в примонтированной папке есть содержимое, то оно «перекроет» содержимое связанной папки на все время работы контейнера.
    4. Использовать связанные папки для работы с конфигурационными файлами небезопасно.
    5. Файловая система и структура папок могут сильно отличаться на разных компьютерах.
    6. Правила описания путей к файлам могут отличаться при переходе от одной платформы к другой.
    7. Вы можете столкнуться с ситуацией, когда приложение в контейнере получит доступ к системным папкам или удалит критически важные файлы.

    Тома (volumes)

    Скопировать ссылку «Тома (volumes)» Скопировано

    Тома — это лучший тип управления данных в Docker. Только объекты или службы Docker должны иметь права на изменение данных, расположенных в томах. На хосте данные хранятся в специальных папках, но без доступа администратора к ним не подобраться. В идеологии Docker тома — что-то вроде образа флэш-накопителя или CD/DVD.

    Тома можно размещать не только на хосте. Можно, например, пользоваться облачными платформами для совместной работы с данными или для тестирования приложений. А ещё тома будут работать как с Linux-контейнерами, так и с Windows-контейнерами, поскольку файловая система томов одна и та же.

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

    Тома могут быть созданы при сборке контейнера (с помощью Dockerfile или Docker Compose) или вручную с помощью Docker Engine. Тома могут иметь имя, назначенное пользователем (именованные тома, named volumes), а могут быть анонимными с именем, которое Docker устанавливает автоматически (анонимные тома, anonymous volumes).

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

    Итак, возможности томов:

    — миграция данных и создание резервных копий;
    — управление с помощью Docker CLI или Docker API;
    — тома работают и с Linux-, и с Windows-контейнерами;
    — данные легко и безопасно можно использовать в нескольких контейнерах;
    — существует механизм драйверов, который позволяет хранить данные не только на хосте, но и на сервере или в облаке, шифровать данные в томе или добавлять дополнительную функциональность;
    — новые тома могут создаваться с уже загруженными с помощью контейнера данными;
    — если на хосте установлены Mac или Windows, тома будут быстрее работать с Docker Desktop, чем связанные папки;
    — тома не увеличивают размер контейнера;
    — тома находятся вне жизненного цикла контейнера.

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

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

    Когда вы хотите хранить данные не только у себя на локальном компьютере, но и на сервере или в облаке.

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

    Если ваше приложение требует высокой скорости обмена данными на Mac и Windows. Тома сохраняются на виртуальной машине Linux VM, на которой работают и контейнеры, поэтому скорость чтения и записи высокая. Нет лишних накладных расходов на доступ к файловой системе хоста.

    Когда важно, чтобы файловая система имела нативное поведение. Например, база данных должна контролировать кэширование на диске для гарантии выполнения транзакций. Файловые системы на Mac и Windows работают не так, как на Linux. Это может привести к ошибкам работы некоторых приложений.

    Как пользоваться

    Скопировать ссылку «Как пользоваться» Скопировано

    Создать том можно с помощью флагов -v или — — mount при запуске контейнера. Для флага -v можно указать параметр ro , который будет означать использование режима только для чтения. Для флага — — mount есть ключ volume — opt , который устанавливает набор опций, разделённых запятыми. Не забывайте, что значения для этого ключа должны быть экранированы кавычками. Работа с томами такова, что изменения в одной точке монтирования в контейнере не будут отображаться в другой точке монтирования (параметр bind — propagation всегда выставлен в значение rprivate ).

    Подключить том с именем my — vol можно следующим образом.

    С флагом — — mount :

     docker run -d \ --name devtest \ --mount source=my-vol,target=/app \ node:lts docker run -d \ --name devtest \ --mount source=my-vol,target=/app \ node:lts     
     docker run -d \ --name devtest \ -v my-vol:/app \ node:lts docker run -d \ --name devtest \ -v my-vol:/app \ node:lts     

    Проверьте корректность результата выполнения команды:

     docker inspect devtest docker inspect devtest     

    Чтобы удалить том, необходимо отключить связанный с ним контейнер и удалить сам контейнер:

     docker container stop devtestdocker container rm devtestdocker volume rm my-vol docker container stop devtest docker container rm devtest docker volume rm my-vol     

    Управлять томами можно через Docker API с помощью Docker CLI и Docker Compose.

    Чтобы создать новый том с помощью Docker CLI, используйте команду:

     docker volume create my-vol docker volume create my-vol     

    Получите список томов на хосте:

     docker volume ls docker volume ls      

    Посмотрите информацию о томе:

     docker volume inspect my-vol docker volume inspect my-vol     

    Удалите том командой:

     docker volume rm my-vol docker volume rm my-vol     

    Если том был анонимным, то можно удалить его сразу после завершения работы контейнера. Для этого при запуске контейнера вы можете прописать флаг — — rm . Вместе с удалением контейнера в этом случае удалится и том:

     docker run --rm -v /foo -v awesome:/bar container app docker run --rm -v /foo -v awesome:/bar container app     

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

    Чтобы удалить все неиспользуемые тома, используйте команду:

     docker volume prune docker volume prune     

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

     FROM node:ltsRUN useradd userRUN mkdir /data && touch /data/xRUN chown -R user:user /dataVOLUME /data FROM node:lts RUN useradd user RUN mkdir /data && touch /data/x RUN chown -R user:user /data VOLUME /data      

    Интересно, что вы не сможете внести какие-либо изменения в данные на этапе сборки образа. Следующий Dockerfile правильно работать не будет:

     FROM node:ltsRUN useradd userVOLUME /dataRUN touch /data/xRUN chown -R user:user /data FROM node:lts RUN useradd user VOLUME /data RUN touch /data/x RUN chown -R user:user /data      

    Том будет подключён только после создания образа на этапе запуска контейнера. Возможно, придётся использовать инструкции CMD или ENTRYPOINT . Подробнее описано в статье «Как устроен Dockerfile».

    Запустить том для отдельного контейнера с Docker Compose можно с помощью следующей конфигурации:

     services: frontend: image: node:lts volumes: - myapp:/home/node/appvolumes: myapp: services: frontend: image: node:lts volumes: - myapp:/home/node/app volumes: myapp:      

    Команда docker — compose up поднимет не только сам контейнер frontend , но и создаст том myapp . Если он уже был создан, Docker Compose подключит его к контейнеру, но надо указать это явно с помощью элемента external так:

     services: frontend: image: node:lts volumes: - myapp:/home/node/appvolumes: myapp: external: true services: frontend: image: node:lts volumes: - myapp:/home/node/app volumes: myapp: external: true      

    Подробнее о формате конфигурации Docker Compose можно прочитать в статье о Docker Compose.

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

    Скопировать ссылку «Использование драйверов» Скопировано

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

    Например, есть два компьютера — хост, на котором установлен Docker и запускаются контейнеры, и файловый сервер, который поставляет данные для них. Контейнеры ничего не знают про эту архитектуру: все запускалось изначально на локальном хосте. Драйвер vieux / sshfs позволяет использовать SSH-соединение для связи с файловым сервером, при этом данные будут представлены в виде тома Docker.

    Для начала необходимо установить соответствующий плагин для Docker Engine:

     docker plugin install --grant-all-permissions vieux/sshfs docker plugin install --grant-all-permissions vieux/sshfs     

    Затем нужно создать том и прописать учётные данные:

     docker volume create --driver vieux/sshfs \ -o sshcmd=test@node2:/home/test \ -o password=testpassword \ sshvolume docker volume create --driver vieux/sshfs \ -o sshcmd=test@node2:/home/test \ -o password=testpassword \ sshvolume     

    Если для связи по SSH между клиентом и сервером уже работают ключи доступа, то пароль можно опустить. Флаг -o указывает на опции, которые могут быть переданы драйверу. Набор доступных опций у каждого драйвера свой.

    Можно создать том и другим способом, при запуске контейнера:

     docker run -d \ --name sshfs-container \ --volume-driver vieux/sshfs \ --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \ nginx:latest docker run -d \ --name sshfs-container \ --volume-driver vieux/sshfs \ --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \ nginx:latest     

    Если драйвер требует передачи опций, приходится использовать флаг — — mount .

    Резервные копии

    Скопировать ссылку «Резервные копии» Скопировано

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

     docker run -v /dbdata --name dbstore node:lts /bin/bash docker run -v /dbdata --name dbstore node:lts /bin/bash     

    Как создать резервную копию данных в томе? Нужно:

    — запустить новый контейнер и примонтировать том, который используется в контейнере dbstore ;
    — примонтировать папку на хосте, чтобы потом в неё положить резервную копию;
    — зайти внутри контейнера в том, заархивировать данные и положить их в связанную папку.

     docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata     

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

    Допустим, у вас возникла необходимость развернуть данные из сохранённой резервной копии внутри контейнера dbstore2 . Нужно запустить его:

     docker run -v /dbdata --name dbstore2 node:lts /bin/bash docker run -v /dbdata --name dbstore2 node:lts /bin/bash     

    Затем разархивировать данные в том:

     docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1" docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"      

    Хранение в оперативной памяти

    Скопировать ссылку «Хранение в оперативной памяти» Скопировано

    Хранение в оперативной памяти бывает двух типов: tmpfs mounts и npipe mounts.

    Механизм tmpfs mount в операционной системе Linux позволяет выделить часть оперативной памяти хоста для хранения данных. Данные не сохраняются в файловой системе, и получается быстрое хранилище. Примонтированная папка tmpfs работает, пока запущен контейнер, поэтому не стоит использовать этот способ для хранения настроек и результатов работы приложения.

    Для пользователей операционной системы Windows существует ещё один тип управления данными — npipe mount. Этот тип позволяет получить доступ к хосту Docker из контейнера и в основном используется для управления данными с Docker Engine API.

    Используем оперативную память:

    Если вы не хотите оставлять данные после завершения работы приложения.

    Как пользоваться

    Скопировать ссылку «Как пользоваться» Скопировано

    Этот раздел посвящён использованию только на Linux.

    С помощью томов и связанных папок вы можете делиться файлами между хостом и контейнером. После остановки контейнера данные сохраняются. Но если на хосте используется операционная система Linux, то существует и третий тип работы с данными — tmpfs. Это временное файловое хранилище, которое располагается в оперативной памяти, присутствует во многих Unix-подобных системах. Когда вы создаёте контейнер, Docker может создать отдельный слой в оперативной памяти снаружи контейнера для хранения и обработки данных.

    При использовании этого типа работы с данными в Docker есть два ограничения:

    — операционной системой хоста может быть только Linux;
    — данные в tmpfs доступны лишь из одного контейнера.

    tmpfs хорошо работает в случае хранения чувствительной информации: ключей шифрования, паролей, сертификатов доступа и тому подобного.

    Чтобы запустить контейнер с tmpfs, используют команду:

     docker run -d \ -it \ --name tmptest \ --mount type=tmpfs,destination=/app \ node:lts docker run -d \ -it \ --name tmptest \ --mount type=tmpfs,destination=/app \ node:lts     

    С помощью ключа tmpfs — size можно определить максимальный размер хранилища в байтах. По умолчанию он не ограничен. Ключ tmpfs — mode служит для определения уровня доступа в восьмеричном формате. Например, значение по умолчанию 1777 обозначает, что любой пользователь или программа в контейнере имеют неограниченный доступ к данным, которые будут доступны и вне контейнера. Этот параметр работает также, как и для tmpfs в Unix-подобных операционных системах.

    Также есть альтернативная более короткая команда для управления tmpfs mounts:

     docker run -d \ -it \ --name tmptest \ --tmpfs /app \ node:lts docker run -d \ -it \ --name tmptest \ --tmpfs /app \ node:lts     

    Проверьте состояние контейнера, чтобы убедиться, что файловое хранилище создано корректно:

     docker container inspect tmptest docker container inspect tmptest     

    В соответствующей секции будет доступна информация о примонтированной папке:

     "Tmpfs":  "/app": "">, "Tmpfs":  "/app": "" >,      

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

     docker container stop tmptestdocker container rm tmptest docker container stop tmptest docker container rm tmptest     

    На практике

    Скопировать ссылку «На практике» Скопировано

    Игорь Коровченко советует

    Скопировать ссылку «Игорь Коровченко советует» Скопировано

    ✨ Вы можете получить данные из определённой папки контейнера, если примонтируете к ней пустую папку или пустой том на хосте. После монтирования данные автоматически окажутся доступны с хоста и останутся там после работы контейнера. Это удобный способ сделать бэкап или получить результаты работы приложения.

    Если папка или том окажутся не пустыми, то при монтировании к контейнеру содержимое будет на время скрыто. Контейнер будет воспринимать эту папку как пустую, данные будут в неё сохраняться и будут доступны с хоста во время работы контейнера. После окончания работы контейнера или после того, как том или папка будут отмонтированы, данные из контейнера будут потеряны, поскольку снова будут доступны те файлы и подпапки, которые были скрыты при монтировании. Это тот же механизм, который Linux будет использовать, когда вы, например, примонтируете USB-накопитель к уже заполненной чем-то папке.

    На собеседовании

    Скопировать ссылку «На собеседовании» Скопировано

    Как работает Docker: подробный гайд от техлида

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

    Фото: Bloomberg / Getty Images

    Мария Даровская

    Мария Даровская

    Журналист, коммерческий автор и редактор. Пишет про IT, цифровой маркетинг и бизнес.
    Сайт: darovska.com.

    Олег Накрайников

    Technical Lead. Любит GYM, путешествия и компьютерные игры. Пишет технические статьи и иногда технические треды в Twitter.

    Ссылки

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

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

    Что такое Docker

    Docker — это платформа, которая позволяет упаковать в контейнер приложение со всем окружением и зависимостями, а затем доставить и запустить его в целевой системе.

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

    Docker разработали в 2008 году. Изначально это был внутренний проект компании dotCloud, которую впоследствии переименовали в Docker Inc. В 2013 году dotCloud открыла исходный код Docker для сообщества.

    Ранние версии Docker представляли собой усовершенствованную обёртку LXC , а с 2015 года Docker уже использовал собственную библиотеку libcontainer, абстрагирующую виртуализационные возможности ядра Linux. Так он превратился в самостоятельную технологию. Платформа неслучайно переехала на libcontainer: гибкость и управляемость LXC-контейнеров оставляла желать лучшего.

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

    Устройство и принцип работы Docker

    Виртуализация в Docker реализуется на уровне ОС. Виртуальная среда запускается прямо из ядра основной операционной системы и использует её ресурсы.

    В поставку Docker входят следующие компоненты:

    • Docker host — это операционная система, на которую устанавливают Docker и на которой он работает.
    • Docker daemon — служба, которая управляет Docker-объектами: сетями, хранилищами, образами и контейнерами.
    • Docker client — консольный клиент, при помощи которого пользователи взаимодействуют с Docker daemon и отправляют ему команды, создают контейнеры и управляют ими.
    • Docker image — это неизменяемый образ, из которого разворачивается контейнер.
    • Docker container — развёрнутое и запущенное приложение.
    • Docker Registry — репозиторий, в котором хранятся образы.
    • Dockerfile — файл-инструкция для сборки образа.
    • Docker Compose — инструмент для управления несколькими контейнерами. Он позволяет создавать контейнеры и задавать их конфигурацию.
    • Docker Desktop — GUI-клиент, который распространяется по GPL. Бесплатная версия работает на Windows, macOS, а с недавних пор и на Linux. Это очень удобный клиент, который отображает все сущности Docker и позволяет запустить однонодовый Kubernetes для компьютера.

    Docker изначально создавался под Linux. Поэтому на Windows и macOS запускают виртуальную машину с Linux, а поверх неё — Docker. В macOS используют VirtualBox, а в Windows — Hyper-V.

    Работа поверх виртуалок повышает потребление ресурсов. Поэтому Docker на macOS и Windows работает медленнее и с рядом ограничений. Для разработки это приемлемо, но «в бою» так делать никто не будет. На всех популярных платформах в проде используют Linux.

    Чем виртуализация отличается от контейнеризации

    Контейнеры и виртуальные машины — это разные способы виртуализации. Только виртуалка реализует её на уровне железа, а Docker — на уровне операционной системы.

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

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

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

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

    Оба способа изолируют приложение от основной операционной системы, но если на виртуалку можно поставить любую ОС, то Docker ориентирован на ядро Linux. Недавно добавили возможность поднимать Windows, но я ещё не пробовал это делать.

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

    Обычно в крупных компаниях работают на виртуальных машинах, которые разворачиваются на железных машинах в ЦОДах . Инфраструктурные инженеры нарезают виртуальные компьютеры и выстраивают на них инфраструктуру. С помощью оркестраторов можно убрать эту лишнюю «прослойку».

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

    Сущности Docker

    Docker работает с несколькими сущностями.

    Docker image (образ). Это шаблон, по которому создают контейнеры. Его часто сравнивают со слоёным пирогом: мы накладываем слой файловой системы поверх слоя базового образа и получаем неизменяемый образ. В него можно установить приложение, конфигурации и зависимости. Другие образы могут наследоваться, поэтому если положить сверху слой файлов и закоммитить, то мы получим ещё один неизменяемый образ.

    Dockerfile. Если Docker image — это пирог, то Dockerfile — рецепт его приготовления. В этом файле описаны основные инструкции для сборки образа: какой базовый образ взять, откуда и куда положить файлы и так далее.

    Контейнер — это runtime-сущность на основе образа, приложение, которое мы развернули с помощью Docker. Можно провести такую аналогию: образ — это инсталлятор программы, а контейнер — уже запущенная программа.

    При развёртывании контейнера поверх файловой системы создаётся ещё один изменяемый слой. Приложение внутри контейнера может записывать туда данные или редактировать их. После удаления контейнера данные стираются, но их можно сохранить с помощью volumes.

    Docker Registry. Это репозиторий, в котором хранятся Docker-образы. Он может быть как локальным, так и публичным. Репозитории создают на платформах вроде Docker Hub и GitLab и размещают в них образы с описанием, разными версиями и тегами.

    Как Docker помогает на практике

    Приведу несколько примеров использования Docker, которые хорошо иллюстрируют его преимущества.

    Разработка приложений с зависимостями

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

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

    Единый интерфейс управления исключает необходимость индивидуальных команд. Достаточно выучить команды Docker: как скачивать образы, запускать контейнеры, пробрасывать, останавливать и удалять порты. С Docker можно запустить сколько угодно одинаковых баз внутри одной операционки. Благодаря изоляции, если что-то пойдёт не так, ошибки не затронут операционную систему и ничего не сломают.

    Автоматизация тестирования

    Чтобы запустить автотесты, требуются определённые зависимости, например базы данных, брокеры сообщений и тому подобное. Их необходимо предварительно установить и сконфигурировать на сервере сборки. В этом месте иногда возникают проблемы: если при настройке упустить какую-то деталь, то можно испортить данные или что-то поломать. Гораздо безопаснее автоматически развернуть зависимости в виде контейнера прямо на сервере. Это позволяет быстро прогнать тесты, а после — бесследно удалить контейнеры.

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

    Публикация приложения

    После тестирования проект упаковывают в образ и публикуют, передают клиентам или инфраструктурным инженерам.

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

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

    Минусы Docker

    Как известно, за удовольствие приходится платить. И Docker — не исключение.

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

    Для больших приложений нужен оркестратор. Docker подходит для запуска нескольких контейнеров. В стандартной поставке Docker Compose есть механизм, который позволяет управлять их запуском с помощью конфигурационного файла YAML. Но этот механизм простой, он не потянет приложение, включающее 50–100 сервисов. У Docker не хватит механизмов управления и распределения ресурсов, резервирования и отказоустойчивости, чтобы реализовывать разные схемы обновления контейнеров.

    В больших приложениях с микросервисной архитектурой используют оркестраторы Kubernetes или OpenShift. Единицей управления в Kubernetes является контейнер Docker, но на голом Docker прод практически никто не держит. Когда-то в России были такие компании — они рассказывали о своём травмирующем опыте на конференциях 🙂

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

    Проблемы с установкой на Windows и macOS. Как я сказал ранее, Docker создавался под Linux. На других операционках он не поддерживает некоторые типы сетей. В большинстве случаев никто этого не заметит, но об этом ограничении нужно помнить. Также на некоторых устройствах возникает конфликт с Virtual Box при установке Docker на Windows.

    Как изучать Docker

    Я рекомендую изучать Docker по книгам, сайтам и закреплять прочитанное на практике.

    Книги. Есть две хорошие книги — Using Docker и Docker in Action. Правда, они немного устарели (опубликованы в 2018–2019 годах), поэтому там может быть неактуальная информация. Надеюсь, скоро будет переиздание.

    Сайт docker.com — основной сайт Docker. На нём есть справочники и референсы по Docker, Docker-файлам, образам и Docker Compose. Читаете книгу, проверяете на сайте актуальность команд и изучаете примеры.

    Упражнения. Я провожу тренинги и внутреннее обучение в командах. Обычно рекомендую такие упражнения:

    • Установите Docker на рабочий компьютер. Возьмите готовый Docker image с Docker Hub с базой данных и запустите на его основе контейнер. Это можно сделать по инструкции, которую производитель image выкладывает на Docker Hub. Затем подключитесь к запущенной БД каким-нибудь клиентом и убедитесь, что всё работает.
    • Напишите простенький сервис REST API и Docker-файл для упаковки сервиса в образ, подглядывая в референсы или книгу. Ваша задача — разобраться в теории, получить Docker image и проставить теги.
    • Из полученного ранее образа создайте и запустите контейнер. Вам придётся разобраться с параметрами команды Docker run, настройками портов, передачей переменных окружению, монтированием и основными параметрами. Также стоит научиться подключаться к контейнеру, выполнять bash-команды и смотреть логи приложения.
    • Усложните тестовый сервис, научив его работать с базой данных. Затем разверните контейнеры с сервисом и базой данных и соедините их внутренней сетью. Простое и в то же время очень полезное упражнение, на котором очень часто возникают затруднения на собеседованиях.
    • Переходим к Docker Compose. Посмотрите, как написать YAML и создать группу контейнеров, как соединять их в сеть и работать с маунтами.
    • Опубликуйте свой Docker image в Docker Hub. На одном аккаунте можно бесплатно публиковать только один образ, но есть GitLab, где нет таких ограничений. Правда, он устроен немного сложнее, новичок может запутаться. Ещё в том же GitLab можно создать приватный registry-режим и публиковать проекты без ограничений.

    Читайте также:

    • Всё о Kubernetes: контейнеры, оркестрация, тулинг, виртуальные машины, конкуренты и экосистема
    • «У меня не было опыта, но было желание. Тестовое, испытательный — и я IT-аналитик в банке»
    • Практика Docker: знакомимся с docker-maven-plugin

    LXC — система виртуализации на уровне ОС. Позволяет запускать несколько изолированных экземпляров Linux на одном узле в отдельных виртуальных окружениях с собственным пространством процессов и сетевым стеком.

    Центры обработки данных.

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

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