IAWE Блог

← Все статьи
Docker для новичков: Полное руководство по контейнеризации

Docker для новичков: Полное руководство по контейнеризации

Современная разработка программного обеспечения неуклонно движется в сторону большей гибкости, скорости развертывания и изоляции приложений. В этом контексте контейнеризация стала одной из ключевых технологий, кардинально изменившей подходы к созданию, тестированию и эксплуатации приложений. Если вы только начинаете свой путь в мире IT или хотите глубже понять основы современных DevOps-практик, то это руководство по Docker для вас. Мы погрузимся в самые глубины этой технологии, разберем ее преимущества, основные концепции и покажем на практике, как начать использовать Docker для своих проектов.

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

Основы контейнеризации: Что это и зачем нам это нужно?

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

1. Проблема «у меня на компьютере все работает»

Это, пожалуй, самая известная и распространенная проблема. Приложение, которое успешно запускается на машине разработчика, может вести себя совершенно иначе на сервере или у другого пользователя. Причины могут быть самыми разнообразными: различия в версиях операционных систем, установленных библиотеках, системных настройках, путях к файлам и так далее. Docker решает эту проблему, упаковывая приложение и все его зависимости в единый, переносимый контейнер. Этот контейнер ведет себя одинаково везде, где установлен Docker, обеспечивая консистентность окружения.

2. Изоляция приложений

Разные приложения могут иметь конфликтующие зависимости. Например, одно приложение может требовать определенную версию библиотеки, а другое – совершенно другую. Без контейнеризации управление такими конфликтами становится кошмаром. Контейнеры Docker предоставляют строгую изоляцию. Каждое приложение запускается в своем собственном контейнере, имеющем собственное файловое пространство, сетевые настройки и процессы. Это исключает конфликты между приложениями, развернутыми на одной и той же машине.

3. Эффективное использование ресурсов

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

4. Ускорение процесса разработки и тестирования

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

5. Стандартизация развертывания

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

Ключевые концепции Docker: От образа к контейнеру

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

1. Docker Image (Образ Docker)

Docker Image – это неизменяемый, исполняемый шаблон, содержащий инструкции для создания Docker-контейнера. Представьте образ как своего рода «снимок» операционной системы с установленным программным обеспечением, кодом и всеми необходимыми зависимостями. Образы строятся на основе слоев. Каждый слой представляет собой набор изменений в файловой системе. При создании нового образа на основе существующего, добавляется новый слой, который переиспользует слои базового образа. Это делает процесс сборки образов эффективным и позволяет значительно сократить их размер, так как общие слои не дублируются.

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

Пример Dockerfile:

# Используем официальный образ Python 3.9 как базовый
FROM python:3.9-slim

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

# Копируем файл зависимостей в рабочую директорию
COPY requirements.txt .

# Устанавливаем зависимости Python
RUN pip install --no-cache-dir -r requirements.txt

# Копируем код приложения в рабочую директорию
COPY . .

# Открываем порт, который будет использовать приложение
EXPOSE 8000

# Команда для запуска приложения при старте контейнера
CMD ["python", "app.py"]

Этот Dockerfile описывает, как создать образ для простого Python-приложения. Он начинается с официального образа Python, устанавливает зависимости из файла requirements.txt, копирует код приложения, открывает порт 8000 и указывает, что для запуска приложения нужно выполнить команду python app.py.

2. Docker Container (Контейнер Docker)

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

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

Каждый контейнер имеет свой собственный, изменяемый слой поверх неизменяемых слоев образа. Все изменения, происходящие внутри контейнера (например, создание новых файлов, изменение существующих), записываются в этот верхний слой. Этот слой является временным, если контейнер не настроен для сохранения данных.

Основные операции с контейнерами:

  • Создание: Запуск нового контейнера на основе образа.
  • Запуск: Старт остановленного контейнера.
  • Остановка: Приостановка работы контейнера.
  • Перезапуск: Остановка и немедленный запуск контейнера.
  • Удаление: Полное уничтожение контейнера и его файловой системы.
  • Просмотр логов: Отслеживание вывода приложения внутри контейнера.
  • Подключение: Доступ к командной строке работающего контейнера.

3. Docker Registry (Реестр Docker)

