Много серверов в стойках

Отказоустойчивая система — это очень легко, на самом деле. Залог успеха — вменяемая архитектура. Но может так случится, что заказчик не умеет в архитектуру. От слова «совсем». А его программисты не умеют в хороший код и лаконичные решения. Но уж очень они хотят получить защищённый от отказа оборудования вычислительный комплекс, не содержащий «специфических» решений (типа внешних дисковых контроллеров с двумя target-каналами). Понятно, что речь идёт о кластере из двух машинок с DRBD. И надо это так сделать, чтобы не влипнуть в настройку кособокого ПО заказчика… Короче, нужно разместить «корень» (корневой раздел) на DRBD!

Попробуем собрать подобное решение? Для этого нам нужны две машины схожей конфигурации. Требуется заранее определится с сетевыми именами машин и их адресацией. В примере будут фигурировать хосты drbd-node0 (172.31.255.1/24) и drbd-node1 (172.31.255.2/24). Для связи друг с другом им понадобятся соединённые между собой сетевые интерфейсы, пропускной способностью не менее 1 Гб/с. Данное подключение будет обслуживать только DRBD, так что понадобятся ещё сетевые интерфейсы, чтобы взаимодействовать с пользователями и сетевыми приложениями. Мы будем устанавливать Debian Jessie, так что на момент начала работ обе машины должны быть включены и загружены с live-cd. Так же заранее нужно настроить сетевые интерфейсы, отвечающие за связь между машинами.

Основным моменты работы:

  1. разметка диска;
  2. установка загрузчика (для x86);
  3. настройка DRBD в live-системе;
  4. установка системы с помощью deboostrap;
  5. настройка новой системы правкой конфигурационных файлов и добавление скриптов;
  6. установка ядер и завершение работ.

Обратите внимание, что настройку имён хостов и их адресов, обязательную к проведению после загрузки live-cd, я описывать не буду. Это вы и сами сделаете так, как вам будет привычней. И да, без этого ничего работать не будет!

1. Разметка диска

Обязательным требованием здесь является выделение отдельного DRBD-раздела под «/boot». Остальное — по вашему усмотрению. В примере мы будем использовать таблицу томов GPT, размеченную следующем образом:

  1. раздел для «хвоста» загрузчика (1 МБ);
  2. раздел для загрузчика (16 МБ);
  3. раздел для DRBD («/boot», 384 МБ);
  4. раздел под swap (4096 МБ);
  5. раздел для DRBD («/», всё оставшееся место).

Размечать я буду это всё в parted’е, в live-cd его изначально нет, так что надо не забыть его поставить… Листинг выполнения:

root@drbd-node0:~# parted /dev/sda
GNU Parted 3.2
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit MiB                                                         
(parted) print
Error: /dev/sda: unrecognised disk label
Model: ATA QEMU HARDDISK (scsi)                                           
Disk /dev/sda: 81920MiB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags: 
(parted) mklabel gpt
(parted) mkpart bios-grub 1 2
(parted) mkpart grub-part 2 18                                            
(parted) mkpart drbd-boot 18 402                                          
(parted) mkpart swap 402 4498                                             
(parted) mkpart drbd-root 4498 81919                                      
(parted) set 1 bios_grub on                                               
(parted) print                                                            
Model: ATA QEMU HARDDISK (scsi)
Disk /dev/sda: 81920MiB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start    End       Size      File system  Name       Flags
 1      1.00MiB  2.00MiB   1.00MiB                bios-grub  bios_grub
 2      2.00MiB  18.0MiB   16.0MiB                grub-part
 3      18.0MiB  402MiB    384MiB                 drbd-boot
 4      402MiB   4498MiB   4096MiB                swap
 5      4498MiB  81919MiB  77421MiB               drbd-root

(parted) quit                                                             
Information: You may need to update /etc/fstab.

root@drbd-node0:~# mkswap /dev/sda4
Setting up swapspace version 1, size = 4194300 KiB
no label, UUID=f1191852-11f0-4f1e-a500-c48f364669e5
root@drbd-node0:~# swapon /dev/sda4 
root@drbd-node0:~# 

