Команды Docker: шпаргалка с примерами для сервера и продакшена

Команды Docker: шпаргалка с примерами для сервера и продакшена
Коротко: что здесь есть
Полный справочник команд Docker с примерами из реальных сценариев. Контейнеры, образы, сети, тома, compose, очистка, безопасность и troubleshooting. Копируй команду — выполняй — проверяй результат. Без предисловий на трёх страницах.

Ты поднял контейнер — что-то не работает. Или работает, но непонятно как. Или работало, а потом перестало. Эта шпаргалка закроет 90% вопросов по Docker которые возникают в реальной работе на сервере.

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

Что понадобится: сервер или VPS с Ubuntu/Debian/CentOS, root или sudo, установленный Docker. Установку разберём отдельным блоком.

Время на освоение: зависит от задачи. Базовые команды — 20 минут. Compose и сети — ещё час. Полный справочник оставь открытым и возвращайся по мере необходимости.

Содержание

  • Архитектура Docker: как это работает
  • Установка Docker на Ubuntu и Debian
  • Системные команды: daemon, info, версия
  • Образы: pull, build, tag, push
  • Контейнеры: run, ps, exec, stop, rm
  • Логи и диагностика
  • Volumes: хранение данных
  • Networks: связь между контейнерами
  • Docker Compose: запуск стека
  • Dockerfile: собрать образ своими руками
  • Продакшен: лимиты, рестарт, безопасность
  • Очистка и обслуживание
  • Troubleshooting
  • FAQ

Архитектура Docker: как это работает

Прежде чем копировать команды — одна минута на структуру. Это сэкономит час отладки позже.

%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#ffffff',
    'primaryTextColor': '#1e293b',
    'primaryBorderColor': '#94a3b8',
    'lineColor': '#64748b',
    'fontSize': '15px',
    'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
  },
  'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart TD
    CLI["Docker CLI\ndocker run / ps / exec"] --> |"API запрос"| D["Docker Daemon\n(dockerd)"]
    D --> |"создаёт"| C1["Контейнер 1"]
    D --> |"создаёт"| C2["Контейнер 2"]
    D --> |"управляет"| I["Docker Images\n(образы)"]
    D --> |"управляет"| V["Volumes\n(данные)"]
    D --> |"управляет"| N["Networks\n(сети)"]
    C1 --> V
    C2 --> V
    C1 --> N
    C2 --> N
    style CLI fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style D fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#9a3412
    style C1 fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style C2 fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style I fill:#f8fafc,stroke:#94a3b8,stroke-width:2px,color:#1e293b
    style V fill:#f8fafc,stroke:#94a3b8,stroke-width:2px,color:#1e293b
    style N fill:#f8fafc,stroke:#94a3b8,stroke-width:2px,color:#1e293b

Docker daemon (dockerd) — это сердце системы. Он получает команды от CLI, управляет образами, контейнерами, сетями и томами. Если daemon не запущен — ничего не работает вообще. Первая точка проверки при любой проблеме.

Образ (image) — шаблон. Неизменяемый. Из одного образа можно запустить сколько угодно контейнеров.

Контейнер (container) — запущенный экземпляр образа. Изолированный процесс с собственной файловой системой. Останови его — данные внутри исчезнут, если не используешь volume.

Volume — постоянное хранилище, живёт отдельно от контейнера. База данных без volume — это не продакшен, это лотерея.

Установка Docker на Ubuntu и Debian

Есть два пути: docker.io из репозитория дистрибутива и официальный репозиторий Docker Inc. Первый — проще. Второй — свежее версия и это важно если используешь Compose v2 или BuildKit.

Вариант 1: из репозитория Ubuntu/Debian (проще)


apt update && apt upgrade -y
apt install -y docker.io
systemctl start docker
systemctl enable docker

Вариант 2: официальный репозиторий Docker (рекомендую для продакшена)


# Убираем старые версии если есть
apt remove docker docker-engine docker.io containerd runc 2>/dev/null

# Зависимости
apt update
apt install -y ca-certificates curl gnupg lsb-release

# GPG ключ
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg

# Репозиторий
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

# Установка
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Проверяем установку


docker --version
docker info
systemctl status docker

После docker --version должна появиться версия. После docker info — подробная информация о системе, контейнерах, образах, хранилище. Если вылезло Cannot connect to the Docker daemon — daemon не запущен, смотри следующий раздел.

Добавляем пользователя в группу docker

Чтобы не запускать каждую команду через sudo:


usermod -aG docker $USER
newgrp docker
Перезайди в сессию
После добавления в группу нужно выйти и зайти заново или выполнить newgrp docker. Иначе права не применятся и docker команды будут давать permission denied.

Таблица: совместимость версий

ОС Версия Docker CE Compose Plugin
Ubuntu 22.04 LTS 24.x, 25.x, 26.x v2.x
Ubuntu 24.04 LTS 26.x, 27.x v2.x
Debian 11 (Bullseye) 24.x, 25.x v2.x
Debian 12 (Bookworm) 26.x, 27.x v2.x
CentOS/RHEL 8, 9 25.x, 26.x v2.x

На момент публикации актуальна версия Docker 27.x. Перед установкой проверь свежие релизы на docs.docker.com/engine/release-notes.

Системные команды: daemon, info, версия

Управление daemon через systemctl


# Статус
systemctl status docker

# Запуск
systemctl start docker

# Перезапуск
systemctl restart docker

# Остановка
systemctl stop docker

# Автозапуск при старте системы
systemctl enable docker

# Отключить автозапуск
systemctl disable docker

Информация о системе


# Версия клиента и сервера
docker version

# Подробная инфо: контейнеры, образы, хранилище, драйвер
docker info

# Использование диска Docker
docker system df

# Подробно с размерами
docker system df -v

Команда docker system df покажет сколько места занимают образы, контейнеры, volumes и build cache. На серверах которые давно не чистили цифра бывает неприятно большой.

Логи docker daemon


# Логи daemon в journald
journalctl -u docker

# Последние 100 строк
journalctl -u docker -n 100

# В реальном времени
journalctl -u docker -f

Образы: pull, build, tag, push

Работа с Docker Hub


# Скачать образ последней версии
docker pull nginx

# Конкретная версия (тег)
docker pull nginx:1.25

# Конкретная версия под архитектуру
docker pull --platform linux/amd64 nginx:1.25

# Список скачанных образов
docker images

# Подробный список с датами
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}"

# Удалить образ
docker rmi nginx:1.25

# Удалить образ принудительно (если используется контейнером)
docker rmi -f nginx:1.25

Поиск образов


# Поиск на Docker Hub
docker search nginx

# Только официальные образы
docker search --filter is-official=true nginx

Авторизация в реестре


# Docker Hub
docker login

# Приватный реестр
docker login registry.example.com

# Выйти
docker logout

Tag и push


# Пометить образ своим тегом
docker tag nginx:latest myregistry.com/myapp:1.0

# Отправить в реестр
docker push myregistry.com/myapp:1.0

Инспект образа


# Метаданные образа
docker inspect nginx

# Только конкретное поле (например, переменные окружения)
docker inspect --format='{{.Config.Env}}' nginx

# История слоёв образа
docker history nginx

Контейнеры: run, ps, exec, stop, rm

Это основа. Здесь половина всех команд которые ты будешь использовать каждый день.

docker run: запуск контейнера


# Простой запуск (в foreground, Ctrl+C останавливает)
docker run nginx

# Фоновый режим (detached)
docker run -d nginx

# С именем
docker run -d --name web nginx

# Проброс порта: порт_хоста:порт_контейнера
docker run -d -p 8080:80 --name web nginx

# Переменные окружения
docker run -d -e MY_VAR=value --name web nginx

# Несколько переменных
docker run -d -e DB_HOST=localhost -e DB_PORT=5432 --name app myapp

# Монтирование директории хоста
docker run -d -v /host/path:/container/path nginx

# Монтирование volume
docker run -d -v myvolume:/data nginx

# Автоматически удалять контейнер после остановки
docker run --rm nginx

# Интерактивный режим (зайти внутрь сразу)
docker run -it ubuntu bash

# Ограничение памяти
docker run -d --memory="512m" nginx

# Ограничение CPU
docker run -d --cpus="1.5" nginx

