【#Chef】Windows 環境で Chef Solo（chef-solo）と Berkshelf を使って IIS をインストール #GetChef_ja

Windows 環境での Chef Solo と Berkshelf の基本的な使い方について自分用のメモとしてまとめました。

AWS の EC2 インスタンス上に作成した Windows Server 2012 R2 環境で Chef Solo と Berkshelf を使って IIS をインストールします。

## PowerShell でのリモート接続

まずは、リモートから PowerShell コマンドを使うためのいくつかの設定を行います。 

### 手順 1: リモートコンピューターにサインインします

```
リモートデスクトップを使って、 Administrator ユーザーでサインインします。
```

### 手順 2: Windows PowerShell を起動します

```
リモートコンピューター側のスタートメニューから Windows PowerShell を起動します。
```

### 手順 3: Windows PowerShell の実行ポリシーを変更します

```ps1
PS> Set-ExecutionPolicy "RemoteSigned" -Force
PS> Get-ExecutionPolicy

RemoteSigned
```

→ RemoteSigned と表示されることを確かめます。

### 手順 4: Windows リモート管理（WinRM）を有効にします

```ps1
PS> Enable-PSRemoting -Force
```

### 手順 5: Windows リモート管理に関するWindowsファイアウォールのルールを変更します

```ps1
PS> Set-NetFireWallRule -Name "WINRM-HTTP-In-TCP-PUBLIC" -RemoteAddress "Any"
```

→ デフォルトでは、同一サブネットのアドレスにのみ WinRM のポート（5985）が開放されています。そこで、ローカルマシンからも接続できるように、ファイアウォールのルールを変更します。

### 手順 6: Windows リモート管理 (WinRM)の接続タイムアウト値を"1,800,000[ミリ秒]（30分）"に設定します

```ps1
PS> Set-Item -Path "WSMan:\localhost\MaxTimeoutms" 1800000
PS> Get-Item -Path "WSMan:\localhost\MaxTimeoutms"

   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost

Type            Name           SourceOfValue   Value
----            ----           -------------   -----
System.String   MaxTimeoutms                   1800000
```

→ 値が 1800000[ミリ秒]（30分） であることを確かめます。デフォルト値は 60000[ミリ秒]（60秒） です。

### 手順 7: リモートコンピューターからサインアウトします

```ps1
PS> & logoff.exe
```

### 手順 8: Windows PowerShell を起動します

```
ローカルコンピューター側のスタートメニューから Windows PowerShell を起動します
```

### 手順 9: ドメインの異なるコンピューターへ接続するための設定を行います

```
PS> Set-Item -Path "WSMan:\localhost\Client\TrustedHosts" -Value "*"

WinRM サービスの起動
WinRM サービスは現在起動していません。このコマンドを実行すると、WinRMサービスが起動します。

続行しますか?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"):Y

WinRM セキュリティの構成。
このコマンドは WinRM クライアントの TrustedHosts の一覧を変更します。TrustedHosts の一覧内にあるコンピューターは認証されない可能性があります。クライアントはこれらのコンピューターに資格情報を送信する可能性があります。この一覧を変更しますか?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"):Y
```

→ 全ての質問に対して、"はい(Y)"" を選択します。

### 手順 10: コマンドレット `New-PSSession` を使ってリモートコンピューターとの PSSession を作成します

```ps1
PS> New-PSSession -ComputerName "IPアドレス" -Credential "Administrator"
```

### 手順 11: パスワードを入力します

```
[パスワード(P):]欄に "Administrator" のパスワードを入力し [OK]ボタンをクリックします。
```

### 手順 12: 作成した PSSession の ID を確認します

```ps1
PS> Get-PSSession

 Id Name      ComputerName    State  ConfigurationName    Availability
 -- --------- --------------- ------ -------------------- ------------
 XX SessionXX xxx.xxx.xxx.xxx Opened Microsoft.PowerShell Available
```

→ Id 欄の値を確認します

### 手順 13: `Enter-PSSession` コマンドレットを使って作成した PSSesion に接続します

```
PS> Enter-PSSession ID番号
```

`[xxx.xxx.xxx.xxx]: PS C:\Users\Administrator\Documents>`

→プロンプトが上記のように変われば成功です。

## Chef と Berkchelf のセットアップ

いよいよ、Chef と Berkshelf のインストール手順です。

Chef のインストールには、Windows 向けパッケージマネージャーである Chocolatey を利用します。