Как вы видите, swap мы подготовили и подключили тоже на этом этапе. Действия одинаковы как для drbd-node0, так и для drbd-node1.

2. Установка загрузчика

Нам нужен отдельный загрузчик. Из конечной системы он должен будет читать только список доступных ядер, хранящийся в томе DRBD «/boot». То есть его надо установить из live-cd, задав ему специфичную конфигурацию. В live-cd понадобятся пакеты grub-pc-bin и grub2-common. Листинг выполнения установки:

root@drbd-node0:~# mkfs.ext2 /dev/sda2
mke2fs 1.42.12 (29-Aug-2014)
Discarding device blocks: done                            
Creating filesystem with 16384 1k blocks and 4096 inodes
Filesystem UUID: 369f6042-6e02-4a2e-821d-852607518a22
Superblock backups stored on blocks: 
	8193

Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

root@drbd-node0:~# mkdir /mnt/boot-grub
root@drbd-node0:~# mount /dev/sda2 /mnt/boot-grub/
root@drbd-node0:~# grub-install --boot-directory=/mnt/boot-grub /dev/sda
Installing for i386-pc platform.
Installation finished. No error reported.
root@drbd-node0:~# vim.tiny /mnt/boot-grub/grub/grub.cfg
root@drbd-node0:~# umount /mnt/boot-grub 
root@drbd-node0:~# 

Действия для обеих машин идентичны, различается только содержимое grub.cfg.

Листинг grub.cfg с машины drbd-node0:

insmod vbe
insmod vga
insmod part_gpt
insmod ext2
insmod gzio

configfile (hd0,gpt3)/drbd-node0.lst

Листинг grub.cfg с машины drbd-node1:

insmod vbe
insmod vga
insmod part_gpt
insmod ext2
insmod gzio

configfile (hd0,gpt3)/drbd-node1.lst

3. Первичная настройка DRBD в live-системе

Не забудьте поставить пакеты с DRBD! После этого можно составить конфиги для ресурсов. Кто не помнит — в примере их два…

Листинг файла /etc/drbd.d/drbd0.res:

resource drbd0 {
	protocol C;

	startup {
		wfc-timeout 5;
		degr-wfc-timeout 5;
	}

	net {
		after-sb-0pri discard-zero-changes;
		after-sb-1pri discard-secondary;
		after-sb-2pri disconnect;				
		sndbuf-size 0;
		unplug-watermark 16;
	}

	disk {
		al-extents 3389;
	}

	on drbd-node0 {
		device /dev/drbd0;
		disk /dev/sda5;
		address 172.31.255.1:7789;
		meta-disk internal;
	}

	on drbd-node1 {
		device /dev/drbd0;
		disk /dev/sda5;
		address 172.31.255.2:7789;
		meta-disk internal;
	}
}

Листинг файла /etc/drbd.d/drbd1.res:

resource drbd1 {
	protocol C;

	startup {
		wfc-timeout 5;
		degr-wfc-timeout 5;
	}

	net {
		after-sb-0pri discard-zero-changes;
		after-sb-1pri discard-secondary;
		after-sb-2pri disconnect;				
		sndbuf-size 0;
		unplug-watermark 16;
	}

	disk {
		al-extents 3389;
	}

	on drbd-node0 {
		device /dev/drbd1;
		disk /dev/sda3;
		address 172.31.255.1:7790;
		meta-disk internal;
	}

	on drbd-node1 {
		device /dev/drbd1;
		disk /dev/sda3;
		address 172.31.255.2:7790;
		meta-disk internal;
	}
}

Да, файлы на машинах одинаковые. Различаются действия после создания. Для drbd-node1 мы только инициализируем блочное устройство и поднимаем сам DRBD, а для drbd-node0 ещё и primary становимся.

Листинг исполнения команд для drbd-node0:

root@drbd-node0:~# drbdadm create-md drbd0 
initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.
root@drbd-node0:~# drbdadm create-md drbd1
initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.
root@drbd-node0:~# drbdadm up all
root@drbd-node0:~# drbdadm --force primary all
root@drbd-node0:~# 

Листинг исполнения команд для drbd-node1:

