История одного upgrade FreeBSD


Или сказка о том, как я на FreeBSD 5.1 переходил
Эта статья не будет рассказывать об особенностях работы тех или иных программ. Она не будет учить Вас чему-то. В ней не будут описываться стандартные конфигурации. Это просто рассказ о том, как я обновлял версию FreeBSD. Со всеми находками и ошибками. Кто-то, прочитав ее, сможет не наступить на те грабли, по которым я топтался. Кто-то вообще откажется от обновления. Кто- то, наоборот, отважится на сей геройский поступок. Новички узнают что-то новое для себя. Матерые сисадмины вспомнят молодость и посмеются над моей наивностью. Итак...

Достался мне по наследству сервер о 32-х мегабайтах памяти. На поле в три гектара гордо раскинулась ось, тридцать пятой фрёй именуемая. Служил сей сервер провайдеру малому, у коего помимо своей локалки еще 150 дайлапников числилось. И крутились на нем окромя биллинга Apache, SQUID, IPFW, Sendmail, BIND и прочая мелочевка. Время шло. Росло число клиентов. Со временем и третья ветка FreeBSD перестала поддерживаться сообществом разработчиков. Устаревал Apache. Читая сообщения от FreeBSD Security Advisory об очередных дырах в защите (и заплатках только для 4.х-систем), надеялся, что никто на наш скромный сервер не покусится и все больше склонялся к мысли, что пора расти до "четверки". Однако сначала дело упиралось в недостаток опыта и неверие в свои силы. Затем стали появляться другие причины отложить это дело (как всегда, впрочем).

Вот уже вышел RELEASE-4.8, на всех форумах во всю обсуждались особенности пятой ветки. А я все еще наслаждался своей "3.5". Однако желание обновить ось с каждым днем крепло все сильнее. Особенно укрепилось оно тремя обстоятельствами - выходом 5.1- RELEASE, вручением нам киски (а вместе с ней и канала в 1 Мб/с) и регулярным переполнением свопа (для него раньше 64 Мб вполне хватало, но теперь то ли от увеличившейся нагрузки, то ли от излишне грамотного администрирования его стало хватать от силы на неделю, после чего приходилось лечиться перезагрузкой). Кроме того, раздела /var, под который были выделены дефолтные 20 Мб, явно стало не хватать, и даже перенос почтовых ящиков, спула, логов на /usr (на /var в связи с этим были оставлены символьные линки на новое местоположение, так что система ничего даже не заметила) не способствовал снижению "забитости" ниже 70%.

Пока я думал да гадал, начали ходить упорные слухи о том, что пятая ветка скоро получит статус стабильной (а вслед за этим довольно скоро следует прекращение поддержки предыдущей ветви). В связи с этим обстоятельством решено было апдейтить систему сразу до версии 5.1. Поскольку в те времена слово cvsup ничего, кроме панического ужаса и благоговения перед теми гуру, которые владели этим методом, в меня не вселяло, то путь оставался один - собирать систему с нуля с последующим переносом накопившихся данных. Да и жутковато было обновляться через целую ветку, да еще на нестабильное ядро.

И вот, собравшись с духом, выпросил я себе у начальства винчестер и начал готовиться к переезду. Помня, как в свое время FreeBSD, установленная на Secondary Slave, упорно не желала запускаться с Primary Master, ругаясь на недоступность раздела, я не стал проверять, сохранилась ли данная фича в новой версии, а сразу стал работать как положено (желая вернуться в Windows, просто перетыкал шлейф на другой винт).

Как и следовало ожидать, "в лоб", то есть с раздела DOS, загрузка не пошла - возникли какие-то проблемы с геометрией диска (а это было чудо о сорока гигабайтах производства Hitachi). Ткнувшись безрезультатно в двух-трех направлениях и списав проблему на нестабильность новой версии, я бросил это грязное дело и поставился по FTP, благо канал уже позволял такую роскошь.

Почти месяц игрался я с cvsup, ставил и удалял разные программулины из портов, практиковался с перекомпиляцией ядра и т.п. Набив в этом деле руку и подняв все, что должно было понадобиться в будущем, стал я искать подходящий момент для того, чтобы прикрутить на сервер новый винчестер. Учитывая опыт предыдущих товарищей (прежде всего себя), на переезд нужно было зарезервировать как минимум день.