Docker Registry – это хранилище для Docker Images. Это место, где вы можете публиковать свои собственные образы и скачивать образы, созданные другими. Самым известным публичным реестром является Docker Hub (hub.docker.com), который предлагает огромное количество готовых образов для различных языков программирования, баз данных, операционных систем и приложений.

Вы можете использовать Docker Hub для:

  • Поиска готовых образов: Найти образы популярных приложений, таких как Nginx, MySQL, PostgreSQL, Node.js, Python и т.д.
  • Публикации собственных образов: Делиться своими Docker-образами с сообществом или вашей командой.
  • Создания приватных реестров: Для хранения конфиденциальных образов вашей компании.

Существуют и другие реестры, например, Google Container Registry (GCR), Amazon Elastic Container Registry (ECR), Azure Container Registry (ACR), а также частные решения, такие как Harbor.

4. Docker Daemon (Демон Docker)

Docker Daemon – это фоновый процесс, который постоянно работает на вашей машине и управляет всеми объектами Docker: образами, контейнерами, сетями и томами. Когда вы выполняете команды Docker через интерфейс командной строки (CLI), например, docker build или docker run, вы взаимодействуете с Docker Daemon. Демон отвечает за построение образов, запуск и управление контейнерами, работу с реестрами и т.д.

5. Docker CLI (Интерфейс командной строки Docker)

Docker CLI – это инструмент, который вы используете для взаимодействия с Docker Daemon. Это основной способ управления Docker. Команды CLI, такие как docker build, docker run, docker ps, docker images, отправляются демону для выполнения.

Практическое руководство: Начинаем работать с Docker

Теперь, когда мы разобрали основные концепции, давайте перейдем к практическим шагам. Установка Docker и первые команды позволят вам почувствовать, как эта технология работает.

1. Установка Docker

Процесс установки Docker зависит от вашей операционной системы.

  • Windows: Рекомендуется установка Docker Desktop для Windows. Он включает в себя Docker Engine, Docker CLI, Docker Compose и другие необходимые инструменты. Для работы Docker Desktop использует подсистему Windows для Linux (WSL 2) или Hyper-V.
  • macOS: Аналогично Windows, используется Docker Desktop для macOS. Он предоставляет удобный графический интерфейс и включает все необходимые компоненты.
  • Linux: Для Linux можно установить Docker Engine непосредственно. Процесс установки различается для разных дистрибутивов (Ubuntu, Debian, Fedora, CentOS и т.д.). Обычно он включает добавление репозитория Docker и установку пакетов через менеджер пакетов.

Шаги для Ubuntu (пример):

  1. Обновление списка пакетов:
sudo apt update
  1. Установка необходимых пакетов для добавления репозитория:
sudo apt install apt-transport-https ca-certificates curl software-properties-common
  1. Добавление официального GPG-ключа Docker:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  1. Добавление репозитория Docker:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  1. Обновление списка пакетов снова после добавления репозитория:
sudo apt update
  1. Установка Docker Engine, CLI, Containerd и Docker Compose:
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. Проверка установки:
sudo systemctl status docker
Вы должны увидеть, что сервис запущен.
  1. Добавление пользователя в группу docker (чтобы избежать использования sudo для каждой команды Docker):
sudo usermod -aG docker ${USER}
После выполнения этой команды вам нужно будет выйти из системы и снова войти, чтобы изменения вступили в силу.

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

2. Первая команда: Запуск тестового контейнера

Самая популярная команда для проверки установки Docker – это запуск контейнера с образом hello-world.

docker run hello-world

Что происходит, когда вы вводите эту команду?

  1. Docker CLI отправляет запрос docker run демону Docker.
  2. Демон Docker проверяет, есть ли образ hello-world локально на вашей машине.
  3. Если образа нет, демон Docker обращается к Docker Hub (по умолчанию) для поиска этого образа.
  4. Найдя образ, демон Docker скачивает его (создает локальный образ).
  5. На основе скачанного образа создается и запускается новый контейнер.
  6. Контейнер hello-world выполняет свою единственную задачу: выводит приветственное сообщение, объясняющее, как работает Docker, и затем завершает работу.
  7. Вы видите это сообщение в своем терминале.