# Политика рестарта
docker run -d --restart=always nginx

# Подключить к сети
docker run -d --network mynetwork nginx

Флаги -d и -it не совместимы как основной режим: -d запускает в фоне, -it открывает терминал. Для продакшена почти всегда -d. Для отладки — -it --rm.

Таблица: политики рестарта

Политика Поведение Когда использовать
no Не перезапускать (по умолчанию) Разработка, тестовые запуски
always Всегда перезапускать Продакшен сервисы
unless-stopped Перезапускать, кроме ручной остановки Продакшен, гибкий контроль
on-failure Перезапускать только при ненулевом exit code Задачи с обработкой ошибок
on-failure:3 Не более 3 попыток перезапуска Предотвращение restart loop

Управление запущенными контейнерами


# Список запущенных контейнеров
docker ps

# Все контейнеры включая остановленные
docker ps -a

# Только ID контейнеров
docker ps -q

# Форматированный вывод
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# Остановить контейнер (SIGTERM, ждёт 10 секунд)
docker stop web

# Остановить немедленно (SIGKILL)
docker kill web

# Запустить остановленный
docker start web

# Перезапустить
docker restart web

# Пауза / снятие паузы
docker pause web
docker unpause web

# Переименовать
docker rename web web-old

# Удалить остановленный контейнер
docker rm web

# Удалить принудительно (работающий)
docker rm -f web

# Удалить все остановленные контейнеры
docker container prune

# Инспект контейнера (полная информация)
docker inspect web

# Статистика ресурсов в реальном времени
docker stats

# Статистика одного контейнера без обновления
docker stats web --no-stream

# Процессы внутри контейнера
docker top web

docker exec: работа внутри контейнера


# Зайти в bash
docker exec -it web bash

# Если bash не установлен - sh
docker exec -it web sh

# Выполнить одну команду
docker exec web nginx -t

# Выполнить команду от имени конкретного пользователя
docker exec -u www-data web whoami

# Открыть ещё один терминал в уже подключённой сессии
docker exec -it web bash

Если контейнер отвечает на docker exec -it web bash ошибкой OCI runtime exec failed — контейнер либо не запущен, либо bash в нём нет. Проверь через docker ps что он вообще работает.

Копирование файлов


# Скопировать файл из контейнера на хост
docker cp web:/etc/nginx/nginx.conf ./nginx.conf

# Скопировать файл с хоста в контейнер
docker cp ./nginx.conf web:/etc/nginx/nginx.conf

# Скопировать директорию
docker cp web:/var/log/nginx/ ./logs/

Логи и диагностика

Команды для работы с логами


# Показать все логи контейнера
docker logs web

# Последние N строк
docker logs web --tail 100

# Следить в реальном времени (как tail -f)
docker logs -f web

# С временными метками
docker logs -t web

# Логи за последний час
docker logs --since 1h web

# Логи с определённого времени
docker logs --since "2024-01-15T10:00:00" web

# Логи между двумя временными точками
docker logs --since 2h --until 1h web

Диагностика без захода внутрь


# Полный инспект контейнера в JSON
docker inspect web

# IP адрес контейнера
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web

# Подключённые порты
docker inspect -f '{{.NetworkSettings.Ports}}' web

# Переменные окружения
docker inspect -f '{{.Config.Env}}' web

# Смонтированные тома
docker inspect -f '{{.Mounts}}' web

# События в реальном времени (старт/стоп контейнеров и т.п.)
docker events

# События за последние 30 минут
docker events --since 30m

Volumes: хранение данных

Всё что записывается внутрь контейнера — исчезает при его удалении. Volumes решают эту проблему. Для баз данных, конфигов и любых данных которые должны пережить перезапуск контейнера — только volumes.

Управление volumes


# Создать volume
docker volume create pgdata

# Список volumes
docker volume ls

# Инспект volume (где хранится, кто использует)
docker volume inspect pgdata

# Удалить volume
docker volume rm pgdata

# Удалить все неиспользуемые volumes
docker volume prune

# Удалить volume принудительно
docker volume rm -f pgdata

Типы монтирования


# Volume (рекомендуется для данных)
docker run -d -v pgdata:/var/lib/postgresql/data postgres

