Виртуализация на уровне операционной системы становится все более популярным решением при развертывании приложений в разных средах. Самый удачный инструмент для этого — Docker.
В двух статьях на Highload я расскажу об основных возможностях инструмента. Вы узнаете, как установить, настроить и запустить Docker, а также как работать с его ключевыми элементами: Dockerfile, Docker Image и Docker Container.
Docker и принцип контейнеров — почему так удобнее?
Виртуальная машина выступает в качестве эмулятора ПО. Предположим, на компьютере уже есть Windows и нужно дополнительно установить, например, Ubuntu. Создаем на том же компьютере виртуальную машину и уже на нее устанавливаем дополнительную операционную систему. В результате у нас будет два компьютера одновременно. Но для виртуальной машины нужно место на жестком диске, достаточно оперативной памяти и ресурсов процессора.
В противоположность этому появился принцип контейнеров, на котором построены Docker и другие подобные инструменты. Главное отличие — в собственной инфраструктуре и единой для всех сред ОС. Сверху этого основания устанавливается Docker, благодаря которому можно создавать множество контейнеров, апликаций и т.п.
Docker разделяет единое ядро ОС на отдельные контейнеры, под каждый из которых выделяется свой процесс. Это гораздо удобнее, чем виртуальная машина. Вам не нужно искать еще и память, диск, оперативку, ведь отдельный процесс тянет значительно меньше ресурсов.
Когда вы работаете со многими виртуальными машинами, они часто мешают друг другу. Docker же может запускать в ядре любое приложение, которое будет полностью изолировано от других. Кроме того, на фоне конкурентов Docker выигрывает за счет простого синтаксиса. Также его можно запустить на всех популярных платформах: Linux, Windows, Mac.
Как работает Docker
Главный принцип работы с Docker можно описать в виде лозунга из трех слов: Build, Ship, Run. Каждое из них означает определенный этап и элемент системы:
- Build. Здесь имеется в виду создание Dockerfile. Это инструкция, по которой «корабль» строится и отправляется «в плавание». В файле вы описываете образ будущего продукта, принципы его работы и создание.
- Ship. Следующий этап — Docker Image. Это готовый образ для создания и запуска контейнера. Если сравнить Dockerfile с планом комнаты, то Docker Image — это дизайн-проект с изображением будущего ремонта, схемами разведения электричества и сантехники.
- Run. На последнем этапе появляется Docker Container — уже запущенный в работу образ на основе Docker Image. И если раньше был дизайн-проект, то это уже готовая к заселению комната.
Так все и работает: строите Dockerfile, из него создаете Docker Image, а на его основе запускаете Docker Container. Далее о каждом элементе системы расскажу по отдельности.
Dockerfile
Dockerfile — это обычный текстовый документ, который мы называем Dockerfile без всяких точек в конце. Этот файл размещается в папке с проектом. В нем вы записываете команды, по которым будет создаваться Image, а затем запускаться Container.
На иллюстрации ниже прописаны следующие команды:
- Берем Python 3.10.2.
- Создаем директорию и устанавливаем туда Django.
- Копируем весь проект, открываем порт 8000 и с помощью CMD запускаем runserver нашего Django.
Таким образом мы прописываем в Dockerfile команды одна за другой. Также пошагово они будут выполняться автоматически согласно этой инструкции. Как видите, синтаксис действительно очень прост:

Команды CMD и ENTRYPOINT
Может показаться, что они одинаковы по функционалу, но это не совсем так. CMD — команда, которая прописывается в консоль при запуске Dockerfile. Если вернуться к предыдущему примеру, то для запуска сервера нужны python, manage.py, runserver, IP и порт. И все это прописывается именно в CMD, после чего запускается сервер.
ENTRYPOINT также запускает команду, которую мы хотим прописать. Но он выполняет это перед CMD, если мы используем их вместе. Именно поэтому ENTRYPOINT и называется «точкой входа» — это будет первая команда.

Берем Debian, копируем проект, запускаем apt-get update и сводим CMD. Если нам нужно сменить эту команду, то при запуске Docker можно прописать docker run image. Тогда выполнится команда, прописанная в Dockerfile по дефолту.
Если мы хотим выполнить другую команду, то пишем docker run my-image и указываем новую команду. Это может быть, например, указание проверить список всех элементов Ubuntu. В результате предварительная команда будет заменена в CMD на ту, которую мы указали:
Если ENTRYPOINT и CMD использовать вместе, первая всегда стартует быстрее. Она может потребоваться, когда к основным командам из CMD нужно запустить еще какую-нибудь команду. К примеру, определенная проверка проекта. В таком случае вы прописываете соответствующую команду ENTRYPOINT, а затем основные параметры в CMD. Этот процесс представлен на иллюстрации ниже:

docker run my-container запишутся параметры и ENTRYPOINT уже в Dockerfile. А если нужно запустить другие CMD-команды, то понадобится docker run my-container cmd:

docker run --entrypoint и путь entrypoint.sh (это entrypoint, который будет меняться), а также название контейнера. Обратите внимание: вы должны указать, что переписываете именно ENTRYPOINT:

Dockerignore
Рассказывая о Dockerfile, следует упомянуть и о Dockerignore. Это аналог .gitignore в Git. Благодаря этому функционалу при копировании проекта в контейнер можно указать определенные файлы, которые не хотите переносить вместе с другими. Это может касаться pycache, логов, environments, docs и так далее. В таком случае прописываете имя файлов в dockerignore и они будут просто игнорироваться при копировании проекта.

Dockerfile создается по принципу Layers — слой за слоем
Сначала вы прописываете основу будущего контейнера. К примеру, при FROM python это будет Python определенной версии, и он становится на базовый уровень всей схемы. В нашем случае далее идет Django, но могут быть и нужны для проекта библиотеки, requirements.txt, зависимости и т.д. Все это формирует средний слой документа. В конце есть верхний слой, который запускает приложение — это CMD-команда:
Этот процесс сравним со строительством дома. В качестве фундамента выступает самая большая часть: Python, Ubuntu, Anaconda и т.д. Далее следуют основные этажи, более компактные по размеру библиотеки и зависимости. И уже на чердаке размещается самая маленькая и самая легкая часть — run проекта контейнера.
Чтобы все слои были понятны, советую тщательно прописывать Layers. Сравните на следующей иллюстрации примеры плохого и хорошего выполнения слоев в Dockerfile. Код в левой и правой частях изображения выполняет по существу одно и то же, но размеры отличаются чуть ли не вдвое. Разобраться сложно, особенно если нет достаточного опыта с Docker.
В другом примере сразу понятно, что к чему. Здесь четко видно установленные Python, Java и virtual environment, а также их активацию. В плохом же примере множество записей об обновлениях, установке и ребилде Python, установке зависимостей, активации virtual environments и многом другом. Это не только труднее читать. Это еще и сложнее делать. Поэтому Dockerfile с множеством слоев будет запускаться дольше.
Docker Image
Docker Image — это блок, созданный по инструкции из Dockerfile, выступающей шаблоном запуска контейнеров. Посредством этого документа можно построить множество одинаковых контейнеров.
Предположим, вы создаете один шаблон, который должен установить Python и определенные зависимости от него, и вам нужно пять одинаковых контейнеров. В этом случае не нужно прописывать пять Dockerfile. Достаточно одного такого файла для создания Docker Image, который вы будете ранить пять раз.

Основные команды Docker Image
При работе с Docker Image выделяют несколько наиболее используемых команд:
docker image --helpпоказывает основные команды в Image с их кратким описанием.
docker image build [OPTIONS] PATH.Билдит сам Image для последующего запуска Container. С помощью этой команды можно назвать свой Image. Для этого добавьте тег-t, а затем укажите желаемое название (в моем примереtest). Вам остается прописать путь к директории (точка в приведенном примере означает текущую директорию). После запуска команды и начнет строиться Image: от создания директории, установки Django, whitenoise, gunicorn до копирования.
В моем случае Docker image сбилден на основе этого Dockerfile:
docker image inspect [OPTIONS] IMAGE.Эта команда выдает всю информацию о Image. Это могут быть ID, дата создания, связанные контейнеры и энвайроменты, версия Python, имеющиеся pip и get pip, CMD и ENTRYPOINT, Volumes, директории и т.д. При запуске команды указывайте название интересующего вас Image.
docker image lsпоказывает список всех Image в Docker. На примере изображен перечень из нескольких тестовых Docker Image:
docker image rm [OPTIONS] IMAGEпредназначена для удаления Image. Ниже на иллюстрации я изобразил типичный сценарий такой процедуры. Сначала с помощьюdocker image lsполучил список всех Image. Далее прописалdocker image rm, указав название Image, которое нужно удалитьdockertest2. Еще одна проверкаdocker image lsпоказала: этого Image больше нет у Docker.
docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG].С помощью этой команды можно записать Docker Image. Это пригодится при использовании Docker Hub, где у всех собранных Images есть теги. В следующей статье поговорим о нем поподробнее.
Продолжение статьи о возможностях Docker читайте скоро на Highload.
Читайте также: Делаем разработку удобной: как использовать Docker в работе с микросервисами
Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.














Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: