Любой контейнер имеет свой жизненный цикл. Он не существует вечно: он создается из образа, выполняет свою задачу (крутится в фоне или завершает расчеты), останавливается и, в конечном итоге, удаляется. Ваша задача как инженера — уметь управлять этим циклом.
1. Откуда берутся образы? (Docker Hub и docker pull)
Прежде чем запустить контейнер, нам нужен чертеж — образ (Image).
Официальный глобальный реестр образов называется Docker Hub. Там лежат готовые и настроенные образы для баз данных (PostgreSQL, MySQL), веб-серверов (Nginx, Apache), языковых сред (Java, Python, Node.js) и тысяч других программ.
Чтобы скачать образ на свой компьютер без его запуска, используется команда:
docker pull postgres:15
- Где postgres — имя образа, а 15 — это тег (tag), указывающий конкретную версию. Если не указать тег, Docker скачает версию latest (последнюю), что в реальных проектах делать не рекомендуется во избежание неожиданных обновлений.
2. Главная команда: docker run
Команда docker run — это швейцарский нож Docker. Она делает три вещи одновременно:
- Ищет образ локально (если нет — делает pull из Docker Hub).
- Создает из него новый контейнер.
- Запускает этот контейнер.
Давайте разберем запуск базы данных, которая часто нужна при разработке backend-приложений.
docker run --name my-database -e POSTGRES_PASSWORD=secret_pass -p 5432:5432 -d postgres:15
Выглядит страшно? Давайте разберем по косточкам (флагам):
- --name my-database
Мы даем нашему контейнеру понятное имя. Если этого не сделать, Docker сгенерирует случайное забавное имя (например, crazy_turing).
- -e POSTGRES_PASSWORD=secret_pass
Флаг -e передает переменные окружения (Environment variables) внутрь контейнера. Официальный образ Postgres требует задать пароль для базы данных, иначе он откажется запускаться.
- -p 5432:5432
Проброс портов (Port mapping). Левая часть — порт на вашем локальном компьютере, правая — порт внутри контейнера. Мы говорим: «Всё, что приходит на порт 5432 моего ноутбука, отправляй на порт 5432 внутрь контейнера».
- -d (detach)
Запуск в фоновом режиме. Если не указать этот флаг, логи базы данных займут ваш терминал, и вы не сможете вводить новые команды (пока не нажмете Ctrl+C, что убьет контейнер).
- postgres:15
Указание образа, из которого создается контейнер (всегда ставится в конце).
3. Мониторинг: Кто здесь работает?
Контейнер запущен в фоне. Как убедиться, что всё хорошо?
- docker ps — показывает список только активных (запущенных) контейнеров. Вы увидите ID контейнера, имя, статус и проброшенные порты.
- docker ps -a (флаг -a означает all) — показывает вообще все контейнеры, включая те, что были остановлены или упали с ошибкой.
- docker logs my-database — выводит логи контейнера. Это главный инструмент отладки! Если ваше приложение не может подключиться к БД или контейнер упал, логи покажут почему. Можно добавить флаг -f (docker logs -f my-database), чтобы читать логи в реальном времени.
4. Остановка, запуск и уборка мусора
Контейнеры — это временные сущности. Если вы закончили работу над проектом на сегодня, вы можете остановить контейнер, чтобы не тратить оперативную память компьютера:
- docker stop my-database: Мягко останавливает контейнер (посылает сигнал завершения процессу).
- docker start my-database: Снова запускает ранее остановленный контейнер. Данные внутри него сохранятся (если только вы его не удалите).
- docker restart my-database: Удобно, если вы поменяли какие-то внешние настройки и нужно перезагрузить сервис.
Когда контейнер вам больше не нужен совсем, его нужно удалить.
- docker rm my-database: Удаляет контейнер (он должен быть предварительно остановлен). Чтобы удалить работающий контейнер принудительно, используйте docker rm -f my-database.
Удаление контейнера не удаляет образ, из которого он был создан. Образ остается на вашем диске, занимая место. Чтобы удалить скачанный образ, используйте:
- docker rmi postgres:15 (rmi = remove image).
Блок самопроверки
Внимательно прочитайте задачу и попробуйте решить типичную проблему разработчика.
Ситуация: Вы разрабатываете новое Java-приложение. Для локального тестирования вам понадобилось поднять веб-сервер Nginx. Вы вводите команду:
docker run -d --name test-server -p 8080:80 nginx
Однако вместо ID успешно запущенного контейнера Docker выдает вам ошибку:
Error response from daemon: driver failed programming external connectivity on endpoint test-server: Bind for 0.0.0.0:8080 failed: port is already allocated.
Ваше Java-приложение, запущенное прямо на вашем ноутбуке в IDE (например, IntelliJ IDEA), сейчас тоже работает и обрабатывает запросы.
Вопросы:
- Что именно означает эта ошибка?
- Как с помощью одной команды Docker посмотреть, не занят ли этот ресурс другим контейнером (на случай, если проблема не в вашей IDE)?
- Как изменить исходную команду запуска Nginx, чтобы контейнер успешно стартовал, не мешая вашему Java-приложению, которое уже работает на ноутбуке?
Подумайте над ответами и зафиксируйте их, прежде чем смотреть разбор.
😎
Ответ и разбор построчно
Краткие ответы:
- Ошибка означает конфликт портов (порт 8080 на хосте уже занят).
- Команда docker ps.
- Изменить левую часть в флаге -p, например: docker run -d --name test-server -p 8081:80 nginx.
Построчный разбор логики:
- «Что именно означает эта ошибка?»
Разбор: Конструкция Bind for 0.0.0.0:8080 failed: port is already allocated — это самая частая ошибка новичков. Флаг -p 8080:80 приказывает Docker "захватить" порт 8080 на вашей физической машине (хосте) и направить его в порт 80 контейнера. Но порт 8080 уже занят запущенным Java-приложением в вашей IDE. Два разных процесса на одном компьютере не могут слушать один и тот же внешний порт одновременно. - «Как с помощью одной команды посмотреть, не занят ли ресурс другим контейнером?»
Разбор: Команда docker ps покажет все запущенные контейнеры. Если вы забыли, что час назад уже запустили другой контейнер (например, панель управления или другой сервис) с пробросом на порт 8080, вы увидите это в столбце PORTS вывода этой команды (там будет строка вроде 0.0.0.0:8080->80/tcp). - «Как изменить команду, чтобы запустить Nginx, не мешая Java-приложению?»
Разбор: Порт внутри контейнера Nginx по умолчанию всегда 80 — это трогать не нужно (он изолирован). Изменить нужно порт на вашей хост-машине (левая часть до двоеточия). Вы можете выбрать любой свободный порт, например 8081 или 9000.
Правильная команда: docker run -d --name test-server -p 8081:80 nginx.
После этого вы сможете открыть в браузере localhost:8081 и увидеть стартовую страницу Nginx, в то время как ваше Java-приложение продолжит спокойно работать на localhost:8080.