# Bind mount (конкретная папка хоста)
docker run -d -v /home/user/data:/app/data myapp

# Tmpfs mount (только в RAM, не сохраняется)
docker run -d --tmpfs /tmp myapp

# Только чтение
docker run -d -v /host/config:/app/config:ro myapp

Где физически лежат volumes


# Путь на хосте
docker volume inspect pgdata --format '{{.Mountpoint}}'
# Обычно: /var/lib/docker/volumes/pgdata/_data

Backup и восстановление volume


# Создать бэкап volume в tar.gz
docker run --rm \
  -v pgdata:/data \
  -v $(pwd):/backup \
  ubuntu tar czf /backup/pgdata-backup.tar.gz -C /data .

# Восстановить из бэкапа
docker run --rm \
  -v pgdata:/data \
  -v $(pwd):/backup \
  ubuntu bash -c "cd /data && tar xzf /backup/pgdata-backup.tar.gz"

Команда создаёт временный контейнер ubuntu, монтирует в него volume и директорию хоста, упаковывает данные в архив. Контейнер удаляется сам после завершения — за это отвечает --rm.

Бэкап баз данных
Для PostgreSQL и MySQL не используй прямой backup volume файлов пока база запущена. Используй pg_dump или mysqldump. Бэкап файлов на работающей БД может дать повреждённые данные. Это не параноя, это стандарт.

Networks: связь между контейнерами

По умолчанию контейнеры могут общаться только внутри одной сети. Правильно организованные сети — это ещё и изоляция: database не должна быть доступна снаружи, только из app-контейнера.

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


# Список сетей
docker network ls

# Создать bridge сеть
docker network create backend

# Создать с настройками подсети
docker network create --subnet=172.20.0.0/24 backend

# Инспект сети
docker network inspect backend

# Удалить сеть
docker network rm backend

# Удалить все неиспользуемые сети
docker network prune

Типы сетей

Тип Описание Когда использовать
bridge Изолированная сеть на хосте (по умолчанию) Большинство сценариев
host Контейнер использует сеть хоста напрямую Высокая производительность, осторожно с безопасностью
none Нет сети Полная изоляция
overlay Сеть между несколькими хостами Docker Swarm, multi-host
macvlan Контейнер получает MAC-адрес в физической сети Legacy системы, требующие Layer 2

Подключение контейнеров к сети


# Запустить контейнер сразу в нужной сети
docker run -d --name db --network backend postgres

# Подключить работающий контейнер к сети
docker network connect backend web

# Отключить контейнер от сети
docker network disconnect backend web

# Контейнер в нескольких сетях
docker network connect frontend web

Связь между контейнерами

Контейнеры в одной user-defined сети могут обращаться друг к другу по имени. Это автоматический DNS внутри Docker.

%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#ffffff',
    'primaryTextColor': '#1e293b',
    'primaryBorderColor': '#94a3b8',
    'lineColor': '#64748b',
    'fontSize': '15px',
    'fontFamily': 'ui-sans-serif, system-ui, sans-serif'
  },
  'flowchart': {'curve': 'linear', 'nodeSpacing': 50, 'rankSpacing': 50}
}}%%
flowchart LR
    U["Пользователь\n:80"] --> |"порт 80"| N["Nginx\ncontainer"]
    N --> |"backend сеть\napp:8000"| A["App\ncontainer"]
    A --> |"backend сеть\ndb:5432"| D["PostgreSQL\ncontainer"]
    style U fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#1e40af
    style N fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style A fill:#f8fafc,stroke:#22c55e,stroke-width:2px,color:#15803d
    style D fill:#f8fafc,stroke:#f97316,stroke-width:2px,color:#9a3412

# Пример: app обращается к db по имени "db"
docker run -d --name db --network backend \
  -e POSTGRES_PASSWORD=secret postgres

docker run -d --name app --network backend \
  -e DB_HOST=db \
  -e DB_PORT=5432 \
  myapp

Обрати внимание: DB_HOST=db — это именно имя контейнера. Docker внутри сети разрешает имена контейнеров в IP адреса автоматически. Никаких hosts файлов, никаких ручных IP.

