Docker — контейнеризация приложений
Docker позволяет упаковывать приложение вместе с его окружением в изолированный контейнер и запускать его одинаково на любой машине. Это решает проблему «работает на моей машине».
1. Что такое Docker и зачем он нужен
У любого приложения есть зависимости: нужные версии Python, системные библиотеки, конфигурационные файлы, базы данных. Когда приложение переезжает на другую машину, что-то обязательно ломается. Это классическая проблема «работает на моей машине».
Docker решает её с помощью контейнеров — лёгких изолированных окружений, в которые упаковывается приложение вместе со всеми зависимостями. Контейнер содержит всё необходимое и работает одинаково на компьютере разработчика и на сервере.
Контейнеры vs виртуальные машины
Часто контейнеры путают с виртуальными машинами (ВМ). Принципиальная разница в том, что ВМ запускают отдельную операционную систему целиком, а контейнеры используют ядро хост-системы.
| Характеристика | Контейнер | Виртуальная машина |
|---|---|---|
| Операционная система | общая с хостом | полная своя ОС |
| Размер | мегабайты | гигабайты |
| Время запуска | секунды | минуты |
| Потребление ресурсов | минимальное | высокое |
| Изоляция | на уровне процессов | полная |
Образы и контейнеры
В Docker есть два ключевых понятия:
- Образ (image) — неизменяемый шаблон, из которого создаются контейнеры. Это «рецепт» или класс.
- Контейнер — запущенный экземпляр образа. Это «блюдо» или объект.
2. Установка Docker
Самый простой способ установить Docker на Windows или macOS — Docker Desktop. Это приложение с графическим интерфейсом, которое включает сам движок Docker и удобное управление контейнерами.
После установки проверь, что Docker работает:
docker --version
# Docker version 27.0.3, build 7d4bcd8
docker run hello-worldКоманда docker run hello-world скачает тестовый образ и запустит его. Если в терминале появилось приветственное сообщение, значит, установка прошла успешно.
3. Образы и реестры
Образы хранятся в реестрах — серверах для распространения контейнеров. Самый известный реестр — Docker Hub (hub.docker.com), где собраны тысячи готовых образов: Python, Node.js, PostgreSQL, Nginx и другие.
Скачивание образов
docker pull python:3.12-slim
docker pull nginx:alpineПосмотреть локальные образы можно командой docker images:
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# python 3.12-slim 88bd7dbe0e15 2 weeks ago 147MB
# nginx alpine 3f8a86689cx9 3 weeks ago 42MBТеги образов
У образов есть теги — версии. Запись nginx:alpine означает образ nginx с тегом alpine (лёгкая редакция на базе Alpine Linux). Если тег не указан, по умолчанию берётся latest.
-slim и -alpine — они заметно меньше по размеру.Загрузка своих образов
Если хочешь поделиться своим образом, сначала создай аккаунт на Docker Hub, затем войди и выполни команды:
docker login
docker push yourname/myapp:1.04. Запуск контейнеров
Основная команда для запуска контейнера — docker run. Разберём её флаги на примере веб-сервера Nginx:
docker run -d -p 8080:80 --name my-web nginx:alpine-d— запустить контейнер в фоновом режиме (detached).-p 8080:80— пробросить порт: внешний 8080 на внутренний 80.--name my-web— дать контейнеру имя.
Теперь сайт доступен по адресу http://localhost:8080.
Тома и переменные окружения
Для передачи переменных окружения используется флаг --env (или короткий -e):
docker run -d -p 5432:5432 --name my-db \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD=secret \
postgres:16Чтобы данные не терялись при пересоздании контейнера, монтируют тома флагом -v:
docker run -d -v pgdata:/var/lib/postgresql/data postgres:16Управление контейнерами
docker ps # список запущенных контейнеров
docker ps -a # список всех контейнеров
docker stop my-web # остановить
docker start my-web # снова запустить
docker rm my-web # удалить контейнер5. Dockerfile
Dockerfile — текстовый файл с инструкциями по сборке образа. Он определяет базовый образ, копирует код, устанавливает зависимости и задаёт команду запуска. Создадим образ для простого Python-приложения.
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8000
CMD ["python", "app.py"]Ключевые инструкции
| Инструкция | Назначение |
|---|---|
| FROM | базовый образ, с которого начинается сборка |
| WORKDIR | рабочая директория внутри контейнера |
| COPY | копирование файлов из хоста в образ |
| RUN | выполнение команды во время сборки |
| EXPOSE | указать порт, который слушает приложение (документация) |
| CMD | команда по умолчанию при запуске контейнера |
| ENTRYPOINT | фиксированная команда, которую нельзя легко переопределить |
Разница между CMD и ENTRYPOINT: CMD можно переопределить при запуске (docker run image команда), а ENTRYPOINT всегда выполняется, а аргументы лишь добавляются к нему.
6. Сборка образа
Образ собирается командой docker build. Параметр -t задаёт имя и тег, а точка в конце указывает на директорию с Dockerfile:
docker build -t myapp:1.0 .Если нужно пересобрать без использования кэша:
docker build --no-cache -t myapp:1.0 .Слои и кэширование
Каждая инструкция в Dockerfile создаёт слой (layer). Docker кэширует слои, поэтому при повторной сборке пересобираются только изменённые шаги, а неизменённые берутся из кэша. Это сильно ускоряет сборку.
docker build -t myapp:1.0 .
docker build -t myapp:1.1 .
# Вторая сборка использует кэш, пока не дойдёт до COPY app.py7. Тома и сети
Том (volume) — специальное хранилище, которое переживает жизнь контейнера. Именно туда стоит класть базы данных и пользовательские файлы.
Создать именованный том и подключить его к контейнеру:
docker volume create mydata
docker run -d -v mydata:/app/data myapp:1.0Можно монтировать и обычную папку с хоста (bind mount) — удобно при разработке, когда код меняется без пересборки образа:
docker run -v /полный/путь/на/хосте:/app myapp:1.0Сети
Контейнеры могут общаться между собой по сети. По умолчанию Docker создаёт сеть bridge. Посмотреть сети и создать новую:
docker network ls
docker network create mynet
docker run -d --network mynet --name web myapp:1.0
docker run -d --network mynet --name db postgres:16web может подключиться к db по адресу db:5432.8. Логи и отладка
Просмотр логов контейнера — первое, что нужно сделать при диагностике. Флаг -f следит за логами в реальном времени:
docker logs my-web
docker logs -f my-web # читать логи непрерывно
docker logs --tail 100 my-web # последние 100 строкЗапуск команд внутри контейнера
Чтобы зайти в запущенный контейнер и выполнять команды, используется docker exec:
docker exec -it my-web bash
docker exec my-web python app.py --help-it (интерактивный режим + выделенный псевдотерминал) нужен для входа в оболочку. Без него команда не начнёт интерактивную сессию.Анализ образа и ресурсов
docker inspect показывает подробную информацию о контейнере или образе в формате JSON, а docker stats — живые показатели использования CPU и памяти:
docker inspect my-web
docker stats9. docker-compose
Приложение часто состоит из нескольких сервисов: веб-сервер, база данных, кэш. Запускать их по отдельности неудобно. docker-compose позволяет описать все сервисы в одном файле и управлять ими одной командой.
Файл docker-compose.yml для приложения Python с PostgreSQL и Redis:
version: "3.9"
services:
web:
build: .
ports:
- "8000:8000"
depends_on:
- db
- redis
db:
image: postgres:16
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:alpine
volumes:
pgdata:Основные команды compose
docker-compose up -d # запустить все сервисы в фоне
docker-compose down # остановить и удалить контейнеры
docker-compose logs -f # логи всех сервисов
docker-compose exec web bash # команда внутри сервиса web
docker-compose ps # статус сервисовdepends_on указывает порядок запуска: web начнётся только после db и redis. Имена сервисов используются как DNS-имена внутри сети compose.10. Чистка и лучшие практики
Со временем накапливаются неиспользуемые образы, контейнеры и тома. Очистить систему помогает одна команда:
docker system prune -a-a удаляет все неиспользуемые образы, включая те, на которые нет ссылок. Проверь, что не удаляешь нужное.Рекомендации
- Один процесс в контейнере — контейнер выполняет одну задачу (веб-сервер, воркер, базу данных — отдельно).
- Используй .dockerignore — файл, который исключает ненужные файлы (кэш, venv, .git) из сборки.
- Не запускай процессы от root — создавай отдельного пользователя в Dockerfile.
- Минимизируй размер образа — используй slim-версии и мультистейдж сборки.
Пример .dockerignore:
__pycache__/
*.pyc
.git/
venv/
.envМультистейдж сборка (кратко)
Мультистейдж собирает образ в несколько этапов: на первом этапе компилируется и устанавливается приложение со всеми зависимостями, а в итоговый образ копируются только необходимые артефакты. В результате финальный образ получается маленьким.
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o app main.go
FROM alpine:latest
COPY --from=builder /src/app /app
CMD ["/app"]11. Docker в CI/CD и рабочий процесс
Docker — ключевая часть современных пайплайнов непрерывной интеграции и доставки (CI/CD). Образ собирается автоматически при каждом изменении кода и затем разворачивается на серверах.
В GitLab пайплайн настраивается с помощью GitLab Runner и файла .gitlab-ci.yml. Типичный этап сборки и публикации образа:
build:
image: docker:27
services:
- docker:27-dind
script:
- docker build -t registry.example.com/myapp:$CI_COMMIT_SHA .
- docker push registry.example.com/myapp:$CI_COMMIT_SHAПосле сборки образ загружается в реестр, откуда его забирают при деплое на сервер или в оркестратор.
Оркестрация
Запускать контейнеры в продакшене на десятках серверов вручную невозможно. Для этого существуют оркестраторы:
- Docker Compose — для небольших проектов на одной машине.
- Amazon ECS — управляемый сервис контейнеров в AWS.
- Kubernetes (K8s) — самый популярный оркестратор, автоматизирует развёртывание, масштабирование и управление контейнерными кластерами.
12. Переменные окружения и .env
Контейнеры не должны содержать секреты в образе. Конфигурацию передают переменными окружения:
docker run -e DATABASE_URL=postgres://db:5432/app myapp
docker run --env-file .env myappФайл .env описывает значения для запуска:
# .env — не коммить в репозиторий
DB_HOST=db
DB_PORT=5432
SECRET_KEY=super-secretВ compose переменные подставляются автоматически и доступны в контейнерах:
services:
web:
build: .
env_file: .env
ports: ["8080:80"].env.example с именами переменных без значений, а реальные секреты — вне git.13. Healthcheck и политики перезапуска
Docker может проверять здоровье контейнера и перезапускать упавшие сервисы:
docker run -d \
--restart unless-stopped \
--health-cmd="curl -f http://localhost/health" \
--health-interval=10s \
--health-retries=5 \
myapp| Политика | Поведение |
|---|---|
| no | не перезапускать (по умолчанию) |
| on-failure[:n] | только при ошибке, максимум n раз |
| always | перезапускать всегда |
| unless-stopped | кроме явной остановки |
docker inspect --format "{{.State.Health.Status}}" myapp14. Ресурсы и безопасность контейнеров
Ограничение ресурсов защищает хост от «жадного» приложения:
docker run -d \
--memory=512m \
--cpus=1.0 \
--pids-limit=256 \
--read-only \
myappservices:
web:
image: myapp
mem_limit: 512m
cpu_shares: 512
read_only: true # приложение может писать только в тома- запускай сервисы от не-root пользователя (USER в Dockerfile);
- минимальные права:
--cap-drop=ALLи точечные добавления; - обновляй образы:
docker image pruneи сканеры уязвимостей (trivy); - не публикуй порты наружу без нужды.
15. Диагностика: events, stats, top
Когда что-то идёт не так, помогают живые команды Docker:
docker events # поток событий: старт/стоп/крэш
docker stats # CPU/память/сеть в реальном времени
docker top myapp # процессы внутри контейнера
docker inspect myapp # полная конфигурация и Health# последние логи с временными метками и фильтром по строке
docker logs -f --timestamps myapp | grep -i errordocker stats до и после нагрузки; рост RSS выше лимита — прямой сигнал к настройке ООМKill и ограничений памяти.16. Анализ состава образа и сканеры уязвимостей
Образ — это слои поверх базового образа. Посмотри, из чего он собран:
docker history myapp:latest # слои и команды, которые их создали
docker image inspect myapp # метаданные, env, entrypoint- утилита
diveинтерактивно показывает вес слоёв и что можно выкинуть; - объединяй команды в один слой и убирай временные файлы установки;
- сканеры уязвимостей:
trivy image myappнаходит известные CVE в образе; - установщик зависимостей лучше pin версиями, а не «latest».
trivy image --severity HIGH,CRITICAL myapp:latest17. Разработка с горячей перезагрузкой в контейнере
Для быстрого цикла правка-перезагрузка не нужно пересобирать образ: смонтируй исходники в контейнер и дай процессу следить за файлами:
services:
web:
build: .
volumes:
- ./src:/app/src # исходники с хоста
command: npm run dev # nodemon / --watch перезапускает сервисdocker compose watch # докеризированный горячий reload- тома перекрывают файлы образа: установленные пакеты остаются в образе;
- не монтируй
node_modulesс хоста — он может отличаться (бинарные зависимости); - убедись, что изменение файла на Windows доходит до контейнера (настрой WSL2/watch polling).
18. Мультиархитектурные образы и buildx
Один тег образа должен работать на разных платформах: ARM-серверы и Raspberry Pi не всегда умеют x86. Сборка нескольких архитектур и публикация единого манифеста делается через buildx:
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t user/myapp:latest --push .- включи QEMU-эмуляцию:
docker run --privileged --rm tonistiigi/binfmt; - проверь, что base image поддерживает обе архитектуры или используй
FROM --platform=$BUILDPLATFORMдля билд-этапа; - манифест с multi-platform позволяет CI автоматически выбрать вариант под раннер/GitHub.
docker buildx ls # посмотри активные билд-стейджы19. Путь к Kubernetes: от compose к манифестам
Compose удобен для одного хоста; рост нагрузки требует оркестратора. Начни с локального Kubernetes:
# kind: кластер в Docker за пару минут
kind create cluster --name dev
kubectl get nodesminikube— кластер с одной ноды для изучения,k3s— лёгкий для продакшена на краю;- компоненты: Deployment (желаемое состояние), Service (доступ), ConfigMap/Secret (конфигурация);
- манифест компилируется из compose утилитами (
kompose convert) как стартовая точка.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 2
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: user/myapp:latest20. Секреты при сборке: BuildKit --secret
Ключи в Dockerfile оседают в истории слоёв — никогда так не делай. BuildKit передаёт секреты без попадания в слой:
# docker build --secret id=npm_token,src=./.npmrc.secret
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci- секрет виден только во время шага сборки и в слой не попадает;
- в рантайме — env-файл или secret store, а не ARG;
- проверяй слои:
docker historyи сканеры из раздела 16.
21. Docker-сети в деталях
Сеть решает, кто с кем говорит. Три драйвера покрывают 95% задач:
docker network create -d bridge mynet
docker network inspect mynet --format '{{json .Containers}}'- bridge — изолированная сеть контейнеров с DNS по имени сервиса;
- host — общий стек с хостом: скорость без NAT, но без изоляции портов;
- macvlan — контейнеру настоящий IP в локальной сети.
docker run --network mynet --name api app:1
# внутри сети: curl http://api:808022. База данных в контейнере: бэкап
PostgreSQL в контейнере — норма для разработки, но данные нужно беречь:
docker exec db pg_dump -U app mydb | gzip > backup.sql.gz
gunzip -c backup.sql.gz | docker exec -i db psql -U app mydb- данные БД всегда в именованном томе — контейнер удаляется и пересоздаётся;
- бэкап до
docker compose down— консистентность гарантирована; - для серьёзных инсталляций — pgbackrest или снапшоты ниже уровня Docker.
23. Чек-лист: контейнер не запускается
Сценарий «docker run падает» отработан многими до тебя. Проходи по порядку:
docker logs <id>— первый и главный источник;docker inspect: статус, exit code, переменные, mounts, health;- запусти с
-it --entrypoint /bin/sh— проверь окружение вручную; - сверь порты:
-p 3000:8080— «хост : контейнер».
docker run --rm -it --entrypoint /bin/sh myimage
# вручную: env | grep и запуск процесса рукамиЧто дальше
Ты освоил базовый набор Docker: образы, контейнеры, Dockerfile, тома, сети и docker-compose. Рекомендуемый следующий шаг — собрать и задеплоить своё Flask или FastAPI-приложение в контейнере, а затем настроить автоматическую сборку через GitLab.