Статья является переводом текста Майкла Лукаса (Micle Lucas),
опубликованного по адресу
http://www.onlamp.com/pub/a/bsd/2002/02/14/Big_Scary_Daemons.html
Недавно мы обсуждали использование распределенных файловых систем,
основанных на протоколе SMB. После полудюжины манипуляций, SMB дает
вам доступ к распределенным ресурсам Windows-машины. Доступ к общим
ресурсам UNIX-машины намного, намного проще! FreeBSD поддерживает
стандартную UNIX'овую Network File System (сетевая файловая система)
прямо "из коробки", т.е. практически без дополнительных манипуляций
(уж GENERIC-ядро вам точно не придется перекомпилировать - прим.
переводчика). NFS пугает многих новичков в деле системного
администрирования, однако на самом деле она весьма проста в
эксплуатации, при условии, что вы знаете что делаете (все как обычно -
прим. переводчика).
Любое NFS-соединение работает по клиент-серверной схеме. Один
компьютер является сервером и предоставляет свои файловые системы
другим машинам. Это называется "NFS-экспортирование", а
предоставляемые файловые системы называют "экспортами". Клиенты могут
монтировать экспорты сервера почти точно так же как и локальные
файловые системы.
Одним из интересных свойств NFS является отсутствие привязки клиента к
текущему состоянию сервера (stateless). Вы можете перезагрузить
сервер, при этом клиенты не "отвалятся". Разумеется они не смогут
получить доступ к экспортам сервера когда он отключен, однако как
только сервер вернется в строй, вы сможете просто продолжить работу с
места вашей остановки. Другие сетевые файловые системы не так
невозмутимы.
В этой статье мы обсудим создание соединений от любых FreeBSD-клиентов
к серверу на основе FreeBSD 4-STABLE. Разные реализации NFS слегка
отличаются друг от друга. Вы обнаружите небольшие отличия в реализации
NFS для Solaris, Linux и любой другой UNIX системы. NFS будет работать
на всех этих системах, однако вам может понадобиться некоторая доводка
настроек для работы в гетерогенной сети (т.е. сети с различными
операционными системами - прим. переводчика). Если вы столкнетесь с
трудностями при реализации NFS-соединения между разными реализациями
NFS, обратитесь к архиву списка рассылки freebsd-net, там почти
наверняка есть описание решения вашей проблемы.
Теперь давайте сконфигурируем какие-нибудь FreeBSD-системы для
использования NFS. И NFS-клиент, и NFS-сервер требуют для своей работы
поддержки NFS ядром. Однако различные команды работающие с NFS
динамически загружают необходимые модули. GENERIC-ядро поставляемое в
комплекте с системой уже содержит модуль поддержки NFS, однако если вы
собираете ядро сами и не хотите загружать поддержку NFS в виде модуля,
то убедитесь что в файле конфигурации содержится следующая строка:
options NFS
Итак, займемся, для начала, серверной стороной. Вы можете разрешить
поддержку NFS добавив в файл /etc/rc.conf следующие строки:
portmap_enable="YES"
nfs_server_enable="YES"
Portmap предоставляет, как вы можете догадаться, функции отображения
для сетевых портов. Различным экспортам и клиентам требуются
уникальные сетевые порты. Клиент спрашивает у portmap номер порта, к
которому следует подключаться для проведения текущего монтирования
файловой системы. Опция nfs_server_enable запускает демонов nfsd и
mountd. Mountd просто ожидает входящие NFS-запросы на определенных
портах с большим номерами, а так же делает эти порты доступными для
portmap. Когда клиент общается с mountd и portmap, на самом деле его
запросы обслуживает демон nfsd.
После перезагрузки ваш сервер должен показывать нечто подобное в ответ
на команду sockstat. Это говорит о том, что ваш сервер работает более
или менее нормально. Если вы не видите подобного сообщения, то
поглядите файл журнала /var/log/massages для обнаружения причины сбоя.
На ваших клиентах sockstat не выведет ничего похожего, пока вы не
смонтировали ни одного ресурса, однако команда ps -ax покажет вам
несколько запущенных процессов nfsiod (странно что автор не указал,
что на клиенте в файл /etc/rc.conf следует добавить только одну
строку: nfs_client_enable="YES", лишь в этом случае запустится демон
nfsiod, служащий для обслуживания запросов поступающих от клиента к
серверу прим. переводчика).
Теперь, когда ваши системы полностью подготовлены к использованию NFS,
нам необходимо указать серверу, какие каталоги он может
экспортировать. Мы можем экспортировать все содержимое сервера, но
обычно это неразумно. Клиенты должны иметь минимальную или вообще не
иметь необходимости в удаленном монтировании корневой директории
сервера. Каталоги разрешенные к экспорту указываются в файле
/etc/exports. Каждая строка в этом файле соответствует физическому
дисковому разделу. Строка конфигурации может содержать до трех
параметров:
* Экспортируемый каталог
* Параметры экспортирования
* Клиенты, которые могут подключаться
Каждая комбинация клиентов и дисковых разделов сервера может иметь
только одну строку в файле /etc/exports. Это значит, что если
/usr/ports и /usr/home находятся на одном физическом разделе, то их
экспорт должен быть описан в одной строке для всех клиентов (к
сожалению с чем связано такое ограничение совершенно непонятно прим.
переводчика). Вам необязательно экспортировать весь раздел, вы можете
сделать доступным один каталог в пределах раздела. Этот каталог должен
быть задан полным путем и не содержать ссылок (симлинков) и символов
"точка" (".") и "две точки" (".."). Если я захочу предоставить доступ
к моему домашнему каталогу любому узлу в Интернете, то в файле
/etc/exports я должен буду написать следующую строку:
/usr/home/mwlucas
Мы не указали ни параметров, ни ограничений на доступ. Для того что бы
изменения вступили в силу нам необходимо заставить mountd перечитать
/etc/exports:
killall -1 mountd
Все ошибки будут зафиксированы в файле /var/log/messages. Например,
когда я первый раз тестировал NFS, в файле /etc/exports была одна
строка /home/mwlucas. Так было до того момента, когда я узнал о
недопустимости ссылок (симлинков) в /etc/exports. Пользовательские
каталоги в FreeBSD находятся в /usr/home и для создания стандартного
каталога /home используется ссылка (симлинк). В журнале ошибок я
обнаружил следующее предупреждение:
Jan 24 07:13:35 server mountd[68]: bad exports list line /home/mwlucas
Эта информация указала мне на место возникновения проблемы. Устранение
проблем - моя работа.
На стороне клиента я создал каталог $HOME/serverhome. Я хотел что бы
NFS-mount монтировала мой домашний каталог на сервере в этот каталог
на клиенте. Это выглядит практически также как и использование обычной
команды mount. Mount использует два аргумента - физическое устройство
и точку монтирования. В данном случае в роли физического устройства
выступает удаленный сервер и экспортируемая файловая система:
# mount server:/usr/home/mwlucas serverhome
#
После выполнения команды монтирования поглядите что получилось при
помощи команды df:
Заметьте, что NFS использует одинаковые имена пользователей на каждой
стороне соединения. Мои файлы, принадлежащие пользователю mwlucas на
сервере, будут принадлежать ему и на клиенте. Это может вызвать
проблемы в больших сетях, где пользователи имеют привилегии root на
своих машинах. Для создания централизованного хранилища авторизованных
пользователей рассмотрите использование Kerberos и NIS (по большому
счету можно сказать, что если вас интересует безопасность, то NFS
следует использовать как минимум вместе с NIS - прим. переводчика). В
малых сетях или сетях с одним администратором это обычно не проблема.
Просмотрев содержимое каталога $HOME/serverhome мы увидим, что
большинством файлов владеет пользователь mwlucas, и лишь некоторыми -
пользователь root. На мой взгляд из здесь быть не должно. Я сделал
несколько png-скриншотов терминального окна для моей книги, которыми
владеет пользователь root. Раз их не должно здесь быть, я их удалю:
# su
# cd serverhome
# rm usersetup.png
override rw-r--r-- root/mwlucas for usersetup.png? y
rm: usersetup.png: Permission denied
#
Но я же root! Почему я не могу удалить этот файл?
Я root на клиенте, но не на сервере. Сервер не доверяет пользователям
root, зарегистрированным на других машинах, выполнять команды от
пользователя root на сервере. NFS имеет специальный параметр для
поддержки пользователя root, при помощи которого вы можете выполнять
запросы клиентского пользователя root от имени любого пользователя
сервера. Например вы можете указать, что все запросы от пользователя
root на клиенте будут выполняться на сервере от имени пользователя
nfsroot. Правильно используя группы вы можете дать этому пользователю
некоторый ограниченный доступ к данным на сервере. Используйте
параметр -maproot для выполнения запросов root'а от имени другого
пользователя.
Так как это моя домашняя сеть и кроме меня в ней нет пользователей, я
могу полностью доверять клиенту. В данном случае я уравняю клиентского
пользователя root с серверным, задав идентификатор 0 (uid пользователя
root) для выполнения команд клиентского root на сервере:
/usr/home/mwlucas -maproot=0
Я опять перезапущу mountd. Так как у NFS отсутствует привязка к
текущему состоянию, ранее смонтированные каталоги не надо
перемонтировать заново -- изменения отразятся на них автоматически. В
это время я на клиенте оставался в том же каталоге; перезапуск mountd
вообще не затронул клиентскую сторону. И команда rm теперь работает
безупречно.
А что если я захочу экспортировать еще один каталог на том же
физическом разделе? Например, предположим, что я хочу экспортировать
каталог /usr/src для моего ноутбука для того, что бы сохранить место
на его небольшом винчестере. Список других каталогов указывается в
/etc/exports через пробелы. Заодно я экспортирую и каталог /usr/obj.
Таким способом я могу запускать make buildworld на быстрой серверной
машине, а на слабом ноутбуке писать только make installworld, что
резко ускорит обновление системы. Теперь мой /etc/exports выглядит вот
так:
/usr/home/mwlucas /usr/src /usr/obj -maproot=0
Между компонентами строки нет никаких разделительных идентификаторов.
Было бы намного проще, если бы каждому каталогу соответствовала одна
строка в файле, но так сделать нельзя, потому что все каталоги
принадлежат одному физическому разделу. Команда разработчиков FreeBSD
легко могла бы устранить это неудобство, но тогда наши /etc/exports
стали бы несовместимы с реализациями NFS в остальных UNIX системах.
Перезапустите mountd и смонтируйте эти файловые системы на клиенте:
# mount server:/usr/obj /usr/obj
# mount server:/usr/src /usr/src
Теперь список файловых систем на моем клиенте выглядит следующим
образом:
Команда make buildworld выполняется на моем ноутбуке два часа, на
сервере она занимает лишь 30 минут. Ранее мне приходилось выполнять
make buildworld и make buildkernel на сервере, и если я хотел такое же
ядро, то я просто входил в /usr/src и писал make installkernel && make
installworld && mergemaster, и FreeBSD собранная на моем сервере,
устанавливалась на ноутбук.
Для того что бы жизнь была немного сложнее, моя домашняя система
подключена через кабельный модем. Для защиты сети от вторжений, я
использую встроенный в FreeBSD брандмауэр, но неплохо бы добавить
защищенности в саму NFS. Вы можете легко ограничивать доступ к
экспортам NFS по IP адресам, позволяя лишь некоторым клиентам их
монтирование. Просто укажите имя или адрес узла в конце строки
описания экспорта. Теперь мой /etc/exports выглядит вот так:
Скоро находится еще повод для обновления списка экспортов - было бы
неплохо собирать FreeBSD-порты на сервере, а устанавливать на клиенте,
экспортируя /usr/ports. Это начинает становится немного забавным, но в
конце концов вы обнаружите, что почти все каталоги находящиеся в /usr
окажутся в файле /etc/exports. Можно было бы покончить с этим
экспортировав каталог /usr целиком. Это не так хорошо как кажется, так
как я хочу монтировать экспортированные каталоги в разные места, так
как если экспортированный /usr/ports вполне может перекрыть тот же
каталог на клиентской машине, то перекрытие домашних каталогов
пользователей (/usr/home) недопустимо. К счастью существует простое
решение: параметр -alldirs позволяет вам экспортировать каталог и все
его подкаталоги. Вы должны указывать раздел диска, когда вы
используете -alldirs. Параметры разделяются запятой:
/usr -alldirs,maproot=0 192.168.1.200
Теперь я опять перезапущу mountd. Все содержимое /usr теперь можно
монтировать по отдельности. Например я оставил /usr/obj и /usr/src
смонтированными. Быстрое тестирование при помощи df и ls показало, что
они остались на своих местах и файлы в них по-прежнему доступны,
несмотря на полное изменение способа их экспортирования. Я могу
монтировать любые каталоги из серверного /usr.
И наконец поговорим о производительности. По-умолчанию NFS использует
"безопасные" параметры монтирования, которые отлично подходят для
взаимодействия с другими реализациями NFS на других UNIX. В этом
случае все машины "разговаривают" используя ограниченный набор
более-менее одинаково понимаемых команд. Вы можете изменить некоторые
параметры, увеличив тем самым производительность, уменьшая, однако,
совместимость с другими реализациями. Если ваша сеть насчитывает
два-три NFS-клиента, то скорее всего изменение этих параметров вам не
понадобится, однако если ваша сеть будет расти, то они могут вам
помочь. Итак следует иметь в виду, что они могут работать или не
работать на разных системах - все зависит от поддержки их операционной
системой.
Во-первых NFS по-умолчанию использует протокол UDP. Параметр tcp
указывает, что для монтирования необходимо использовать протокол TCP.
Теперь сделаем монтированные каталоги "прерываемыми". Это значит, что
при отключении сервера по какой-нибудь причине, клиентская программа,
пытающаяся получить доступ к недоступному в данный момент экспорту
может быть прервана. Если не указать этот параметр, то клиентская
программа будет продолжать пытаться получить доступ к экспорту, пока
не окончится таймаут файловой системы (т.е. программа на время "глухо"
зависнет - прим. переводчика). "Прерываемость" устанавливается
параметром intr.
NFS существует в нескольких версиях. Последняя и самая широко
распространенная на текущий момент версия 3. Вы можете потребовать
использование клиентами третьей версии используя параметр nfsv3.
Наконец, вы можете изменить размер блоков данных, которыми
обмениваются клиент и сервер. По-умолчанию он слишком мал. Такой
размер хорошо подходил для сетей в начале девяностых годов. Вы можете
установить более современные значения для пакетов чтения и записи
используя параметры -r и -w. 32768 - хорошее значение для обоих.
Итак собрав все вместе я буду монтировать мои экспорты следующим
способом:
# mount -o tcp,intr,nfsv3,-w=32768,-r=32768 server:/usr/home/mwlucas serverhome
Таким образом я получил максимальную производительность при
минимальных издержках. Дальнейшая тонкая настройка NFS потребует от
вас тестирования различных параметров на вашем конкретном сетевом
оборудовании.
Теперь, когда я использую NFS дома, я стал замечать, что монтирую
каталоги одной машины на другой при малейшей необходимости. Это стоит
того.