Назад | Перейти на главную страницу

Обработка снимков и клонирования XenServer с помощью ZFS SAN

Я планирую настроить машину XenServer, которая использует сеть SAN на базе NexentaOS / ZFS для хранения образов виртуальных дисков (VDI) через iSCSI. Я знаю, что могу просто настроить большой репозиторий хранилища (SR) в SAN и позволить XenServer позаботиться о создании снимков и клонировании образов дисков. Тем не менее, я бы хотел больше использовать возможности ZFS и использовать их для создания снимков / клонирования по нескольким причинам:

  1. Я не уверен, как работает моментальный снимок / клонирование XenServer, но если он основан на LVM, я опасаюсь, что столкнусь с проблемами при работе с несколькими снимками. Некоторое время назад я провел несколько экспериментов с несколькими снимками LVM одних и тех же данных, и производительность казалась низкой, а снимки зря занимали много места. Кажется, что снимки ZFS намного превосходят снимки LVM.
  2. SAN будет делать автоматические (и эффективные) периодические моментальные снимки ZFS, которые могут возвращаться во времени на некоторое время, и я бы хотел иметь возможность вернуть виртуальную машину к такому моментальному снимку ZFS.

Было бы целесообразно позволить ZFS обрабатывать моментальные снимки / клонирование вместо того, чтобы делать это через XenServer, и если да, то как лучше всего это сделать? Если я помещу все VDI в один большой SR и сделаю снимки ZFS всего SR, я не смогу откатить отдельную виртуальную машину за раз. Я мог бы создать один SR для каждого VDI, и если мне нужно откатить VDI, я бы осторожно отсоединил SR, откатил его обратно в SAN и снова подключил. Однако я предполагаю, что при подключении клонированного SR у меня возникнут проблемы, если XenServer обнаружит повторяющиеся UUID SR. Есть ли более эффективные способы обработки клонирования или отката к предыдущим снимкам из SAN?

Как упоминалось в других ответах, идеальным подходом является LUN-per-VDI. Сначала это не выглядело возможным, но есть недокументированный драйвер SR "iscsi", который создаст SR LUN-per-VDI (я обнаружил это, просматривая каталог / opt / xensource / sm - см. файл ISCSISR.py). По сути, вы настраиваете один SR для каждой цели iSCSI, а XenServer создает VDI для каждого LUN на этой цели. Вы можете настроить это только через командную строку, включая создание VBD и прикрепление его к виртуальным машинам. VBD и VDI даже не отображаются в XenCenter.

Вот пример команды для его настройки:

xe sr-create name-label=san type=iscsi device-config:target=<IP address of target> device-config:targetIQN=<IQN of target> shared=true

Это автоматически создаст VDI для каждого iSCSI LUN. Если вы в конечном итоге добавите новый iSCSI LUN в SAN, XenServer добавит для него новый VDI после выполнения следующей команды:

xe sr-scan uuid=<UUID of SR>

Это также работает при добавлении VDI для клонированных LUN - новому VDI назначается новый UUID.

Кроме того, если вы в конечном итоге измените размер LUN, XenServer не подхватит это автоматически, поэтому вам придется выполнить следующее:

xe vdi-forget uuid=<UUID of VDI that you resized>
iscsiadm -m node -R
xe sr-scan uuid=<UUID of SR>

А чтобы создать VBD и подключить его к виртуальной машине:

xe vbd-create vm-uuid=<UUID of VM> device=<VBD device #, e.g. 0> vdi-uuid=<VDI of UUID>

Я сделал несколько настроек с xenserver, аналогичных этой настройке

И я использовал один из двух методов

  1. Если у меня мало виртуальных машин, я создаю системный диск с VDI для каждой виртуальной машины и диск данных как прямое подключение Iscsi lun

  2. Если у меня много vm (20+), я создаю большой SR, и когда мне нужно откатиться, я могу

    A. переименуйте VG перед подключением к xenserver (vgrename на другой машине - даже виртуальной)

    Б. Вы даже можете прикрепить большой снимок SR к виртуальной машине и снова экспортировать его с помощью iscsi,

