*nix
9 December 2009

Бинарное обновление FreeBSD 6.2 до 8.0

Года два назад я поднимал знакокому сервер для трекера местной локалки. Вопрос выбора ОС не стоял в принципе, естественно FreeBSD, а версия была взята актуальная на тот момент — 6.2 i386. Но вот состоялся релиз FreeBSD 8.0, и я решил попробовать обновиться до 8-й версии на этом сервере, все равно трекер уже полмесяца не работал из-за битой базы при очередном внезапном отключении питания, а за сервером никто не следил, поэтому пару часов даунтайма никому не помешают.

Задача


Произвести бинарное обновление FreeBSD 6.2 i386 до 8.0 i386. Не хочу инициировать очередной холивар на тему «бинарное обновление vs пересборка ядра и мира с исходников», просто хотелось быстро обновиться, а машинка там по нынешним меркам довольно слабая, пересборка мира заняла бы много-много часов. Задача усугубляется тем, что сервер доступен только удаленно, всякие KVM и т.д. подключать просто некому, площадка не обслуживаемая, да и нет их там все равно в наличии. Поэтому варианты типа «не завелось ядро после ребута — загрузим старое», или же в случае чего в сингл мод — не подходят изначально. В случае потери сети и ssh входа задача считается проваленной.

Подготовка


В результате продолжительного гугления сложилось стойкое впечатление, что это гиблое дело: во-первых рекомендуют исключительно пересбор с исходников, а, во-вторых, только поэтапное обновление 6.2 -> 6.3 -> 7.x -> 8.0. Такой вариант меня не устраивал по причине ограниченности времени, дело было вечером, переходящим в ночь, и хотелось бы хоть немного поспать. Поэтому еще немного погуглив основные причины возможных косяков при обновлении, было принято решение рискнуть.

Прежде всего, был внимательно изучен Release Notes к версиям 7.0 и 8.0 на предмет изменений в железе. И, надо сказать, не зря, потому как в сервере используется материнка на чипсете nForce и сеть используется бортовая, а в документе явно сказано

[amd64, i386] The nfe(4) driver, an open-source driver for nForce Ethernet devices, has been added, originally from OpenBSD. This driver has replaced the nve(4) driver in the GENERIC kernel.

В версии 6.2 сетевой интерфейс назывался nve0, значит в 7.0 и выше он будет называться nfe0, учтем это позже при подготовке /etc/rc.conf к обновлению, иначе после первого же ребута мы теряем сервер, поскольку без настроек сетевого интерфейса сеть не поднимется, провайдер не пустит.

Идем далее. Практически все неудачные обновления заканчивались на том, что после установки нового «мира» отказывались работать базовые команды cp, mv, ee и т.д., т.е. дальше по сети мы уже ничего сделать не можем. Отказывали потому, что кто-то где-то зависел от устаревших библиотек, которые удаляются при обновлении. В качестве возможного решения проблемы я решил установить порт compat6x, который содержит все необходимые либы, и они не будут удалены после завершения обновления. Но этот порт естественно отсутствует в дереве портов 6-ой ветки, поэтому мы возьмем его вручную из дерева портов для ветки 8.x.

И еще один момент. Поскольку утилита для бинарного обновления freebsd-update впервые появилась как раз в версии 6.2 и в том виде не поддерживала обновление системы до новой версии, то я взял freebsd-update с другого сервера, на котором работает FreeBSD 7.2.

Обновление


Перед обновлением крайне желательно обновить все порты до последних версий, так и делаем. Для этого будем использовать /usr/ports/sysutils/portupgrade
# portsnap fetch update
# portupgrade -a

Скачиваем обновленный freebsd-update на сервер:
# cd /root && fetch http:// freebsd72.server/freebsd-update
# chmod +x freebsd-update

Устанавливаем либы совместимости с 6-ой веткой compat6x
# fetch ftp6.ua.freebsd.org/pub/FreeBSD/ports/i386/packages-8.0-release/misc/compat6x-i386-6.4.604000.200810_3.tbz
compat6x-i386-6.4.604000.200810_3.tbz 100% of 3060 kB 6805 kBps
# fetch ftp6.ua.freebsd.org/pub/FreeBSD/ports/i386/packages-8.0-release/misc/localedata-5.4.tbz
localedata-5.4.tbz 100% of 71 kB 2243 kBps
# pkg_add compat6x-i386-6.4.604000.200810_3.tbz
# pkg_add localedata-5.4.tbz

Останавливаем всех 3rd party демонов, отключаем их автозапуск в /etc/rc.conf. Также удаляем из файла все строки, связанные с автозапуском или настройкой фич, которые появились в результате пересборки ядра на старой системе, например: firewall_enable, firewall_type, gateway_enable, linux_enable, natd_enable, natd_interface, usbd_enable, enable_quotas. В общем, всего того, что может помешать нам загрузиться на чистой системе. Тут же исправляем настройку сетевого интерфейса ifconfig_nve0 на ifconfig_nfe0, чтобы после установки нового ядра и ребута поднялась сеть.