Вывод команды docker run hello-world будет примерно таким:

Hello from Docker!
This message shows that your installation appears to be working.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (Assuming it was not already present locally.)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run our Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

3. Популярные команды Docker CLI

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

  • docker images: Отображает список всех Docker-образов, доступных на вашей локальной машине. Вы увидите информацию о репозитории образа, теге (версии), идентификаторе образа (IMAGE ID) и дате его создания.
docker images
  • docker pull <image_name>:<tag>: Скачивает образ из реестра (например, Docker Hub) на вашу локальную машину. Если тег не указан, будет скачан тег latest.
docker pull ubuntu:latest
  • docker run <image_name>:<tag>: Создает и запускает новый контейнер из указанного образа.
docker run ubuntu
Эта команда запустит контейнер из образа ubuntu, но он сразу же завершит работу, так как в образе ubuntu по умолчанию не определена команда, которая должна выполняться.
  • docker run -it <image_name>:<tag> <command>: Запускает контейнер в интерактивном режиме (-i – интерактивный, -t – псевдо-терминал) и выполняет указанную команду. Часто используется для получения доступа к командной строке контейнера.
docker run -it ubuntu bash
Эта команда запустит контейнер из образа ubuntu, откроет интерактивную сессию bash внутри этого контейнера. Вы окажетесь внутри файловой системы контейнера, как будто это отдельная Linux-система.
  • docker ps: Отображает список запущенных контейнеров. Вы увидите идентификатор контейнера (CONTAINER ID), образ, из которого он был создан, команду, команду запуска, время создания, статус и порты, которые проброшены.
docker ps
  • docker ps -a: Отображает список ВСЕХ контейнеров, включая остановленные.
docker ps -a
  • docker stop <container_id_or_name>: Останавливает указанный запущенный контейнер.
docker stop a3b1c4d5e6f7
  • docker start <container_id_or_name>: Запускает остановленный контейнер.
docker start a3b1c4d5e6f7
  • docker rm <container_id_or_name>: Удаляет указанный контейнер. Удалить можно только остановленный контейнер.
docker rm a3b1c4d5e6f7
  • docker logs <container_id_or_name>: Отображает логи (вывод) указанного контейнера.
docker logs my_web_server
  • docker exec -it <container_id_or_name> <command>: Выполняет команду внутри уже запущенного контейнера. Это очень полезно для отладки или выполнения каких-либо действий внутри работающего контейнера.
docker exec -it my_web_server ls /app
  • docker build -t <image_name>:<tag> .: Собирает Docker-образ из Dockerfile, находящегося в текущей директории. Флаг -t используется для задания имени и тега образа. Точка (.) в конце указывает Docker искать Dockerfile в текущей директории.
# Предполагается, что вы находитесь в директории с Dockerfile
docker build -t my-python-app:1.0 .

4. Создание своего первого Dockerfile и образа

Давайте создадим простой веб-сервер на Python, который будет отдавать статические HTML-файлы, и упакуем его в Docker-образ.

Шаг 1: Создайте директорию для вашего проекта

mkdir my-simple-webserver
cd my-simple-webserver

Шаг 2: Создайте файл index.html

<!DOCTYPE html>
<html>
<head>
    <title>Привет из Docker!</title>
</head>
<body>
    <h1>Добро пожаловать в мой первый Docker-контейнер!</h1>
    <p>Этот HTML-файл обслуживается простым Python-веб-сервером.</p>
</body>
</html>

Шаг 3: Создайте файл app.py

import http.server
import socketserver

PORT = 8000

Handler = http.server.SimpleHTTPRequestHandler

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print(f"Сервер запущен на порту {PORT}")
    print("Откройте http://localhost:8000 в вашем браузере")
    httpd.serve_forever()

Этот скрипт использует встроенный в Python простой HTTP-сервер для обслуживания файлов из текущей директории.

Шаг 4: Создайте файл requirements.txt

Для этого простого сервера нам не нужны сторонние библиотеки, поэтому файл будет пустым. Но если бы были, мы бы указали их здесь.

Шаг 5: Создайте файл Dockerfile

# Используем официальный образ Python 3.9 как базовый.
# Вариант slim меньше по размеру.
FROM python:3.9-slim

