Концепция дескриптора файла важна из-за выбора дизайна UNIX, согласно которому «все является файлом», включая вещи, не являющиеся частью файловой системы. Такие как ленточные накопители, клавиатура и экран (или телетайп!), Устройства чтения перфокарт / лент, последовательные соединения, сетевые соединения и (ключевое изобретение UNIX) прямые соединения с другими программами, называемые «каналами».
Если вы посмотрите на многие простые стандартные утилиты UNIX, такие как grep
, особенно в их исходных версиях, вы заметите, что они не включают вызовы к open ()
и close ()
, но просто читать
и писать
. Дескрипторы файлов устанавливаются вне программы оболочкой и передаются при ее запуске. Таким образом, программе не нужно заботиться о том, пишет ли она в файл или в другую программу.
Помимо open
, другие способы получения файловых дескрипторов: socket
, listen
, pipe
, dup
и очень удобный механизм Хита Робинсона для отправки дескрипторов файлов по каналам: https://stackoverflow.com/questions/28003921/sending-file-descriptor-by-linux-socket
Изменить: некоторые лекции , описывающие уровни косвенного обращения и то, как это позволяет O_APPEND работать разумно. Обратите внимание, что сохранение данных inode в памяти гарантирует, что системе не придется снова их извлекать для следующей операции записи.
Есть две проблемы (и на самом деле не -задал 3-й вопрос, который я рассмотрю простым, если не лучшим решением, на всякий случай, чтобы быть тщательным):
Локально инициированные пакеты не пересылаются (не маршрутизируются ). Таким образом, эти пакеты никогда не видят цепочку nat/PREROUTING
. Взгляните на Поток пакетов в Netfilter и General Networking , чтобы получить представление о том, что происходит во время жизни пакета в ядре. Локальные пакеты приходят из "локального процесса".
Таким образом, в дополнение к правилу nat/PREROUTING
выполняется DNAT
для пакетов, прибывающих "извне", что должно выглядеть как:
iptables -t nat -I PREROUTING -i eno1 -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443
Вы также должны использовать цепочку nat/OUTPUT
. На выходе его синтаксис допускает только исходящие интерфейсы, поэтому он изменен следующим образом:
iptables -t nat -I OUTPUT -o lo -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443
Исходный пакет, а затем поток будут фактически перенаправлены на другой интерфейс (Я подозреваю, что "проверка перенаправления" на схеме предыдущей ссылки может быть размещена неправильно ).
Это будет работать с любым IP-адресом, принадлежащим хосту (, т.е. :172.16.214.45 и 172.17.0.1 ), кроме...
lo
Ядро Linux имеет специальные настройки, запрещающие маршрутизацию любого IP-адреса в диапазоне 127.0.0.0/8 куда-либо, кроме интерфейса lo
, и отбрасывает любой такой пакет как марсианский источник при «попытке» использовать другой интерфейс, и правильно :удаленная система (даже если это контейнер )не примет входящий пакет с источником 127.0.0.1 и пунктом назначения 172.17.0.2 хотя бы потому, что не будет знать, куда на него ответить.
Таким образом,SNAT
(или простойMASQUERADE
)к пакету в дополнение к DNAT
также необходимо сделать, на этот раз в цепочке nat/POSTROUTING
, которая проходится (см. предыдущую схему):
iptables -t nat -I POSTROUTING -s 127.0.0.1 -d 172.17.0.2 -j MASQUERADE
Этого еще недостаточно :как следует из названия, nat/POSTROUTING
происходит после маршрутизации (на самом деле проверка перемаршрутизации происходит после DNAT
), и пакет уже был отброшен как марсианский источник.
В особых случаях, таких как этот, можно переопределить ограничение локальной сети с помощью переключателя интерфейса -route_localnet
:
echo 1 > /proc/sys/net/ipv4/conf/docker0/route_localnet
Теперь стек маршрутизации пропускает пакеты с источником 127.0.0.1, а их источник корректируется на 172.17.0.1 по предыдущему правилу перед выходом по виртуальному проводу в контейнер :это работает.
Вам действительно следует избегать всего, что требует этого второго случая, потому что это ненужная сложность :использование IP-адреса, принадлежащего хосту, а не 127.0.0.1, должно быть достаточно для любого теста. Кроме того, если интерфейс docker0
будет удален и создан заново, настройка route_localnet
будет потеряна, и было бы неразумно устанавливать ее по умолчанию.
Не задано, но если вы добавите сюда вторую систему (контейнер )в той же локальной сети, возникнут проблемы с локальной сетью -на -хост -на -тот же -перенаправления локальной сети (, если только Docker уже не обрабатывает это на сетевом уровне ).
Правило nat/PREROUTING
, которое я написал в начале ответа, обрабатывает только интерфейс eno1
. Была причина, по которой я добавил это -i eno1
ограничение :без него, если другой контейнер в сети 172.17.0.0/16 попытается подключиться, например, к 172.16.214.45 :8443 (или к 172.17.0.1 :8443 ), пакет будет перенаправлен на 172.17.0.2. Затем 172.17.0.2 ответит напрямую источнику :другому контейнеру и полностью обойдет хост и его правила NAT.Этот контейнер увидит ответный пакет, пришедший из источника, о котором он не знает, и отклонит его (с помощьюTCP RST
). Так что лучше не справляться с этим вообще, чем справляться плохо. Docker, вероятно, предоставляет определенные способы прямого разрешения службы на IP/порт другого контейнера без участия хоста.
В любом случае, если это необходимо, существует несколько способов преодолеть это, часто с компромиссом, от простого NAT (, который теряет исходный IP-адрес или должен транслировать его в фиктивную сеть, для целей регистрации )до сложного моста и /или настройки маршрутизатора, способные перехватывать связь по локальной сети.
Вот простое решение, где источником является SNAT -ed, использующий NETMAP
, для фиктивной сети 10.17.0.0/16. Простое предварительное условие :10.17.0.0/16, вероятно, должно быть направлено на хост (, даже если он на самом деле не используется ), либо по маршруту по умолчанию (, вероятно, в случае ), определенному маршруту, либо с помощью хост, имеющий IP-адрес в этой фиктивной сети для этой цели. Пакеты с этим IP-адресом будут существовать только внутри сети docker0
.
После удаления -i eno1
из правила PREROUTING
выше добавьте это новое правило:
iptables -t nat -I POSTROUTING -s 172.17.0.0/16 -d 172.17.0.0/16 -j NETMAP --to 10.17.0.0/16
Теперь перенаправление из локальной сети в ту же локальную сеть будет работать, а журналы контейнера назначения будут показывать исходные IP-адреса в диапазоне 10.17.0.0/16.
Конечно, следует также избегать ситуаций, связанных со шпильками.