Эта публикация - текстовый вариант и сценарий для видео на YouTube (оно удобно разбито на эпизоды).
Привет, сегодня я расскажу о том что такое Docker, контейнеризация, как это работает и зачем это нужно вам как разработчикам и то как создать и запустить контейнер. Этот курс будет хорошим стартовым материалом для новичков.
Если вам будет интересно погрузиться в тему Docker глубже, то в следующих частях будет подробно рассмотрен Dockerfile, docker-compose и Command line interface. Этот курс поможет вам погрузиться в Docker и понимать детали того как он работает.
В описании (прим. к видео по ссылке) будут ссылки на полезные ресурсы и на плейлист с этим курсом по Docker.
Обычно никто не переводит термины на русский язык, поэтому мы будем использовать английские обозначения.
Терминология
Давайте начнем с того, что вообще такое Docker.
Docker - это платформа для разработки, доставки и запуска контейнерных приложений. Все кроме “контейнерные приложения” кажется понятным, поэтому стоит понять что такое контейнер.
Контейнер - единица программного обеспечения, которая упаковывает код и все его зависимости так, что приложение работает быстро и надежно как на одном компьютере так и на другом.
Соответственно контейнеризация или докеризация - процесс помещения приложения в контейнеры, все просто.
Image - это легкий, независимый, исполняемый набор программ, который включает в себя все что нужно для работы приложения: код, окружение, системные инструменты, библиотеки и настройки.
Image становится контейнером во время выполнения, когда он работает на Docker Engine.
Docker доступен как для Linux, так и для Windows приложений, а контейнерное приложение всегда будет работать одинаково, вне зависимости от окружения. Контейнеры изолируют программу от внешнего окружения и обеспечивают их одинаковую работу.
Сейчас нам важно понять, что контейнер - это по сути своя отдельная операционная система с какой-то работающей внутри программой. То, что она не зависит от операционной системы, позволяет запускать любое количество одинаковых контейнеров, удалять и конфигурировать их, и это никак не скажется на компьютере на котором это все работает.
Некоторые начинающие разработчики, когда создают проект, устанавливают себе на компьютер - локально - все необходимые приложения - базы данных, какие-то еще сервисы.
Первый очевидный недостаток - для вашего компьютера может не быть подходящей версии приложения, что же тогда делать?
Второй - вы устанавливаете и запускаете один инстанс приложения. У вас локально может работать один постгрес, а не 5 или 10.
Третий - если вы захотите поделиться приложением со своим товарищем, то ему придется устанавливать все эти зависимости, либо же писать docker-compose за вас. Если бы вы разрабатывали приложение на Windows, а потом его нужно было запустить на Linux, то вы бы потратили очень много усилий, чтобы заставить это все работать. Это все не очень удобно, правда?
Для этого и был придуман Docker. Поместив все в контейнеры вы избавляете себя от забот проверять все ли работает, что вам нужно, или о том как конфигурировать эти зависимости.
Некоторые из вас могут сказать, что есть виртуальные машины и они делают примерно то же самое. Да, их функции схожи с функциями контейнеров, но есть недостаток.
Для каждой виртуальной машины нужна копия операционной системы, чтобы взаимодействовать с процессором и памятью компьютера. А это может занимать десяток гигабайт, что совсем не похоже на контейнер базы данных Postgres, занимающий 100 мегабайт.
Еще одна причина использования контейнеров - микросервисы и их оркестрация. Когда вы будете писать большие приложения, в которых будут работать десятки микросервисов, то это так или иначе будет использовать контейнеры, чтобы управлять жизненным циклом не отдельно запущенного приложения, а контейнера.
Разобравшись с этим мы можем перейти к следующей теме - как создаются контейнеры и Image.
Откуда взять image
Есть два способа.
Первый - это скачать image из специального места - Registry, хранилища docker images. У многих компаний есть свои registry, но в основном все используют DockerHub.
Перейдя на hub.docker.com вы можете найти любой image, который был публично опубликован. Иногда можно увидеть синие галочки возле названия, что говорит о том, что разработчик подтвержден и ему можно доверять. Давайте посмотрим на официальный image от Docker, в котором есть гайд для новичков - https://hub.docker.com/r/docker/welcome-to-docker
Мы видим синюю галочку, число скачиваний этого image, его описание и вкладку "теги".
Теги - специальные человекочитаемые идентификаторы, которые указывают конкретную версию или вариант image. Как и при установке обычных программ, вы можете выбрать необходимую версию, либо же не указывать ее, тогда будет выбрана версия latest
. Я рекомендую явно указывать нужные версии, так как это гарантирует, что вы скачаете один и тот же image даже спустя длительное время. Здесь, как видим, один тег - latest
.
Давайте скачаем себе на компьютер этот image. У вас должен быть установлен и запущен Docker Desktop для того, чтобы это было возможно. Поэтому проверьте, что это так. Множество операций с Docker производится через консоль, и я хочу, чтобы вы не боялись консоль и могли ею пользоваться. Откроем консоль и напишем команду, которую мы видим на DockerHub.
docker pull docker/welcome-to-docker
Видим, что контейнер не был найден локально, поэтому началось скачивание.
Стоит отметить, что при такой простой команде Docker ищет image на DockerHub, но как я говорил раньше, можно использовать разные хранилища images, для этого перед названием image нужно указать путь к нему.
Если мы просто скачаем image, как указано здесь, то новый контейнер создан не будет. Мы просто скачали себе image локально.
Выполнив команду из Overview, мы сможем запустить контейнер.
В DockerHub Overview нам говорят перейти по адресу http://localhost:8088. Не всегда Overview содержит подробную информацию о том как запустить контейнер и как он работает, что приводит к тому, что порой мы должны разбираться сами. Здесь мы увидели поздравления с тем, что мы запустили первый контейнер.
Возможности Docker Desktop
Давайте перейдем в Docker Desktop и посмотрим на то, что у нас есть.
Во вкладке Images мы можем увидеть тот image, который был скачан и запущен только что.
Во вкладке Containers мы видим работающий контейнер с названием welcome-to-docker.
В Docker контейнеры можно называть своими названиями, либо же ему будет присвоено такое название. Давайте нажмем на контейнер и зайдем в него.
Первым делом мы попадаем в логи, здесь мы можем увидеть некоторую информацию о том, что сделал контейнер при работе. Когда вы будете запускать свои приложения, то здесь сможете увидеть логи, если вдруг что-то пойдет не так.
Во второй вкладке Inspect можно увидеть переменные контейнера и порты, на котором он работает.
У многих приложений есть порт, по которому к нему можно обратиться. Этот порт доступен внутри контейнера и так как контейнеры не зависят друг от друга, то все работает хорошо. Внутри каждого контейнера есть этот порт и они не мешают друг другу. Но мы ведь хотим как-то попасть в контейнер. Для этого необходимо сделать маппинг или отображение порта внутри контейнера на порт снаружи контейнера - на машине.
В нашем случае внутренний порт 80. И при старте приложения мы указывали отображение на порт 8088 (-p 8088:80
).
docker run -d -p 8088:80 --name welcome-to-docker docker/welcome-to-docker
Так мы и смогли попасть внутрь контейнера. То есть нужно понять, что сейчас на локальной машине при обращении к порту 8088 идет проброс обращения к Docker, который пробрасывает его на порт 80 этого контейнера. Если мы запустим еще раз команду из DockerHub, то контейнер не запустится, потому что порт 8088 уже занят этим существующим контейнером.
Заменив его на 8089 к примеру, мы сможем запустить еще один контейнер. Пробрасывать порты из контейнера нужно только в случае необходимости, иначе это будет занимать свободные порты на машине и может быть небезопасно.
Третья вкладка - Terminal. Это консоль внутри контейнера, где можно выполнять различные команды, доступные для этого контейнера. Так как тут установлен nginx, то мы можем запустить команду nginx -v и увидеть актуальную версию nginx.
В следующей вкладке Files мы можем увидеть всю файловую систему контейнера.
В последней вкладке Stats находится статистика использования ресурсов контейнером. Здесь можно отслеживать потребление оперативной памяти, процессора и число операций чтения и записи на локальный диск.
Давайте вернемся во вкладку контейнеров и удалим этот контейнер. После удалим image этого контейнера. Его нельзя удалить, если есть хотя бы один работающий контейнер с этим image.
Создание image из Dockerfile
Второй способ получить image - создание из собственного приложения. Фактически вы можете сделать пустой image, в котором не будет ничего, но это не очень то полезно, но такая возможность есть. Вы сами вольны выбирать то, что будет происходить внутри image.
Для того, чтобы создать Image, который потом можно будет запустить и который станет контейнером, необходимо описать приложение в специальном файле - Dockerfile. Читая этот файл Docker может создать image с той конфигурацией, которую вы ему указали.
Давайте вернемся на Dockerhub и найдем официальный getting-started image от Docker. Тут уже 10 миллионов установок.
Скопировав команду из Overview в консоль, запустим контейнер и перейдем на http://localhost.
Мы встречаем Getting started гайд. Перейдя на вкладку Our Application займемся созданием Dockerfile. Для начала скачаем тестовый Node.js проект, который мы будем докеризовать, что значит помещать в контейнер.
На втором шаге нам нужно создать файл Dockerfile без расширения, просто Dockerfile, в который поместить следующие команды.
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
Запустим сборку image с помощью команды (в консоли из той же директории, где находится Dockerfile).
docker build -t getting-started .
Дадим ему тег getting-started, чтобы мы могли его различать. После этого запустим этот image.
docker run -dp 3000:3000 getting-started
Перейдя на localhost:3000, мы можем воспользоваться приложением. Как видим, для того, чтобы им воспользоваться нужен лишь Docker.
Этот контейнер точно так же можно открыть в Docker Desktop, посмотреть его переменные и файлы, статистику и логи.
Итоги
Давайте закрепим то, что было в этом видео.
Docker - платформа, позволяющая создавать, запускать и управлять контейнерными приложениями.
Контейнер - такое приложение, которое работает независимо от операционной системы и окружения.
Контейнеризация или докеризация - процесс помещения приложений в контейнеры.
Image - приложение и набор файлов, необходимый для его работы.
Image становится контейнером, когда он запускается.
Image можно создать двумя способами - скачать из DockerHub и собрать из файла Dockerfile.
Контейнеры работают независимо друг от друга, поэтому чтобы обратиться к контейнеру с локальной машины, нужно пробросить порт локальной машины внутрь Docker.
В Docker Desktop можно управлять images, контейнерами, просматривать статистику и логи работающих контейнеров.