Надеюсь, это не слишком сложно :)

Это кажется актуальным. В приведенном ниже сценарии bash есть функции для присоединения и отсоединения SR, а также для переименования всех UUID в существующем (например, клонированном SAN) SR. Его можно использовать для переименования UUID старого клона и присоединения его без конфликта с последней версией подключаемого тома.

    # returns scsi_id, scsi_lun_id and as a bonus host_uuid
    probe_sr(){
            xen_host_ip=$1
            iscsi_device_ip=$2
            iscsi_device_target_iqn=$3
            iscsi_vol_name=$4

            cmd="ssh root@$xen_host_ip xe sr-probe type=lvmoiscsi device-config:target=$iscsi_device_ip device-config:targetIQN=$iscsi_device_target_iqn:$iscsi_vol_name"
            echo $cmd
            probe_out=`$cmd 2>&1`
            #echo probe_out=$probe_out

            scsi_id=`echo $probe_out | awk '{for(i=1;i<=NF;i++){if($i=="<SCSIid>"){i+=1;o=o","$i}}}END{print substr(o,2)}'`
            echo scsi_id=$scsi_id
            if [ -z $scsi_id ];then
                    exit
            fi
            # Only allow one LUN per target. To allow for more, enhance input to specify volume serial number and search probe output for it.
            if [ `echo $scsi_id | awk -F, '{print NF}'` != 1 ];then
                    echo Only one LUN per iscsi target is supported
                    exit
            fi

            scsi_lun_id=`echo $probe_out | awk '{for(i=1;i<=NF;i++){if($i=="<LUNid>"){i+=1;o=o" "$i}}}END{print substr(o,2)}'`
            echo scsi_lun_id=$scsi_lun_id
            if [ -z $scsi_lun_id ];then
                    exit
            fi

            # This only works if it is a standalone XenServer, not in a Xen pool - so this becomes a requirement
            host_uuid=`ssh root@$xen_host_ip xe host-list --minimal`
            if [ -z $host_uuid ];then
                    echo host_uuid=$host_uuid
                    exit
            fi
    }


    # Create SR wipes out contents of previous SR
    create_sr(){
            xen_host_ip=$1
            iscsi_device_ip=$2
            iscsi_device_target_iqn=$3
            iscsi_vol_name=$4
            sr_name=$5

            probe_sr $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name

            cmd="ssh root@$xen_host_ip xe sr-create host-uuid=$host_uuid content-type=user name-label=$sr_name shared=true device-config:target=$iscsi_device_ip device-config:targetIQN=$iscsi_device_target_iqn:$iscsi_vol_name device-config:SCSIid=$scsi_id type=lvmoiscsi"
            echo $cmd
            $cmd
    }

    # mainly returns sr_uuid, but also pv_device used in uuid_regen_sr
    get_sr_uuid_from_file_system(){
            xen_host_ip=$1
            iscsi_device_ip=$2
            iscsi_device_target_iqn=$3
            iscsi_vol_name=$4
            scsi_lun_id=$5

            # Ensure the the VG for the new volume gets created
            ##iscsiadm -m discovery -t sendtargets -p $iscsi_device_ip
            echo ssh root@$xen_host_ip iscsiadm -m node -T $iscsi_device_target_iqn:$iscsi_vol_name -p $iscsi_device_ip:3260 --login
            ssh root@$xen_host_ip iscsiadm -m node -T $iscsi_device_target_iqn:$iscsi_vol_name -p $iscsi_device_ip:3260 --login

            # get the pv_device name
            # Some iSCSI SAN might need customization here
            #scsi_id_short=`echo $scsi_id | awk '{print substr($1,1,length("36589cfc000000"))}'`
            scsi_id_short=$scsi_id
            echo scsi_id_short=$scsi_id_short
            unset pv_device_short
            tries=1
            while [ $tries -le 3 ]&&[ -z $pv_device_short ];do
                    echo "ssh root@$xen_host_ip ls -l /dev/disk/by-scsibus/ | egrep \"$scsi_id_short.*-[0-9]+:[0-9]+:[0-9]+:$scsi_lun_id -> \" | awk '{print \$NF}' | awk -F/ '{print \$NF}'"
                    pv_device_short=`ssh root@$xen_host_ip ls -l /dev/disk/by-scsibus/ | egrep "$scsi_id_short.*-[0-9]+:[0-9]+:[0-9]+:$scsi_lun_id -> " | awk '{print $NF}' | awk -F/ '{print $NF}'`
                    pv_device=/dev/$pv_device_short
                    echo pv_device=$pv_device
                    if [ -z "$pv_device_short" ];then
                            sleep 1
                    fi
                    tries=$(( tries + 1 ))
            done
            if [ -z "$pv_device_short" ];then
                    exit
            fi
            if [ `echo $pv_device | wc -l` -gt 1 ];then
                    exit
            fi

            # pvscan ensure PVs, VGs and LVMs are visible
            echo ssh root@$xen_host_ip pvscan
            ssh root@$xen_host_ip pvscan 2>/dev/null

            # get the VG UUID which is also what Xen uses for the SR UUID
            sr_uuid=`ssh root@$xen_host_ip "pvs 2>/dev/null" | egrep "$pv_device.*VG_XenStorage-" | awk '{print substr($2,length("VG_XenStorage-")+1)}'`
            echo sr_uuid=$sr_uuid
            if [ -z "$sr_uuid" ];then
                    exit
            fi

            # Thought this might be good, but think it caused problems.  Better and seemingly required place is in detach_sr
            #echo ssh root@$xen_host_ip iscsiadm -m node -T $iscsi_device_target_iqn:$iscsi_vol_name -p $iscsi_device_ip:3260 --logout
            #ssh root@$xen_host_ip iscsiadm -m node -T $iscsi_device_target_iqn:$iscsi_vol_name -p $iscsi_device_ip:3260 --logout
    }

    attach_sr_xen(){
            xen_host_ip=$1
            iscsi_device_ip=$2
            iscsi_device_target_iqn=$3
            iscsi_vol_name=$4
            sr_name=$5

            # Attach volume as a Xen SR
            echo ssh root@$xen_host_ip "xe sr-introduce uuid=$sr_uuid name-label=\"$sr_name\" type=lvmoiscsi shared=true"
            ssh root@$xen_host_ip "xe sr-introduce uuid=$sr_uuid name-label=\"$sr_name\" type=lvmoiscsi shared=true"

            echo ssh root@$xen_host_ip "xe pbd-create sr-uuid=$sr_uuid host-uuid=$host_uuid type=lvmoiscsi device-config-target=$iscsi_device_ip device-config-targetIQN=$iscsi_device_target_iqn:$iscsi_vol_name device-config-SCSIid=$scsi_id"
            pbd_uuid=`ssh root@$xen_host_ip "xe pbd-create sr-uuid=$sr_uuid host-uuid=$host_uuid type=lvmoiscsi device-config-target=$iscsi_device_ip device-config-targetIQN=$iscsi_device_target_iqn:$iscsi_vol_name device-config-SCSIid=$scsi_id"`
            echo pbd_uuid=$pbd_uuid
            if [ -z $pbd_uuid ];then
                    exit
            fi

            echo ssh root@$xen_host_ip "xe pbd-plug uuid=$pbd_uuid"
            ssh root@$xen_host_ip "xe pbd-plug uuid=$pbd_uuid"
    }

    # Attach SR retains prior contents as opposed to create_sr
    attach_sr(){
            xen_host_ip=$1
            iscsi_device_ip=$2
            iscsi_device_target_iqn=$3
            iscsi_vol_name=$4
            sr_name=$5

            probe_sr $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name
            get_sr_uuid_from_file_system $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name $scsi_lun_id
            attach_sr_xen $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name $sr_name
    }

    # Detach/forget SR
    detach_sr(){
            xen_host_ip=$1
            iscsi_device_ip=$2
            iscsi_device_target_iqn=$3
            iscsi_vol_name=$4
            sr_name=$5

            echo ssh root@$xen_host_ip "xe sr-list name-label=\"$sr_name\" --minimal"
            sr_uuid=`ssh root@$xen_host_ip "xe sr-list name-label=\"$sr_name\" --minimal"`
            echo sr_uuid=$sr_uuid
            if [ -z $sr_uuid  ];then
                    exit
            fi
            echo ssh root@$xen_host_ip "xe pbd-list sr-uuid=$sr_uuid --minimal"
            pbd_uuid=`ssh root@$xen_host_ip "xe pbd-list sr-uuid=$sr_uuid --minimal"`
            echo pbd_uuid=$pbd_uuid
            if [ -z $pbd_uuid ];then
                    echo No PBD found, proceeding anyway
            fi
            echo ssh root@$xen_host_ip iscsiadm -m node -T $iscsi_device_target_iqn:$iscsi_vol_name -p $iscsi_device_ip:3260 --logout
            ssh root@$xen_host_ip iscsiadm -m node -T $iscsi_device_target_iqn:$iscsi_vol_name -p $iscsi_device_ip:3260 --logout
            if [ ! -z $pbd_uuid ];then
                    echo ssh root@$xen_host_ip "xe pbd-unplug uuid=$pbd_uuid"
                    ssh root@$xen_host_ip "xe pbd-unplug uuid=$pbd_uuid"
            fi
            echo ssh root@$xen_host_ip "xe sr-forget uuid=$sr_uuid"
            ssh root@$xen_host_ip "xe sr-forget uuid=$sr_uuid"

            echo "It is now ok to remove the volume from the storage array"

    }

    # generates new PV, SR (VG) and VDI (LVM) uuids for a cloned and unattached iSCSI SR, leaving it unattached
    uuid_regen_sr(){
            xen_host_ip=$1
            iscsi_device_ip=$2
            iscsi_device_target_iqn=$3
            iscsi_vol_name=$4
            sr_name=$5

            probe_sr $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name

            get_sr_uuid_from_file_system $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name $scsi_lun_id

            # Import the clone giving it a new PV ID and VG UUID
            new_sr_uuid=`uuidgen`
            echo ssh root@$xen_host_ip vgimportclone --basevgname VG_XenStorage-$new_sr_uuid --import $pv_device
            ssh root@$xen_host_ip vgimportclone --basevgname VG_XenStorage-$new_sr_uuid --import $pv_device

            # get the new VG UUID which is also what Xen uses for the SR UUID
            sr_uuid=`ssh root@$xen_host_ip "pvs 2>/dev/null" | egrep "$pv_device.*VG_XenStorage-" | awk '{print substr($2,length("VG_XenStorage-")+1)}'`
            echo sr_uuid=$sr_uuid
            if [ -z $sr_uuid ]||[ $sr_uuid != $new_sr_uuid ];then
                    echo bad sr_uuid
                    exit
            fi

            attach_sr_xen $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name $sr_name

            # pvscan to get rid of some Linux duplicate dev errors
            echo ssh root@$xen_host_ip pvscan
            ssh root@$xen_host_ip pvscan 2>/dev/null

            echo -n waiting for VDI count to settle :
            prev_num_vdis=`ssh root@$xen_host_ip "xe vdi-list sr-uuid=$sr_uuid" | grep name-label | wc -l`
            echo -n $prev_num_vdis" "
            sleep 5
            num_vdis=`ssh root@$xen_host_ip "xe vdi-list sr-uuid=$sr_uuid" | grep name-label | wc -l`
            echo -n $num_vdis" "
            while [ $num_vdis != $prev_num_vdis ];do
                    sleep 5
                    num_vdis=`ssh root@$xen_host_ip "xe vdi-list sr-uuid=$sr_uuid" | grep name-label | wc -l`
                    echo -n $num_vdis" "
                    prev_num_vdis=$num_vdis
            done
            echo ""

            metadata_sr_uuid=`echo $sr_uuid | awk '{for(i=1;i<=length($1);i++){c=substr($1,i,1);if(c=="-"){o=o"--"}else{o=o""c}};print o}'`
            echo ssh root@$xen_host_ip "cp VG_XenStorage--$metadata_sr_uuid""-MGT ."
            ssh root@$xen_host_ip "cp /dev/mapper/VG_XenStorage--$metadata_sr_uuid""-MGT ."

            for vdi_uuid in `ssh root@$xen_host_ip lvs VG_XenStorage-$sr_uuid | grep VHD\- | awk '{print substr($1,length("VHD-")+1)}'`;do
                    new_uuid=`uuidgen`
                    echo ssh root@$xen_host_ip "sed -i \"s/$vdi_uuid/$new_uuid/g\" VG_XenStorage--$metadata_sr_uuid""-MGT"
                    ssh root@$xen_host_ip "sed -i \"s/$vdi_uuid/$new_uuid/g\" VG_XenStorage--$metadata_sr_uuid""-MGT"

                    echo ssh root@$xen_host_ip "lvrename /dev/VG_XenStorage-$sr_uuid/VHD-$vdi_uuid /dev/VG_XenStorage-$sr_uuid/VHD-$new_uuid"
                    ssh root@$xen_host_ip "lvrename /dev/VG_XenStorage-$sr_uuid/VHD-$vdi_uuid /dev/VG_XenStorage-$sr_uuid/VHD-$new_uuid"
            done

            echo ssh root@$xen_host_ip "cp VG_XenStorage--$metadata_sr_uuid""-MGT /dev/mapper/VG_XenStorage--$metadata_sr_uuid""-MGT"
            ssh root@$xen_host_ip "cp VG_XenStorage--$metadata_sr_uuid""-MGT /dev/mapper/VG_XenStorage--$metadata_sr_uuid""-MGT"

            echo ssh root@$xen_host_ip "rm -f VG_XenStorage--$metadata_sr_uuid""-MGT"
            ssh root@$xen_host_ip "rm -f VG_XenStorage--$metadata_sr_uuid""-MGT"

            echo ssh root@$xen_host_ip "xe sr-scan uuid=$sr_uuid"
            ssh root@$xen_host_ip "xe sr-scan uuid=$sr_uuid"

            detach_sr $xen_host_ip $iscsi_device_ip $iscsi_device_target_iqn $iscsi_vol_name $sr_name
}

