Как эффективно настраивать и запускать контейнеры Docker

DockerBeginner
Практиковаться сейчас

Введение

Этот исчерпывающий учебник по Docker предоставляет разработчикам и IT-специалистам глубокое погружение в технологию контейнеризации. От понимания основных концепций Docker до практических методов установки и управления, руководство охватывает все необходимое для использования мощных возможностей контейнеризации Docker в современной разработке и развертывании программного обеспечения.

Основы Docker

Введение в технологию контейнеризации

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

Основные концепции Docker

graph TD
    A[Docker Engine] --> B[Container]
    A --> C[Image]
    A --> D[Dockerfile]
Концепция Описание
Docker Image Шаблон только для чтения, содержащий код приложения и зависимости
Container Запускаемый экземпляр Docker-образа
Docker Engine Среда выполнения для создания и управления контейнерами

Проверка установки Docker

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

docker --version

Вывод должен отобразить версию Docker, например, Docker version 20.10.21, build baeda1f. Это подтверждает, что Docker установлен корректно и доступен.

Загрузка первого Docker-образа

Docker-образ — это шаблон только для чтения, содержащий набор инструкций для создания контейнера. Мы загрузим образ hello-world, который является минимальным образом, используемым для тестирования установки Docker.

docker pull hello-world

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

Запуск первого Docker-контейнера

Теперь, когда у нас есть образ, давайте запустим контейнер из него. Запуск контейнера означает создание экземпляра образа.

docker run hello-world

При запуске hello-world Docker выполняет следующие действия:

  1. Проверяет, существует ли образ hello-world локально. Если нет, он загружает его (что мы уже сделали).
  2. Создает новый контейнер из образа.
  3. Запускает исполняемый файл внутри контейнера.
  4. Контейнер выводит сообщение "Hello from Docker!" и затем завершает работу.

Это демонстрирует базовый жизненный цикл Docker-контейнера: загрузка образа, запуск контейнера, и контейнер выполняет свою определенную задачу.

Список Docker-образов

Чтобы увидеть загруженные вами образы, используйте команду docker images.

docker images

Эта команда выводит список всех Docker-образов, хранящихся в вашей локальной системе, включая образ hello-world, который мы только что загрузили. Вы увидите такие детали, как репозиторий, тег, ID образа, дату создания и размер.

Понимание жизненного цикла контейнера

Контейнеры предоставляют изолированные среды со своим собственным файловым пространством, процессами и сетевыми интерфейсами. Их можно быстро запускать, останавливать, перемещать и удалять, что делает их идеальными для микросервисов и облачных приложений.

Управление файлами Dockerfile

Основы Dockerfile

Dockerfile — это текстовый документ, содержащий все команды, которые пользователь может вызвать из командной строки для сборки образа. Он определяет среду, зависимости и конфигурацию для контейнеризированных приложений.

graph TD
    A[Dockerfile] --> B[Команда сборки]
    B --> C[Docker Image]
    C --> D[Container]

Создание первого Dockerfile

Перейдите в каталог docker_app, который был создан на этапе настройки. Это будет наш рабочий каталог для данной лаборатории.

cd /home/labex/project/docker_app

Теперь давайте создадим простой Dockerfile с именем Dockerfile в этом каталоге. Этот Dockerfile создаст образ на основе Ubuntu и добавит в него простой текстовый файл.

nano Dockerfile

Добавьте следующее содержимое в Dockerfile:

## Используем официальный базовый образ Ubuntu
FROM ubuntu:22.04

## Устанавливаем рабочий каталог внутри контейнера
WORKDIR /app

## Создаем простой текстовый файл
RUN echo "Hello from Dockerfile!" > /app/message.txt

## Команда для выполнения при запуске контейнера
CMD ["cat", "/app/message.txt"]
  • FROM ubuntu:22.04: Эта инструкция указывает базовый образ для нашего нового образа. Мы используем Ubuntu 22.04.
  • WORKDIR /app: Эта инструкция устанавливает рабочий каталог для любых последующих инструкций RUN, CMD, ENTRYPOINT, COPY или ADD в Dockerfile. Если /app не существует, он будет создан.
  • RUN echo "Hello from Dockerfile!" > /app/message.txt: Эта инструкция выполняет команду внутри образа в процессе сборки. Здесь она создает файл с именем message.txt в каталоге /app с содержимым "Hello from Dockerfile!".
  • CMD ["cat", "/app/message.txt"]: Эта инструкция предоставляет команды по умолчанию для запускаемого контейнера. Когда контейнер запускается из этого образа, он выполнит cat /app/message.txt, отображая содержимое нашего файла сообщения.

Сохраните файл, нажав Ctrl+S, и выйдите из nano, нажав Ctrl+X.

Сборка Docker-образа

Теперь, когда у нас есть Dockerfile, давайте соберем из него Docker-образ. Команда docker build считывает Dockerfile и создает Docker-образ.

docker build -t my-ubuntu-app .
  • docker build: Команда для сборки Docker-образа.
  • -t my-ubuntu-app: Это присваивает нашему образу тег с именем my-ubuntu-app. Вы можете выбрать любое имя.
  • .: Это указывает контекст сборки, который представляет собой набор файлов по указанному PATH или URL. Точка (.) означает, что текущий каталог (/home/labex/project/docker_app) является контекстом сборки. Docker будет искать Dockerfile в этом каталоге.

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

Запуск пользовательского Docker-контейнера

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

docker run my-ubuntu-app

Эта команда создаст и запустит новый контейнер из вашего образа my-ubuntu-app. Будет выполнена инструкция CMD из вашего Dockerfile, и вы должны увидеть "Hello from Dockerfile!" напечатанное в вашем терминале.

Инспекция файловой системы контейнера

Чтобы лучше понять, как файлы управляются внутри контейнера, давайте запустим интерактивную сессию и проверим созданный нами файл.

docker run -it my-ubuntu-app /bin/bash
  • -it: Этот флаг выделяет псевдо-TTY и оставляет STDIN открытым, позволяя вам взаимодействовать с контейнером.
  • my-ubuntu-app: Имя образа, который мы хотим запустить.
  • /bin/bash: Это переопределяет инструкцию CMD в Dockerfile и вместо этого запускает оболочку Bash внутри контейнера, предоставляя вам командную строку.

Оказавшись внутри контейнера, вы увидите новую командную строку (например, root@<container_id>:/app#). Теперь вы можете вывести список файлов и просмотреть содержимое message.txt.

ls -l
cat message.txt

Вы должны увидеть message.txt в списке и его содержимое. Чтобы выйти из контейнера, просто введите exit.

exit

Эта интерактивная сессия демонстрирует, что файл message.txt был успешно создан и доступен в файловой системе контейнера.

Продвинутые техники Docker

Стратегии многоэтапной сборки (Multi-Stage Build)

Многоэтапная сборка — это мощная функция, позволяющая использовать несколько инструкций FROM в вашем Dockerfile. Каждая инструкция FROM может использовать другой базовый образ, и каждая инструкция FROM начинает новый этап сборки. Это помогает оптимизировать сложность Dockerfile и уменьшить размер конечного образа, разделяя среды сборки и выполнения.

graph TD
    A[Этап сборки] --> B[Компиляция/Сборка]
    B --> C[Этап выполнения]
    C --> D[Минимальный образ для продакшена]

Подготовка к многоэтапной сборке

Для этого примера мы смоделируем простое приложение, требующее этапа сборки. Мы создадим файлы build_script.sh и final_app.txt.

Сначала убедитесь, что вы находитесь в каталоге docker_app:

cd /home/labex/project/docker_app

Теперь создайте простой скрипт сборки:

nano build_script.sh

Добавьте следующее содержимое в build_script.sh:

#!/bin/bash
echo "Running build process..."
echo "This is the final application output." > /app/output/final_app.txt
echo "Build complete."

Сохраните файл (Ctrl+S) и выйдите (Ctrl+X).

Затем создайте заполнитель для содержимого нашего финального приложения. В реальном сценарии это будет сгенерировано процессом сборки.

nano final_app.txt

Добавьте следующее содержимое в final_app.txt:

This is a placeholder for the final application.

Сохраните файл (Ctrl+S) и выйдите (Ctrl+X).

Реализация многоэтапного Dockerfile

Теперь давайте модифицируем наш Dockerfile для использования многоэтапной сборки. У нас будет этап "сборщика" (builder), который выполнит наш build_script.sh, а затем этап "продакшена" (production), который скопирует только необходимые выходные данные из этапа сборщика.

nano Dockerfile

Замените существующее содержимое следующим:

## Этап 1: Этап сборки
FROM ubuntu:22.04 AS builder

## Устанавливаем bash для выполнения скрипта
RUN apt-get update && apt-get install -y bash

## Устанавливаем рабочий каталог для этапа сборки
WORKDIR /build

## Копируем скрипт сборки и делаем его исполняемым
COPY build_script.sh .
RUN chmod +x build_script.sh

## Создаем каталог для выходных данных
RUN mkdir -p /build/output

## Запускаем скрипт сборки
RUN ./build_script.sh

## Этап 2: Этап продакшена
FROM ubuntu:22.04

## Устанавливаем рабочий каталог для этапа продакшена
WORKDIR /app

## Копируем только необходимый артефакт из этапа сборки
COPY --from=builder /build/output/final_app.txt .

## Команда для выполнения при запуске контейнера
CMD ["cat", "final_app.txt"]
  • FROM ubuntu:22.04 AS builder: Это начинает первый этап и присваивает ему имя builder.
  • RUN apt-get update && apt-get install -y bash: Устанавливает bash на этапе сборки, который необходим для выполнения нашего скрипта.
  • WORKDIR /build: Устанавливает рабочий каталог для этапа сборки.
  • COPY build_script.sh .: Копирует наш скрипт сборки в этап сборки.
  • RUN chmod +x build_script.sh: Делает скрипт исполняемым.
  • RUN mkdir -p /build/output: Создает выходной каталог на этапе сборки.
  • RUN ./build_script.sh: Выполняет скрипт сборки, который генерирует final_app.txt в /build/output.
  • FROM ubuntu:22.04: Это начинает второй этап (этап продакшена). Он использует свежий образ ubuntu:22.04, что означает, что он по умолчанию не наследует ничего от этапа builder.
  • WORKDIR /app: Устанавливает рабочий каталог для этапа продакшена.
  • COPY --from=builder /build/output/final_app.txt .: Это ключевая инструкция для многоэтапной сборки. Она копирует final_app.txt из каталога /build/output этапа builder в текущий каталог (/app) этапа продакшена. Это гарантирует, что включен только конечный артефакт, что делает образ продакшена меньше.
  • CMD ["cat", "final_app.txt"]: Команда, которая будет выполнена при запуске контейнера продакшена, отображая содержимое скопированного файла.

Сохраните файл (Ctrl+S) и выйдите (Ctrl+X).

Сборка и запуск многоэтапного образа

Теперь давайте соберем новый образ, используя наш многоэтапный Dockerfile.

docker build -t multi-stage-app .

Наблюдайте за выводом сборки. Вы увидите шаги как для этапа builder, так и для финального этапа.

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

docker run multi-stage-app

Вы должны увидеть "This is the final application output.", что подтверждает, что многоэтапная сборка успешно скопировала артефакт из этапа сборки в конечный образ.

Очистка ресурсов Docker

Хорошей практикой является очистка ресурсов Docker (контейнеров и образов), которые больше не нужны, чтобы освободить дисковое пространство.

Сначала выведите список всех контейнеров (включая остановленные):

docker ps -a

Вы можете удалить конкретные контейнеры по их ID или имени:

docker rm $(docker ps -aq)

Эта команда удаляет все остановленные контейнеры. docker ps -aq выводит список всех ID контейнеров, а docker rm удаляет их.

Затем выведите список всех образов:

docker images

Вы можете удалить конкретные образы по их ID или имени. Будьте осторожны, чтобы не удалить образы, которые все еще используются запущенными контейнерами.

docker rmi my-ubuntu-app multi-stage-app hello-world ubuntu:22.04

Эта команда удаляет образы, которые мы создали и использовали в этой лаборатории. Если образ все еще используется контейнером, вам сначала потребуется удалить контейнер.

docker images

Эта команда покажет, что образы были удалены.

На этом завершается лаборатория по основам Docker и продвинутым техникам. Вы узнали, как создавать Dockerfile, собирать образы, запускать контейнеры и оптимизировать размер образов с помощью многоэтапной сборки.

Резюме

Овладев основами Docker, управлением Dockerfile и продвинутыми техниками, разработчики могут создавать более эффективные, переносимые и масштабируемые программные среды. Этот учебник вооружил вас практическими навыками в создании контейнеров, управлении образами и стратегиях развертывания, позволяя оптимизировать рабочие процессы разработки и применять архитектуры облачных приложений (cloud-native).