Berkshelf のバージョンは 3 ではなく、インストールが容易な 2.0.16 を利用します。

### 手順 1: Chocolatey をインストールします

```ps1
PS> Invoke-Expression (New-Object System.Net.WebClient).DownloadString("https://chocolatey.org/install.ps1")
```

### 手順 2: Chocolatey を使って、Chef と Git をインストールします

```ps1
PS> & chocolatey install "chef-client" "git"
```

### 手順 3: Chef Solo の設定ファイル `solo.rb` を作成します

```ps1
PS> New-Item -Path "$env:SystemDrive\chef\solo.rb" -ItemType "File" -Value @"
environment_path '$env:SystemDrive\chef\environments'
data_bag_path '$env:SystemDrive\chef\data_bags'
cookbook_path '$env:SystemDrive\chef\cookbooks'
file_cache_path '$env:SystemDrive\chef\cache'
"@
```

### 手順 4. Chef の Omnibus Installer でインストールされたパッケージ群と Git をパスに通します。

```ps1
PS> $env:Path = "$env:SystemDrive\opscode\chef\bin;$env:SystemDrive\opscode\chef\embedded\bin;${env:ProgramFiles(x86)}\git\bin;$env:ProgramFiles\git\bin;$env:Path"
```

### 手順 5. gem コマンドを使って、Berkshelf をインストールします

```ps1
PS> & gem install "buff-extensions" -v "0.5.0" --no-ri --no-rdoc
PS> & gem install "varia_model" -v "0.3.2" --no-ri --no-rdoc
PS> & gem install "berkshelf" -v "2.0.16" --no-ri --no-rdoc
PS> & gem list --local | Select-String "berkshelf"

berkshelf (2.0.16)
```

## ラッパークックブックの作成

コミュニティに公開されているクックブック `iis` をラップするだけの簡単なクックブックを作成します。

### 手順 1: Cookbook の置き場を作成します

```ps1
PS> New-Item -Path "$env:SystemDrive\chef\site-cookbooks" -ItemType "Directory"
```

### 手順 2: berks コマンドを使って `wrapper-cookbook` という名前でクックブックのひな形を作成します

```ps1
PS> Set-Location -Path "$env:SystemDrive\chef\site-cookbooks"
PS> & berks cookbook "wrapper-cookbook" --skip-vagrant --skip-test-kitchen --license="reserved" --maintainer="YOUR_NAME" --maintainer-email="YOUR_EMAIL"
```

### 手順 3: Cookbook のメタデータ設定ファイル `metadata.rb` を編集します

```ps1
PS> Add-Content -Path "$env:SystemDrive\chef\site-cookbooks\wrapper-cookbook\metadata.rb" -Value @'
depends          "iis"
'@
```

### 手順 4: Cookbook のデフォルトレシピファイル `default.rb` を編集します

```ps1
PS> Add-Content -Path "$env:SystemDrive\chef\site-cookbooks\wrapper-cookbook\recipes\default.rb" -Value @'
include_recipe "iis::default"
'@
```

## クックブックの適用（Chef Solo の実行）

ここでは、Chef の Environment という機能を利用して Chef Solo の実行します。

Environment を利用することで、クックブック内で指定している Attribute（変数）の値を上書きすることができます。

開発環境と本番環境など、環境によって異なるパラメーターを設定する必要がある場合に便利です。

### 手順 1: Berkshelf を使って依存関係のあるクックブックをダウンロードします

```ps1
PS> & berks install --berksfile="$env:SystemDrive\chef\site-cookbooks\wrapper-cookbook\Berksfile" --path="$env:SystemDrive\chef\cookbooks\"
```

### 手順 2: Node の設定ファイル `node.json` を作成します

```ps1
PS> New-Item -Path "$env:SystemDrive\chef\node.json" -ItemType "File" -Value @'
{
  "run_list": "wrapper-cookbook::default"
}
'@
```

### 手順 3: Environment の置き場を作成します

```ps1
PS> New-Item -Path "$env:SystemDrive\chef\environments" -ItemType "Directory"
```

### 手順 4: Environment の設定ファイル `development.json` を作成します

```ps1
PS> New-Item -Path "$env:SystemDrive\chef\environments\development.json" -ItemType "File" -Value @'
{
  "name": "development",
  "json_class": "Chef::Environment",
  "chef_type": "environment",
  "default_attributes": {
    "iis": {
      "home": "#{ENV['WINDIR']}\\System32\\inetsrv",
      "conf_dir": "#{iis['home']}\\config",
      "pubroot": "#{ENV['SYSTEMDRIVE']}\\inetpub",
      "docroot": "#{iis['pubroot']}\\wwwroot",
      "log_dir": "#{iis['pubroot']}\\logs\\LogFiles",
      "cache_dir": "#{iis['pubroot']}\\temp"
    }
  }
}
'@
```