Наши клиенты (клиенты Nexenta), у которых не очень много виртуальных машин, в основном менее 1000, время от времени выбирают LUN для каждой виртуальной машины. Это позволяет легко делать снимки из NexentaStor каждой отдельной виртуальной машины. Что круто, так это то, что вы можете создать одно золотое изображение, также известное как clome-master. Затем используйте этот clone-master для запуска новых виртуальных машин, просто клонируя его. Дополнительным преимуществом является то, что вы не используете дополнительное дисковое пространство.

Интересная конфигурация .. специально для ZFS.

Согласно моему опыту работы с XenServer, лучшее, что вы можете сделать, - это позволить системе хранения управлять диском (а также делать снимки и другие административные задачи).

Я думаю, вам следует позволить ZFS обрабатывать моментальные снимки и клонирование, но я не уверен, что лучшее, что вы можете сделать, - это дать XenServer один большой SR (я согласен с тем, что вы сказали о откате). Это очень сложная настройка, потому что, если у вас много виртуальных машин, у вас будет много VDI, администрирование может быть беспорядочным, но вы получите возможность отката. Я бы использовал один VDI на каждую виртуальную машину.

Отвечая на ваш вопрос, если вы дважды проверите, что вы отключаете SR при откате, у вас не будет никаких проблем при подключении клонированного SR. Я делал это раньше, но не в XenServer, а в XCP (http://goo.gl/4wfE)