Packer + Ansible で Azure Managed Image (VHDではなく) を作る


[Packer] \(1.0.4〜\) と [Ansible] で [Azure Managed Image] を作る方法です。
旧来の [VHD] (Storage Account) を作る方法ではありません。

AWS の [AMI] \([Builders >> amazon-ebs]\) と同じでしょ？と思ってましたが、実際はかなりハマったのでまとめ。

## ハマりポイント

* [Azure Managed Image] が作れるのは [Packer] 1.0.3 から〜
    * 〜1.0.2 で作れるのは [VHD] (Storage Account) だけ
* [Packer] 1.0.3 は [Ansible Provisioner が使えないバグ](https://github.com/hashicorp/packer/issues/5142) があります (sshがフリーズする)
	* 2017/07/27現在は、未リリースの 1.0.4 を [自前でビルド](https://github.com/hashicorp/packer/blob/master/CONTRIBUTING.md#setting-up-go-to-work-on-packer) して使う

```shell-session:Packerビルド方法(Mac版)
# install go.
$ brew install go. # ← ここがMac専用 (あとはLinux共通)
$ export GOPATH=$HOME/go
$ export PATH=$PATH:$GOPATH/bin

# get packer git repository into "~/go".
$ go get github.com/hashicorp/packer
$ cd $GOPATH/src/github.com/hashicorp/packer

# compile.
$ make
$ go build -o bin/packer .
$ $GOPATH/src/github.com/hashicorp/packer/bin/packer -v
1.0.4

# install.
$ mv $GOPATH/src/github.com/hashicorp/packer/bin/packer /usr/local/bin
$ which packer
/usr/local/bin/packer
```

* [Builders >> amazon-ebs] とは異なり、[Deprovision](https://www.packer.io/docs/builders/azure.html#deprovision) という対応を自分でやらないといけない。これを忘れると **Image作成は成功するが、出来たImageからVMが起動できない!!**


## Packer設定例

Packer公式のガイドはこれです。

* [Builders >> azure-arm]

実際にImageを作れた時の ``packer.json`` 。CentOS7ベースです。

```json
{
  "builders": [
    {
      "type": "azure-arm",

      "client_id": "{アプリケーションID}",
      "client_secret": "{パスワード}",
      "tenant_id": "{テナントID}",
      "subscription_id": "{サブスクリプションID}",

      "managed_image_name": "{登録したいイメージ名}",
      "managed_image_resource_group_name": "{イメージ登録先のリソースグループ}",

      "os_type": "Linux",
      "image_publisher": "OpenLogic",
      "image_offer": "CentOS",
      "image_sku": "7.3",

      "location": "eastasia",
      "vm_size": "Standard_DS2"
    }
  ],
  "provisioners": [
    {
      "type": "ansible",
      "playbook_file": "playbook.yml"
    },
    {
      "type": "shell",
      "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'",
      "inline": [
        "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync"
      ],
      "inline_shebang": "/bin/sh -x"
    }
  ]
}
```

一応 [Ansible] の ``playbook.yml`` の例も。

```yaml
---
- hosts: all
  become: true
  tasks:
    - name: you can do anythin in this playbook.
      shell: echo hello world !!
```

## Builders設定

[Azure Portal] で ``packer.json`` に指定するID類を確認＆作成していきます。基本↓に書いてあります。

* [リソースにアクセスできる Azure Active Directory アプリケーションとサービス プリンシパルをポータルで作成する]
* [How to use Packer to create Windows virtual machine images in Azure] \(←VHD作成なので注意\)

まずはリソースグループを作ります。これは ``packer.json`` の "managed_image_resource_group_name" に指定するリソースグループ名です。

* https://portal.azure.com/#blade/HubsExtension/Resources/resourceType/Microsoft.Resources%2Fsubscriptions%2FresourceGroups

*Azure Active Directory >> App registrations* でアプリを登録します

* https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps

上部メニューの "+ADD" を押して、アプリIDを発行します。

> ![1-appregistration.png](https://qiita-image-store.s3.amazonaws.com/0/60131/ca007282-0edf-30f1-edcf-dce2c9082158.png "1-appregistration.png")

アプリIDは↓です。これは ``packer.json`` の "client_id" に指定するIDです。

> ![2-appid.png](https://qiita-image-store.s3.amazonaws.com/0/60131/3c5edc78-b061-ce13-1c2e-27a2ceb448e2.png "2-appid.png")

*Azure Active Directory >> App registrations >> sampleapp >> API ACCESS:Keys* でキー (パスワード) の発行をします。

> ![3-keys.png](https://qiita-image-store.s3.amazonaws.com/0/60131/5a7de07d-afc4-0193-c155-cb84d7f9e923.png "3-keys.png")

"DESCRIPTION", "EXPIRES" を入力して "Save" を押すとキー (パスワード) が発行されます。これは ``packer.json`` の "client_secret" に指定します。

> ![4-keys.png](https://qiita-image-store.s3.amazonaws.com/0/60131/8fff1002-2f2e-0fa9-9957-3832d68055f3.png "4-keys.png")

*Subscriptions >> {Subscription名} >> Access control (IAM)* でアプリにロール (アクセス権) の登録をします。ロールは "Contributor" (日本語では"共同作成者") を指定します。

> ![6-addrole.png](https://qiita-image-store.s3.amazonaws.com/0/60131/2b9d1bd6-949d-d2c3-53a0-2086a5d37c51.png "6-addrole.png")

*Azure Active Directory >> Properties* でテナントID (Directory ID) が見れます。これは ``packer.json`` の "tenant_id" に指定します。

> ![5-tenantid.png](https://qiita-image-store.s3.amazonaws.com/0/60131/bf771900-979e-caa5-4a86-dd5716b84704.png "5-tenantid.png")

*Subscriptions* で Subscription ID が見れます。これは ``packer.json`` の "subscription_id" に指定します。

![7-subscription.png](https://qiita-image-store.s3.amazonaws.com/0/60131/4f66839b-d59d-ee8c-0e76-da37fb43bbd3.png "7-subscription.png")

## Deprovision処理を忘れるな！

からなず "provisioners" の最後に↓の [Deprovision] 処理が必要です。これを忘れると **Image作成は成功しますが、VMの起動は失敗** します。

```json
{
  "provisioners": [
    {
      "type": "shell",
      "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'",
      "inline": [
        "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync"
      ],
      "inline_shebang": "/bin/sh -x"
    }
  ]
}
```

> Windowsマシン用の処理は↑とは違うので [Deprovision] を参照

## 参考

* [Builders >> azure-arm]
* [How to use Packer to create Windows virtual machine images in Azure]
* [リソースにアクセスできる Azure Active Directory アプリケーションとサービス プリンシパルをポータルで作成する]


[Packer]:https://www.packer.io/
[Ansible]:https://www.ansible.com/
[Azure Managed Image]:https://docs.microsoft.com/en-us/azure/virtual-machines/windows/capture-image-resource
[VHD]:https://docs.microsoft.com/en-us/azure/storage/storage-about-disks-and-vhds-linux
[AMI]:http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AMIs.html
[Builders >> azure-arm]:https://www.packer.io/docs/builders/azure.html
[Builders >> amazon-ebs]:https://www.packer.io/docs/builders/amazon-ebs.html
[Deprovision]:https://www.packer.io/docs/builders/azure.html#deprovision
[Azure Portal]:https://portal.azure.com/
[リソースにアクセスできる Azure Active Directory アプリケーションとサービス プリンシパルをポータルで作成する]:https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/resource-group-create-service-principal-portal
[How to use Packer to create Windows virtual machine images in Azure]:https://docs.microsoft.com/en-us/azure/virtual-machines/windows/build-image-with-packer