Skip to content
Документация
Введение в Docker

Введение в Docker

Введение

Одна из самых распространённых проблем в мире разработки программного обеспечения — фраза «На моём компьютере работает!». Код, написанный разработчиком на его машине, перестаёт работать на тестовом сервере, потому что версии библиотек различаются, операционная система другая или отсутствуют конфигурационные файлы. Для решения этой проблемы был создан Docker.

Docker — это open-source платформа, позволяющая упаковывать программное обеспечение в контейнеры и запускать его одинаково в любом окружении. Docker был создан в 2013 году Соломоном Хайксом (Solomon Hykes) в компании dotCloud и быстро распространился по всему миру.

Название Docker происходит от слова dock worker (портовый рабочий). Портовые рабочие укладывают различные грузы в стандартные контейнеры и загружают их на корабль. Точно так же Docker упаковывает приложения в стандартные контейнеры и «загружает» их на любой сервер.


Что такое контейнеризация?

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

Традиционное развёртывание (Traditional deployment)

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

┌─────────────────────────────────────────────┐
│          Физический сервер                  │
│                                             │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│  │  App A   │ │  App B   │ │  App C   │     │
│  │ Node 18  │ │ Node 16  │ │ Python 3 │     │
│  └──────────┘ └──────────┘ └──────────┘     │
│                                             │
│  ┌─────────────────────────────────────┐    │
│  │     Операционная система (ОС)       │    │
│  └─────────────────────────────────────┘    │
│  ┌─────────────────────────────────────┐    │
│  │           Hardware                  │    │
│  └─────────────────────────────────────┘    │
└─────────────────────────────────────────────┘

❌ Проблема: App A и App B требуют разных
   версий Node.js — conflict!

Развёртывание на виртуальных машинах (VM deployment)

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

┌─────────────────────────────────────────────┐
│          Физический сервер                  │
│                                             │
│  ┌─────────────┐  ┌─────────────┐           │
│  │    VM 1     │  │    VM 2     │           │
│  │  ┌───────┐  │  │  ┌───────┐  │           │
│  │  │ App A │  │  │  │ App B │  │           │
│  │  └───────┘  │  │  └───────┘  │           │
│  │  ┌───────┐  │  │  ┌───────┐  │           │
│  │  │ Libs  │  │  │  │ Libs  │  │           │
│  │  └───────┘  │  │  └───────┘  │           │
│  │  ┌───────┐  │  │  ┌───────┐  │           │
│  │  │ Guest │  │  │  │ Guest │  │           │
│  │  │  OS   │  │  │  │  OS   │  │           │
│  │  └───────┘  │  │  └───────┘  │           │
│  └─────────────┘  └─────────────┘           │
│                                             │
│  ┌─────────────────────────────────────┐    │
│  │           Hypervisor                │    │
│  └─────────────────────────────────────┘    │
│  ┌─────────────────────────────────────┐    │
│  │           Host OS                   │    │
│  └─────────────────────────────────────┘    │
│  ┌─────────────────────────────────────┐    │
│  │           Hardware                  │    │
│  └─────────────────────────────────────┘    │
└─────────────────────────────────────────────┘

⚠️ Каждая VM имеет полную ОС — расход 1-2 ГБ RAM

Развёртывание в контейнерах (Docker)

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

┌─────────────────────────────────────────────┐
│          Физический сервер                  │
│                                             │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│  │Container │ │Container │ │Container │     │
│  │  ┌────┐  │ │  ┌────┐  │ │  ┌────┐  │     │
│  │  │App │  │ │  │App │  │ │  │App │  │     │
│  │  │ A  │  │ │  │ B  │  │ │  │ C  │  │     │
│  │  └────┘  │ │  └────┘  │ │  └────┘  │     │
│  │  ┌────┐  │ │  ┌────┐  │ │  ┌────┐  │     │
│  │  │Libs│  │ │  │Libs│  │ │  │Libs│  │     │
│  │  └────┘  │ │  └────┘  │ │  └────┘  │     │
│  └──────────┘ └──────────┘ └──────────┘     │
│                                             │
│  ┌─────────────────────────────────────┐    │
│  │          Docker Engine              │    │
│  └─────────────────────────────────────┘    │
│  ┌─────────────────────────────────────┐    │
│  │         Host OS (kernel)            │    │
│  └─────────────────────────────────────┘    │
│  ┌─────────────────────────────────────┐    │
│  │           Hardware                  │    │
│  └─────────────────────────────────────┘    │
└─────────────────────────────────────────────┘