Dockerfile: собрать образ

Dockerfile — текстовый файл с инструкциями для сборки образа. Каждая инструкция создаёт новый слой. Слои кэшируются — поэтому порядок инструкций влияет на скорость повторных сборок.

Базовая структура Dockerfile


# Базовый образ
FROM ubuntu:22.04

# Метаданные
LABEL maintainer="admin@example.com"

# Переменные сборки
ARG APP_VERSION=1.0

# Переменные окружения
ENV APP_HOME=/app

# Рабочая директория
WORKDIR /app

# Копировать файлы
COPY . .

# Установка зависимостей
RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

# Установить зависимости Python
RUN pip3 install -r requirements.txt

# Открыть порт (документация, не реальный проброс)
EXPOSE 8000

# Пользователь для запуска (не root!)
USER nobody

# Команда запуска
CMD ["python3", "app.py"]

Сборка образа


# Собрать с тегом
docker build -t myapp:1.0 .

# Собрать из конкретного Dockerfile
docker build -f Dockerfile.prod -t myapp:prod .

# Без кэша
docker build --no-cache -t myapp:1.0 .

# С аргументами сборки
docker build --build-arg APP_VERSION=2.0 -t myapp:2.0 .

# Посмотреть слои при сборке
docker build --progress=plain -t myapp:1.0 .

Многоступенчатая сборка (multi-stage build)

Уменьшает итоговый размер образа: в первом этапе компилируем, во второй копируем только бинарник.


# Этап 1: сборка
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .

# Этап 2: финальный образ
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]

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

Docker Compose: запуск стека

Compose позволяет описать несколько сервисов в одном файле и запустить их одной командой. Версия 2 (compose plugin) встроена в Docker и вызывается через docker compose без дефиса.

Базовый docker-compose.yml


version: "3.8"

services:
  web:
    image: nginx:1.25
    container_name: web
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./html:/usr/share/nginx/html:ro
    networks:
      - frontend
    depends_on:
      - app

  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: app
    restart: unless-stopped
    environment:
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=mydb
      - DB_USER=appuser
      - DB_PASSWORD=${DB_PASSWORD}
    networks:
      - frontend
      - backend
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    container_name: db
    restart: unless-stopped
    environment:
      - POSTGRES_DB=mydb
      - POSTGRES_USER=appuser
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d mydb"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  frontend:
  backend:

volumes:
  pgdata:
Пароли в .env файле
Переменная DB_PASSWORD берётся из файла .env в той же директории. Создай файл .env с содержимым DB_PASSWORD=yourpassword и добавь его в .gitignore. Пароли в docker-compose.yml это не практика, это катастрофа которая ждёт своего момента.

Команды Docker Compose


# Запустить стек в фоне
docker compose up -d

# Запустить с пересборкой образов
docker compose up -d --build

# Остановить стек (контейнеры останавливаются, не удаляются)
docker compose stop

# Остановить и удалить контейнеры
docker compose down

# Остановить, удалить контейнеры и volumes
docker compose down -v

# Остановить, удалить и удалить образы
docker compose down --rmi all

# Статус сервисов
docker compose ps

# Логи всех сервисов
docker compose logs

# Логи конкретного сервиса в реальном времени
docker compose logs -f app

# Зайти в контейнер сервиса
docker compose exec app bash

# Выполнить команду в сервисе
docker compose exec db psql -U appuser mydb

# Перезапустить один сервис без остановки других
docker compose restart app

# Масштабировать сервис
docker compose up -d --scale app=3

# Посмотреть переменные окружения
docker compose config

Healthcheck в Compose

Конструкция depends_on: condition: service_healthy дождётся пока база не пройдёт healthcheck перед запуском app. Без этого app стартует раньше базы и получает ошибку подключения.


healthcheck:
  test: ["CMD-SHELL", "pg_isready -U appuser -d mydb"]
  interval: 10s
  timeout: 5s
  retries: 5
  start_period: 30s

Docker для продакшена: настройки которые нельзя пропускать

Ограничения ресурсов


# Ограничение памяти и CPU через run
docker run -d \
  --name app \
  --memory="512m" \
  --memory-swap="512m" \
  --cpus="2.0" \
  --restart=unless-stopped \
  myapp

