窓使いのためのInfrastructure as Code

WindowsサーバーやAzure上で利用できるInfrastructure as Codeの様々な手法を、Windowsサーバーエンジニアのためにまとめて紹介します。

クラウドサービスに代表される仮想化が主流となった現在では、サーバー自体も仮想化基盤上でソフトウェア的に組み立てて利用する必要があるため、インフラエンジニアといえどもコードを書いてソフトウェア開発者として作業を行うということが必須になってきています。

今回は、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 TemplatesGitHub 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 Stack
Azure 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.0
WSManStackVersion
 
3.0
SerializationVersion
 
1.1.0.1
CLRVersion
 
4.0.30319.34014
BuildVersion
 
6.3.9600.17090
PSCompatibleVersions
 
{1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion
 
2.2

Windows Server 2016 TP5

PS C:\> $PSVersionTableName
 
Value
--------
 
--------
PSVersion
 
5.1.14300.1000
PSEdition
 
Desktop
PSCompatibleVersions
 
{1.0, 2.0, 3.0, 4.0...}
CLRVersion
 
4.0.30319.42000
BuildVersion
 
10.0.14300.1000
WSManStackVersion
 
3.0
PSRemotingProtocolVersion
 
2.3
SerializationVersion
 
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 $ProcesserCount
Set-VMMemory $VM -DynamicMemoryEnabled $DynamicMemoryEnabled -StartupBytes $MemoryStartup -Priority $MemoryPriority
 
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]
              }
}
 
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はインフラエンジニアにとって決して難しいものではなく、より正確に、より効率化を実現することのできる新しい武器となります。ぜひお試しください。

著書の紹介欄

Hyper-Vで本格的なサーバー仮想環境を構築。仮想環境を設定・操作できる!

できるPRO Windows Server 2016 Hyper-V

◇Hyper-Vのさまざまな機能がわかる ◇インストールからの操作手順を解説 ◇チェックポイントやレプリカも活用できる Windows Server 2016 Hyper-Vは、仮想化ソフトウェア基盤を提供する機能であり、クラウドの実現に不可欠のものです。 本書では、仮想化の基礎知識から、Hyper-Vでの仮想マシンや仮想スイッチの設定・操作、プライベートクラウドの構築、Azureとの連携などを解説します。

初めてのWindows Azure Pack本が発売

Windows Azure Pack プライベートクラウド構築ガイド

本書は、Windows Azure PackとHyper-Vを利用し、企業内IaaS(仮想マシン提供サービス)を構成するための、IT管理者に向けた手引書です。試用したサーバーは、最小限度の物理サーバーと仮想マシンで構成しています。Windows Azure Packに必要なコンポーネントのダウンロード、実際にプライベートクラウド構築する過程を、手順を追って解説しています。これからプライベートクラウドの構築を検討するうえで、作業負担の軽減に役立つ一冊です。

ブログの著者欄

樋口 勝一

GMOインターネット株式会社

1999年6月GMOインターネットに入社。Windows Serverをプラットフォームとしたサービス開発から運用・保守まで幅広く担当。講演登壇や出版、ネット記事連載などでマイクロソフト社と強い信頼関係を構築。2007年より「マイクロソフトMVPアワード」を受賞し、インターネットソリューションのスペシャリストとして活躍。

関連記事