root@drbd-node1:~# drbdadm create-md drbd0
initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.
root@drbd-node1:~# drbdadm create-md drbd1
initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.
root@drbd-node1:~# drbdadm up all
root@drbd-node1:~# 

И пока в procfs отображается синхронизация, можно прерваться. Например на сон…

root@drbd-node0:~# cat /proc/drbd 
version: 8.4.3 (api:1/proto:86-101)
srcversion: 1A9F77B1CA5FF92235C2213 
 0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r-----
    ns:258888 nr:0 dw:0 dr:259800 al:0 bm:15 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:79017760
	[>....................] sync'ed:  0.4% (77164/77416)Mfinish: 1:45:41 speed: 12,440 (8,088) K/sec
 1: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r-----
    ns:29404 nr:0 dw:0 dr:30316 al:0 bm:1 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:363764
	[>...................] sync'ed:  8.4% (363764/393168)K
	finish: 0:06:32 speed: 916 (916) K/sec
root@drbd-node0:~# 

4. Установка системы с помощью deboostrap

Выполняется только на primary, то есть на drbd-node0. Не забудьте предварительно установить deboostrap! Листинг выполнения:

root@drbd-node0:~# mkfs.ext4 /dev/drbd0
root@drbd-node0:~# mkfs.ext2 /dev/drbd1
root@drbd-node0:~# mkdir /mnt/new-root
root@drbd-node0:~# mount /dev/drbd0 /mnt/new-root/
root@drbd-node0:~# debootstrap --include=pciutils,usbutils,dnsutils,bash-completion,drbd-utils,initramfs-tools,linux-base,perl,busybox jessie /mnt/new-root/ http://ftp.ru.debian.org/debian/
root@drbd-node0:~# mount /dev/drbd1 /mnt/new-root/boot/

Debootsrap работает долго, выводит много, так что его вывод опущен.

5. Правка системных файлов

Выполняется только на drbd-node0. Листинг исполнения команд:

root@drbd-node0:~# cp /etc/drbd.d/*.res /mnt/new-root/etc/drbd.d/
root@drbd-node0:~# vim.tiny /mnt/new-root/etc/hosts
root@drbd-node0:~# vim.tiny /mnt/new-root/etc/fstab 
root@drbd-node0:~# vim.tiny /mnt/new-root/etc/initramfs-tools/modules 
root@drbd-node0:~# vim.tiny /mnt/new-root/etc/initramfs-tools/hooks/drbd
root@drbd-node0:~# chmod +x /mnt/new-root/etc/initramfs-tools/hooks/drbd
root@drbd-node0:~# vim.tiny /mnt/new-root/etc/initramfs-tools/scripts/init-premount/drbd
root@drbd-node0:~# chmod +x /mnt/new-root/etc/initramfs-tools/scripts/init-premount/drbd
root@drbd-node0:~# touch /run/hostname.conf
root@drbd-node0:~# rm /mnt/new-root/etc/hostname 
root@drbd-node0:~# ln -s /run/hostname.conf /mnt/new-root/etc/hostname
root@drbd-node0:~# vim.tiny /mnt/new-root/etc/kernel/postrm.d/zz-update-boot-list
root@drbd-node0:~# ln /mnt/new-root/etc/kernel/postrm.d/zz-update-boot-list /mnt/new-root/etc/kernel/postinst.d/zz-update-boot-list
root@drbd-node0:~# chmod +x /mnt/new-root/etc/kernel/postrm.d/zz-update-boot-list /mnt/new-root/etc/kernel/postinst.d/zz-update-boot-list 

Листинг содержимого файла /mnt/new-root/etc/hosts:

172.31.255.1	drbd-node0
172.31.255.2	drbd-node1

127.0.0.1	localhost
::1		localhost ip6-localhost ip6-loopback
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters

Листинг содержимого файла /mnt/new-root/etc/fstab:

/dev/drbd0	/	ext4	errors=remount-ro			0 1
/dev/sda4	none	swap	sw					0 0
/dev/drbd1	/boot	ext2	nodev,nosuid				0 2