✅ Без отдельной ОС — 10-100 МБ, запуск за секунды

Сравнение VM и Container

ХарактеристикаVirtual MachineDocker Container
Время запуска1–3 минуты1–5 секунд
Размер1–10 ГБ10–500 МБ
Потребление RAM512 МБ – 2 ГБ (на каждую VM)5–50 МБ (на каждый контейнер)
ИзоляцияПолная (отдельная ОС)На уровне процессов (shared kernel)
ПортативностьНизкая (зависит от hypervisor)Высокая (работает где угодно)
Количество на одном сервере5–20 VM100+ контейнеров
ОСКаждая VM имеет свою ОСКонтейнеры разделяют kernel хостовой ОС

Когда использовать VM, а когда контейнер?

  • VM — когда требуются разные операционные системы (например, запуск Windows на Linux-сервере) или необходима полная изоляция
  • Контейнер — для microservice-архитектуры, CI/CD pipeline, быстрого развёртывания приложений, стандартизации среды разработки

Архитектура Docker

Docker работает по клиент-серверной архитектуре. Понимание этого крайне важно для эффективной работы с Docker.

┌───────────────────────────────────────────────────────────────┐
│                     Архитектура Docker                        │
│                                                               │
│  ┌────────── ───┐         ┌──────────────────────────────┐    │
│  │   Docker     │  REST   │       Docker Daemon          │    │
│  │   Client     │  API    │       (dockerd)              │    │
│  │             ─┼────────►│                              │    │
│  │  docker run  │         │  ┌────────────────────────┐  │    │
│  │  docker build│         │  │     Container Runtime  │  │    │
│  │  docker pull │         │  │      (containerd)      │  │    │
│  │  docker push │         │  └────────────────────────┘  │    │
│  │              │         │                              │    │
│  └──────────── ─┘         │  ┌────────┐  ┌────────┐      │    │
│                           │  │  Img 1 │  │  Img 2 │      │    │
│                           │  └────────┘  └────────┘      │    │
│                           │                              │    │
│                           │  ┌──────┐ ┌──────┐ ┌──────┐  │    │
│                           │  │Cont 1│ │Cont 2│ │Cont 3│  │    │
│                           │  └──────┘ └──────┘ └──────┘  │    │
│                           └──────────────────────────────┘    │
│                                          │                    │
│                                          ▼                    │
│                           ┌──────────────────────────────┐    │
│                           │      Docker Registry         │    │
│                           │   (Docker Hub, Harbor, etc.) │    │
│                           └──────────────────────────────┘    │
└───────────────────────────────────────────────────────────────┘

Docker Engine

Docker Engine — это основной компонент платформы Docker. Он состоит из трёх компонентов:

1. Docker Daemon (dockerd)

Docker Daemon — это серверный процесс, работающий в фоновом режиме. Он принимает запросы через Docker API и управляет образами, контейнерами, сетями и томами.

# Статус Docker Daemon
sudo systemctl status docker
 
# Перезапуск Docker Daemon
sudo systemctl restart docker

Docker Daemon выполняет следующие задачи:

  • Сборка и хранение образов
  • Создание, запуск и остановка контейнеров
  • Управление Docker-сетями
  • Управление томами (volumes)

2. Docker Client (docker)

Docker Client — это CLI-инструмент (Command Line Interface), через который пользователь взаимодействует с Docker. Когда вы вводите команды docker в терминале, Client отправляет эти команды Docker Daemon через REST API.

# Взаимодействие Client с Daemon
docker version    # Версия Client и Server
docker info       # Подробная информация о системе Docker

3. Docker Registry

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

RegistryТипОписание
Docker HubPublic/PrivateСамый популярный, стандартный registry
HarborPrivate (self-hosted)Проект CNCF, для корпоративного использования
NexusPrivate (self-hosted)Мультиформатный менеджер артефактов
GCRPrivate (cloud)Google Cloud Container Registry
ECRPrivate (cloud)AWS Elastic Container Registry
ACRPrivate (cloud)Azure Container Registry
GHCRPublic/PrivateGitHub Container Registry

Docker Image

