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

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

Однако приложение перестало работать на производственном сервере из-за различий в среде - программном обеспечении, библиотеках, операционной системе и т. Д.

Но это нормально, ведь вы всегда можете объяснить это своим клиентам, верно?

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

Послушайте, мы все не хотим, чтобы это произошло, и теперь Docker спасает положение.

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

Концепции

Основные компоненты

В экосистеме докеров есть 3 основных компонента. Образ, контейнер и реестр.

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

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

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

Чем Docker отличается от виртуальной машины (ВМ)?

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

В отличие от ВМ, контейнеры Docker совместно используют ядро ​​ОС хоста. Это делает контейнеры докеров легко масштабируемыми и легкими. Это означает, что вы можете легко развернуть несколько контейнеров за секунды, а не за минуты. Вот почему Docker - гораздо более привлекательное решение, чем Vagrant и другие подобные технологии.

Давайте начнем

Установка Docker

Перейдите на https://docs.docker.com/ и выберите свою операционную систему. Затем следуйте инструкциям.

Если вы используете VSCode, я настоятельно рекомендую вам установить расширение docker от Microsoft.

Мы будем создавать супер простой веб-сайт на PHP, который будет печатать текст на экране:

<?php
  //  /src/index.php
  
  echo "Hello there";
?>

Создание Dockerfile

Создайте Dockerfile (с большой буквы D) в корневой папке. Каталог вашего проекта должен выглядеть примерно так:

Скопируйте следующие инструкции в Dockerfile, я построчно объясню, что здесь происходит:

FROM php:7.4.1-apache
COPY src/ /var/www/html/
EXPOSE 80

Ключевое слово FROM

Файл Dockerfile обычно начинается с ключевого слова FROM, за которым следует метка «image: tag», которая ссылается на предварительно созданный образ в реестре.

Вы можете искать тысячи готовых образов в Dockerhub. В нашем случае мы используем официальный образ PHP с тегом 7.4.1-apache, что означает, что он поставляется со встроенным веб-сервером Apache.

Каждая строка представляет собой вариант, и слева направо версия изображения становится все менее и менее конкретной. Рекомендуется использовать конкретную версию, иначе, если мы выберем последний тег, мы можем столкнуться с неожиданными критическими изменениями при обновлении PHP. Теги со словом «buster» означают, что образ основан на Debian Buster, а «alpine» означает, что это миниатюрный образ, в котором он построен с использованием только минимума.

Ключевое слово COPY и EXPOSE

КОПИРОВАТЬ позволяет нам копировать файлы и папки в изображение. Первый аргумент - это путь к хосту, а второй аргумент - это путь к контейнеру.

Мы также хотим предоставить хосту порт 80 контейнера. Это пока не сделает наш веб-сайт доступным для публики, только для хоста. Нам все еще нужно перенаправить порт хоста на порт 80 контейнера.

Создание имиджа

Запустите docker build -t php-demo ./ в корне проекта.

  • docker build - это команда для создания образа.
  • -t для определения тега изображения, в данном случае я назову его php-demo.
  • ./ указывает на расположение Dockerfile. В данном случае это текущий каталог.

Запуск образа

Запускаем docker run -p 3000:80 php-demo в оболочке. Вы можете запустить эту команду где угодно, поскольку мы создали образ, и Docker Engine автоматически регистрирует образ в локальном реестре.

  • -p флаг для перенаправления порта 3000 хоста на порт 80 контейнера.

Вы должны увидеть Apache, работающий в оболочке. Теперь перейдите на localhost: 3000, и вы должны увидеть это:

Однако, если мы редактируем наш index.php (например, меняем эхо-текст на что-то другое), изменения не сразу отражаются в нашем контейнере. Это потому, что с ключевым словом COPY наш index.php был скопирован в изображение в то время, когда оно было построено. Таким образом, даже несмотря на то, что мы изменили файл на нашем главном компьютере, файл в контейнере остается как исходный файл.

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

Давайте остановим наш контейнер и создадим его заново. Просто нажмите Control + c в терминале. Затем запустите это:

docker run -p 3000:80 -v /absolute/host/path/to/src/:/var/www/html php-demo

  • -v Укажите путь к монтируемому хост-компьютеру.

Теперь попробуйте внести изменения в index.php. Вы заметите, как только обновите страницу в браузере, изменения сразу же отобразятся.

Как войти в контейнер и запускать команды оболочки

  1. Вам понадобится идентификатор целевого контейнера. Запустите docker container ls, чтобы вывести список всех активных экземпляров контейнера.
  2. Запустите docker exec -it {container_id} bash, чтобы запустить сеанс оболочки в контейнере.
  • -i флаг для интерактивного
  • -t флаг для сеанса оболочки TTY
  • bash программа, которую мы хотим запустить в контейнере. В этом случае мы хотим запустить bash

Как установить дополнительное ПО в наш образ

Мы можем запустить любую произвольную команду оболочки, используя ключевое слово RUN в файле Dockerfile. Например, вы можете установить wget:

# Dockerfile
# ...
RUN apt-get update && apt-get install -y wget 

Ключевое слово ARG

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

Например:

# Dockerfile
ARG PHP_VERSION=7.4.1-apache  # default image tag: 7.4.1-apache
FROM php:${PHP_VERSION}  
ARG INSTALL_WGET=false

# conditionally install wget based on env variable supplied
RUN if [ ${INSTALL_WGET} = true ]; then \  
    apt-get update && apt-get install -y wget \
;fi
# ...

Мы можем перезаписать переменные ARG, используя флаг — build-arg во время сборки.

Например, docker build --build-arg PHP_VERSION=7.4.1-fpm-buster --build-arg INSTALL_WGET=true создаст образ с PHP 7.4.1 FPM-Buster и установит wget.

Пользователь и разрешение

По умолчанию Docker выполняет все команды от имени пользователя root. Вы можете явно изменить пользователя с помощью ключевого слова USER. Однако сначала вам нужно создать пользователя.

# Adding a user 
RUN useradd -ms /bin/bash sam
USER sam
RUN mkdir ./folder
# set the active user back to root
USER root

Исполняемый контейнер

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

Хотя оба ключевых слова могут сосуществовать в файле Dockerfile, у вас не может быть 2 ключевых слов CMD или 2 ENTRYPOINT одновременно, последнее перезапишет первое.

С CMD это будет команда по умолчанию, с которой будет работать контейнер при его создании. Например, я могу заставить контейнер выводить «привет» каждый раз, когда он запускается, сделав следующее:

# Dockerfile
# ...
CMD ["echo", "helloo!"]

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

Обратите внимание, что наш сервер Apache перестал работать. Это связано с тем, что ключевое слово CMD, которое мы использовали в нашем Dockerfile, перезаписало исходную инструкцию CMD для запуска Apache в базовом образе.

Теперь, если я укажу команду для запуска при запуске контейнера:

docker run php-demo pwd

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

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

# Dockerfile
# ...
ENTRYPOINT ["echo", "helloo!"]

«Pwd» добавляется в конец «helloo!». Это было передано в качестве аргумента для эха.

Что произойдет, если я использую одновременно ENTRYPOINT и CMD?

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

# Dockerfile
# ...
CMD ["echo", "helloo!"]
ENTRYPOINT [ "echo", "entrypoint" ]
# ...

Что дальше?

Ознакомьтесь со второй частью этого руководства, где мы поговорим о docker compose и микросервисах!