В initrd должен обязательно оказаться модуль для сетевой карты! Листинг файла /mnt/new-root/etc/initramfs-tools/modules:

# List of modules that you want to include in your initramfs.
# They will be loaded at boot time in the order below.
#
# Syntax:  module_name [args ...]
#
# You must run update-initramfs(8) to effect this change.
#
# Examples:
#
# raid1
# sd_mod
e1000

Листинг файла /mnt/new-root/etc/initramfs-tools/hooks/drbd:

#!/bin/sh

case $1 in
prereqs)
	echo "udev"
	exit 0
	;;
esac

. /usr/share/initramfs-tools/hook-functions


mkdir -p $DESTDIR/lib/udev/rules.d/
for rules in 65-drbd.rules; do
	if   [ -e /etc/udev/rules.d/$rules ]; then
		cp -p /etc/udev/rules.d/$rules $DESTDIR/lib/udev/rules.d/
	elif [ -e /lib/udev/rules.d/$rules ]; then
		cp -p /lib/udev/rules.d/$rules $DESTDIR/lib/udev/rules.d/
	fi
done


mkdir -p $DESTDIR/lib/drbd/
for libfile in drbdadm-84 drbdsetup-84; do
	cp -p /lib/drbd/$libfile $DESTDIR/lib/drbd/
done


cat /etc/drbd.d/global_common.conf >> $DESTDIR/etc/drbd.conf
for config in `ls -1 /etc/drbd.d/ | grep -E '\.res$' | tr "\n" " "`; do
	cat /etc/drbd.d/$config >> $DESTDIR/etc/drbd.conf
done


copy_exec /sbin/drbdadm
copy_exec /sbin/drbdmeta
copy_exec /sbin/drbdsetup


touch $DESTDIR/etc/drbd.initrd


manual_add_modules drbd

Листинг файла /mnt/new-root/etc/initramfs-tools/scripts/init-premount/drbd:

#!/bin/sh

test -e /etc/drbd.initrd || exit 0


SDC_HNAME=`grep -o -E '(^|\s)sdc_hname=\S+(\s|$)' /proc/cmdline | sed -r 's/^\s*sdc_hname=//g' | sed -r 's/\s*$//g'`
if [ -z "$SDC_HNAME" ]; then
	echo "SDC: sdc_hname isn't set!"
	exit 1
fi

SDC_IFACE=`grep -o -E '(^|\s)sdc_iface=\S+(\s|$)' /proc/cmdline | sed -r 's/^\s*sdc_iface=//g' | sed -r 's/\s*$//g'`
if [ -z "$SDC_IFACE" ]; then
	echo "SDC: sdc_iface isn't set!"
	exit 1
fi

SDC_ADDR=`grep -o -E '(^|\s)sdc_addr=\S+(\s|$)' /proc/cmdline | sed -r 's/^\s*sdc_addr=//g' | sed -r 's/\s*$//g'`
if [ -z "$SDC_HNAME" ]; then
	echo "SDC: sdc_hname isn't set!"
	exit 1
fi

SDC_MTU=`grep -o -E '(^|\s)sdc_mtu=\S+(\s|$)' /proc/cmdline | sed -r 's/^\s*sdc_mtu=//g' | sed -r 's/\s*$//g'`

SDC_WAIT=`grep -o -E '(^|\s)sdc_wait=\S+(\s|$)' /proc/cmdline | sed -r 's/^\s*sdc_wait=//g' | sed -r 's/\s*$//g'`
if [ -z "$SDC_WAIT" ]; then
	echo "SDC: sdc_wait isn't set!"
	exit 1
fi


grep -q -E '(^|\s)sdc_debug0(\s|$)' /proc/cmdline
if [ "$?" -eq "0" ]; then
	echo "SDC: interupted at point 0!"
	exit 0
fi


echo "SDC: settings up in-cluster network..."

hostname $SDC_HNAME
if [ "$?" -ne "0" ]; then
	echo "SDC: can't set up hostname!"
	exit 1
fi
echo "$SDC_HNAME" > /run/hostname.conf