Убираем из крона всех юзеров все задачи, кроме системных (конечно же не буквально удаляем, комментируем).

Есть еще одна хитрость. Дело в том, что при бинарном обновлении системы с установленными исходниками нужно скачать более чем в 2 раза больше файлов, нежели при обновлении системы без исходников. Эта проблема особенно актуальна при относительно медленном соединении с интернетом, или же в первые дни релиза новой версии FreeBSD, когда сервера обновления перегружены. Поэтому я перед обновлением удаляю каталог /usr/src, чтобы «обновлялка» думала, что исходники у меня не установлены и не подтягивала для них обновление, а после обновления беру исходники из дистрибутива новой версии, который выложен в виде одного файла и скачивается достаточно быстро.
# rm -rf /usr/src


Скачивание обновления

Начинаем
# /root/freebsd-update upgrade -r 8.0-RELEASE
Looking up update.FreeBSD.org mirrors... 3 mirrors found.
Fetching metadata signature for 6.2-RELEASE from update5.FreeBSD.org... done.
Fetching metadata index... done.
Inspecting system... done.

The following components of FreeBSD seem to be installed:
kernel/generic world/base world/catpages world/dict world/doc
world/games world/info world/manpages world/proflibs

The following components of FreeBSD do not seem to be installed:
kernel/smp src/base src/bin src/contrib src/crypto src/etc src/games
src/gnu src/include src/krb5 src/lib src/libexec src/release src/rescue
src/sbin src/secure src/share src/sys src/tools src/ubin src/usbin

Does this look reasonable (y/n)? y

Fetching metadata signature for 8.0-RELEASE from update5.FreeBSD.org... done.
Fetching metadata index... done.
Fetching 1 metadata patches. done.
Applying metadata patches... done.
Fetching 1 metadata files... done.
Inspecting system... done.
Preparing to download files... done.
Fetching 13306 patches.....10....20....30....40....50............13280....13290....13300... done.
Applying patches... done.
Fetching 5413 files... done.


После скачивания всех файлов для обновления утилита попытается обновить системные файлы конфигурации в автоматическом режиме, если какой-то файл вызовет затруднение — пользователю будет предложен новый вариант конфигурационного файла, с возможностью принять его, или же отредактировать файл в ручную.
The following changes, which occurred between FreeBSD 6.2-RELEASE and
FreeBSD 8.0-RELEASE have been merged into /etc/passwd:
...
Attempting to automatically merge changes in files... done.

После слияния всех конфигов будет выведен список всех файлов, которые будут удалены, добавлены или обновлены. Обратите внимание, что на этом этапе в работающую систему еще не вносятся никакие изменения.
The following files will be removed as part of updating to 8.0-RELEASE-p0:
...
The following files will be added as part of updating to 8.0-RELEASE-p0:
...
The following files will be updated as part of updating to 8.0-RELEASE-p0:
...


Обновление ядра

Поскольку исходники системы мы ранее удалили, а они нам понадобятся при сборке собственного ядра, то берем их из дистрибутива новой версии:
# cd /root && fetch ftp6.ua.freebsd.org/pub/FreeBSD/releases/i386/ISO-IMAGES/8.0/8.0-RELEASE-i386-disc1.iso
# mkdir /mnt/freebsd80
# mount -rt cd9660 /dev/`mdconfig -a -t vnode -f "/root/8.0-RELEASE-i386-disc1.iso"` /mnt/freebsd80
# cd /mnt/freebsd80/8.0-RELEASE/src
# ./install.sh all

На этом этапе можно собрать свое ядро при необходимости, обязательно взяв за основу новый конфиг GENERIC-ядра, внеся в него необходимые изменения.
Поскольку я использую панель управления сервером ISPmanager, то я обычно добавляю такие опции в конфиг ядра:
options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=10
options IPFIREWALL_DEFAULT_TO_ACCEPT
options QUOTA

и пересобираю
# cd /usr/src
# make buildkernel KERNCONF=MYKERNEL
# make installkernel KERNCONF=MYKERNEL

Но для начала я решил загрузиться хотя бы в GENERIC-е.

Устанавливаем обновление ядра
# /root/freebsd-update install
Installing updates...
Kernel updates have been installed. Please reboot and run
"./freebsd-update install" again to finish installing updates.
# reboot

Перезагружаемся. Если что-то может пойти не так, то это как правило происходит именно на этом этапе — система просто не загрузится, например из-за неучтенных изменений в драйверах, и мы потеряем сервер. Поэтому скрещиваем пальцы и судорожно пингуем сервер:
Обмен пакетами с tracker.server [123.123.123.123] с 32 байтами данных:
Превышен интервал ожидания для запроса.
...
Превышен интервал ожидания для запроса.
Ответ от 123.123.123.123: число байт=32 время=13мс TTL=58

