
Опубликовано: 26 июня 2025 г. | Время чтения: 15 минут
Знаете, что самое болезненное в работе с Docker? Когда всё идеально работает на локалке, а в продакшене превращается в тыкву. Классика жанра — контейнер падает в три часа ночи, а ты сидишь в трусах и пытаешься понять, что пошло не так.
За 12 лет в DevOps я повидал столько эпичных ошибок с Docker, что можно книгу писать. И знаете что? Большинство проблем — это одни и те же грабли, на которые наступают снова и снова.
Сегодня разберём топ-10 косяков при настройке Docker в production. Без воды, только реальные кейсы и конкретные решения. Поехали!
Ошибка №1: Запуск контейнеров от root
Это прям классика. Разработчик пишет Dockerfile, всё работает, деплоит в прод — и бум! Контейнер запущен от root. А потом удивляемся, когда хакеры устраивают праздник жизни на сервере.
Реальная история из практики: Приходит ко мне паренёк, у него стартап — сервис для обработки фотографий. Всё на Docker, красота! Только вот беда — через месяц после запуска кто-то залез на сервер и устроил там майнинг-ферму.
Смотрим — все контейнеры от root запущены. Злоумышленник нашёл уязвимость в приложении, выбрался из контейнера и получил root-доступ к хосту. Итог — счёт за сервер на 300 тысяч рублей за месяц.
Как правильно:
Всегда создавайте отдельного пользователя в Dockerfile:
FROM node:18-alpine RUN addgroup -g 1001 -S nodejs RUN adduser -S nodejs -u 1001 USER nodejs
И обязательно проверяйте права доступа к файлам. Если приложению нужно писать в какую-то директорию — дайте права только на неё, а не на весь контейнер.
Ошибка №2: Хранение секретов в образах
О, это вообще хит-парад глупости! Видел я Dockerfile, где прямо в ENV переменных были пароли от базы данных. А потом этот образ залили на Docker Hub. Публично. Фейспалм.
Вот типичный пример говнокода:
# НИКОГДА ТАК НЕ ДЕЛАЙТЕ! FROM python:3.9 ENV DATABASE_PASSWORD="superSecretPass123" ENV API_KEY="sk-1234567890abcdef"
Знаете, что самое смешное? Даже если вы удалите эти строки потом — они останутся в истории слоёв образа. Любой желающий может их достать командой `docker history`.
Как надо делать:
Используйте Docker Secrets или внешние системы управления секретами. Для простых случаев — передавайте через переменные окружения при запуске:
docker run -e DATABASE_PASSWORD=$DB_PASS myapp
А ещё лучше — используйте специальные инструменты типа HashiCorp Vault или AWS Secrets Manager. Да, это сложнее, но безопасность того стоит.
Ошибка №3: Отсутствие лимитов на ресурсы
Представьте ситуацию: запустили вы 10 контейнеров на сервере. Всё работает отлично. А потом в одном контейнере происходит утечка памяти, он сжирает всю оперативку, и сервер уходит в своп. Результат — всё тормозит как черепаха с похмелья.
История из жизни: У клиента был интернет-магазин на микросервисах. 15 контейнеров на одном выделенном сервере. И вот в чёрную пятницу один сервис обработки картинок начал течь по памяти. За час съел 32 ГБ и положил весь магазин. Потери — около миллиона рублей за день распродажи.
Решение простое — всегда ставьте лимиты:
docker run -m 512m --memory-swap 1g --cpus="1.5" myapp
Или в docker-compose.yml:
services: app: image: myapp deploy: resources: limits: cpus: '1.5' memory: 512M reservations: cpus: '0.5' memory: 256M
Причём ставьте и limits (максимум), и reservations (гарантированный минимум). Это поможет избежать ситуации, когда один жадный контейнер съедает все ресурсы.
Ошибка №4: Игнорирование логов
"А зачем нам логи? У нас же всё работает!" — сказал один мой знакомый. А через неделю его сервис упал, и он три дня разбирался, что произошло. Потому что логи писались в контейнер и умерли вместе с ним.
Типичные косяки с логами:
Первый — логи пишутся внутрь контейнера. Контейнер перезапустился — логи потерялись. Классика!
Второй — нет ротации логов. Через пару месяцев диск забивается под завязку. Особенно весело, когда это происходит на проде в выходные.
Третий — логи в json-формате без нормального драйвера. Попробуй потом в этой каше что-то найти!
Как настроить правильно:
Минимум — настройте json-file драйвер с ротацией:
docker run --log-driver json-file \ --log-opt max-size=10m \ --log-opt max-file=3 \ myapp
Но лучше — централизованная система логирования. ELK-стек, Graylog или хотя бы простой rsyslog. И обязательно настройте мониторинг — чтобы сразу узнавать о проблемах, а не через жалобы пользователей.
Ошибка №5: Неправильная работа с томами
Volumes в Docker — это как женщины. Вроде понимаешь принцип работы, но постоянно что-то идёт не так. То права доступа не те, то данные потерялись, то производительность упала в 10 раз.
Самые частые факапы:
Использование bind mounts в продакшене для данных приложения. Это прям ад для производительности, особенно если хост-система не Linux.
Забывают про права доступа. Контейнер запущен от пользователя с UID 1000, а файлы принадлежат root. Итог — permission denied и слёзы.
Не делают бэкапы данных из volumes. "А что там бэкапить, это же просто кэш!" — говорили они. А потом оказывается, что там критичные данные.
Правильный подход:
# Создаём named volume docker volume create myapp-data # Используем в контейнере docker run -v myapp-data:/data myapp # Настраиваем автоматические бэкапы docker run --rm -v myapp-data:/source \ -v /backup:/backup \ alpine tar czf /backup/myapp-$(date +%Y%m%d).tar.gz -C /source .
И обязательно используйте профессиональные решения для бэкапов. Поверьте, когда данные полетят (а они полетят), вы скажете себе спасибо.
Ошибка №6: Отсутствие health checks
Знаете, что происходит, когда в контейнере нет health check? Docker думает, что всё хорошо, даже если приложение внутри сдохло. Load balancer продолжает слать запросы на мёртвый контейнер, пользователи видят 502 ошибку, а вы спите спокойно, не подозревая о проблеме.
Пример из практики: Java-приложение с утечкой памяти. JVM ещё жива, порт открыт, но приложение уже в OutOfMemory и не отвечает. Без health check это может висеть часами.
Добавляем health check в Dockerfile:
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1
Или в docker-compose.yml:
services: app: image: myapp healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 3s retries: 3 start_period: 40s
Важно: не делайте слишком агрессивные проверки. Если проверять каждую секунду — можно создать дополнительную нагрузку на приложение.
Ошибка №7: Игнорирование правил построения образов
Видел я Dockerfile на 2000 строк и образ весом 5 ГБ для простого Node.js приложения. Это как ехать на КамАЗе за хлебом — можно, но зачем?
Типичные косяки при создании образов:
Используют полноценные ОС вместо alpine версий. Ubuntu для Go-приложения? Серьёзно? Добавляет 100+ МБ просто так.
Не используют multi-stage builds. В итоге в проде тащится весь build-тулчейн, который вообще не нужен.
Каждая команда в отдельном RUN. Результат — 50 слоёв и образ размером с космическую станцию.
Пример правильного Dockerfile:
# Build stage FROM golang:1.21-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -o main . # Final stage FROM alpine:3.18 RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/main . CMD ["./main"]
Итоговый образ — 15 МБ вместо 500. Быстрее скачивается, быстрее стартует, меньше места занимает.
Ошибка №8: Неправильная организация сети
Docker networking — это отдельная песня. Тут можно так наколбасить, что потом сам чёрт ногу сломит. Особенно когда начинают микросервисы между собой связывать.
История ужасов: Один товарищ запустил 20 контейнеров, каждый на своём порту. 8080, 8081, 8082... И всё это торчало наружу! Сканеры ботов нашли открытые порты за час. Хорошо, что там только тестовые данные были.
Главные правила сетевой безопасности:
Никогда не используйте сеть host в проде. Это дыра в безопасности размером с футбольное поле.
Создавайте отдельные сети для разных групп сервисов:
docker network create frontend docker network create backend docker network cre ate database
Открывайте наружу только то, что реально нужно. Nginx — да, база данных — ни в коем случае!
Используйте внутренние DNS-имена Docker вместо IP-адресов. Они автоматически резолвятся и не ломаются при перезапуске.
Ошибка №9: Отсутствие стратегии обновления
"Давайте просто остановим старый контейнер и запустим новый!" — сказал junior DevOps. И весь сайт лёг на 5 минут в самый пик продаж. Минус полмиллиона к выручке.
Как делать не надо:
Останавливать все контейнеры разом. Привет, downtime!
Не тестировать новые образы перед деплоем. "Работает же на моей машине!"
Не иметь возможности быстрого отката. Задеплоили багу — и сидите чините час.
Правильная стратегия обновления:
Используйте rolling updates. Запускаете новые контейнеры параллельно со старыми, переключаете трафик, убиваете старые. Zero downtime!
Всегда держите предыдущую версию образа. Откат должен занимать секунды, а не часы.
Автоматизируйте процесс. CI/CD pipeline должен уметь и деплоить, и откатывать одной кнопкой.
И обязательно мониторьте процесс обновления. Если что-то пошло не так — сразу откат.
Ошибка №10: Пренебрежение мониторингом
Последняя, но самая критичная ошибка — отсутствие нормального мониторинга. "Зачем мониторинг? Если что сломается — пользователи напишут!" Ага, напишут. В отзывах на маркетплейсе. Со звёздочкой из пяти.
Что обязательно нужно мониторить:
- CPU и память каждого контейнера
- Количество рестартов
- Время ответа приложений
- Размер логов и volumes
- Сетевой трафик между контейнерами
Минимальный набор для мониторинга:
Prometheus + Grafana для метрик. Настраивается за час, работает годами.
cAdvisor для сбора метрик с контейнеров. Ставится одной командой.
AlertManager для уведомлений. Чтобы не проспать, когда всё упадёт.
Но если не хочется заморачиваться — используйте готовые решения для мониторинга. Дороже, зато работает из коробки и не требует танцев с бубном.
Реальные истории ошибок
Кейс 1: Криптобиржа и root-права
Молодая криптобиржа, всё на Docker, красиво, современно. Только вот все контейнеры запущены от root. Итог предсказуем — хакеры нашли SQL-инъекцию, выбрались из контейнера и получили полный доступ к серверу.
Украли не только криптовалюту, но и всю базу данных с KYC пользователей. Ущерб — около 50 миллионов рублей + репутация в минусе. Биржа закрылась через месяц.
Что сделали неправильно:
- Все контейнеры от root
- Нет сегментации сети
- Секреты хранились в ENV переменных
- Отсутствовал мониторинг аномальной активности
Кейс 2: Интернет-магазин и отсутствие лимитов
Крупный интернет-магазин электроники. 30+ микросервисов, всё в Docker на нескольких VPS серверах. И никаких лимитов на ресурсы!
В чёрную пятницу сервис обработки изображений словил баг и начал течь по памяти. За 2 часа сожрал всю память на сервере, остальные контейнеры начали падать по OOM. Сайт лежал 4 часа в самый пик продаж.
Потери:
- Прямые потери от недополученных заказов — 3.5 млн рублей
- Компенсации клиентам — 500 тысяч
- Репутационные потери — неизмеримо
Чек-лист для production-ready Docker
Сохраните себе этот чек-лист и пройдитесь по нему перед деплоем в прод:
Безопасность:
- ☐ Контейнеры запускаются НЕ от root
- ☐ Секреты вынесены из образов
- ☐ Используются только необходимые порты
- ☐ Настроена сегментация сети
- ☐ Образы регулярно обновляются
Надёжность:
- ☐ Установлены лимиты на CPU и память
- ☐ Настроены health checks
- ☐ Есть стратегия обновления без downtime
- ☐ Настроено автоматическое восстановление
Наблюдаемость:
- ☐ Централизованный сбор логов
- ☐ Мониторинг всех метрик
- ☐ Настроены алерты на критичные события
- ☐ Есть дашборды для визуализации
Данные:
- ☐ Критичные данные в named volumes
- ☐ Настроено регулярное резервное копирование
- ☐ Проверена процедура восстановления
- ☐ Права доступа корректно настроены
Практические советы от бывалого
Совет 1: Начинайте с малого. Не надо сразу переводить всё на Kubernetes. Сначала научитесь готовить Docker Compose, потом уже замахивайтесь на оркестраторы.
Совет 2: Инвестируйте в инфраструктуру. Лучше заплатить за нормальный выделенный сервер или колокацию, чем потом терять деньги из-за даунтаймов.
Совет 3: Автоматизируйте всё, что можно. Ручной деплой в 2025 году — это моветон. CI/CD должен быть с первого дня.
Совет 4: Не экономьте на безопасности. Один взлом может стоить дороже, чем годы работы SSL-сертификатов и систем мониторинга.
Совет 5: Учитесь на чужих ошибках. Читайте post-mortem крупных компаний, смотрите, как они факапятся, и не повторяйте.
Итоги
Docker — это мощный инструмент, но с большой силой приходит большая ответственность. Одна маленькая ошибка в конфигурации может стоить миллионов рублей и седых волос.
Главные мысли, которые стоит запомнить:
- Безопасность — это не паранойя, а необходимость
- Мониторинг должен быть с первого дня
- Лимиты на ресурсы спасут вас от многих проблем
- Автоматизация — ваш лучший друг
- Всегда имейте план Б (бэкапы и откаты)
И помните — лучше потратить неделю на правильную настройку, чем потом месяцами разгребать последствия. Docker прощает ошибки на локалке, но в проде он беспощаден.
Нужна помощь с Docker в production?
Если не хотите наступать на все эти грабли самостоятельно — обращайтесь к профессионалам. У нас есть всё необходимое для надёжного хостинга контейнеризированных приложений: от мощных VPS до выделенных серверов и размещения в ЦОД.
Поможем правильно настроить инфраструктуру, организовать мониторинг и резервное копирование. А главное — наша круглосуточная поддержка всегда на связи, когда что-то пойдёт не так.
Потому что в production не бывает удобного времени для проблем. Они случаются всегда некстати. Но с правильной инфраструктурой и поддержкой — любую проблему можно решить быстро и без паники.