Итак, в наличии имеется пять дешевых серверов Supermicro с 8 D дисками по 2Tb, подключенных через RAID контроллер Adaptec 6805, одним диском SATA малого размера, подключенным напрямую к материнской плате. На каждом сервере по 2 гигабитные сетевые карты, 16 гигабайт оперативной памяти и по два процессора Xeon E5-2670.
По одному эти сервера для меня представляют мало пользы, но вместе, они представляют из себя сырой объем в 80 терабайт, что уже может быть вкусно для файлового хранилища, без требований к скорости.
Попробую собрать из этого отказоустойчивое хранилище с использованием технологии Storage Spaces Direct. Забегая вперед, скажу что нечетное количество серверов нам понадобится для того, чтобы не заводить в кластере свидетеля. Нечетное количество нод позволяет работать кластеру без свидетеля.
На момент написания статьи в доступе был релиз Windows Server 2016 TP4. Его я и установил на все пять серверов.
ОС определила все оборудование, имеющееся на борту, за исключением SAS контроллера с идентификатором PCI\VEN_8086&DEV_1D6B&CC_0107, что соответствует Intel(R) C600 Series Chipset SAS RAID, который мне сейчас не понадобится.

RAID контроллер позволяет презентовать подключенные к нему диски в виде JBOD, что в нашем случае идеальный вариант.
Первая проблема, которую пришлось решать довольно старая, с которой я столкнулся еще в Windows 2008. Представленные диски ОС видит как набор маленьких RAID массивов:
Get-PhysicalDisk | FT FriendlyName, Mediatype, BusType -autosize

Такую шину S2D не поддерживает. Решить это дело в моем случае помог тот же прием, что и раньше - в реестре исправить тип шины на SATA для нужного типа контроллера:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\arcsas\Parameters]
"BusType"=dword:0000000b
вместо
"BusType"=dword:00000008
Делаем эту операцию на всех нодах, перегружаем их. Устанавливаем нужный нам для кластерного файлсервера роли и компоненты:

Проверяем работу интерфейсов. В моем случае с двумя сетевыми картами, сделал две сети - клиентскую и кластерную. В идеале, нужно иметь 4 сетевых интерфейса на каждой ноде, создать два switch independent тима и подключить их в два независимых свича, исключив отказ сетевого оборудования:
Get-NetAdapter | FT Name, InterfaceDescription, LinkSpeed -autosize
Name InterfaceDescription LinkSpeed
---- -------------------- ---------
HEARTBEAT Intel(R) I350 Gigabit Network Connection #2 1 Gbps
LAN Intel(R) I350 Gigabit Network Connection 1 Gbps
Собираем кластер из 5 нод:


Включаем функционал S2D:
Enable-ClusterStorageSpacesDirect
Смотрим какие локальные диски на нодах могут быть помещены в пул:
Get-PhysicalDisk | ? CanPool -eq $true
У меня это по 8 локальных физических дисков на каждом из 5 серверов:

Проверяем работоспособность подсистемы StorageSubSystem
Get-StorageSubSystem *cluster*
FriendlyName HealthStatus OperationalStatus
------------ ------------ -----------------
Clustered Windows Storage on s-ssdcl1 Healthy OK
-----
Собираем пул:
Если у нас в пуле было бы три диска, то их можно собрать только в уровень Mirror:
New-StoragePool -StorageSubSystemName s-ssdcl1.tnt-tv.ru -FriendlyName StorageSpacesDirect -WriteCacheSizeDefault 0 -ProvisioningTypeDefault Fixed -ResiliencySettingNameDefault Mirror -PhysicalDisks (Get-StorageSubSystem -Name s-mos1-w16.tnt-tv.ru | Get-PhysicalDisk)
Так как дисков у нас сильно побольше, создаем пул Parity, который возможен от 4 и более дисков:
New-StoragePool -StorageSubSystemName s-ssdcl1.tnt-tv.ru -FriendlyName StorageSpacesDirect -WriteCacheSizeDefault 0 -ProvisioningTypeDefault Fixed -ResiliencySettingNameDefault Parity -PhysicalDisks (Get-StorageSubSystem -Name s-ssdcl1.tnt-tv.ru | Get-PhysicalDisk)

-----
Обозначаем тир:
Тиринг нужен, при наличии разнородных носителей (SSD, SAS, SATA). Tier-зеркало (актуальный для SSD носителей) создается так:
New-StorageTier -StoragePoolFriendlyName "StorageSpacesDirect" -FriendlyName "MirrorTier" -MediaType SSD -ResiliencySettingName Mirror
В нашем случае, можно создавать тир, а можно обойтись и без него, так как диски все одинаковые. Я обозначил Parity тир больше для проформы:
New-StorageTier -StoragePoolFriendlyName "StorageSpacesDirect" -FriendlyName "ParityTier" -MediaType HDD -ResiliencySettingName Parity
-----
Создаем VHD с рабочей емкостью:
Для создания VHD, лично мне удобно пользоваться GUI Failover Clustering.
В повершелле это выглядит так. Если несколько тиров:
New-Volume -StoragePoolFriendlyName "StorageSpacesDirect" -FriendlyName "FailSafeData" -AccessPath "S:" -ResiliencySettingName "Parity" -ProvisioningType "Fixed" -StorageTiers (Get-StorageTier -FriendlyName "ParityTier") -StorageTierSizes 55000GB -FileSystem NTFS
Если один тир, можно просто:
New-Volume -StoragePoolFriendlyName "StorageSpacesDirect" -FriendlyName "FailSafeData" -Size 100GB -ResiliencySettingName "Mirror" -FileSystem NTFS -AccessPath "S: "-ProvisioningType Fixed
Выделил опцию Enclosure awareness - это поможет прозрачно отработать отказ одного из серверов в кластере. Тем не менее сразу теряю емкость 5 дисков (одной ноды).

Полезную емкость у диска выбрал меньшую, чем может дать мой набор дисков. Рекомендуется держать неразмеченный кусок, как кеш для перестроений при замене отказавших дисков:

Проверил отказоустойчивость отключением любого из серверов, и вытаскиванием двух любых дисков - хранилище доступно и работает!
Напоследок несколько заметок по работе с готовым S2D.
Проверить отказоустойчивость:
Get-StoragePool -FriendlyName "StorageSpacesDirect" | FL FriendlyName, Size, FaultDomainAwarenessDefault
Удаление в обратном порядке:
смотрим какие есть виртуальные диски (тут я его удалил из оснастки, но видно что он не удален раельно а только Detached)
Get-VirtualDisk
FriendlyName ResiliencySettingName OperationalStatus HealthStatus IsManualAttach Size
------------ --------------------- ----------------- ------------ -------------- ----
StorageSpacesDirect Parity Detached Unknown True 402 GB
Удаляем диск
Remove-VirtualDisk "StorageSpacesDirect"
Если нужно, изменяем свойство пула IsReadonly на False (иначе не сможем удалить пул):
Set-StoragePool "StorageSpacesDirect" -IsReadOnly $False
Удаляем пул
Remove-StoragePool "StorageSpacesDirect"