if [ ! -z "$SDC_MTU" ]; then
	ip link set $SDC_IFACE mtu $SDC_MTU
	if [ "$?" -ne "0" ]; then
		echo "SDC: can't set up mtu value!"
		exit 1
	fi
fi

ip link set $SDC_IFACE up
if [ "$?" -ne "0" ]; then
	echo "SDC: can't bring up network interface!"
	exit 1
fi

ip addr add $SDC_ADDR dev $SDC_IFACE
if [ "$?" -ne "0" ]; then
	echo "SDC: can't add network address to network interface!"
	exit 1
fi


grep -q -E '(^|\s)sdc_debug1(\s|$)' /proc/cmdline
if [ "$?" -eq "0" ]; then
	echo "SDC: interupted at point 1!"
	exit 0
fi


echo "SDC: bring up DRBD resources..."

modprobe drbd
if [ "$?" -ne "0" ]; then
	echo "SDC: can't insert kernel module!"
	exit 1
fi

sleep 1

drbdadm up all
if [ "$?" -ne "0" ]; then
	echo "SDC: can't bring up DRBD resources"
	exit 1
fi

RESOURCES_COUNT=`grep -E '^\s*[0-9]+:\s+cs:' /proc/drbd | awk 'END { print NR }'`
echo "SDC: we found $RESOURCES_COUNT resources."


grep -q -E '(^|\s)sdc_debug2(\s|$)' /proc/cmdline
if [ "$?" -eq "0" ]; then
	echo "SDC: interupted at point 2!"
	exit 0
fi


grep -q -E '(^|\s)sdc_skip_sync(\s|$)' /proc/cmdline
if [ "$?" -ne "0" ]; then
	ALREADY_SYNCED=0
	while [ "$ALREADY_SYNCED" -ne "$RESOURCES_COUNT" ]; do
		sleep 1
		ALREADY_SYNCED=`grep -E '^\s*[0-9]+:\s+cs:\S+\s+ro:Secondary/(Primary|Secondary)\s+ds:UpToDate/UpToDate\s+C' /proc/drbd | awk 'END { print NR }'`
		DATESTR=`date "+%d.%m.%y %H:%M:%S"`
		printf "\033[1A"
		printf "\033[K"
		echo "SDC: $ALREADY_SYNCED/$RESOURCES_COUNT resources have synced data ($DATESTR)"
	done
fi


grep -q -E '(^|\s)sdc_debug3(\s|$)' /proc/cmdline
if [ "$?" -eq "0" ]; then
	echo "SDC: interupted at point 3!"
	exit 0
fi


echo "SDC: to avoid 'race condition' we wait $SDC_WAIT seconds..."
sleep $SDC_WAIT

echo "SDC: checking resources state..."
READY_TO_MASTER=0
while [ "$READY_TO_MASTER" -ne "$RESOURCES_COUNT" ]; do
	sleep 1
	READY_TO_MASTER=`grep -E '^\s*[0-9]+:\s+cs:\S+\s+ro:Secondary/(Secondary|Unknown)\s+ds:UpToDate/\S+\s+C' /proc/drbd | awk 'END { print NR }'`
	DATESTR=`date "+%d.%m.%y %H:%M:%S"`
	printf "\033[1A"
	printf "\033[K"
	echo "SDC: $READY_TO_MASTER/$RESOURCES_COUNT resources ready to became a master ($DATESTR)"
done

drbdadm primary all
if [ "$?" -ne "0" ]; then
	echo "SDC: can't bring primary state on DRBD resources"
	exit 1
fi


exit 0

Ну и листинг файла /mnt/new-root/etc/kernel/postinst.d/zz-update-boot-list (именно тут вносятся настройки для скрипта инициализации, для каждой ноды отдельно):

#!/usr/bin/perl

use strict;
use warnings;
use Fcntl qw(:flock SEEK_END);


my %config = (
	'grub_part_id'	=> "hd0,gpt3",
	'common_opts'	=> "root=/dev/drbd0 ro",
	'default_opts'	=> "quiet",
	'kernel_pref'	=> "vmlinuz-",
	'initrd_pref'	=> "initrd.img-",
	'entry_pref'	=> "Debian GNU/Linux with ",
	'def_boot'	=> 0,
	'boot_timeout'	=> 5
);