# Обновить лимиты работающего контейнера
docker update --memory="1g" --cpus="2.0" app

--memory-swap равный --memory означает что swap не используется. Если не задать — контейнер сможет использовать swap в два раза больше лимита памяти. На продакшене это нежелательно.

Настройка docker daemon для продакшена

Файл конфигурации: /etc/docker/daemon.json


{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "live-restore": true,
  "userland-proxy": false,
  "no-new-privileges": true
}

Что здесь важно:

  • log-driver: json-file + ограничения — без этого логи растут бесконечно и заполняют диск. Проверенный способ убить сервер в 3 ночи.
  • live-restore: true — контейнеры продолжают работать при перезапуске daemon. Для обновления Docker без даунтайма.
  • no-new-privileges: true — процессы внутри контейнера не могут получить новые привилегии через setuid.

# Применить изменения daemon.json
systemctl restart docker

Безопасность: минимальный набор


# Никогда не запускать как root если можно без этого
docker run -d --user 1000:1000 myapp

# Read-only файловая система
docker run -d --read-only myapp

# Запретить запись в tmp (если приложение не требует)
docker run -d --read-only --tmpfs /tmp myapp

# Без дополнительных capabilities
docker run -d --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp

# Запрет эскалации привилегий
docker run -d --security-opt no-new-privileges myapp

Firewall: порты Docker и UFW

Важно: Docker обходит UFW
Docker по умолчанию напрямую модифицирует iptables и обходит правила UFW. Если ты открыл порт через docker run -p, он будет доступен всем даже если UFW его закрывает. Чтобы этого не было — используй 127.0.0.1 для привязки портов которые не должны быть публичными.

# Привязать порт только к localhost (не публичный)
docker run -d -p 127.0.0.1:5432:5432 postgres

# Публичный порт (доступен всем)
docker run -d -p 0.0.0.0:80:80 nginx

# Или просто
docker run -d -p 80:80 nginx

Таблица портов: стандартные сервисы в Docker

Сервис Порт контейнера Рекомендуемая привязка Примечание
Nginx/Apache 80, 443 0.0.0.0:80:80 Публичный
PostgreSQL 5432 127.0.0.1:5432:5432 Только localhost
MySQL/MariaDB 3306 127.0.0.1:3306:3306 Только localhost
Redis 6379 127.0.0.1:6379:6379 Только localhost
MongoDB 27017 127.0.0.1:27017:27017 Только localhost
RabbitMQ 5672, 15672 127.0.0.1:15672:15672 Management только localhost

Очистка и обслуживание

Docker накапливает мусор: остановленные контейнеры, неиспользуемые образы, осиротевшие volumes и build cache. На серверах которые работают больше года без чистки это запросто 50+ гигабайт.


# Посмотреть что занимает место
docker system df
docker system df -v

# Удалить всё неиспользуемое (контейнеры, сети, образы без тегов, build cache)
docker system prune

# То же самое но и volumes
docker system prune --volumes

# Удалить вообще всё неиспользуемое включая образы с тегами
docker system prune -a

# Только остановленные контейнеры
docker container prune

# Только образы без тегов (dangling)
docker image prune

# Все образы без запущенных контейнеров
docker image prune -a

# Только volumes без контейнеров
docker volume prune

# Только неиспользуемые сети
docker network prune

# Только build cache
docker builder prune
docker system prune -a --volumes
Эта команда удаляет вообще всё: и образы, и тома без контейнеров. Если у тебя есть данные только в volumes без контейнера — они исчезнут. Проверь docker volume ls и сделай бэкап перед выполнением.

Автоматическая очистка через cron


# Добавить в crontab (каждое воскресенье в 3 ночи)
crontab -e

0 3 * * 0 /usr/bin/docker system prune -f >> /var/log/docker-prune.log 2>&1

Флаг -f убирает запрос подтверждения. Без него cron задача просто зависнет.

Обновление Docker и контейнеров

Обновление самого Docker


# Проверить текущую версию
docker --version

# Обновить (если ставили из официального репозитория)
apt update
apt upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Проверить что daemon работает после обновления
systemctl status docker
docker ps