Docker Image — это read-only шаблон для создания контейнеров. Образ содержит код приложения, runtime, библиотеки, переменные окружения и конфигурационные файлы.

Слои образа (Image Layers)

Docker-образы построены на системе слоёв (layers). Каждая инструкция в Dockerfile создаёт новый слой. Слои являются read-only и кэшируются для повторного использования.

┌─────────────────────────────────────┐
│         Docker Image                │
│                                     │
│  ┌───────────────────────────────┐  │
│  │ Layer 5: COPY app/ /app/      │  │  ← Ваш код
│  ├───────────────────────────────┤  │
│  │ Layer 4: RUN npm install      │  │  ← Зависимости
│  ├───────────────────────────────┤  │
│  │ Layer 3: COPY package.json    │  │  ← Файл пакетов
│  ├───────────────────────────────┤  │
│  │ Layer 2: RUN apt-get update   │  │  ← Системные пакеты
│  ├───────────────────────────────┤  │
│  │ Layer 1: FROM node:20-alpine  │  │  ← Base image
│  └───────────────────────────────┘  │
│                                     │
│  Все слои READ-ONLY                 │
└─────────────────────────────────────┘

Преимущество кэширования слоёв: Если вы изменили только код приложения (Layer 5), Docker возьмёт нижние слои (1–4) из кэша и пересоберёт только изменённый слой. Это ускоряет сборку в 10–100 раз.

Соглашение об именовании образов

Полное имя Docker-образа имеет следующий формат:

[registry-url/][namespace/]image-name[:tag]

Примеры:

# Из Docker Hub (registry-url опускается)
nginx:latest                          # Official image, latest tag
node:20-alpine                        # Official image, конкретная версия
ismoilovdev/my-app:v1.2.3            # User namespace, custom image
 
# Из приватного registry
harbor.helm.uz/devops/my-app:v1.0    # Harbor registry
gcr.io/my-project/api-server:latest  # Google Container Registry
ghcr.io/username/my-app:main         # GitHub Container Registry

Теги образов (Image tags)

Теги используются для обозначения версии образа:

Тип тегаПримерИспользование
latestnginx:latestТег по умолчанию, но не используйте в production
Semantic versioningnode:20.11.1Точная версия, надёжно
Major-версияpython:3Последняя в диапазоне 3.x.x
Вариант ОСnode:20-alpineНа базе Alpine Linux (малый размер)
Slim-вариантpython:3.12-slimБез лишних пакетов
Custommy-app:v1.2.3-rc1Ваши собственные версии

Предупреждение о теге latest: latest — это не «самый новый», а просто имя тега по умолчанию. Если вы выполните docker build -t myapp ., образ получит тег myapp:latest. В production-среде всегда используйте конкретную версию: myapp:v1.2.3.

Практический пример: работа с образами

# Загрузка образа из Docker Hub
docker pull nginx:1.25-alpine
 
# Просмотр доступных образов в системе
docker images
 
# Подробная информация об образе
docker inspect nginx:1.25-alpine
 
# Просмотр слоёв образа
docker history nginx:1.25-alpine
 
# Удаление образа
docker rmi nginx:1.25-alpine

Docker Container

Docker Container — это запущенный экземпляр (running instance) образа. Если образ является read-only шаблоном, то контейнер добавляет поверх него записываемый слой (writable layer).

Различие между Image и Container

Docker Image (шаблон)           Docker Container (запущенный)
┌─────────────────────┐         ┌─────────────────────┐
│                     │         │  Writable Layer     │ ← Новый
│  Read-only Layers   │  run    │─────────────────────│
│                     │ ──────► │                     │
│  App + Libs + OS    │         │  Read-only Layers   │ ← Из образа
│                     │         │  App + Libs + OS    │
└─────────────────────┘         └─────────────────────┘

Один образ → можно создать много контейнеров

                   ┌──────────────┐
                   │ Container 1  │
┌──────────┐       ├──────────────┤
│  nginx   │──────►│ Container 2  │
│  image   │       ├──────────────┤
└──────────┘       │ Container 3  │
                   └──────────────┘

Жизненный цикл контейнера (Container Lifecycle)

Жизненный цикл Docker-контейнера состоит из следующих этапов:

                    docker create
                  ┌──────────────────┐
                  │                  │
                  ▼                  │