# Устанавливаем рабочую директорию внутри контейнера.
# Все последующие команды будут выполняться относительно этой директории.
WORKDIR /app

# Копируем файлы приложения из текущей директории хоста
# в рабочую директорию контейнера.
COPY index.html .
COPY app.py .

# Если бы у нас были зависимости, мы бы скопировали requirements.txt
# и выполнили установку:
# COPY requirements.txt .
# RUN pip install --no-cache-dir -r requirements.txt

# Открываем порт 8000. Это информация для человека и других инструментов,
# но не публикует порт на хост-машину автоматически.
EXPOSE 8000

# Команда, которая будет выполнена при запуске контейнера.
# Запускает наш Python-сервер.
CMD ["python", "app.py"]

Шаг 6: Соберите Docker-образ

Откройте терминал в директории my-simple-webserver и выполните команду:

docker build -t my-simple-web:latest .

Вы увидите процесс сборки: создание слоев, копирование файлов, выполнение команд. После завершения образ my-simple-web:latest будет доступен в выводе docker images.

Шаг 7: Запустите контейнер из вашего образа

docker run -p 8080:8000 my-simple-web:latest
  • -p 8080:8000: Этот флаг пробрасывает порт 8000 внутри контейнера на порт 8080 вашей хост-машины. Это означает, что когда вы обратитесь к localhost:8080 в браузере, трафик будет перенаправлен в контейнер на порт 8000.
  • my-simple-web:latest: Имя и тег образа, из которого нужно создать контейнер.

Откройте ваш веб-браузер и перейдите по адресу http://localhost:8080. Вы должны увидеть страницу "Добро пожаловать в мой первый Docker-контейнер!".

Чтобы остановить контейнер, нажмите Ctrl+C в терминале, где он запущен. Если вы запустили его в фоновом режиме (с флагом -d), вам нужно будет найти его CONTAINER ID с помощью docker ps и остановить командой docker stop.

Docker Compose: Оркестрация нескольких контейнеров

В реальных приложениях редко бывает только один сервис. Чаще всего это связка из веб-сервера, базы данных, кэша и других компонентов. Управлять каждым контейнером по отдельности (например, запускать Nginx, затем PostgreSQL, затем ваше приложение, пробрасывая порты, настраивая сети) становится громоздко. Здесь на помощь приходит Docker Compose.

Docker Compose – это инструмент для определения и запуска многоконтейнерных Docker-приложений. Вы описываете все сервисы вашего приложения в одном файле docker-compose.yml, а затем одной командой запускаете, останавливаете или перестраиваете все приложение целиком.

1. Файл docker-compose.yml

docker-compose.yml – это YAML-файл, в котором описываются сервисы, сети и тома для вашего приложения.

Пример docker-compose.yml для простого веб-приложения с базой данных:

version: '3.8' # Указываем версию синтаксиса Docker Compose

services:
  # Сервис веб-приложения
  web:
    build: . # Указываем, что Dockerfile для сборки находится в текущей директории
    ports:
      - "8080:8000" # Пробрасываем порт 8000 контейнера на порт 8080 хоста
    volumes:
      - .:/app # Монтируем текущую директорию хоста в /app внутри контейнера (для разработки)
    depends_on:
      - db # Сервис web зависит от сервиса db, db будет запущен первым

  # Сервис базы данных PostgreSQL
  db:
    image: postgres:13 # Используем готовый образ PostgreSQL
    environment:
      POSTGRES_DB: mydatabase # Имя базы данных
      POSTGRES_USER: user # Имя пользователя
      POSTGRES_PASSWORD: password # Пароль пользователя
    volumes:
      - db_data:/var/lib/postgresql/data # Сохраняем данные базы данных в томе

volumes:
  db_data: # Объявляем именованный том для хранения данных базы данных