my %nodes_params = (
	'drbd-node0'	=> "sdc_hname=drbd-node0 sdc_iface=eth1 sdc_addr=172.31.255.1/24 sdc_wait=1",
	'drbd-node1'	=> "sdc_hname=drbd-node1 sdc_iface=eth1 sdc_addr=172.31.255.2/24 sdc_wait=10",
);


my $kernels_list = search_kernels(\%config) or die("Can't get kernels list!\n");
my $sorted_list = sort_kernels_list($kernels_list);

foreach my $node (keys(%nodes_params)) {
	my $fpath = "/boot/" . $node . ".lst";

	my $fh = undef;
	open($fh, ">", $fpath) or die("Can't open file " . $fpath . ": " . $! . "\n");
	flock($fh, LOCK_EX) or die("Can't set write lock on file " . $fpath . ": " . $! . "\n");

	print_to_fh($fh, \%config, $sorted_list, $nodes_params{$node});

	close($fh);
}

exit(0);


sub search_kernels {
	my $config = shift();

	my %result_hash = ();

	my $dh;
	if(not opendir($dh, "/boot")) {
		warn("Can't open boot directory: " . $! . "\n");
		return(undef);
	}

	my @kernel_files = grep(/^$config->{'kernel_pref'}/, readdir($dh));
	closedir($dh);

	foreach my $kernel_file (@kernel_files) {
		my $stat_file = "/boot/" . $kernel_file;
		my @stats = stat($stat_file);

		if($#stats < 0) {
			warn("Can't stat file " . $stat_file . ": " . $! . "\n");
			return(undef);
		}

		$result_hash{$stats[10]} = $kernel_file;
	}

	return(\%result_hash);
}


sub sort_kernels_list {
	my $input_hash = shift();

	my @result_list = ();

	foreach my $timestamp (sort({$b <=> $a} keys(%{$input_hash}))) {
		push(@result_list, $input_hash->{$timestamp});
	}

	return(\@result_list);
}


sub print_to_fh {
	my $fh = shift();
	my $config = shift();
	my $kernels = shift();
	my $node_opts = shift();

	print($fh "set default=" . $config->{'def_boot'} . "\n");
	print($fh "set timeout=" . $config->{'boot_timeout'} . "\n");
	print($fh "\n");

	my $no_first = undef;
	foreach my $kernel (@{$kernels}) {
		if($no_first) {
			print($fh "\n");
		}
		else {
			$no_first = 1;
		}

		my $initrd = $kernel;
		$initrd =~ s/^$config->{'kernel_pref'}/$config->{'initrd_pref'}/g;

		my $kversion = $kernel;
		$kversion =~ s/^$config->{'kernel_pref'}//g;

		print($fh "menuentry \"" . $config->{'entry_pref'} . $kversion . " (normal mode)\" {\n");
		print($fh "\tset root=(" . $config->{'grub_part_id'} . ")\n");
		print($fh "\tlinux\t/" . $kernel . " " . $config->{'common_opts'} . " " . $node_opts . " " . $config->{'default_opts'} . "\n");

		if(-e "/boot/" . $initrd) {
			print($fh "\tinitrd\t/" . $initrd . "\n");
		}

		print($fh "}\n");
		print($fh "\n");

		print($fh "menuentry \"" . $config->{'entry_pref'} . $kversion . " (single-user mode)\" {\n");
		print($fh "\tset root=(" . $config->{'grub_part_id'} . ")\n");
		print($fh "\tlinux\t/" . $kernel . " " . $config->{'common_opts'} . " " . $node_opts . " single\n");

		if(-e "/boot/" . $initrd) {
			print($fh "\tinitrd\t/" . $initrd . "\n");
		}

		print($fh "}\n");
	}

	return(1);
}

6. Установка ядра и завершение работы

Делаем chroot в новую систему, монтируем в ней procfs и sysfs, доустанавливаем ядро, сбрасываем пароль root’а. Размонтируем файловые системы и перезагружаемся. В полном объёме выполняется на drbd-node0, частично на drbd-node1.

