Образ, контейнер, Dockerfile

Откуда берутся контейнеры

Контейнер создаётся из образа (англ. image).
Образ — это шаблон, который содержит всё необходимое для автономной работы контейнера: в образ может быть упакована операционная система, сервер, интерпретатор языка (в нашем случае — Python), виртуальное окружение проекта, файлы приложения — всё.
И всё это добро лежит и пассивно ждёт команды run: операционная система не работает, сервер не крутится, приложение не запущено.
По команде docker run имя-образа докер создаёт контейнер, в котором запускается операционка и все остальные необходимые программы, приложение начинает работать в своей изолированной среде.
Запущенное таким образом приложение — это и есть контейнер. При создании контейнер получает уникальный идентификатор (CONTAINER ID), который выглядит примерно так: 94f92052f55f.
По команде docker stop ID-контейнера все процессы в контейнере останавливаются, но он сохраняется в системе и его можно запустить вновь, обратившись к нему по ID: нет необходимости заново выполнять run для образа. Для окончательного удаления контейнера есть команда docker rm ID-контейнера.
Управление докером происходит через терминал и принципиально ничем не отличается от работы с другими программами: вызывается консольная утилита docker и указываются команды с параметрами и ключами. Всё происходит точно так же, как при работе с psql, apt или manage.py

Run, Image, run!

Выполните команду:
Скопировать кодBASH
docker run hello-world # Docker, запусти образ под названием "hello-world"
После недолгих раздумий консоль выдаст пару информационных сообщений, а потом расскажет историю:
image
Вы выполнили команду для создания контейнера на основе образа hello-world. Демон докера попытался найти образ hello-world на вашем компьютере, но не нашел (вы такого образа не создавали, откуда ему тут быть):
Скопировать кодBASH
Unable to find image 'hello-world:latest' locally # Невозможно найти образ 'hello-world:latest' локально
Затем докер пошёл искать этот образ в облачное хранилище DockerHub — и обнаружил его там: образ hello-world хранится на https://hub.docker.com/_/hello-world.
DockerHub — общедоступный репозиторий, куда разработчики выкладывают образы, а Docker автоматически подключается к этому хранилищу и ищет там запрошенные образы.
В результате Docker нашёл образ hello-world, автоматически скачал его на ваш компьютер и запустил. На основе этого образа создался контейнер с приложением, а приложение показало вам в консоли всё, на что оно способно.
Единственное умение этого приложения — выводить в консоль сообщение "Hello from Docker!" и короткий текст после этого приветствия. Не так уж и много, зато теперь у вас на компьютере:
  • сохранён образ hello-world — и вы в любой момент можете его запустить, создать контейнер на его основе;
  • запущено приложение в контейнере.
Со временем у вас накопится множество образов, и чтобы осмотреть свои запасы — выполните команду
Скопировать кодBASH
docker images
Docker покажет вам список локально сохранённых образов.
Удержать в голове все команды разных утилит практически невозможно, но любая утилита подскажет вам, что она умеет и как этого добиться.
Выполните команду docker без аргументов:
Скопировать кодBASH
docker # ... ***#*** attach Attach local standard input, output, and error streams to a running container # build Build an image from a Dockerfile # commit Create a new image from a container's changes # cp Copy files/folders between a container and the local filesystem # create Create a new container # ... # Run 'docker COMMAND --help' for more information on a command.
В терминал будет выведен полный список команд, которые понимает Docker. В конце списка — дополнительная подсказка: Run 'docker COMMAND --help' for more information on a command. (англ. «запустите docker COMMAND -- help для получения дополнительной информации о команде»).
Удалите образ hello-world, он больше не пригодится. Найдите нужную команду и удалите образ hello-world.
image
Образ не удалится, если есть созданные контейнеры. Нужно сначала удалить их. Или использовать флаг -f (англ. "force", принудительно).
Какая команда удаляет образ из локального хранилища?

Откуда берутся образы

Вызовите справку для команды build:
Скопировать кодBASH
docker build --help # Build an image from a Dockerfile # англ. "собрать образ из докерфайла"
Ясно, что эта команда связана с созданием образа, и что в этом процессе задействован некий Dockerfile. Сейчас разберёмся.
Dockerfile — это файл с инструкциями для создания образа. В докерфайле разработчик описывает, что должно быть включено в образ: какая операционная система, какой интерпретатор языка, где взять пакеты для приложения.
Там же описываются и операции, которые должны быть выполнены при старте контейнера: например, для старта Django-проекта в режиме разработки надо выполнить команду manage.py runserver, а если в контейнере должен быть запущен nginx — то systemctl start nginx. Эти команды тоже указываются в докерфайле.
Каждая инструкция докерфайла добавляет в образ какие-то пакеты или файлы, при этом создается слой образа.
Фактически создаётся новый «промежуточный» образ; при выполнении следующей инструкции создаётся следующий слой, следующий «промежуточный образ». Все эти «промежуточные образы» кэшируются (сохраняются локально), и если придётся пересобирать образ (например, если нужно внести изменения в приложение) — сборка начнётся не с нуля, а с последнего неизменённого слоя. В результате процесс сборки займёт гораздо меньше времени.
image
Исходно образ собирается на основе базового слоя (base image). Базовый слой — это образ, который может содержать просто пустую операционную систему (например, можно взять образ ubuntu:20.04), а может состоять из операционной системы с уже установленным интерпретатором языка (например, так устроен образ python:3.8). Как и другие образы, подходящий базовый слой можно найти на DockerHub.
Поверх базового слоя «накладываются» все остальные слои: это все необходимые зависимости и файлы приложения.
При запуске контейнера создаётся ещё один, временный слой. Этот слой доступен для записи и в нём хранятся все данные, которые создаются при работе приложения. При остановке контейнера этот слой сохраняется, а при удалении — удаляется вместе с контейнером.
Теория закончилась, в следующем уроке начнётся практика.