Если включён live-restore: true в daemon.json — контейнеры продолжат работать во время перезапуска daemon при обновлении. Без этого флага все контейнеры остановятся.

Обновление контейнеров (вручную)


# Скачать новый образ
docker pull nginx:latest

# Остановить старый контейнер
docker stop web

# Удалить старый контейнер (данные в volumes сохранятся)
docker rm web

# Запустить с новым образом
docker run -d --name web -p 80:80 --restart=unless-stopped nginx:latest

# Удалить старый образ
docker image prune

Обновление стека через Compose


# Скачать новые образы
docker compose pull

# Пересобрать и перезапустить
docker compose up -d --build

# Только пересоздать контейнеры с новыми образами без сборки
docker compose up -d --pull always

Откат к предыдущей версии


# Посмотреть доступные теги через Hub
docker search nginx

# Запустить конкретную версию
docker run -d --name web -p 80:80 nginx:1.24

# В compose - изменить тег в файле и перезапустить
# image: nginx:1.24
docker compose up -d

Troubleshooting

Cannot connect to the Docker daemon

Daemon не запущен или нет прав.


# Проверить статус
systemctl status docker

# Запустить
systemctl start docker

# Проверить права текущего пользователя
groups $USER

# Добавить в группу docker
usermod -aG docker $USER
newgrp docker

Port is already allocated / address already in use

Порт занят другим процессом или контейнером.


# Найти что занимает порт
ss -tlnp | grep :80
lsof -i :80

# Найти контейнер который использует порт
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep 80

# Остановить конкурирующий контейнер
docker stop old_container

No space left on device

Закончилось место на диске.