Листинг исполнения для drbd-node0:

root@drbd-node0:~# env LANG=C chroot /mnt/new-root/ /bin/bash
root@drbd-node0:/# mount -tproc none /proc/
root@drbd-node0:/# mount -tsysfs none /sys/
root@drbd-node0:/# passwd -d root
passwd: password expiry information changed.
root@drbd-node0:/# apt-get update
Ign http://ftp.ru.debian.org jessie InRelease
Hit http://ftp.ru.debian.org jessie Release.gpg
Hit http://ftp.ru.debian.org jessie Release
Hit http://ftp.ru.debian.org jessie/main amd64 Packages
Hit http://ftp.ru.debian.org jessie/main Translation-en
Reading package lists... Done           
root@drbd-node0:/# apt-get install linux-image-amd64
Reading package lists... Done
Building dependency tree... Done
The following extra packages will be installed:
  firmware-linux-free irqbalance libcap-ng0 libglib2.0-0 libglib2.0-data
  libnuma1 linux-image-3.16.0-4-amd64 shared-mime-info xdg-user-dirs
Suggested packages:
  linux-doc-3.16 debian-kernel-handbook grub-pc grub-efi extlinux
The following NEW packages will be installed:
  firmware-linux-free irqbalance libcap-ng0 libglib2.0-0 libglib2.0-data
  libnuma1 linux-image-3.16.0-4-amd64 linux-image-amd64 shared-mime-info
  xdg-user-dirs