### 手順 5: Chef Solo を実行します

```ps1
PS> & chef-solo -j "$env:SystemDrive\chef\node.json" -E "development"
```

### 手順 6: ブラウザを使って `http://[IPAddress]/` にアクセスします

```
ブラウザを使って http://[IPAddress]/ にアクセスします
```

→ Internet Infomation Services と書かれたページが表示されれば成功です。

## おまけ

これらの手順をスクリプト風にすると次のようになります。

```ps1
# Installation of 'Chocolatey'
Invoke-Expression (New-Object System.Net.WebClient).DownloadString("https://chocolatey.org/install.ps1")

# Installation of 'Chef Client' and 'Git'
& $env:SystemDrive\chocolatey\bin\cinst.bat "chef-client" "git"

# Creation of 'solo.rb'
New-Item -Path "$env:SystemDrive\chef\solo.rb" -ItemType "File" -Value @"
environment_path '$env:SystemDrive\chef\environments'
data_bag_path '$env:SystemDrive\chef\data_bags'
cookbook_path '$env:SystemDrive\chef\cookbooks'
file_cache_path '$env:SystemDrive\chef\cache'
"@ -Force

# Setting 'PATH'
$env:Path = "$env:SystemDrive\opscode\chef\bin;$env:SystemDrive\opscode\chef\embedded\bin;${env:ProgramFiles(x86)}\git\bin;$env:ProgramFiles\git\bin;$env:Path"

# Installation of 'Berkshelf'
& gem install "buff-extensions" -v "0.5.0" --no-ri --no-rdoc
& gem install "varia_model" -v "0.3.2" --no-ri --no-rdoc
& gem install "berkshelf" -v "2.0.16" --no-ri --no-rdoc
& gem list --local | Select-String "berkshelf"

# Creation of a cookbook template
New-Item -Path "$env:SystemDrive\chef\site-cookbooks" -ItemType "Directory" -Force
Remove-Item -Path "$env:SystemDrive\chef\site-cookbooks\wrapper-cookbook" -Force -Recurse
Set-Location -Path "$env:SystemDrive\chef\site-cookbooks"
& berks cookbook "wrapper-cookbook" --skip-vagrant --skip-test-kitchen --license="reserved" --maintainer="YOUR_NAME" --maintainer-email="YOUR_EMAIL"

# Editting 'metadata.rb'
Add-Content -Path "$env:SystemDrive\chef\site-cookbooks\wrapper-cookbook\metadata.rb" -Value @'
depends          "iis"
'@

# Editting the default recipe
Add-Content -Path "$env:SystemDrive\chef\site-cookbooks\wrapper-cookbook\recipes\default.rb" -Value @'
include_recipe "iis::default"
'@

# Installation of the depended cookbooks
& berks install --berksfile="$env:SystemDrive\chef\site-cookbooks\wrapper-cookbook\Berksfile" --path="$env:SystemDrive\chef\cookbooks\"

# Creation of 'node.json'
New-Item -Path "$env:SystemDrive\chef\node.json" -ItemType "File" -Value @'
{
  "run_list": "wrapper-cookbook::default"
}
'@ -Force

# Creation of 'development.json'
New-Item -Path "$env:SystemDrive\chef\environments" -ItemType "Directory" -Force
New-Item -Path "$env:SystemDrive\chef\environments\development.json" -ItemType "File" -Value @'
{
  "name": "development",
  "json_class": "Chef::Environment",
  "chef_type": "environment",
  "default_attributes": {
    "iis": {
      "home": "#{ENV['WINDIR']}\\System32\\inetsrv",
      "conf_dir": "#{iis['home']}\\config",
      "pubroot": "#{ENV['SYSTEMDRIVE']}\\inetpub",
      "docroot": "#{iis['pubroot']}\\wwwroot",
      "log_dir": "#{iis['pubroot']}\\logs\\LogFiles",
      "cache_dir": "#{iis['pubroot']}\\temp"
    }
  }
}
'@ -Force

# Execution of 'Chef Solo'
& chef-solo -j "$env:SystemDrive\chef\node.json" -E "development"

exit 0
```

以上