Как заблокировать внешний доступ к порту, который опубликован (exposed) контейнером?

«Как заблокировать внешний доступ к порту, который опубликован (exposed) контейнером?» — вопрос из категории Docker, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Если контейнер публикует порт на хост (через -p 8080:80), блокировка осуществляется на уровне хоста, а не контейнера. Самый прямой способ — не публиковать порт при запуске. Если же контейнер уже запущен, нужно действовать иначе.

Мои действия по решению этой проблемы:

  1. Изменить способ запуска контейнера (предпочтительно):

    • Остановить и перезапустить без проброса порта:
      docker stop my-container
      docker run -d --name my-container my-image  # Без флага -p
    • В Docker Compose: Удалить или закомментировать секцию ports: в docker-compose.yml и выполнить docker-compose up -d.
  2. Блокировка на уровне сетевого фаервола хоста (экстренная мера): Если нужно срочно закрыть порт, но перезапускать контейнер нельзя, можно использовать iptables или ufw.

    # Блокировать входящие соединения на порт 8080 с помощью iptables
    sudo iptables -A INPUT -p tcp --dport 8080 -j DROP
    # Для сохранения правил после перезагрузки (зависит от дистрибутива)
    sudo iptables-save | sudo tee /etc/iptables/rules.v4

    Важно: Docker сам управляет правилами iptables. Прямое редактирование может конфликтовать с Docker. Лучше всего управлять доступом через Docker Network или не публиковать порт изначально.

  3. Использовать Docker Network для изоляции: Создать внутреннюю сеть и запускать в ней контейнеры. Тогда они будут доступны друг другу по имени, но не с хоста.

    docker network create internal-net
    docker run -d --name app --network internal-net my-app
    docker run -d --name nginx --network internal-net -p 80:80 nginx # Только Nginx публикует порт

    В этом примере порт приложения my-app не опубликован наружу, доступ к нему есть только у nginx внутри сети internal-net.