0 upgraded, 10 newly installed, 0 to remove and 0 not upgraded.
Need to get 39.3 MB of archives.
After this operation, 183 MB of additional disk space will be used.
Do you want to continue? [Y/n] 
Get:1 http://ftp.ru.debian.org/debian/ jessie/main libcap-ng0 amd64 0.7.4-2 [13.2 kB]
Get:2 http://ftp.ru.debian.org/debian/ jessie/main libglib2.0-0 amd64 2.42.1-1+b1 [2401 kB]
Get:3 http://ftp.ru.debian.org/debian/ jessie/main libnuma1 amd64 2.0.10-1 [32.5 kB]
Get:4 http://ftp.ru.debian.org/debian/ jessie/main linux-image-3.16.0-4-amd64 amd64 3.16.39-1 [33.9 MB]
Get:5 http://ftp.ru.debian.org/debian/ jessie/main firmware-linux-free all 3.3 [19.1 kB]
Get:6 http://ftp.ru.debian.org/debian/ jessie/main libglib2.0-data all 2.42.1-1 [2173 kB]
Get:7 http://ftp.ru.debian.org/debian/ jessie/main linux-image-amd64 amd64 3.16+63 [5824 B]
Get:8 http://ftp.ru.debian.org/debian/ jessie/main shared-mime-info amd64 1.3-1 [634 kB]
Get:9 http://ftp.ru.debian.org/debian/ jessie/main xdg-user-dirs amd64 0.15-2 [52.1 kB]
Get:10 http://ftp.ru.debian.org/debian/ jessie/main irqbalance amd64 1.0.6-3 [31.1 kB]
Fetched 39.3 MB in 8s (4801 kB/s)                                              
Preconfiguring packages ...
E: Can not write log (Is /dev/pts mounted?) - posix_openpt (2: No such file or directory)
Selecting previously unselected package libcap-ng0:amd64.
(Reading database ... 11907 files and directories currently installed.)
Preparing to unpack .../libcap-ng0_0.7.4-2_amd64.deb ...
Unpacking libcap-ng0:amd64 (0.7.4-2) ...
Selecting previously unselected package libglib2.0-0:amd64.
Preparing to unpack .../libglib2.0-0_2.42.1-1+b1_amd64.deb ...
Unpacking libglib2.0-0:amd64 (2.42.1-1+b1) ...
Selecting previously unselected package libnuma1:amd64.
Preparing to unpack .../libnuma1_2.0.10-1_amd64.deb ...
Unpacking libnuma1:amd64 (2.0.10-1) ...
Selecting previously unselected package linux-image-3.16.0-4-amd64.
Preparing to unpack .../linux-image-3.16.0-4-amd64_3.16.39-1_amd64.deb ...
Unpacking linux-image-3.16.0-4-amd64 (3.16.39-1) ...
Selecting previously unselected package firmware-linux-free.
Preparing to unpack .../firmware-linux-free_3.3_all.deb ...
Unpacking firmware-linux-free (3.3) ...
Selecting previously unselected package libglib2.0-data.
Preparing to unpack .../libglib2.0-data_2.42.1-1_all.deb ...
Unpacking libglib2.0-data (2.42.1-1) ...
Selecting previously unselected package linux-image-amd64.
Preparing to unpack .../linux-image-amd64_3.16+63_amd64.deb ...
Unpacking linux-image-amd64 (3.16+63) ...
Selecting previously unselected package shared-mime-info.
Preparing to unpack .../shared-mime-info_1.3-1_amd64.deb ...
Unpacking shared-mime-info (1.3-1) ...
Selecting previously unselected package xdg-user-dirs.
Preparing to unpack .../xdg-user-dirs_0.15-2_amd64.deb ...
Unpacking xdg-user-dirs (0.15-2) ...
Selecting previously unselected package irqbalance.
Preparing to unpack .../irqbalance_1.0.6-3_amd64.deb ...
Unpacking irqbalance (1.0.6-3) ...
Processing triggers for man-db (2.7.0.2-5) ...
Processing triggers for systemd (215-17+deb8u6) ...
Setting up libcap-ng0:amd64 (0.7.4-2) ...
Setting up libglib2.0-0:amd64 (2.42.1-1+b1) ...
No schema files found: doing nothing.
Setting up libnuma1:amd64 (2.0.10-1) ...
Setting up linux-image-3.16.0-4-amd64 (3.16.39-1) ...
/etc/kernel/postinst.d/initramfs-tools:
update-initramfs: Generating /boot/initrd.img-3.16.0-4-amd64
Setting up firmware-linux-free (3.3) ...
update-initramfs: deferring update (trigger activated)
Setting up libglib2.0-data (2.42.1-1) ...
Setting up linux-image-amd64 (3.16+63) ...
Setting up shared-mime-info (1.3-1) ...
Setting up xdg-user-dirs (0.15-2) ...
Setting up irqbalance (1.0.6-3) ...
[ ok ] Starting SMP IRQ Balancer: irqbalance.
Processing triggers for libc-bin (2.19-18+deb8u7) ...
Processing triggers for initramfs-tools (0.120+deb8u2) ...
update-initramfs: Generating /boot/initrd.img-3.16.0-4-amd64
Processing triggers for systemd (215-17+deb8u6) ...
root@drbd-node0:/# umount /proc/
root@drbd-node0:/# umount /sys/ 
root@drbd-node0:/# exit       
exit
root@drbd-node0:~# umount /mnt/new-root/boot 
root@drbd-node0:~# umount /mnt/new-root/
root@drbd-node0:~# swapoff /dev/sda4
root@drbd-node0:~# poweroff 

Листинг исполнения для drbd-node1:

root@drbd-node1:~# swapoff /dev/sda4
root@drbd-node1:~# poweroff 

Ну и в заключении…

Хотелось бы отметить, что сетевые карточки нужны с jumbo frame, чтобы оно всё сносно работало… Если они таковые, то можете просто добавить к ядру параметр sdc_mtu=9000 (9000 — оптимальный размер кадра, который не приведёт к двойному обсчёту контрольной суммы для кадров). Для того, чтобы вручную это не вводить каждый раз, достаточно отредактировать файл zz-update-boot-list.

Думается, что ещё мог удивить читателя колхоз с загрузчиком. Но вот так уж пришлось. На других архитектурах, где часть параметров можно сохранить в nvram (например для ARM и U-Boot), нет необходимости ставить отдельно grub. Вернее он просто не нужен. Так же как и не нужен скрипт zz-update-boot-list. Для U-Boot’а больше подошло бы моё предыдущее решение, его надо лишь чуть-чуть адаптировать. Хотя не думаю, что у кого-то есть кластер с DRBD на ARM’ах…

Happy hacking!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

85 − 78 =