В этом файле:

  • version: '3.8' указывает на версию синтаксиса файла.
  • services: определяет различные контейнеры (сервисы) вашего приложения.
  • web: Наш сервис веб-приложения.
  • build: .: Указывает Docker Compose собрать образ, используя Dockerfile из текущей директории.
  • ports:: Определяет правила проброса портов.
  • volumes:: Определяет монтирование томов. В данном случае, мы монтируем локальную директорию проекта в /app контейнера. Это удобно для разработки, так как изменения в коде на хосте сразу отражаются в контейнере без необходимости пересборки образа.
  • depends_on: - db: Указывает, что сервис web должен быть запущен после сервиса db.
  • db: Сервис базы данных.
  • image: postgres:13: Использует готовый образ PostgreSQL версии 13.
  • environment:: Задает переменные окружения, необходимые для инициализации PostgreSQL (имя БД, пользователь, пароль).
  • volumes:: Монтирует именованный том db_data в директорию данных PostgreSQL. Это гарантирует, что данные базы данных сохранятся даже после удаления контейнера db.
  • volumes:: Определяет именованные тома, используемые сервисами.

2. Основные команды Docker Compose

Для работы с Docker Compose вам понадобится установить его. В новых версиях Docker Desktop он включен по умолчанию. Если вы устанавливали Docker Engine отдельно, возможно, потребуется установить docker-compose как отдельный плагин или пакет.

Предположим, ваш Dockerfile для веб-приложения находится в той же директории, что и docker-compose.yml.

  • docker-compose up: Строит образы (если они не существуют), создает и запускает контейнеры, определенные в docker-compose.yml.
  • docker-compose up: Запускает контейнеры в foreground (включая логи). Вам придется нажать Ctrl+C для остановки.
  • docker-compose up -d: Запускает контейнеры в detached (фоновом) режиме. Логи не отображаются в терминале.
  • docker-compose down: Останавливает и удаляет контейнеры, сети и тома, созданные командой up.
  • docker-compose down: Удаляет только контейнеры и сети.
  • docker-compose down -v: Удаляет контейнеры, сети и именованные тома, определенные в docker-compose.yml. Будьте осторожны с этим флагом, так как он удалит все данные!
  • docker-compose ps: Отображает статус контейнеров, запущенных для данного проекта.
  • docker-compose logs: Отображает логи контейнеров.
  • docker-compose logs -f: Следит за логами в реальном времени (аналогично tail -f).
  • docker-compose build: Перестраивает образы для сервисов, определенных в docker-compose.yml, у которых есть секция build.
  • docker-compose stop: Останавливает работающие контейнеры, но не удаляет их.
  • docker-compose start: Запускает остановленные контейнеры.

3. Пример использования Docker Compose

  1. Создайте новую директорию для вашего проекта my-compose-app.
  2. Внутри нее создайте Dockerfile (можете использовать тот, что мы создавали ранее для my-simple-web).
  3. Создайте файл index.html и app.py (или адаптируйте их, если нужно).
  4. Создайте файл docker-compose.yml с содержанием, приведенным выше (с сервисом web, который собирается из текущей директории, и сервисом db).
  5. Откройте терминал в директории my-compose-app.
  6. Запустите приложение:
docker-compose up -d
  1. Проверьте, запущены ли контейнеры:
docker-compose ps
Вы должны увидеть два запущенных сервиса: web и db.
  1. Откройте браузер и перейдите по адресу http://localhost:8080. Вы увидите вашу страницу.
  2. Для остановки всего приложения выполните:
docker-compose down
Если вы хотите сохранить данные базы данных, используйте docker-compose down. Если хотите удалить и том с данными, используйте docker-compose down -v.

Сети и Тома в Docker: Управление данными и коммуникацией

Два важнейших аспекта работы с контейнерами – это управление данными (чтобы они не терялись при удалении контейнера) и организация сетевого взаимодействия между контейнерами и внешним миром.

1. Docker Volumes (Тома Docker)

Тома – это основной механизм для сохранения данных, генерируемых и используемых Docker-контейнерами. Тома управляются Docker и находятся вне файловой системы самого контейнера.

Преимущества использования томов:

  • Сохранение данных: Данные, хранящиеся в томах, переживают контейнер. Если контейнер удаляется, том остается, и его можно подключить к новому контейнеру, чтобы восстановить данные.
  • Управление: Томами можно управлять с помощью команд Docker (docker volume create, docker volume ls, docker volume rm).
  • Производительность: Тома, как правило, более производительны, чем монтирование директорий хостовой системы (bind mounts), особенно на macOS и Windows.
  • Разделение данных: Позволяют легко переносить или резервировать данные.