Особенно меня смущала мультипортовка, которая обеспечивала должное число портов на сервере и которая на моей тестовой машине отсутствовала. Новый подход FreeBSD к описанию портов, примененный в пятой ветке, пугал и обнадеживал одновременно. Заключается он в том, что в конфигурационном файле ядра (который в /usr/src/sys/i386/conf лежит), теперь большинство устройств, в том числе последовательные порты, описываются просто строкой типа "device sio", то есть ядру указывается, что последовательные порты есть, и предлагается во время загрузки самостоятельно с ними разобраться. Чтобы ядру было проще, введен файл /boot/device.hints, в котором представлены строки-подсказки о том, какие конкретно устройства с какими ресурсами (прерываниями, номерами портов и т.д.) следует пытаться найти. Например, для контроллера дисковода там представлены следующие строки:

hint.fdc.0.at="isa"
hint.fdc.0.port="0x3F0"
hint.fdc.0.irq="6"
hint.fdc.0.drq="2"

Руководствуясь этими подсказками, ядро при загрузке попытается найти на порту 0x3F0 контроллер НГМД и назначить ему прерывание номер 6.

Безусловно, это нововведение существенно облегчает жизнь системным администраторам. Только представьте - при добавлении мультипортовки или еще каких манипуляциях с устройствами ядро не нужно пересобирать! Но с другой стороны, просто перенести строки с описанием моей мультипортовки в новое ядро уже не получалось. Не сильно напрягая свой думательный орган, я эти строки перенес в хинты, просто приведя их в соответствие с синтаксисом по аналогии с тем, что там было, и теперь был готов сотню раз менять эти описания и даже перекомпиливать ядро, пока не наткнусь на работающий вариант.

Дождавшись субботы (когда желающих проломиться в Интернет меньше всего), я воткнул новый винт в сервер и загрузился с него. На мое удивление, шаманить с device.hints не пришлось - все порты определились без проблем. Подмонтировав старый винт, я перебросил на новый львиную долю конфигурационных файлов (включая файл паролей), а также папки биллинга и папку с почтовыми ящиками пользователей (/var/mail). А теперь внимание! Никогда так не делайте, не сохранив предварительно исходную конфигурацию в надежном месте!

Затерев добрую половину конфигов старыми, я получил ряд весьма интересных проблем. Нет, перезагрузка выполнилась "на ура", и даже пользователи, изголодавшиеся по сети за то время, пока я прикручивал новый винчестер, коннектились как положено, на что я, честно говоря, не особо рассчитывал.

Первая обнаруженная неприятность заключалась в том, что перестал запускаться sendmail. Анализ логов выявил, что новая версия запускается не от рута, как было раньше, а от лица непривилегированного пользователя smmsp. Которого, как Вы уже, наверное, догадались, в моем старом master.passwd не было. И нового файла паролей тоже уже не было... Однако безвыходных ситуаций не бывает. Точнее, бывают, но не надолго. Нужен тебе пользователь? Получи!

После добавления пользователя запускаем почтаря, благо в пятой фре это стало сделать проще, чем когда-либо (можно даже перефразировать известную надпись и сказать, что FreeBSD стала лучше во всех отношениях; кто часто ставил Windows 98, тот поймет, о чем я):

cd /etc/mail
make start

Пишет, что не может войти в /var/spool/clientmqueue. Еще бы! Раньше ведь эта директория принадлежала пользователю - владельцу sendmail, а теперь-то он другой... Выходит, не угадал с UID-ом. Не беда - меняю этой папке владельца:

chown smmsp:smmsp /var/spool/clientmqueue

Снова запуск. Ошибок не последовало. Однако снаружи почту ни принять, ни отправить нельзя. В ходе всесторонней проверки выясняется, что почта отправляется только с консоли. В логи пишет что-то про ошибку SMTP-сокета. Пробую соединиться телнетом на 25-й порт - не пускает. На 110 - тоже. И на родной телнетовский порт заходить тоже не хочет. Хотя по SSH соединяется без проблем. Случайно выясняю, что FTP тоже не пашет... Делаю предположение, что все проблемы взаимосвязаны и начинаю искать FTP-сервер, поскольку думаю, что это проще всего.