┌────────┐   docker run  ┌──────────────┐   docker stop  ┌────────────┐
│  Image │──────────────►│   Running    │──────────────► │ Stopped    │
└────────┘               │  (работает)  │                │(остановлен)│
                         └──────┬───────┘                └──────┬─────┘
                                │                               │
                          docker pause                   docker start
                                │                               │
                          ┌─────▼────────┐                       │
                          │   Paused     │               ┌───────▼─────┐
                          │ (пауза)      │               │  Running    │
                          └──────────────┘               └─────────────┘

                          docker rm → контейнер удаляется (только в состоянии stopped)
СостояниеОписаниеКоманда
CreatedКонтейнер создан, но не запущенdocker create
RunningКонтейнер работаетdocker start / docker run
PausedПроцессы приостановлены, но остаются в памятиdocker pause
StoppedКонтейнер остановленdocker stop / docker kill
RemovedКонтейнер удалёнdocker rm

Практический пример: работа с контейнерами

# Создание и запуск контейнера (run = create + start)
docker run -d --name my-nginx -p 8080:80 nginx:1.25-alpine
 
# Просмотр запущенных контейнеров
docker ps
 
# Вход внутрь контейнера
docker exec -it my-nginx /bin/sh
 
# Просмотр логов контейнера
docker logs -f my-nginx
 
# Остановка контейнера
docker stop my-nginx
 
# Повторный запуск контейнера
docker start my-nginx
 
# Удаление контейнера (сначала необходимо остановить)
docker stop my-nginx && docker rm my-nginx

Что делает docker run? docker run на самом деле выполняет несколько операций:

  1. Проверяет наличие образа в системе (если нет — выполняет docker pull)
  2. Создаёт контейнер (docker create)
  3. Добавляет записываемый слой (writable layer)
  4. Создаёт сетевой интерфейс и назначает IP-адрес
  5. Запускает контейнер (docker start)

Dockerfile

Dockerfile — это текстовый файл, содержащий инструкции для создания Docker-образа. Он поэтапно описывает, как будет собран образ. Каждая инструкция создаёт новый слой (layer).

Инструкции Dockerfile

ИнструкцияНазначениеПример
FROMВыбор базового образа (всегда первая)FROM node:20-alpine
WORKDIRУстановка рабочей директорииWORKDIR /app
COPYКопирование файлов из хоста в образCOPY package.json .
ADDCOPY + загрузка по URL и распаковка архивовADD app.tar.gz /app/
RUNВыполнение команды во время сборкиRUN npm install
CMDКоманда по умолчанию при запуске контейнераCMD ["node", "server.js"]
ENTRYPOINTОсновной процесс контейнераENTRYPOINT ["python"]
ENVУстановка переменной окруженияENV NODE_ENV=production
ARGПриём аргумента во время сборкиARG VERSION=1.0
EXPOSEДокументирование порта контейнераEXPOSE 3000
VOLUMEТочка хранения данныхVOLUME ["/data"]
USERУказание пользователя для выполненияUSER node
LABELДобавление метаданных к образуLABEL version="1.0"
HEALTHCHECKПроверка состояния контейнераHEALTHCHECK CMD curl -f http://localhost/

Различие между CMD и ENTRYPOINT

Эти две инструкции часто вызывают путаницу. Важно понимать разницу:

# CMD — команда по умолчанию, может быть переопределена при docker run
FROM ubuntu:24.04
CMD ["echo", "Salom Dunyo"]
docker run my-image                  # Natija: "Salom Dunyo"
docker run my-image echo "Boshqa"    # Natija: "Boshqa" (CMD o'zgartirildi)
# ENTRYPOINT — выполняется всегда, не переопределяется
FROM ubuntu:24.04
ENTRYPOINT ["echo"]
CMD ["Salom Dunyo"]
docker run my-image                  # Natija: "Salom Dunyo"
docker run my-image "Boshqa"         # Natija: "Boshqa" (CMD o'zgardi, lekin ENTRYPOINT saqlandi)

Правило: ENTRYPOINT — это основная программа контейнера, CMDаргументы по умолчанию для неё. Реальный пример: ENTRYPOINT ["python"] + CMD ["app.py"] — по умолчанию выполняется python app.py, но если указать docker run my-image test.py, то выполнится python test.py.

Реальные примеры Dockerfile

1. Для приложения на Node.js (Express):

Dockerfile
# 1. Base image — Alpine-вариант для малого размера
FROM node:20-alpine