# Проверить диск
df -h
du -sh /var/lib/docker/*

# Очистить Docker
docker system prune -f

# Если не помогает - смотри логи контейнеров (они могут занимать много места)
find /var/lib/docker/containers -name "*.log" -exec du -sh {} \; | sort -rh | head

Container exits immediately (exit code 1 или 137)


# Посмотреть логи остановленного контейнера
docker logs mycontainer

# Запустить интерактивно для диагностики
docker run -it --entrypoint bash myimage

# Exit code 137 - контейнер убит по OOM (нехватка памяти)
# Проверить системные сообщения
journalctl -k | grep -i "oom"
dmesg | grep -i "oom"

Контейнер не может подключиться к другому контейнеру


# Проверить что оба в одной сети
docker inspect container1 | grep -A 20 Networks
docker inspect container2 | grep -A 20 Networks

# Пинг по имени изнутри контейнера
docker exec container1 ping container2

# Проверить DNS
docker exec container1 nslookup container2

# Создать общую сеть и подключить оба
docker network create shared
docker network connect shared container1
docker network connect shared container2

Образ не собирается / COPY failed / файл не найден


# Проверить .dockerignore - возможно файл исключён
cat .dockerignore

# Собрать с verbose выводом
docker build --progress=plain -t myapp . 2>&1 | tee build.log

# Проверить context сборки (что отправляется в daemon)
docker build --no-cache -t myapp . 2>&1 | head -5

Volume не монтируется / Permission denied


# Проверить владельца директории на хосте
ls -la /host/path

# Проверить UID внутри контейнера
docker run --rm myimage id

# Исправить права
chown -R 1000:1000 /host/path

# Или запустить контейнер с нужным пользователем
docker run -d --user $(id -u):$(id -g) -v /host/path:/app/data myapp

docker compose up зависает на «Waiting for container…»


# Посмотреть статус healthcheck
docker inspect db | grep -A 10 Health

# Проверить логи сервиса
docker compose logs db

# Запустить без depends_on для диагностики
docker compose up db

Таблица: коды выхода контейнеров

Exit Code Причина Что делать
0 Штатное завершение Норма для одноразовых задач
1 Ошибка приложения Смотреть docker logs
125 Ошибка docker run Проверить параметры команды
126 Команда найдена, но не исполняема Проверить права на файл
127 Команда не найдена Проверить entrypoint/cmd
137 SIGKILL — OOM или docker kill Проверить лимиты памяти
139 Segfault Баг в приложении
143 SIGTERM — штатная остановка Норма при docker stop

Мониторинг Docker

Встроенный мониторинг


# Статистика всех контейнеров в реальном времени
docker stats

# Одиночный снимок без обновления
docker stats --no-stream

# Конкретные контейнеры
docker stats web app db --no-stream

# Форматированный вывод
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"

Cadvisor для метрик


# Запустить cAdvisor для мониторинга контейнеров
docker run -d \
  --name cadvisor \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:ro \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --restart=unless-stopped \
  gcr.io/cadvisor/cadvisor:latest

После запуска метрики доступны на http://server:8080. Prometheus может их собирать — cAdvisor экспортирует в нужном формате из коробки.

Альтернативные инструменты

Docker — не единственный вариант. Знать альтернативы полезно.

Инструмент Когда использовать Отличие от Docker
Podman Rootless контейнеры, RHEL среды Без daemon, совместимые команды
containerd Kubernetes, минимальный рантайм Только рантайм, нет CLI для людей
Docker Swarm Кластер из нескольких хостов Встроен в Docker, проще Kubernetes
Kubernetes Большие кластеры, оркестрация Гораздо сложнее, гораздо мощнее
Portainer Веб-интерфейс для Docker GUI поверх Docker API

FAQ

Как посмотреть IP адрес контейнера?


docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name

Как зайти внутрь контейнера без bash?

Многие минимальные образы не содержат bash. Используй sh:


docker exec -it container_name sh
# или
docker exec -it container_name /bin/sh

Почему docker ps не показывает мой контейнер?

docker ps без флагов показывает только запущенные контейнеры. Если контейнер упал — используй docker ps -a. Потом docker logs container_name чтобы понять почему упал.

Как передать переменные окружения безопасно?


# Через файл .env (не добавлять в git)
docker run --env-file .env myapp

# Через Docker secrets (Swarm)
docker secret create db_password ./password.txt

Как посмотреть что слушает контейнер изнутри?


docker exec container_name ss -tlnp
# или если ss нет
docker exec container_name netstat -tlnp

Как ограничить лог файлы Docker чтобы они не заполняли диск?

Глобально в /etc/docker/daemon.json:


{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  }
}

Или для конкретного контейнера:


docker run -d \
  --log-driver json-file \
  --log-opt max-size=50m \
  --log-opt max-file=3 \
  myapp

Как скопировать данные между двумя volumes?


docker run --rm \
  -v source_volume:/source:ro \
  -v target_volume:/target \
  alpine cp -r /source/. /target/

Как обновить переменную окружения в работающем контейнере?

Никак. Переменные окружения устанавливаются при создании контейнера. Нужно пересоздать контейнер с новыми значениями. Это ещё одна причина использовать Compose — docker compose up -d пересоздаёт контейнеры с обновлённой конфигурацией.

Профилактика: как не сломать снова

  • Всегда фиксируй версии образов (nginx:1.25, а не nginx:latest) на продакшене. latest — это билет в ситуацию «всё работало вчера».
  • Настрой ротацию логов в daemon.json до того как диск заполнится.
  • Базы данных — только с volume. Без исключений.
  • Пароли и секреты — только через env файлы или Docker secrets. Не в Dockerfile, не в compose.yml.
  • Добавь healthcheck к критичным сервисам — это даст понять когда контейнер запущен но не работает.
  • Делай бэкап volumes перед обновлением. Особенно баз данных.
  • Настрой --restart=unless-stopped для всех продакшен контейнеров.

Итог

Ты закрыл справочник который покрывает 95% реальных сценариев работы с Docker. Образы, контейнеры, сети, тома, Compose, безопасность, очистка, мониторинг и troubleshooting — всё на одной странице.

Держи страницу в закладках. Когда что-то снова пойдёт не так — начинай с раздела Troubleshooting. Если там нет ответа — docker logs и docker inspect закроют оставшиеся 5%.

Не заработало?
Пиши в комментарии: команда, вывод ошибки, версия Docker и ОС. Разберёмся.

Оставайтесь на связи

Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.

Подписаться на IT-Аптеку →

Мы ВКонтакте

IT-Аптека — советы, новости и помощь рядом.

Вступить в группу ВКонтакте →
Поделитесь:

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх