Виртуализация на уровне операционной системы становится все более популярным решением при развертывании приложений в разных средах. Самый удачный инструмент для этого — Docker.
В двух статьях на Highload я расскажу об основных возможностях инструмента. Вы узнаете, как установить, настроить и запустить Docker, а также как работать с его ключевыми элементами: Dockerfile, Docker Image и Docker Container.
Виртуальная машина выступает в качестве эмулятора ПО. Предположим, на компьютере уже есть Windows и нужно дополнительно установить, например, Ubuntu. Создаем на том же компьютере виртуальную машину и уже на нее устанавливаем дополнительную операционную систему. В результате у нас будет два компьютера одновременно. Но для виртуальной машины нужно место на жестком диске, достаточно оперативной памяти и ресурсов процессора.
В противоположность этому появился принцип контейнеров, на котором построены Docker и другие подобные инструменты. Главное отличие — в собственной инфраструктуре и единой для всех сред ОС. Сверху этого основания устанавливается Docker, благодаря которому можно создавать множество контейнеров, апликаций и т.п.
Docker разделяет единое ядро ОС на отдельные контейнеры, под каждый из которых выделяется свой процесс. Это гораздо удобнее, чем виртуальная машина. Вам не нужно искать еще и память, диск, оперативку, ведь отдельный процесс тянет значительно меньше ресурсов.
Когда вы работаете со многими виртуальными машинами, они часто мешают друг другу. Docker же может запускать в ядре любое приложение, которое будет полностью изолировано от других. Кроме того, на фоне конкурентов Docker выигрывает за счет простого синтаксиса. Также его можно запустить на всех популярных платформах: Linux, Windows, Mac.
Главный принцип работы с Docker можно описать в виде лозунга из трех слов: Build, Ship, Run. Каждое из них означает определенный этап и элемент системы:
Так все и работает: строите Dockerfile, из него создаете Docker Image, а на его основе запускаете Docker Container. Далее о каждом элементе системы расскажу по отдельности.
Dockerfile — это обычный текстовый документ, который мы называем Dockerfile без всяких точек в конце. Этот файл размещается в папке с проектом. В нем вы записываете команды, по которым будет создаваться Image, а затем запускаться Container.
На иллюстрации ниже прописаны следующие команды:
Таким образом мы прописываем в Dockerfile команды одна за другой. Также пошагово они будут выполняться автоматически согласно этой инструкции. Как видите, синтаксис действительно очень прост:
Может показаться, что они одинаковы по функционалу, но это не совсем так. 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:
Рассказывая о Dockerfile, следует упомянуть и о Dockerignore. Это аналог .gitignore
в Git. Благодаря этому функционалу при копировании проекта в контейнер можно указать определенные файлы, которые не хотите переносить вместе с другими. Это может касаться pycache, логов, environments, docs и так далее. В таком случае прописываете имя файлов в dockerignore и они будут просто игнорироваться при копировании проекта.
Сначала вы прописываете основу будущего контейнера. К примеру, при FROM python
это будет Python определенной версии, и он становится на базовый уровень всей схемы. В нашем случае далее идет Django, но могут быть и нужны для проекта библиотеки, requirements.txt, зависимости и т.д. Все это формирует средний слой документа. В конце есть верхний слой, который запускает приложение — это CMD-команда:
Этот процесс сравним со строительством дома. В качестве фундамента выступает самая большая часть: Python, Ubuntu, Anaconda и т.д. Далее следуют основные этажи, более компактные по размеру библиотеки и зависимости. И уже на чердаке размещается самая маленькая и самая легкая часть — run проекта контейнера.
Чтобы все слои были понятны, советую тщательно прописывать Layers. Сравните на следующей иллюстрации примеры плохого и хорошего выполнения слоев в Dockerfile. Код в левой и правой частях изображения выполняет по существу одно и то же, но размеры отличаются чуть ли не вдвое. Разобраться сложно, особенно если нет достаточного опыта с Docker.
В другом примере сразу понятно, что к чему. Здесь четко видно установленные Python, Java и virtual environment, а также их активацию. В плохом же примере множество записей об обновлениях, установке и ребилде Python, установке зависимостей, активации virtual environments и многом другом. Это не только труднее читать. Это еще и сложнее делать. Поэтому Dockerfile с множеством слоев будет запускаться дольше.
Docker Image — это блок, созданный по инструкции из Dockerfile, выступающей шаблоном запуска контейнеров. Посредством этого документа можно построить множество одинаковых контейнеров.
Предположим, вы создаете один шаблон, который должен установить Python и определенные зависимости от него, и вам нужно пять одинаковых контейнеров. В этом случае не нужно прописывать пять Dockerfile. Достаточно одного такого файла для создания 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 в работе с микросервисами
В благословенные офисные времена, когда не было большой войны и коронавируса, люди гораздо больше общались…
Вот две истории из собственного опыта, с тех пор, когда только начинал делать свою карьеру…
«Ты же программист». За свою жизнь я много раз слышал эту фразу. От всех. Кто…
Отличные новости! Если вы пропустили, GitHub Copilot — это уже не отдельный продукт, а набор…
Несколько месяцев назад мы с командой Promodo (агентство инвестировало в продукт более $100 000) запустили…
Пару дней назад прочитал сообщение о том, что хорошие курсы могут стать альтернативой классическому образованию.…