Типы томов:

  • Именованные тома (Named Volumes): Это предпочтительный способ управления данными. Вы даете тому имя (например, db_data), и Docker управляет его расположением на хостовой машине. Примером было использование db_data в docker-compose.yml.
  • Bind Mounts: Позволяют монтировать файл или директорию с хостовой машины непосредственно в контейнер. Это удобно для разработки, когда нужно видеть изменения кода в реальном времени, или для предоставления конфигурационных файлов. Пример: volumes: - ./config:/etc/nginx/conf.d
  • tmpfs Volumes: Временные тома, которые хранятся в оперативной памяти хоста и уничтожаются при остановке контейнера. Используются для хранения временных данных, которые не нужно сохранять.

Пример использования именованного тома:

# Создаем именованный том
docker volume create my-data-volume

# Запускаем контейнер, монтируя том в директорию /data внутри контейнера
docker run -d --name my-app-container -v my-data-volume:/app/data my-custom-image

# Теперь все, что записывается в /app/data внутри контейнера,
# будет сохранено в томе my-data-volume на хосте.

# Чтобы увидеть, где Docker хранит тома на хосте (зависит от ОС)
docker volume inspect my-data-volume

2. Docker Networks (Сети Docker)

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

Основные типы сетей:

  • Bridge (Мост): Сеть по умолчанию. Контейнеры, подключенные к мостовой сети, получают IP-адреса из подсети, управляемой Docker. Они могут общаться друг с другом и с внешним миром (через NAT).
  • Host: Контейнер использует сетевой стек хостовой машины. Изоляция отсутствует, порты контейнера доступны напрямую на хосте.
  • Overlay: Используется для организации сетей между контейнерами, запущенными на разных хостах Docker (например, в Docker Swarm или Kubernetes).
  • Macvlan: Позволяет назначить контейнеру MAC-адрес, как будто он является физическим устройством в вашей сети.

Управление сетями:

  • docker network create <network_name>: Создает новую пользовательскую сеть.
  • docker network ls: Отображает список доступных сетей.
  • docker network inspect <network_name>: Показывает информацию о сети.
  • docker network rm <network_name>: Удаляет сеть.

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

# Создаем пользовательскую сеть
docker network create my-app-network

# Запускаем базу данных в этой сети
docker run -d --name db --network my-app-network postgres:13

# Запускаем наше приложение в той же сети, оно сможет обращаться к базе данных по имени 'db'
docker run -d --name web --network my-app-network -p 8080:80 my-custom-web-image

Docker Compose автоматически создает и управляет сетями для ваших сервисов, что значительно упрощает сетевую конфигурацию. По умолчанию, Docker Compose создает отдельную сеть для каждого проекта (<project_name>_default). Все сервисы в этом файле автоматически подключаются к этой сети, позволяя им взаимодействовать друг с другом по имени сервиса.

Безопасность Docker: Важные аспекты

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

1. Использование минимальных образов

Старайтесь использовать минимальные базовые образы (например, alpine, python:3.9-slim, nginx:alpine). Они содержат только самые необходимые компоненты, что уменьшает площадь атаки и размер образа.

2. Сканирование образов на уязвимости

Существует множество инструментов (например, Trivy, Clair, Anchore), которые могут сканировать ваши Docker-образы на наличие известных уязвимостей в пакетах. Интегрируйте такие сканирования в ваш CI/CD-пайплайн.

3. Работа с привилегиями

  • Избегайте запуска контейнеров от имени root: Если возможно, настраивайте пользовательскую учетную запись внутри контейнера и запускайте приложение от ее имени. Это делается с помощью инструкции USER в Dockerfile.
  • Минимизируйте использование --privileged: Этот флаг дает контейнеру полный доступ к устройствам хостовой системы, что является крайне небезопасным. Используйте его только в крайних случаях и полностью понимая риски.
  • Ограничивайте права доступа: При монтировании томов, убедитесь, что у контейнера есть только те права доступа, которые ему действительно нужны.

4. Изоляция и сети

  • Используйте пользовательские сети: Не полагайтесь на сеть bridge по умолчанию для критически важных приложений. Создавайте отдельные сети для разных групп сервисов.
  • Ограничивайте сетевой доступ: Настраивайте правила файрвола на хосте и используйте возможности Docker для ограничения трафика между контейнерами.