Есть контакт! Система поднялась, сеть тоже, логинимся на сервер по ssh и видим
# uname -a
FreeBSD tracker.server 8.0-RELEASE FreeBSD 8.0-RELEASE #0: Sat Nov 21 15:48:17 UTC 2009 root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386
# ifconfig
nfe0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=10b<RXCSUM,TXCSUM,VLAN_MTU>
inet 123.123.123.123 netmask 0xffffff00 broadcast 123.123.123.255
...

Как я верно заметил на подготовительном этапе, сетевой интерфейс теперь называется по-другому.

Обновление мира

Устанавливаем обновление мира
# /root/freebsd-update install
Installing updates...
Completing this upgrade requires removing old shared object files.
Please rebuild all installed 3rd party software (e.g., programs
installed from the ports tree) and then run "./freebsd-update install"
again to finish installing updates.

Тут я бы советовал ребутнуть сервер, поскольку в процессе обновления других серверов до FreeBSD 8.0 проявлялись различные нежелательные эффекты сразу после установки мира, как то пожирание процессорного времени ipfw, пару зависших процессов awk и т.д. После перезагрузки все тихо и спокойно.
# reboot

На все про все понадобилось около 45 минут, включая закачку файлов обновления, которая происходила не очень быстро. Поэтому хорошо, что я избавил freebsd-update от необходимости обновлять исходники системы.

Пересборка портов

Теперь нам нужно пересобрать абсолютно все порты. Для начала пересобираем ruby, от которого зависит portupgrade, которым в свою очередь мы будем пересобирать все остальные порты. При этом мы удаляем базу установленных пакетов, потому что при изменении мажорной версии системы portupgrade почему-то считает, что эта база битая.
# rm /var/db/pkg/pkgdb.db
# portupgrade -f ruby\*

При первом старте portupgrade сразу после обновления системы будет скачан новый индекс дерева портов /usr/ports/INDEX-8, и для него будет создана, почему-то битая, база /usr/ports/INDEX-8.db. Поэтому мы ее удаляем, вместе с базой установленных пакетов, и пересоздаем их. Если этого не сделать, portupgrade будет ругаться на битые базы одну и другую при каждом запуске.
# rm /var/db/pkg/pkgdb.db
# rm /usr/ports/INDEX-8.db
# portsdb -fu
# pkgdb -fu

Теперь пересобираем все установленные порты. На сайте FreeBSD советуют использовать portupgrade -fa, но в моем случае portupgrade начал ругаться на неизвестные опции в старых установленных портах (не забываем, все ставилось на 6.2), поэтому пришлось обновлять порты вручную.
# pkg_version -vI
# portupgrade -f pcre
# portupgrade -f perl
# portupgrade -f python25
# portupgrade -f lib\*
# portupgrade -f auto\*
# portupgrade -f p5-\*
...
# portupgrade -f php5\*
...

и т.д., по списку.

Завершение обновления системы

Удаляем устаревшие либы
# /root/freebsd-update install
Installing updates... done.

Включаем задачи крона всех юзеров назад, возвращаем в /etc/rc.conf автозапуск всех дополнительных демонов, и перезагружаемся последний раз
# reboot

Все, FreeBSD 6.2 успешно удаленно бинарно обновлена до 8.0.

Обновление ISPmanager

На сервере установлен ISPmanager, поэтому обновляем и его, поддержка 8-й ветки появилась буквально на днях. Находим необходимый дистрибутив здесь: download.ispsystem.com/FreeBSD-8.0
# cd /root && fetch http:// download.ispsystem.com/FreeBSD-8.0/i386/ISPmanager-Lite/install.tgz
# tar xvf install.tgz -C /usr/local/ispmgr/

Создаем симлинк на расширение для апача правильной версии
# cd /usr/local/ispmgr/lib/apache/
# rm -rf mod_ispmgr.so
# ln -s mod_ispmgr.2.2.0.so mod_ispmgr.so

и обновляем кеш установленных пакетов и его конфигов
# killall ispmgr
# /usr/local/ispmgr/sbin/pkgctl cache
# /usr/local/ispmgr/sbin/pkgctl cache
# rm -rf /usr/local/ispmgr/var/.xmlcache


На этом все, имеем сервер с установленной FreeBSD 8.0 и последними версиями софта из портов.

В процессе подготовки и обновления был использован опыт человечества, изложенный на сайтах, которые можно найти через гугл, в частности freebsd.org, opennet.ru и другие.

UPD: Спасибо всем за карму, перенес в BSDельники

+67
12.9k 55
Comments 34