クラウドサービスに代表される仮想化が主流となった現在では、サーバー自体も仮想化基盤上でソフトウェア的に組み立てて利用する必要があるため、インフラエンジニアといえどもコードを書いてソフトウェア開発者として作業を行うということが必須になってきています。今回は、WindowsサーバーやAzure上で利用できるInfrastructure as Codeの様々な手法をWindowsサーバーエンジニアのために、まとめて紹介します。
Configuration as Codeでサーバーのソフトウェア構成を制御
かつてサーバー管理者は、システムインフラ(基盤)の構築を、ドライバー片手にサーバーにメモリやHDD、ネットワークカードなどを差し込んで組み立てていました。ネットワークケーブルも、実際にスイッチからNICまで線をひっぱりながら繋いでいたような状況で、まさに手作業の世界です。
しかし、クラウドサービスに代表される仮想化が主流となった現在では、サーバー自体も仮想化基盤上でソフトウェア的に組み立てて利用する形態に変わりました。Infrastructure as Codeはこれまで手作業で行ってきた作業を、コードを実行することで実現するという考え方です。
Infrastructure as Codeは、仮想マシンに代表されるように、サーバーの仮想化されたハードウェア構成をコードで制御するという意味もありますが、Configuration as Codeという考え方で、サーバーのソフトウェア構成を制御するという考え方もあるようです。
Windowsベースのサービス開発を長年続けてきた私にとっては、サービス開発=プロビジョニング=自動化という絶対条件があり、Windowsサーバーや仮想マシンをコードによって制御するということは、改めて定義しなくとも日常的にごくあたりまえにやってきたことでした。Infrastructure as Codeとはこういったものだという定義や解釈は様々に書かれているので、ズバリこれ!という指摘は難しいのですが、個人的には、コードを書いて、構築~運用~管理を簡単にして楽をしようという感じです。
これまで、インフラエンジニアは物理的なサーバーに対して設置、組み立てなどを行い、Windowsサーバーの機能を細かく構成し、せいぜいバッチ程度のスクリプトを利用してサーバーの運用管理を行うといった具合でした。しかし、クラウド全盛期となった現在においては、物理的なサーバーをサービスごとに構築するといった作業は少なくなり、最小の物理サーバーでHyper-Vを展開し、サービスや用途ごとに多くの仮想マシンを作成して上手にリソースを振り分けて利用することが主流となっています。インフラエンジニアといえどもHyper-Vや仮想マシンを管理するためにはコードを書いてソフトウェア開発者として作業を行うということが必須になってきている状況です。
ですが、いくらコードでWindowsサーバーを制御することができるようになってきたとはいっても、アプリケーション開発者がいきなりHyper-V上の仮想マシンを使ってシステム構築ができるものではありません。やはり、Windowsサーバーのことをよく理解した、Windowsサーバーエンジニアの力が必要となります。今回は、WindowsサーバーやAzure上で利用できるInfrastructure as Codeの様々な手法をWindowsサーバーエンジニアのために、まとめて紹介したいと思います。
【Microsoft Azure】JSON形式のテンプレートを利用したデプロイ
Microsoft Azureでは、新しいAzureポータルからAzure Resource Managerを利用することで、IaaSの仮想マシンやサービスの利用構成をJSON形式の定義ファイルで展開することができるようになっています。JSON (JavaScript Object Notation)はデータとして見やすく、システムにとっても解析しやすいシンプルで軽量なテキストファイル形式の構文です。
Azure Quickstart TemplatesやGitHub Azure/azure-quickstart-templates では、すでに数多くのAzure上で利用できるテンプレートやサンプルが公開されており、そのまま利用したり、オリジナルにカスタマイズして再利用することですぐにInfrastructure as CodeをAzure上で実現することができるようになっています。
(02 GitHub Azure/azure-quickstart-templates)
テンプレートの使い方は簡単です。まずは適当なテンプレートを選択してみましょう。
Anti-Malwareの機能があらかじめ設定された仮想マシンのテンプレートを選択しました。左上の「Deploy to Azure」ボタンを選択すると、そのままAzureポータル画面が開きます。
(04 自動的にAzureポータルへ)
管理者名やパスワードなど必要なパラメーターを設定すると、自動的にJSON形式のテンプレートが作成されます。このまま「作成」ボタンを選択すればAzure上に仮想マシンが作成されますし、これをテンプレートとして保存しておくこともできます。テンプレートとして保存しておけば、同様の仮想マシンを、パラメーターを変えて簡単に作成することも可能です。
(05 作成されたJSON形式のテンプレート)
GitHubからダウンロードしたり、オリジナルで作成したJSONファイルを元に仮想マシンなどを作成したりする場合は、Azureポータルから「テンプレートのデプロイ」を選択して、JSONファイルを直接作成、編集することも可能です。
(06 テンプレートのデプロイ)
(07 直接JSONファイルを作成・編集)
さらにAzureでは、リソースマネージャーベースのポータルで作成した仮想マシンやサービスの構成情報を、JSON形式のテンプレートファイルとして出力することもできるようになっています。
(08 テンプレートのエクスポート)
既存の仮想マシンなどの構成をコピーして使いまわしたり、簡易的なバックアップとしても利用できます。
【Microsoft Azure】PowerShellを利用したデプロイ
Microsoft Azureは、Windows Serverと同様にPowerShellからも管理することが可能となっています。具体的な細かい設定方法は参考サイトを参照してもらうということで、簡単な手順を紹介します。
1. Azure PowerShell のインストールAzureを管理するための専用モジュールをインストールしておきます。https://azure.microsoft.com/ja-jp/documentation/articles/powershell-install-configure/
インストール後にインターネット接続可能な手元のPCからPowerShell経由でAzureに接続して、Azure上にコードベースで仮想マシンを作成できるようになります。
2. PowerShellのコードを作成するAzure上に仮想マシンを作成する場合、クラシックポータルに作成する方法と、リソースマネージャーベースの新しいポータルに作成する方法の2つがあります。この2つのポータル上の仮想マシンは作成方法・管理方法が異なるため、それぞれで実行するPowerShellのコードが異なります。
●クラシックデプロイメントモデルを使用した仮想マシンの作成方法https://azure.microsoft.com/ja-jp/documentation/articles/virtual-machines-windows-classic-create-powershell/
アカウントの追加 ↓サブスクリプションとストレージアカウントの設定 ↓ImageFamilyの特定(OSの選択) ↓コマンド セットの構築(PowerShellのパラメーター設定) ↓仮想マシンの作成
●リソースマネージャーを利用した仮想マシンの作成方法https://azure.microsoft.com/ja-jp/documentation/articles/virtual-machines-windows-ps-create/
リソースグループの作成 ↓ストレージアカウントの作成 ↓仮想ネットワークの作成 ↓IP アドレスとネットワークインターフェイスの作成 ↓仮想マシンの作成
それぞれのPowerShellのサンプルクリプトが参照サイトに用意されているので、パラメーターを修正するだけで、Infrastructure as Codeを実現することができます。現在の主流はリソースマネージャーベースの新しいポータルとなっており、Microsoftもこちらを推奨しています。
Windows Server
パブリッククラウドであるMicrosoft Azureは、Windows Serverをベースとして構築されているので、当然、オンプレミスのWindows ServerもInfrastructure as Codeの恩恵を受けることができます。もちろん、ベースとなるのは実サーバーに展開されたHyper-V上の仮想マシンや、IISなどのサービスが対象にはなりますが、Azureと比べ、手元にあるWindows Serverはパブリッククラウドのような制約がない分、自由に様々なアプローチ方法でInfrastructure as Codeを実現することができます。
Azure StackAzure Stackは、Microsoftが展開しているクラウドサービス「Microsoft Azure」のリソースマネージャーベースの新しいポータルであるWebインターフェイスや機能をそのまま利用して、プライベートクラウドのサービス提供を可能にするシステムです。上記のAzureの節でも述べた通り、JSONやAzure PowerShellを利用したInfrastructure as Codeも当然同じように利用できる環境がオンプレにも提供されます。現在、Technical Preview 1(TP1)が提供されていますが、正式リリースは2017年以降となる予定です。https://azure.microsoft.com/ja-jp/overview/azure-stack/
PowerShellもはや、Windows Server管理者の必須ツールとなっているPowerShellです。Windows Serverに対しての制御はほぼPowerShellのコマンドレッドから実行可能となっています。Windows ServerのPowerShellは、改めてインストールする必要がなく、標準で搭載されています。PowerShell ISEという専用の統合開発環境も用意されています。Hyper-Vの役割がインストールされていれば、たった一行のNew-VMコマンドレッドで簡単に仮想マシンが作成できてしまいます。
New-VM –Name "VM01" –MemoryStartupBytes 1GB –NewVHDPath D:\HV\VM01.vhdx
10台の仮想マシンもこれだけのコードで完了です。
for ( $i = 0; $i -lt 10; $i++ ){New-VM –Name ("VM" + $i) -Generation 2 –MemoryStartupBytes 1GB}
New-VMコマンドレッド以外にも、仮想マシンの起動やネットワークスイッチへの接続、チェックポイントの作成など、Hyper-V上の仮想マシンでできるほとんどのことが、PowerShellのコマンドレッドで記述することができます。Windows Server 2016では、注目の新しい技術であるWindowsコンテナーや、NanoServerが提供される予定です。これらの新技術につては、すべてPowerShellやDockerなどのコマンドでの操作・管理のみとなっています。
サーバー管理においてはGUIではなくPowerShellが標準となりつつあります。様々なPowerShellのコマンドを組み合わせて、操作・管理を実現することがまさにInfrastructure as Codeとなります。
PowerShell Desired State Configuration(DSC)
PowerShell Desired State Configuration(DSC)は、Windows Server 2012 R2と同時期にリリースされた、PowerShellをベースとする構成管理ツールです。DSCは仮想マシンのハードウェア状態を構成するだけではなく、役割や機能の追加、ユーザー管理など、Configuration as Codeも実現することが可能となっています。構成方法としては、それぞれの項目についてPowerShellのコマンドレッドを実行するというわけはなく、Configurationキーワードを使って宣言構文を作成して実行するといった形態となっています。Windows Server 2012 R2ではバージョン4.0が、Windows Server 2016 TP5ではバージョン5.1がすでにインストールされています。詳細を確認するには$PSVersionTable をPowerShellで実行します。
Windows Server 2012 R2
PS C:\> $PSVersionTableName Value-------- --------PSVersion 4.0WSManStackVersion 3.0SerializationVersion 1.1.0.1CLRVersion 4.0.30319.34014BuildVersion 6.3.9600.17090PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}PSRemotingProtocolVersion 2.2
Windows Server 2016 TP5
PS C:\> $PSVersionTableName Value-------- --------PSVersion 5.1.14300.1000PSEdition DesktopPSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}CLRVersion 4.0.30319.42000BuildVersion 10.0.14300.1000WSManStackVersion 3.0PSRemotingProtocolVersion 2.3SerializationVersion 1.1.0.1
簡単な例として、Windows ServerにWebサーバー(IIS)の役割を追加して、ASP.NETの機能を有効化します。PowerShellのコマンドレッドを元に実行する場合は
Add-WindowsFeature Web-Server -IncludeManagementTools
こちらを実行することとなります。ですが、もし、すでにWebサーバーの役割が有効となっている場合はエラーとなってしまいます。スクリプト化して自動化する場合にはそういったエラー対策も必要となってきます。
DSCではPowerShellのコマンドレッドでインストールを行うのではなく、Configurationキーワードで定義された内容にサーバーを構成することになります。なので、すでにWebサーバーの役割が有効となっていたとして、構成定義としてはエラーとならず、スキップされるだけとなります。
Configuration IISInstall{ Node localhost { WindowsFeature IIS { Ensure = "Present" Name = "Web-Server" } WindowsFeature IISMgmt { Ensure = "Present" Name = " Web-Mgmt-Tools" } WindowsFeature ASP { Ensure = "Present" Name = "Web-Asp-Net45" } } } WebSiteConfigInstall -OutputPath .Start-DscConfiguration .\IISInstall -Wait -Verbose
DSCの利点としては、PowerShellのコマンドで、ある意味強制的に状態を変更するのではなく、あるべき状態を定義して、その構成情報に基づいて必要な部分だけサーバー自身が変化するといった感じでしょうか。サーバー管理者は構成情報を定義するだけですので、重複設定によるエラーや整合性の矛盾といった問題がなくなり、PowerShellのスクリプト作成によるエラー処理などの手間が大幅に削減されます。エラー処理などのコードは開発にとってはあたりまえのことですが、Windows Serverエンジニアこそ使うべきInfrastructure as Codeの恩恵を受けるために、開発者と同様の開発スキルを必要とするといった矛盾を解消してくれるものとなります。
Hyper-V上の仮想マシンの構成をPowerShellで出力するサンプル
最後に、窓使いのためのInfrastructure as Code の付録として、PowerShellのサンプルスクリプトを紹介します。現在のWindows ServerのHyper-Vでは、PowerShellのコマンドによって仮想マシンを作成できますが、Azureのリソースマネージャーのように、構成情報だけをエクスポートする機能がありません。仮想マシンのエクスポートという機能はありますが、これは仮想ハードディスクもまるごとエクスポートするので、それなりに時間がかかり使う機会を選ぶ場合があります。もっと簡単に仮想マシンの構成情報を取得できて、さらにカスタマイズもできるようにするためのサンプルスクリプトです。
Sample1.ps1→ Sample1.ps1 ファイルダウンロード
Param( [string]$VMName) $VM = Get-VM $VMName $VMName = $VM.VMName $Generation = $VM.Generation $Path = Split-Path $VM.Path -Parent $Processer = Get-VM $VMName | Get-VMProcessor $ProcesserCount = $Processer.Count $Memory = Get-VM $VMName | Get-VMMemory $DynamicMemoryEnabled = $Memory.DynamicMemoryEnabled $MemoryStartup = $Memory.Startup / 1024 / 1024 $MemoryMinimum = $Memory.Minimum / 1024 / 1024 $MemoryMaximum = $Memory.Maximum / 1024 / 1024 $MemoryBuffer = $Memory.Buffer $MemoryPriority = $Memory.Priority $Script += "Param(`r`n" $Script += ' [String]$VMName = "' + $VMName + """" +",`r`n" $Script += ' [Int16]$Generation = ' + $Generation + ",`r`n" $Script += ' [String]$Path = "' + $Path + """" + ",`r`n" $Script += ' [Int64]$ProcesserCount = ' + $ProcesserCount + ",`r`n" $Script += ' [Int64]$MemoryStartup = ' + $MemoryStartup + "MB" + ",`r`n" $Script += ' [Boolean]$DynamicMemoryEnabled = $' + $DynamicMemoryEnabled + ",`r`n" $Script += ' [Int64]$MemoryMinimum = ' + $MemoryMinimum + "MB" + ",`r`n" $Script += ' [Int64]$MemoryMaximum = ' + $MemoryMaximum + "MB" + ",`r`n" $Script += ' [Int32]$MemoryBuffer = ' + $MemoryBuffer + ",`r`n" $Script += ' [Int32]$MemoryPriority = ' + $MemoryPriority + ",`r`n" $NetworkAdapters = Get-VM $VMName | Get-VMNetworkAdapter for ( $i = 0; $i -lt $NetworkAdapters.Length; $i++ ) { $NetworkAdapterName += '"' + $NetworkAdapters[$i].Name + '"' $SwitchName += '"' + $NetworkAdapters[$i].SwitchName + '"' if($i -lt $NetworkAdapters.Length - 1){ $NetworkAdapterName += ", " $SwitchName += ", " } } $Script += ' [Object]$NetworkAdapter = @(@(' + $NetworkAdapterName +'), @(' + $SwitchName +'))' + ",`r`n" $ScsiControllers = Get-VMScsiController $VMName $ScsiControllerCount = $ScsiControllers.Length $Script += ' [Int16]$ScsiControllerCount = ' + $ScsiControllerCount + ",`r`n" $DiskDrives = Get-VMHardDiskDrive $VMName for ( $i = 0; $i -lt $DiskDrives.Length; $i++ ) { $ControllerType += '"' + $DiskDrives[$i].ControllerType + '"' $ControllerNumber += '"' + $DiskDrives[$i].ControllerNumber + '"' $DiskPath += '"' + $DiskDrives[$i].Path + '"' if($i -lt $DiskDrives.Length - 1){ $ControllerType += ", " $ControllerNumber += ", " $DiskPath += ", " } } $Script += ' [Object]$DiskDrive = @(@(' + $ControllerType +'), @(' + $ControllerNumber +'), @(' + $DiskPath +'))' + "`r`n" $Script += ")" + "`r`n`r`n" $Script += '$VM = New-VM -Name $VMName -Generation $Generation -Path $Path -VHDPath $DiskDrive[2][0]' + "`r`n" $Script += 'Set-VMProcessor $VM -Count $ProcesserCount' + "`r`n" if($DynamicMemoryEnabled -eq $True){ $Script += 'Set-VMMemory $VM -DynamicMemoryEnabled $DynamicMemoryEnabled -MinimumBytes $MemoryMinimum -StartupBytes $MemoryStartup -MaximumBytes $MemoryMaximum -Buffer $MemoryBuffer -Priority $MemoryPriority' + "`r`n" }else{ $Script += 'Set-VMMemory $VM -DynamicMemoryEnabled $DynamicMemoryEnabled -StartupBytes $MemoryStartup -Priority $MemoryPriority' + "`r`n" } $Script += "`r`n" $Script += 'Remove-VMNetworkAdapter $VM' + "`r`n" $Script += 'for ( $i = 0; $i -lt $NetworkAdapter[0].Length; $i++ )' + "`r`n" $Script += '{' + "`r`n" $Script += ' if($NetworkAdapter[1][$i] -eq ""){' + "`r`n" $Script += ' Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i]' + "`r`n" $Script += ' }else{' + "`r`n" $Script += ' Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i] -SwitchName $NetworkAdapter[1][$i]' + "`r`n" $Script += ' }' + "`r`n" $Script += '}' + "`r`n" $Script += "`r`n" $Script += 'for ( $i = 1; $i -lt $ScsiControllerCount; $i++ )' + "`r`n" $Script += '{' + "`r`n" $Script += ' Add-VMScsiController $VM' + "`r`n" $Script += '}' + "`r`n" $Script += "`r`n" $Script += 'for ( $i = 1; $i -lt $DiskDrive[0].Length; $i++ )' + "`r`n" $Script += '{' + "`r`n" $Script += ' Add-VMHardDiskDrive $VM ?ControllerType $DiskDrive[0][$i] -ControllerNumber $DiskDrive[1][$i] -Path $DiskDrive[2][$i]' + "`r`n" $Script += '}' + "`r`n" $Script2 += '#$VMName = "' + $VMName + '"' + "`r`n" $Script2 += '#$VM = New-VM -Name $VMName' + " -Generation $Generation ?Path ""$Path"" -VHDPath """ + $DiskDrives[0].Path + """" + "`r`n" $Script2 += '#Set-VMProcessor $VM' + " -Count $ProcesserCount"+ "`r`n" if($DynamicMemoryEnabled -eq $True){ $Script2 += '#Set-VMMemory $VM' + " -DynamicMemoryEnabled $" + "$DynamicMemoryEnabled -MinimumBytes $MemoryMinimum" + "MB -StartupBytes $MemoryStartup" + "MB -MaximumBytes $MemoryMaximum" + "MB -Buffer $MemoryBuffer -Priority $MemoryPriority"+ "`r`n" }else{ $Script2 += '#Set-VMMemory $VM' + " -DynamicMemoryEnabled $" + "$DynamicMemoryEnabled -StartupBytes $MemoryStartup" + "MB -Priority $MemoryPriority"+ "`r`n" } $Script2 += '#$NetworkAdapter = @(@(' + $NetworkAdapterName +'), @(' + $SwitchName +'))' + "`r`n" $Script2 += '#Remove-VMNetworkAdapter $VM' + "`r`n" $Script2 += '#for ( $i = 0; $i -lt $NetworkAdapter[0].Length; $i++ )' + "`r`n" $Script2 += '#{' + "`r`n" $Script2 += '# if($NetworkAdapter[1][$i] -eq ""){' + "`r`n" $Script2 += '# Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i]' + "`r`n" $Script2 += '# }else{' + "`r`n" $Script2 += '# Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i] -SwitchName $NetworkAdapter[1][$i]' + "`r`n" $Script2 += '# }' + "`r`n" $Script2 += '#}' + "`r`n" $Script2 += '#$ScsiControllerCount = ' + $ScsiControllerCount + "`r`n" $Script2 += '#for ( $i = 1; $i -lt $ScsiControllerCount; $i++ )' + "`r`n" $Script2 += '#{' + "`r`n" $Script2 += '# Add-VMScsiController $VM' + "`r`n" $Script2 += '#}' + "`r`n" $Script2 += '#$DiskDrive = @(@(' + $ControllerType +'), @(' + $ControllerNumber +'), @(' + $DiskPath +'))' + "`r`n" $Script2 += '#for ( $i = 1; $i -lt $DiskDrive[0].Length; $i++ )' + "`r`n" $Script2 += '#{' + "`r`n" $Script2 += '# Add-VMHardDiskDrive $VM ?ControllerType $DiskDrive[0][$i] -ControllerNumber $DiskDrive[1][$i] -Path $DiskDrive[2][$i]' + "`r`n" $Script2 += '#}' + "`r`n" Write-Output $Script Write-Output `r`n Write-Output $Script2
使い方
C:\Script\Sample.ps1 -VMName VM01 | Out-File C:\Script\VM01.ps1
Hyper-V上の既存の仮想マシンの構成をPS1ファイルに出力します。
仮想マシンVM01を作成するためのスクリプトが生成されます。
Param( [String]$VMName = "VM01", [Int16]$Generation = 2, [String]$Path = "C:\ProgramData\Microsoft\Windows", [Int64]$ProcesserCount = 4, [Int64]$MemoryStartup = 4096MB, [Boolean]$DynamicMemoryEnabled = $False, [Int64]$MemoryMinimum = 512MB, [Int64]$MemoryMaximum = 1048576MB, [Int32]$MemoryBuffer = 45, [Int32]$MemoryPriority = 100, [Object]$NetworkAdapter = @(@("Network Adapter"), @("Private")), [Int16]$ScsiControllerCount = 1, [Object]$DiskDrive = @(@("SCSI"), @("0"), @("C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks\VM01.vhdx"))) $VM = New-VM -Name $VMName -Generation $Generation -Path $Path -VHDPath $DiskDrive[2][0]Set-VMProcessor $VM -Count $ProcesserCountSet-VMMemory $VM -DynamicMemoryEnabled $DynamicMemoryEnabled -StartupBytes $MemoryStartup -Priority $MemoryPriority Remove-VMNetworkAdapter $VMfor ( $i = 0; $i -lt $NetworkAdapter[0].Length; $i++ ){ if($NetworkAdapter[1][$i] -eq ""){ Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i] }else{ Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i] -SwitchName $NetworkAdapter[1][$i] }} for ( $i = 1; $i -lt $ScsiControllerCount; $i++ ){ Add-VMScsiController $VM} for ( $i = 1; $i -lt $DiskDrive[0].Length; $i++ ){ Add-VMHardDiskDrive $VM –ControllerType $DiskDrive[0][$i] -ControllerNumber $DiskDrive[1][$i] -Path $DiskDrive[2][$i]} #$VMName = "VM01"#$VM = New-VM -Name $VMName -Generation 2 –Path "C:\ProgramData\Microsoft\Windows" -VHDPath "C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks\VM01.vhdx"#Set-VMProcessor $VM -Count 4#Set-VMMemory $VM -DynamicMemoryEnabled $False -StartupBytes 4096MB -Priority 100#$NetworkAdapter = @(@("Network Adapter"), @("Private"))#Remove-VMNetworkAdapter $VM#for ( $i = 0; $i -lt $NetworkAdapter[0].Length; $i++ )#{# if($NetworkAdapter[1][$i] -eq ""){# Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i]# }else{# Add-VMNetworkAdapter $VM -Name $NetworkAdapter[0][$i] -SwitchName $NetworkAdapter[1][$i]# }#}#$ScsiControllerCount = 1#for ( $i = 1; $i -lt $ScsiControllerCount; $i++ )#{# Add-VMScsiController $VM#}#$DiskDrive = @(@("SCSI"), @("0"), @("C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks\VM01.vhdx"))#for ( $i = 1; $i -lt $DiskDrive[0].Length; $i++ )#{# Add-VMHardDiskDrive $VM –ControllerType $DiskDrive[0][$i] -ControllerNumber $DiskDrive[1][$i] -Path $DiskDrive[2][$i]#}
Hyper-V上で仮想マシンを削除してしまった場合、仮想ハードディスクが残っていればこのVM01.ps1を実行することで同様のハードウェア構成で作成されます。また、VM01.ps1のパラメーター$VMNameの値を変更すれば、別マシン名でVM01を同様の構成で仮想マシンを作成することができます。VM01と同時に起動するのであれば、パラメーター$DiskDriveで仮想ハードディスクも別のものを指定する必要があります。同様の構成でいくつも仮想マシンをコピーしたい場合などにも有効です。現時点では、IOPSやNUMAの詳細設定値などについては対応していませんが、Sample.ps1をカスタマイズすることで、完全なコピーを作成するスクリプトも可能です。
以上、Windows Serverで実現できるInfrastructure as Codeの例をいくつか紹介しました。コードでインフラ環境を定義するとは言っても、実際に白紙の状態からコードを書くわけではなく、あらかじめ用意されているサンプルやテンプレートを利用して、必要なパラメーターを用途に適した値にカスタマイズするだけで、手軽にInfrastructure as Codeが実現できることがお分かりいただけたと思います。Infrastructure as Codeはインフラエンジニアにとって決して難しいものではなく、より正確に、より効率化を実現することのできる新しい武器となります。ぜひお試しください。