5. Обновление Docker Engine

Регулярно обновляйте Docker Engine и Docker Compose до последних версий. Обновления часто содержат исправления безопасности.

6. Конфигурационные файлы

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

Docker для разработки и продакшена

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

1. Docker в разработке

  • Единообразные среды разработки: Каждый разработчик в команде может иметь идентичную среду, независимо от его операционной системы.
  • Быстрое развертывание зависимостей: Нужна база данных или Redis? Просто запустите соответствующий контейнер, а не устанавливайте их локально.
  • Изоляция экспериментов: Создавайте временные контейнеры для тестирования новых библиотек или фреймворков, не засоряя основную систему.
  • Упрощение совместной работы: Легко делитесь рабочими окружениями с коллегами, передавая им Dockerfile и docker-compose.yml.

2. Docker в продакшене

  • Консистентность окружений: Гарантия того, что приложение, которое прекрасно работало на этапе тестирования, будет работать так же и в продакшене.
  • Быстрое развертывание и откат: Обновление приложения сводится к развертыванию нового контейнера. В случае проблем, можно быстро откатиться к предыдущей версии, просто запустив старый образ.
  • Масштабируемость: Docker легко интегрируется с системами оркестрации (Kubernetes, Docker Swarm), которые позволяют автоматически масштабировать количество экземпляров вашего приложения в зависимости от нагрузки.
  • Эффективное использование ресурсов: Меньшее потребление ресурсов по сравнению с виртуальными машинами позволяет снизить затраты на инфраструктуру.
  • Микросервисная архитектура: Docker идеально подходит для развертывания микросервисов, где каждое приложение упаковано в свой контейнер.

Распространенные ошибки новичков и как их избежать

ОшибкаОбъяснениеКак избежать
Запуск контейнеров с флагом --privilegedПредоставляет контейнеру слишком много прав, что создает серьезные риски безопасности.Используйте этот флаг только в крайних случаях. Ищите более безопасные альтернативы: монтирование конкретных устройств, изменение прав.
Хранение секретных данных в образахПароли, ключи API, сертификаты, закодированные в образе, могут быть легко извлечены.Используйте переменные окружения (для некритичных данных) или системы управления секретами (Docker Secrets, Vault, Kubernetes Secrets).
Использование latest тега для продакшенаТег latest может быть переопределен, что приводит к непредсказуемому поведению при обновлении.Всегда указывайте конкретный тег версии образа (например, my-app:1.2.3).
Отсутствие сохранения данных (томов)Данные, генерируемые приложением (например, база данных, логи), теряются при удалении контейнера.Используйте именованные тома (volumes) для баз данных и других важных данных.
Запуск всего от имени rootЗапуск процессов внутри контейнера от имени root повышает риски при компрометации.Используйте инструкцию USER в Dockerfile для создания и использования непривилегированного пользователя внутри контейнера.
Слишком большие образыБольшие образы медленнее скачиваются, занимают больше места и потенциально содержат больше уязвимостей.Используйте минимальные базовые образы (alpine), объединяйте команды RUN в Dockerfile для уменьшения количества слоев, очищайте кэш.
Проблема «не видно порт»Контейнер запущен, но сервис недоступен извне, потому что порты не проброшены.Убедитесь, что вы правильно используете флаг -p <host_port>:<container_port> при запуске контейнера или настраиваете ports в docker-compose.yml.
Забывание очисткиНакопленные остановленные контейнеры, неиспользуемые образы и тома могут занимать много места на диске.Регулярно используйте docker system prune для очистки.

Заключение: Ваш путь в мир контейнеризации

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

Это руководство предоставило вам прочную основу для начала работы с Docker. Главное – это практика. Экспериментируйте, пробуйте запускать разные приложения, создавайте свои Dockerfile и docker-compose.yml. Чем больше вы будете практиковаться, тем увереннее будете чувствовать себя в мире контейнеризации. Docker открывает двери к более быстрой, надежной и масштабируемой разработке, и освоение этой технологии станет ценным вкладом в ваше профессиональное развитие.

Успехов в освоении Docker!

← Все статьи