訳しながら理解していくPacker_Ansible Provisioner編

## はじめに
Packerのドキュメントって英語だし、英検3級レベルで英語力のない私にはつらい・・・
そして、一回(google翻訳を使って)訳しながら読んでまた忘れてまた(google翻訳を使って)訳すを繰り返すのをやめたい。
調べるときは全文を見ずに、必要な部分だけを見てたりするので、公式ドキュメントを訳しながら全体を理解していこうと思う。

英語読むのめんどくせーーーとなっている人の助けになればと思い公開した

今回は [Ansible Provisioner](https://www.packer.io/docs/provisioners/ansible.html)


## 注意事項
* 基本的にGoogle翻訳のまんまです。
* 一応、意味が分かるようには訳してるつもりですが、ちょいちょい意味分からない部分もあります。  
誤訳がある可能性があるので、最後はちゃんと公式ドキュメントを読みましょう
* 私の知りたい部分からやるので、訳す部分はバラバラになります。
* 公式ドキュメントに記載されていない部分(自分で調べた部分とか)は_italic_で記載しています。

# Ansible Provisioner

Type: ansible

packerのansible provisionerは、Aniableプレイブックを実行します。 これは、SSHを使用するように設定されたAnsibleインベントリファイルを動的に作成し、SSHサーバを実行し、実行可能なプレイブックを実行し、Packerによってプロビジョニングされているマシンに対してSSHサーバを介して実行されます。

>注::タスクに定義されているremote_userはすべて無視されます。 Packerは、このプロビジョナーのjson configで指定されたユーザーと常に接続します。

## Basic Example

これはDigitalOceanに画像をプロビジョニングする完全機能テンプレートです。 mock api_tokenの値を自分のものに置き換えます。

```json
{
  "provisioners": [
    {
      "type": "ansible",
      "playbook_file": "./playbook.yml"
    }
  ],

  "builders": [
    {
      "type": "digitalocean",
      "api_token": "6a561151587389c7cf8faa2d83e94150a4202da0e2bad34dd2bf236018ffaeeb",
      "image": "ubuntu-14-04-x64",
      "region": "sfo1"
    }
  ]
}
```

## Configuration Reference


Required Parameters:

* playbook_file - Ansibleによって実行されるplaybook

Optional Parameters:

* ansible_env_vars (array of strings) - 環境変数を実行する前に設定する。使用例：

  ```json
{
  "ansible_env_vars": [ "ANSIBLE_HOST_KEY_CHECKING=False", "ANSIBLE_SSH_ARGS='-o ForwardAgent=yes -o ControlMaster=auto -o ControlPersist=60s'", "ANSIBLE_NOCOLOR=True" ]
}
  ```

AWS、AzureまたはGoogle ComputeでWindowsビルドを実行していて、WinRM経由でPackerがWindowsインスタンスに接続するために使用する自動生成パスワードにアクセスしたい場合は、テンプレート変数{{.WinRMPassword}}を使用します オプション。 例えば：

```json
"ansible_env_vars": [ "WINRM_PASSWORD={{.WinRMPassword}}" ],
```

* command (string) - ansibleで呼び出すコマンド。デフォルトはansible-playbookになります。
* empty_groups (array of strings) - インベントリファイルには存在するが、空のままでなければならないグループ。
* extra_arguments (array of strings) - Ansibleに渡す引数。これらの引数はシェルに渡されず、引数は引用符で囲まれません。使用例：

```json
{
  "extra_arguments": [ "--extra-vars", "Region={{user `Region`}} Stage={{user `Stage`}}" ]
}
```

AWS、AzureまたはGoogle ComputeでWindowsビルドを実行していて、WinRM経由でPackerがWindowsインスタンスに接続するために使用する自動生成パスワードにアクセスしたい場合は、テンプレート変数{{.WinRMPassword}}を使用します オプション。 例えば：

```json
  "extra_arguments": [
    "--extra-vars", "winrm_password={{ .WinRMPassword }}"
  ]
```

* groups (array of strings) - Ansibleホストを配置するグループ。指定されていない場合、ホストはどのグループにも関連付けられていません。
* inventory_file (string) - プロビジョニング中に使用するインベントリファイル。指定されていない場合、Packerは一時インベントリファイルを作成し、host_aliasを使用します。
* inventory_directory (string) - 一時的に生成されたansibleインベントリファイルを配置するディレクトリ。デフォルトでは、これはシステム固有の一時ファイルの場所です。この一時ファイルの完全修飾名は、このansibleが動作するprovisionerが実行されたときに、ansibleのコマンドの-i引き数に渡されます。このプロビジョニングを実行するプレイブックで使用するhost_vars group_varsを持つ既存のインベントリディレクトリがある場合は、これを指定します。
* local_port (string) - SSH接続のリスンを試みるポート。この値は開始点です。provisionerは、local_portから始まる10個のポートのうち、最初に使用可能なlocal_portでSSH接続をリッスンしようとします。システムで選択されたポートは、local_portがないか空である場合に使用されます。
* sftp_command (string) - ansibleがファイルの転送に使用するSFTPプロトコルを処理するためにPackerによってプロビジョニングされているマシン上で実行するコマンド。このコマンドは、それぞれstdinとstdoutを読み書きする必要があります。デフォルトは/usr/lib/sftp-server -eです。
* skip_version_check (boolean) - 実行する前にansibleがインストールされているか確認してください。これをtrueに設定します。たとえば、packerの実行中に、あなたがインストールする場合はtrueです。
* ssh_host_key_file (string) - ターゲットマシンにコマンドを転送するためにホストマシン上でSSHサーバーを実行するために使用されるSSHキー。このサーバーに接続すると、known_hostsシステムを使用してサーバーのIDが検証されます。デフォルトの動作は、ワンタイムキーを生成して使用することです。キーが生成されている場合は、ANSIBLE_HOST_KEY_CHECKING環境変数を介してホストキーのチェックが無効になります。
* ssh_authorized_key_file (string) - 安全なssh_userのSSH公開鍵。デフォルトの動作は、ワンタイムキーを生成して使用することです。このキーが生成された場合、対応する秘密鍵は、--private-keyオプションを使用して、安全なプレイブックに渡されます。
* user (string) - 使用するansible_user。デフォルトはpackerを実行しているユーザーです。

## Default Extra Variables
extra_arguments設定を使用して余分(extra)な引数を指定できることに加えて、provisionerは一般的にansibleの変数を自動的に定義します。

* packer_build_nameには、Packerが実行されているビルドの名前が設定されます。これは、Packerが複数のビルドを行い、共通のプレイブックを使用しているときにそれらをわずかに区別したい場合に最も便利です。
* packer_builder_typeは、スクリプトが実行されているマシンを作成するために使用されたBuilderのタイプです。これは、特定のビルダーで構築されたシステムで、プレイブックの特定の部分だけを実行する場合に便利です。
* packer_http_addrファイル転送用のHTTPサーバー（hyperv、parallels、qemu、virtualbox、およびvmwareなど）を提供するBuilderを使用している場合、これはアドレスに設定されます。このアドレスをプロビジョナで使用して、http経由で大きなファイルをダウンロードすることができます。これは、デフォルトのファイルプロビジョナを使用して速度が低下している場合に役立ちます。 winrmコミュニケータを使用するファイルプロビジョナリには、この種の問題が発生する可能性があります。

## Debugging
Ansibleの根本的な問題をデバッグするには、詳細ログを有効にするために "-vvvv"を "extra_arguments"に追加します。

```json
{
  "extra_arguments": [ "-vvvv" ]
}
```

## Limitations

### Redhat / CentOS
Redhat/CentOSビルドは、sftp_commandのために次のエラーで失敗することが知られています。これは、/usr/libexec/openssh/sftp-server -eに設定する必要があります。

```
==> virtualbox-ovf: starting sftp subsystem
    virtualbox-ovf: fatal: [default]: UNREACHABLE! => {"changed": false, "msg": "SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh", "unreachable": true}
```

### chroot communicator
chroot（例えばamazon-chroot）内にビルドするには、Ansible接続をchrootに変更する必要があります。

```json
{
  "builders": [
    {
      "type": "amazon-chroot",
      "mount_path": "/mnt/packer-amazon-chroot",
      "region": "us-east-1",
      "source_ami": "ami-123456"
    }
  ],
  "provisioners": [
    {
      "type": "ansible",
      "extra_arguments": [
        "--connection=chroot",
        "--inventory-file=/mnt/packer-amazon-chroot,"
      ],
      "playbook_file": "main.yml"
    }
  ]
}
```

### winrm communicator
Windowsのビルドには、カスタムAnsible接続プラグインと特定の設定が必要です。connection_pluginsという名前のディレクトリが、プレイブックの隣にあり、接続プラグインを実装するpacker.pyという名前のファイルを含んでいると仮定します。2.4.xより前のansibleのバージョンでは、以下が接続プラグインとして機能します。

```python
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.plugins.connection.ssh import Connection as SSHConnection

class Connection(SSHConnection):
    ''' ssh based connections for powershell via packer'''

    transport = 'packer'
    has_pipelining = True
    become_methods = []
    allow_executable = False
    module_implementation_preferences = ('.ps1', '')

    def __init__(self, *args, **kwargs):
        super(Connection, self).__init__(*args, **kwargs)
```

Ansibleの新しいバージョンでは、すべてのプラグインにドキュメンテーション文字列が必要です。[ここ](https://github.com/hashicorp/packer/tree/master/examples/ansible/connection-plugin)で使用しているバージョンのAnsibleに対応しているプラ​​グインがあるかどうかを確認できます。

プラグインを自分で作成するには、使用しているAnsibleバージョンの[ssh.py Ansible connection plugin](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/connection/ssh.py)のDOCUMENTATION文字列のすべてのオプションをコピーし、以下のようにpacker.pyファイルに追加する必要があります

```python
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.plugins.connection.ssh import Connection as SSHConnection

DOCUMENTATION = '''
    connection: packer
    short_description: ssh based connections for powershell via packer
    description:
        - This connection plugin allows ansible to communicate to the target packer
        machines via ssh based connections for powershell.
    author: Packer
    version_added: na
    options:
      **** Copy ALL the options from
      https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/connection/ssh.py
      for the version of Ansible you are using ****
'''

class Connection(SSHConnection):
    ''' ssh based connections for powershell via packer'''

    transport = 'packer'
    has_pipelining = True
    become_methods = []
    allow_executable = False
    module_implementation_preferences = ('.ps1', '')

    def __init__(self, *args, **kwargs):
        super(Connection, self).__init__(*args, **kwargs)
```

このテンプレートは、Google Cloud PlatformにWindows Server 2012イメージを作成する必要があります。

```json
{
  "variables": {},
  "provisioners": [
    {
      "type":  "ansible",
      "playbook_file": "./win-playbook.yml",
      "extra_arguments": [
        "--connection", "packer",
        "--extra-vars", "ansible_shell_type=powershell ansible_shell_executable=None"
      ]
    }
  ],
  "builders": [
    {
      "type": "googlecompute",
      "account_file": "{{user `account_file`}}",
      "project_id": "{{user `project_id`}}",
      "source_image": "windows-server-2012-r2-dc-v20160916",
      "communicator": "winrm",
      "zone": "us-central1-a",
      "disk_size": 50,
      "winrm_username": "packer",
      "winrm_use_ssl": true,
      "winrm_insecure": true,
      "metadata": {
        "sysprep-specialize-script-cmd": "winrm set winrm/config/service/auth @{Basic=\"true\"}"
      }
    }
  ]
}
```

### Post i/o timeout errors
不明なエラーが表示された場合：Windowsマシンのプロビジョニング中にhttp：//<ip>：<port>/wsman：dial tcp <ip>：<port>：入出力タイムアウトエラーが発生したら、[sftpの代わりssh経由](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#envvar-ANSIBLE_SCP_IF_SSH)でファイルをコピーするようにAnsibleを設定してみてください。

### Too many SSH keys
SSHサーバーでは、特定の回数だけ認証を試みることができます。読み込まれたすべてのキーは、動的に生成されるキーの前に試行されます。 ssh-agentにSSH鍵があまりにも多くロードされている場合、Anufactoryプロビジョナーは次のようなメッセージで認証に失敗することがあります：

```
googlecompute: fatal: [default]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added '[127.0.0.1]:62684' (RSA) to the list of known hosts.\r\nReceived disconnect from 127.0.0.1 port 62684:2: too many authentication failures\r\nAuthentication failed.\r\n", "unreachable": true}
```

ssh-agentからすべての鍵をアンロードするには、次のコマンドを実行します。

```
$ ssh-add -D
```

### Become: yes
Packerをrootとして実行することをお勧めします。あなたがそうした場合は、あなたのAnsibleをrootとして正常に実行することはできません。become:yesは失敗します。