# 2. Установка рабочей директории
WORKDIR /app

# 3. Сначала копируем только package-файлы (для кэширования слоёв)
COPY package.json package-lock.json ./

# 4. Установка зависимостей
RUN npm ci --only=production

# 5. Копирование кода приложения
COPY . .

# 6. Использование non-root пользователя (безопасность)
USER node

# 7. Документирование порта
EXPOSE 3000

# 8. Health check
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1

# 9. Запуск приложения
CMD ["node", "server.js"]

2. Для приложения на Python (Flask/Django):

Dockerfile
FROM python:3.12-slim

WORKDIR /app

# Системные зависимости
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# Python-зависимости (кэширование слоёв)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Код приложения
COPY . .

# Создание и использование non-root пользователя
RUN useradd --create-home appuser
USER appuser

EXPOSE 8000

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

3. Для приложения на Go (multi-stage build):

Dockerfile
# ======= Build stage =======
FROM golang:1.22-alpine AS builder

WORKDIR /build

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .

# ======= Production stage =======
FROM alpine:3.19

RUN apk --no-cache add ca-certificates

WORKDIR /app

# Копирование только бинарного файла из build stage
COPY --from=builder /app/server .

RUN adduser -D -g '' appuser
USER appuser

EXPOSE 8080

ENTRYPOINT ["./server"]

Multi-stage build — это способ значительно уменьшить размер образа. В примере с Go на этапе сборки присутствует компилятор Go и все инструменты (~800 МБ), но на этапе production остаётся только скомпилированный бинарный файл (~15 МБ). Результат: 15 МБ вместо 800 МБ.

Лучшие практики написания Dockerfile

1. Оптимизируйте порядок слоёв — размещайте редко изменяемые файлы вверху, а часто изменяемые — внизу:

# ✅ Правильно — зависимости меняются редко
COPY package.json package-lock.json ./
RUN npm ci
COPY . .    # Код меняется часто — в самом конце

# ❌ Неправильно — при каждом изменении кода npm install выполняется заново
COPY . .
RUN npm ci

2. Используйте файл .dockerignore — исключайте ненужные файлы из образа:

.dockerignore
node_modules
.git
.env
*.md
Dockerfile
docker-compose.yml
.dockerignore

3. Выбирайте минимальные базовые образы:

Базовый образРазмерПрименение
ubuntu:24.04~78 МБКогда нужно полноценное Linux-окружение
debian:bookworm-slim~74 МБSlim-вариант — меньше пакетов
alpine:3.19~7 МБМинимальный образ, достаточен в большинстве случаев
node:20~1.1 ГБДля разработки (большой)
node:20-alpine~130 МБДля production (рекомендуется)
scratch0 МБТолько для статических бинарных файлов (Go, Rust)

4. Используйте non-root пользователя:

# Для безопасности не работайте от root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

5. Объединяйте RUN-команды — для уменьшения количества слоёв:

