Глиф Учебники

Урок 4. Запуск сервиса: порты, переменные, имя и перезапуск

Курс «Docker» · урок 4 из 10 · 5 минут чтения

В прошлом уроке Nginx работал в контейнере, но открыть его в браузере было нельзя. В этом уроке — всё, что превращает контейнер в настоящий сервис: порт снаружи, настройки, понятное имя и автоматический запуск после перезагрузки сервера.

Сервис одной командой

Удалите контейнер из прошлого урока, если он остался, и запустите Nginx заново:

Bash
docker rm -f web
docker run -d --name web -p 8080:80 --restart unless-stopped nginx:alpine

Откройте в браузере http://localhost:8080 (на сервере — http://адрес-сервера:8080): появится страница «Welcome to nginx!». Проверить можно и из терминала:

Терминал
$ curl -I http://localhost:8080
HTTP/1.1 200 OK

Ниже ответа будут ещё заголовки, среди них Server: nginx/… с номером версии. Разберём ключи по одному.

-d и --name

-p: порт снаружи

У каждого контейнера своя сеть, и порты внутри него снаружи не видны. Ключ -p (publish — опубликовать) связывает порт хоста с портом контейнера:

Текст
-p 8080:80
   │    └── порт внутри контейнера (его слушает Nginx)
   └─────── порт на хосте (к нему подключаются снаружи)

Порядок важен: сначала порт хоста, потом порт контейнера. Какой порт слушает программа в контейнере, написано в описании образа на Docker Hub: у Nginx — 80, у PostgreSQL — 5432, у MariaDB и MySQL — 3306.

Варианты записи:

ЗаписьЧто значит
-p 8080:80порт 8080 на всех адресах хоста → порт 80 контейнера
-p 80:80 -p 443:443несколько портов — несколько ключей -p
-p 127.0.0.1:8080:80порт доступен только с самого хоста
-p 192.168.1.10:8080:80порт только на одном адресе хоста
-p 5353:53/udpпорт UDP (без /udp — TCP)

Какие порты опубликованы у работающего контейнера, показывает docker port web.

-p 8080:80 другой компьютер адрес-сервера:8080 хост 8080 80 Nginx контейнер web -p 127.0.0.1:8080:80 другой компьютер адрес-сервера:8080 хост 127.0.0.1:8080 80 Nginx контейнер web браузер на хосте
С -p 8080:80 порт 8080 хоста ведёт в порт 80 контейнера для всех, а с 127.0.0.1 впереди — только с самого хоста.

Опубликованный порт доступен не только с хоста, но и всем, кто может достучаться до сервера по сети. На Linux Docker открывает такие порты своими правилами брандмауэра — в обход ufw: запрет в ufw их не закроет. Порты баз данных и панелей управления публикуйте только на 127.0.0.1 или не публикуйте вовсе. Подробно — в справке Docker открывает порты в обход ufw.

-e: настройки через переменные

Большинство образов настраиваются переменными окружения: пароль базы, имя пользователя, режим работы. Их передают ключом -e (environment). Пример — PostgreSQL 18, которому при первом запуске нужен пароль суперпользователя:

Bash
docker run -d --name db -e POSTGRES_PASSWORD=Smena-Parol-2026 --restart unless-stopped postgres:18

Пароль в примере придумайте свой.

Какие переменные понимает образ, перечислено в его описании на Docker Hub. У PostgreSQL обязательна только POSTGRES_PASSWORD, а POSTGRES_USER и POSTGRES_DB создают своего пользователя и базу.

Проверьте, что база запустилась, и подключитесь к ней изнутри контейнера:

Bash
docker logs db
docker exec -it db psql -U postgres

В логах должна появиться строка database system is ready to accept connections. Вторая команда запускает консоль psql внутри работающего контейнера; выход — \q. Команда docker exec подробно разобрана в справке Как зайти в контейнер.

Когда переменных много, их держат в файле — по одной ИМЯ=значение в строке, например в db.env, — и передают целиком:

db.env
POSTGRES_PASSWORD=Smena-Parol-2026
POSTGRES_USER=app
POSTGRES_DB=app
Bash
docker run -d --name db --env-file ./db.env postgres:18

Переменные контейнера видны любому, кто может выполнить docker inspect. Файл с паролями не кладите в git и не отправляйте в чаты; права на него — только для владельца: chmod 600 db.env.

Файлы базы у этого контейнера пока лежат в анонимном томе (томе без имени, который Docker создал сам): новый контейнер его не подхватит, и после пересоздания база окажется пустой. Как хранить данные правильно — в следующем уроке.

--restart: запуск после перезагрузки

Без --restart контейнер, упавший с ошибкой или остановленный перезагрузкой сервера, так и останется лежать. Политика перезапуска говорит Docker, что делать:

ЗначениеПоведение
noне перезапускать (по умолчанию)
on-failureперезапускать, только если программа завершилась с ошибкой (код не 0)
alwaysперезапускать всегда; остановленный вручную — поднимется после перезапуска Docker
unless-stoppedкак always, но остановленный вручную контейнер остаётся остановленным

Для сервисов обычно берут unless-stopped: сервер перезагрузился — контейнер поднялся сам, а если вы остановили его командой docker stop, он не оживёт неожиданно. Политику работающего контейнера можно поменять без пересоздания: docker update --restart unless-stopped web.

no always unless-stopped программа упала с ошибкой сервер перезагрузился остановлен docker stop, потом перезагрузка поднимется сам останется остановленным on-failure — только после выхода с ошибкой (код не 0)
Политики no, always и unless-stopped по-разному поднимают контейнер после ошибки, перезагрузки сервера и ручной остановки.

Порядок в команде

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

Bash
docker run -d --name web -p 8080:80 nginx:alpine
docker run --rm alpine ls -l /etc

В первой строке все ключи относятся к Docker. Во второй ls -l /etc выполнится внутри контейнера. Ошибка новичка — docker run nginx:alpine -p 8080:80: здесь -p 8080:80 уйдёт программе в контейнере, а не Docker, и порт не откроется.

ключи Docker образ команда в контейнере docker run -d --name web -p 8080:80 nginx:alpine docker run --rm alpine ls -l /etc docker run nginx:alpine -p 8080:80 ключ после образа достаётся программе в контейнере — порт не откроется
Всё до имени образа — ключи Docker, всё после него — команда для программы в контейнере, поэтому -p после образа не сработает.

Как поменять параметры

Порты, переменные и тома задаются при создании контейнера, и у готового контейнера их не поменять. Порядок такой: удалить контейнер и создать заново с новыми ключами.

Bash
docker rm -f web
docker run -d --name web -p 8081:80 --restart unless-stopped nginx:alpine

Поэтому команды запуска стоит сохранять — в заметках, в скрипте или, лучше всего, в файле Docker Compose (урок Docker Compose). Данные при этом не теряются, если они в томе.

Коротко

Проверьте себя

1. Что значит -p 8080:80?
2. Как опубликовать порт базы данных так, чтобы к нему можно было подключиться только с самого сервера?
3. Какая политика перезапуска поднимет контейнер после перезагрузки сервера, но не запустит его, если вы остановили его вручную?
4. Почему в команде docker run nginx:alpine -p 8080:80 порт не откроется?