Процесса ftpd не обнаруживаю. При перезагрузке в логи ничего по этому поводу не пишется. Читаю умную книжку: "...Процесс ftpd запускается супер-сервером inetd при обращении к порту 21..."; Кошмар! Как я мог забыть про эту основополагающую особенность системы? Точно - процесс inetd не запущен! Соответственно не будут работать ни POP3, ни FTP, ни TELNET (SSH имеет своего демона в системе и к inetd не привязана, потому и работает). Запускаю его руками:

inetd -wW

Все, что к нему было привязано, начинает работать. Перегружаюсь - никого. В логах сообщений об ошибках нет. Читаю умную книжку дальше: "...Если система запущена с securelevel=1 или выше, то процесс inetd не запускается". Хм, раньше уровни безопасности во FreeBSD или вообще отсутствовали, или работали неявно. По крайней мере я про них ничего не знал. А тут уже что-то новенькое. В ходе дальнейшего прочтения выясняю, что установить уровень безопасности можно в файле /etc/rc.conf, в параметре "kern_securelevel". А родной rc.conf я затер... Не зная, как система грузится по умолчанию (можно, кончено, в /etc/default/rc.conf посмотреть, но лень), набиваю руками:

kern_securelevel="0"
inetd_enable="YES"

Наверное, достаточно было бы только второй строчки, но экспериментировать уже как-то лень. Да и умная книжка тоже авторитет.

Перегружаюсь и радостно созерцаю inetd в списке процессов. Теперь почта принимается, но не отправляется (имеется в виду "на клиентских машинах"). Значит, sendmail все-таки как-то не так настроен. Вспоминаю ту страшную минуту, когда я бездумно перезаписывал родной sendmail.cf своим от старой системы... А почтарь-то уже новый, как-никак 8.12.9p1. Принимаю скоропалительное решение - кэвэсапиться. Уже потом, когда "make buildworld" был запущен, понимаю, что достаточно было просто скопировать конфиги из /usr/src/etc/sendmail или поискать что- нибудь подходящее в /usr/share/sendmail/cf. Но уже поздно...

Честно выполняю всю процедуру до конца:

cd /usr/src
make buildworld
make buildkernel KERNCONF=MYKERN
make installkernel KERNCONF=MYKERN
make installworld

На все уходит около четырех часов, из них львиная доля - построение системы (buildworld). Если бы предварительно убил папку /usr/obj, то можно было бы немного времени сэкономить, но хорошая мысля приходит опосля...

Прежде чем перегрузиться, делаю то, ради чего все, собственно, и затевалось:

mergemaster -cv

То есть сравниваю свои конфигурационные файлы со вновь построенными. Пользоваться утилитой mergemaster - одно удовольствие (а не пользоваться - другое, как сказал бы Фоменко). При обнаружении в файлах различий список оных выводится на экран, и Вам предлагается нажать одну из четырех клавиш:

i - установить новый файл вместо старого;
d - удалить новый файл и оставить старый;
m - провести построчное сравнение;
v - посмотреть список различий еще раз.
В случае с sendmail я установил новые файлы, для файлов паролей, групп и ряда других провел построчное сравнение, когда на экран выводятся обе различающиеся строки и Вам предлагается выбрать, какую из них записать в итоговый файл - левую или правую. Bосстановил таким образом законного пользователя smmsp. Переопределить владельца папки clientmqueue я, естественно, забыл. Sendmail при первой же перезагрузке мне об этом напомнил, однако нас таким уже не запугать. Владельцев мы менять умеем.

Несмотря на приведение системы в исходное состояние, почта не отправлялась. Если быть точнее, то не принималась ни с наружи, ни из локальной сети. С сервера уходила нормально. Значит, что- то с процессом, который прослушивает 25-й порт. Попытка зайти туда телнетом к добру не привела. Выходит, порт не прослушивается в принципе. Вспомнил про одну очень полезную утилиту:

netstat -a

Она показала, что 25-й порт (который smtp) прослушивается только на localhost. Проверил DNS, файлы hosts.allow, resolv.conf. Вроде все как надо. MX-запись для хоста есть. На всякий случай создал файл /etc/mail/local-host-names, хотя сервер у меня всего один. Не помогло...

Иду со своей проблемой в Интернет. После некоторых метаний нахожу то, что нужно - оказывается, с некоторой версии sendmail по умолчанию конфигурируется для работы только с локальным хостом. То есть стартовая конфигурация ориентирована на пользовательскую рабочую станцию. Чтобы заставить его работать "снаружи", нужно добавить в мастер-конфиг freebsd.mc, на основе которого собирается все остальное, строчку:

DAEMON_OPTIONS(`Name=IPv4, Family=inet)dnl

Точнее, эта строка в нем уже есть, ее просто нужно раскомментировать (в формате mc-файла комментарий обозначается символами dnl, вот их нужно перенести в конец строки или вообще убрать).

Собирать конфигурационный файл sendmail.cf тоже стало предельно просто:

cd /etc/mail
make
make install

Перезапускаемся:

make restart

И почта работает! Ура! Почти... Дело в том, что у меня есть абоненты, которые пользуются UUCP-почтой. Для этого sendmail должен быть соответствующим образом настроен. Знать бы только, как именно... В состав системы UUCP уже не включена, поэтому ставилась отдельно из портов (/usr/ports/net/freebsd-uucp). Конфиги также были молча перезаписаны старыми.

Поскольку я уже знал, как нужно поправить mc-файл sendmail-а, чтобы заставить его "слушать" внешние адреса, то вместо того, чтобы разбираться с настройками uucp, я просто добавил соответствующую строку в свой старый конфигурационный файл и рискнул пересоздать sendmail.cf уже на его основе. Как ни странно, но это сработало, то есть почту, адресованную uucp- пользователям, sendmail стал принимать и складывать куда надо. Для тех, кому интересно, привожу свой файл /etc/mail/freebsd.mc, на основе которого собирался sendmail.cf:

divert(0)dnl
VERSIONID(`@(#)server.ru$Revision: 1.4.2.1 $')
OSTYPE(freebsd5)dnl
DOMAIN(generic)dnl
DAEMON_OPTIONS(`Name=IPv4, Family=inet')dnl
FEATURE(use_cw_file)dnl
FEATURE(accept_unqualified_senders)dnl
FEATURE(relay_based_on_MX)dnl
FEATURE(mailertable, `hash -o /etc/mail/mailertable')dnl
FEATURE(access_db, `hash -o -T /etc/mail/access')dnl
FEATURE(blacklist_recipients)dnl
FEATURE(virtusertable, `hash -o /etc/mail/virtusertable')dnl
FEATURE(local_lmtp)dnl
define(`LOCAL_MAILER_FLAGS', LOCAL_MAILER_FLAGS`'P)dnl
define(`confCW_FILE', `-o /etc/mail/local-host-names')dnl
define(`confNO_RCPT_ACTION', `add-apparently-to')dnl
define(`confMAX_MIME_HEADER_LENGTH', `256/128')dnl
define(`confMAX_MESSAGE_SIZE', `1500000')dnl
define(`UUCP_MAILER_MAX', `1500000')dnl
define(`confMAX_DAEMON_CHILDREN',`25')dnl
MAILER(local)dnl
MAILER(smtp)dnl
MAILER(uucp)dnl

Наиболее важной в UUCP-плане строкой здесь, по моему глубокому разумению, является последняя. Остальные, в большинстве своем, рассказывают sendmail-у, что и где у него лежит.

Итак, почти все хорошо. Только вот UUCP-пользователи почему-то не коннектятся. Выкидывает их с криком "LOGIN FAILURE". Начал разбираться, как у них проходит авторизация. Файла passwd или чего-нибудь в этом роде в папке /usr/local/etc/uucp не нашлось. Значит - через /etc/master.passwd. Полез я туда - точно, все пользователи там лежат. И в качестве командного интерпретатора у них /usr/libexec/uucico числится. Вроде как все логично...

Стал я эту uucico искать. И вспомнил про еще один основополагающий принцип FreeBSD - в /usr лежит только то, что ставится вместе с системой, например, sendmail. Все остальное - в /usr/local. Поскольку uucp уже не часть системы, то искать ее нужно в /usr/local/libexec. Там она и оказалась. Вносим нужные исправления в /etc/master.passwd (естественно не напрямую, а используя замечательную утилиту vipw), и получаем работоспособный сервер электронной почты. Хорошая все-таки вещь - преемственность.

Резюмируя все сказанное выше, можно сделать вывод, что в большинстве случаев прямой перенос конфигурационных файлов из старой системы в новую - самое быстрое решение при обновлении системы (не считая, конечно, CVSup). Нужно только учитывать идеологию системы и не забывать сохранять конфигурационные файлы, если Вы не уверены, что сможете их легко восстановить по памяти.

Обновлено: 12.03.2015