# ✅ Один слой — очистка в том же слое
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl wget git \
    && rm -rf /var/lib/apt/lists/*

# ❌ Три отдельных слоя — лишний кэш остаётся
RUN apt-get update
RUN apt-get install -y curl wget git
RUN rm -rf /var/lib/apt/lists/*

Docker Volume

Docker-контейнеры являются эфемерными (временными) — при удалении контейнера все данные в нём теряются. Volume решает эту проблему — позволяет хранить данные за пределами контейнера.

Типы Volume

┌───────────────────────────────────────────────────────────┐
│                    Host Server                            │
│                                                           │
│  Named Volume          Bind Mount          tmpfs Mount    │
│  (Управляется Docker)  (Host path)         (В RAM)        │
│                                                           │
│  /var/lib/docker/      /home/user/         tmpfs          │
│  volumes/mydata/       project/            (в памяти)     │
│       │                    │                    │         │
│       ▼                    ▼                    ▼         │
│  ┌──────────────────────────────────────────────────┐     │
│  │              Docker Container                    │     │
│  │                                                  │     │
│  │    /data          /app              /tmp/secret  │     │
│  └──────────────────────────────────────────────────┘     │
└───────────────────────────────────────────────────────────┘
ТипКомандаПрименение
Named Volume-v mydata:/dataProduction — управляется Docker, удобное резервное копирование
Bind Mount-v /host/path:/container/pathРазработка — синхронизация с файловой системой хоста
tmpfs--tmpfs /tmpВременные данные — только в оперативной памяти, на диск не записывается

Реальный пример: сохранение данных PostgreSQL

# Создание named volume
docker volume create postgres-data
 
# Запуск контейнера PostgreSQL с volume
docker run -d \
  --name my-postgres \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -e POSTGRES_DB=myapp \
  -v postgres-data:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16-alpine
 
# Даже при удалении контейнера данные сохраняются
docker stop my-postgres && docker rm my-postgres
 
# Новый контейнер — старые данные на месте!
docker run -d \
  --name my-postgres-new \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -v postgres-data:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16-alpine

Важно: Если вы удалите контейнер с базой данных без использования volume, все данные будут безвозвратно потеряны. В production-среде всегда используйте volume!


Docker Network

Docker-сети управляют коммуникацией между контейнерами. По умолчанию Docker предоставляет несколько сетевых драйверов.

Сетевые драйверы

┌─────────────────────────────────────────────────────┐
│                                                     │
│  Bridge Network (default)                           │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐         │
│  │   App    │   │   DB     │   │  Cache   │         │
│  │ :3000    │◄─►│ :5432    │◄─►│ :6379    │         │
│  └──────────┘   └──────────┘   └──────────┘         │
│       ▲              Находят друг друга             │
│       │              по имени через DNS             │
│       │                                             │
│  ─────┼──────────────────────────────────────       │
│       │                                             │
│       ▼                                             │
│  Host:8080 ──► Container:3000                       │
│  (внешний мир подключается через port mapping)      │
│                                                     │
└─────────────────────────────────────────────────────┘
ДрайверОписаниеПрименение
bridgeСеть по умолчанию. Контейнеры на одном хосте взаимодействуют между собойНаиболее используемый
hostКонтейнер напрямую использует сеть хостаНе требует port mapping, высокая производительность
noneСеть отсутствует. Контейнер не взаимодействует с внешним миромКогда требуется безопасность
overlayСеть между несколькими хостами (Docker Swarm)Для контейнеров в кластере
macvlanКонтейнеру назначается собственный MAC-адресДля прямого подключения к физической сети

Реальный пример: сеть приложения + базы данных

# Создание пользовательской сети
docker network create app-network
 
# PostgreSQL — в app-network
docker run -d \
  --name postgres \
  --network app-network \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  postgres:16-alpine
 
# Приложение — в app-network (находит postgres по имени)
docker run -d \
  --name my-app \
  --network app-network \
  -e DATABASE_URL=postgresql://postgres:secret@postgres:5432/myapp \
  -p 3000:3000 \
  my-app:latest

DNS-резолвинг: Контейнеры в одной сети находят друг друга по имени контейнера. В примере выше контейнер my-app подключается к контейнеру postgres через postgres:5432 — IP-адрес не нужен!


Docker Compose

Во многих случаях приложение состоит из нескольких сервисов — web-сервер, база данных, кэш, очередь сообщений и т.д. Запускать каждый из них отдельной командой docker run неудобно. Docker Compose позволяет описать все сервисы в одном файле docker-compose.yml и управлять ими одной командой.

Структура docker-compose.yml

docker-compose.yml
# Реальный пример: Full-stack приложение
version: "3.8"
 
services:
  # Frontend — React-приложение
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    environment:
      - REACT_APP_API_URL=http://localhost:8000
    depends_on:
      - backend
    restart: unless-stopped
 
  # Backend — Python API
  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache
    restart: unless-stopped
 
  # Database — PostgreSQL
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
    volumes:
      - postgres-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    restart: unless-stopped
 
  # Cache — Redis
  cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    restart: unless-stopped
 
volumes:
  postgres-data:

Команды Docker Compose

# Запуск всех сервисов (в фоновом режиме)
docker compose up -d
 
# Просмотр состояния сервисов
docker compose ps
 
# Просмотр всех логов
docker compose logs -f
 
# Просмотр логов только backend
docker compose logs -f backend
 
# Остановка и удаление всех сервисов
docker compose down
 
# Остановка сервисов + удаление volume
docker compose down -v

О depends_on: depends_on определяет лишь порядок запуска контейнеров. Он не ждёт готовности базы данных. В production используйте healthcheck или скрипты wait-for-it.


Docker Hub

Docker Hub — это крупнейший публичный registry для хранения и распространения Docker-образов. Он подобен GitHub, но для Docker-образов.

Работа с Docker Hub

# Вход в Docker Hub
docker login -u username
 
# Тегирование образа (в формате Docker Hub)
docker tag my-app:latest username/my-app:v1.0
 
# Загрузка образа в registry
docker push username/my-app:v1.0
 
# Скачивание образа из registry
docker pull username/my-app:v1.0
 
# Выход из Docker Hub
docker logout

Official vs User Image

ТипФорматПримерНадёжность
Officialimage:tagnginx:latest, postgres:16Проверен Docker, безопасен
Useruser/image:tagismoilovdev/my-app:v1Создан пользователем
Organizationorg/image:tagbitnami/postgresql:16Создан организацией

Безопасность: При загрузке образов из Docker Hub всегда используйте Official образы или образы из доверенных источников. Неизвестные образы могут содержать вредоносный код!


Как Docker используется в реальной жизни?

1. Среда разработки

Когда новый разработчик присоединяется к команде, он настраивает всё окружение с помощью Docker за считанные секунды:

# Первый день нового разработчика:
git clone https://github.com/company/project.git
cd project
docker compose up -d
 
# Готово! База данных, Redis, API — всё работает

2. CI/CD Pipeline

При каждом git push Docker-образ автоматически собирается и разворачивается:

Developer → git push → CI Server → docker build → docker push → Deploy

                        ┌─────────────────────────────────────────┘

              ┌─────────────────┐
              │   Production    │
              │   Server        │
              │                 │
              │  docker pull    │
              │  docker run     │
              └─────────────────┘

3. Microservice-архитектура

Крупное приложение разделяется на небольшие, независимые сервисы:

┌──────────────────────────────────────────────────┐
│                  Kubernetes Cluster              │
│                                                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐        │
│  │  Auth    │  │  Orders  │  │ Payments │        │
│  │ Service  │  │ Service  │  │ Service  │        │
│  │ (Go)     │  │ (Python) │  │ (Java)   │        │
│  └──────────┘  └──────────┘  └──────────┘        │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐        │
│  │  Email   │  │  Search  │  │   API    │        │
│  │ Service  │  │ Service  │  │ Gateway  │        │
│  │ (Node)   │  │ (Rust)   │  │ (Nginx)  │        │
│  └──────────┘  └──────────┘  └──────────┘        │
│                                                  │
│  Каждый сервис в своём Docker-контейнере         │
└──────────────────────────────────────────────────┘

4. Тестирование и QA

# Параллельное тестирование разных версий
docker run -d -p 8001:80 my-app:v1.0
docker run -d -p 8002:80 my-app:v2.0-beta
docker run -d -p 8003:80 my-app:v2.0-rc1
 
# После завершения тестов — полная очистка
docker stop $(docker ps -q) && docker rm $(docker ps -aq)

Экосистема Docker

Вокруг Docker сформировалась обширная экосистема. Полезно ознакомиться со следующими инструментами:

ИнструментНазначение
Docker ComposeУправление многоконтейнерными приложениями
Docker SwarmВстроенный инструмент оркестрации кластеров Docker
Kubernetes (K8s)Самая популярная платформа оркестрации контейнеров
HarborПриватный container registry (проект CNCF)
PodmanАльтернатива Docker (daemonless, rootless)
BuildahИнструмент для сборки OCI-образов
SkopeoКопирование и инспекция container-образов
TrivyСканер уязвимостей container-образов
DiveАнализ слоёв Docker-образа

Заключение

Docker — один из ключевых инструментов современной разработки и развёртывания программного обеспечения. В данном руководстве вы изучили основные концепции Docker:

  • Контейнеризация — запуск приложений в изолированных окружениях
  • Docker Image — read-only шаблон для создания контейнеров
  • Docker Container — запущенный экземпляр образа
  • Dockerfile — инструкции для создания образа
  • Docker Volume — постоянное хранение данных
  • Docker Network — коммуникация между контейнерами
  • Docker Compose — управление многосервисными приложениями

Следующие шаги:

  1. Установка Docker на серверы Linux (opens in a new tab) — установите Docker и начните практику
  2. Написание Dockerfile (opens in a new tab) — создавайте собственные образы
  3. Команды Docker (opens in a new tab) — полностью освойте Docker CLI

Дополнительно