Kubernetes 1.10のクラスタを全手動で構築するのをAnsibleで全自動化した」の続きで、さらにPackerを組み合わせて、VM作成まで自動化した話。

AnsibleをWindows(MSYS2)で動かした話でもある。

書いたPackerテンプレートはGitHubに置いた。

Packerとは

Packerは、様々な種類のVMを構築できるツール。 VagrantとかTerraformとかを開発しているHashiCorpが開発している。

テンプレートと呼ばれるビルド定義をJSONファイルに書いて、ビルド、プロビジョニング、ポストプロセスを実行して、アーティファクトと呼ばれるビルドの成果物を生成する。

ビルドのステップでは、VMを作成して、ハードウェア構成を設定したり、OSをインストールしたりする。

以下のような環境でVMを作れる。

  • VirtualBox
  • Hyper-V
  • VMware Workstation
  • VMware vSphere Hypervisor
  • Docker
  • AWS EC2


プロビジョニングのステップでは、ビルドで作ったVMのOS上で指定された操作を実行し、ソフトウェアのインストールなどのセットアップ処理をする。

プロビジョニングには以下のようなツールを使える。

  • Shell
  • PowerShell
  • Ansible
  • Chef
  • Puppet

プロビジョニングが終わるとアーティファクト(VMイメージファイルや、AWS EC2のAMI IDとか)が出力される。


ポストプロセスのステップでは、アーティファクトを入力として何らかの処理をして、最終的なアーティファクトを生成する。

ポストプロセスでは以下のような処理を実行できる。

  • アーカイブ
  • VagrantBox生成
  • AWS EC2へのインポート
  • Docker push


PackerはGoで書かれていてビルド済みのバイナリが配布されているので、ダウンロードページから落として PATHの通ったところに置くだけでインストールできる。


今回はPacker 1.2.4のWindows版をインストールした。

Packerのテンプレート概要

Packerのテンプレートにはビルド、プロビジョニング、ポストプロセスの定義を複数かけて、複数環境のVM生成を1ファイルで定義できる。

テンプレートには以下のプロパティを書く。

  • builders: ビルドの定義のリスト。
  • description: テンプレートの説明。
  • min_packer_version: Packer の最低バージョン指定。
  • post-processors: ポストプロセスの定義のリスト。
  • provisioners: プロビジョニングの定義のリスト。
  • variables: テンプレート内で使う変数の定義。
  • _comment: コメントなどを書くためのプロパティ。実際はアンダースコアで始まればなんでもいい。JSON オブジェクトのルートレベルのみで使える。

これらのうち、必須なのはbuildersだけ。


一つのビルド定義には一つのcommunicatorを紐づける。 communicatorはビルド時にVMにつなぐための設定。 基本はSSHだけど、WinRMとかもある。

やりたいこと

Windows 10上でPackerとAnsibleを動かして、VirtualBoxのVMをOracle Linux 7.4で作って、Kubernetes 1.10をインストールしたい。 Windowsでやりたいのは、単にベアメタルのLinuxの環境が無いからってのもあるし、いずれHyper-VのVMも作りたいからってのもある。

PackerはGo製で普通にWindowsで動くからいいけど、問題はAnsibleがPython製のくせにWindowsのPythonでは動かないこと。 AnsibleはWSLでは動くけど、VirtualBoxとかHyper-VはWindows上で動くから、PackerはWindows上で動かさないといけないはずで、そうなるとPackerから呼ばれるAnsibleもWindows上で動かさないといけない気がする。 のでWSLではだめな気がするし、そもそも実はWindows 7でも同じことやりたいのでWSLは無し。

要はWindows上でLinuxのPythonを使ってAnsibleを動かしたい。 ならばCygwinかMSYS2+MinGW-w64かGit Bashか。

ここにAnsibleはCygwinでもGit Bashでも動かすの難しいと書いてあって、逆にMSYS2でAnsible動かした記事はあったので、安直にMSYS2でやることにした。

MSYS2インストール

MSYS2は、公式サイトからx86_64のインストーラ(msys2-x86_64-20180531.exe)をダウンロードして実行して普通にインストールしただけ。

Ansibleインストール

MSYS2でのパッケージ管理にはpacmanを使う。

何はともあれPythonを入れる。3系でいい。 MSYS2 MSYSのショートカット(MSYS2 MinGW 64-bitじゃだめ)からターミナルを開いて、

$ pacman -S python

で、Python 3.6.2が入った。

次に、Ansible(の依存)のビルドに必要なパッケージを入れる。

$ pacman -S gcc
$ pacman -S make
$ pacman -S libffi-devel
$ pacman -S openssl-devel

さらに、AnsibleからのSSH接続で(鍵ではなくて)パスワードを使う場合に必要なパッケージも入れる。

$ pacman -S sshpass

sshpassの依存としてopensshも入った。


Ansibleはpipでインストールするんだけど、pacmanで入れたPython 3にはpipが付いてなかったので、別途入れる

$ curl https://bootstrap.pypa.io/get-pip.py -LO
$ python get-pip.py

(ちょっと古いけどpipはpacman python3-pipでも入る。)


で、ようやくAnsibleインストール。

$ export CFLAGS=-I/usr/lib/libffi-3.2.1/include
$ pip install ansible

依存するPyNaClのビルドに20分くらいかかるのでゆっくり待つと、インストール完了するはず。

今回はAnsible 2.5.4がインストールされた。

AnsibleでJinja2のipaddrフィルターを使うために、もう一つPyPiパッケージ入れる。

$ pip install netaddr

Packerテンプレート作成

ビルドは、OSインストールメディアのISOファイルを使うVirtualBoxのビルダであるvirtualbox-isoを指定して書いた。

OSのインストールは、Boot Commandをテンプレートに書くことで、インストーラのGUIを操作してやることもできるけど、RHEL系ならKickstartを使うのが楽。

Kickstartの定義ファイルは、普通に手動でOSをインストールした後、/root/anaconda-ks.cfgを採取して、必要に応じて編集して作る。 今回作ったのはこれで、このスレを参考に、Minimalインストールから、Wifiのファームウェアとか要らないのを抜いてる。


プロビジョニングは、「Kubernetes 1.10のクラスタを全手動で構築するのをAnsibleで全自動化した」ときのPlaybookを実行するやつを公式マニュアル見ながら適当に書いて、ポストプロセスも適当に書いて、できたのがこれ

ansible_env_varsANSIBLE_SSH_ARGS-o ControlMaster=noを入れているのは、この問題に対応するため。

ビルド実行

MSYS2 MSYSのショートカットからターミナルを開いて、Packerを実行してみたら以下のエラー。

$ packer build -var-file=variables.json k8s_single_node_cluster-vb.json
bash: packer: コマンドが見つかりません

WindowsのPathが通ったところにPackerバイナリを置いておいてもMSYS2からは見えない。 のでpackerバイナリのフルパス(今回はC:\Users\kaitoy\Desktop\bin\にインストールしてたのでそのパス)を指定してやる。

$ /c/Users/kaitoy/Desktop/bin/packer.exe build -var-file=variables.json k8s_single_node_cluster-vb.json
k8s-single-node-cluster output will be in this color.

1 error(s) occurred:

* Error running "ansible-playbook --version": exec: "ansible-playbook": executable file not found in %PATH%

と、今度は、ansible-playbookが無いと言われる。 ansible-playbookはansibleパッケージに入っていて/usr/bin/にインストールされているんだけど、Windows界で動いているPackerからはLinuxのPATHが見えないので、見つけられない。

さらに、AnsibleのPlaybookのパスなど、Packerが妙な気を利かせてWindowsのフルパスにしてansible-playbookに渡してくれちゃうので、それをLinuxなパスに変換してやる必要がある。

ということで、以下のようなラッパスクリプトを書いて、カレントディレクトリに置くことにした。

@echo off
setlocal enabledelayedexpansion

for %%f in (%*) do (
  if !key_file! == 1 (
    rem The value of ansible_ssh_private_key_file is the path to
    rem a key file in Windows TMP directory from MSYS2 point of view.
    set arg=/%tmp:\=/%
    set arg=!arg::=!
    set args=!args!=!arg!/%%~nxf
    set key_file=0
  ) else if %%~xf == .yml (
    rem Convert the passed Playbook path to relative one.
    set arg=%%f
    set arg=!arg:%CD%=!
    set arg=!arg:\=/!
    set args=!args! !arg:~1!
  ) else (
    rem Add other args as they are
    set args=!args! %%f
  )
  if %%f == ansible_ssh_private_key_file (
    rem The next arg will be the value of ansible_ssh_private_key_file
    set key_file=1
  )
)

echo args: %args%
C:\msys64\usr\bin\python C:\msys64\usr\bin\ansible-playbook -v %args%


以上でちゃんと実行できるようになった。

まとめると、

  1. Windows 10に、
  2. VirtualBox 5.1.28をインストールして、
  3. Packer 1.2.4のWindows版をインストールして、
  4. MSYS2をインストールして、
  5. MSYS2 MSYSのターミナルでPython 3.6.2とAnsible 2.5.4とか(とGit)をインストールして、
  6. 以下を実行すればいい。

    $ git clone --recursive https://github.com/kaitoy/packer-k8s.git
    $ cd packer-k8s
    $ /c/Users/kaitoy/Desktop/bin/packer.exe build -var-file=variables.json k8s_single_node_cluster-vb.json

packer.exe build-debugを渡すと、内部の処理ステップごとに停止するようになり、デバッグしやすい。


一回実行したらゴミができて、次回実行時にエラーになるので、以下でクリーンアップする必要がある。

$ rm -rf /tmp/ansible
$ rm -f ~/.ssh/known_hosts

因みに、上記known_hostsを消し忘れると以下のようなエラーになる。

 k8s-single-node-cluster: fatal: [k8s_master]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @\r\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\nIT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\r\nSomeone could be eavesdropping on you right now (man-in-the-middle attack)!\r\nIt is also possible that a host key has just been changed.\r\nThe fingerprint for the ECDSA key sent by the remote host is\nSHA256:JNs/ZY38VpIuBE3QEzLHyLFGYe+Qg+bEWi8BOzgSNc0.\r\nPlease contact your system administrator.\r\nAdd correct host key in /home/kaitoy/.ssh/known_hosts to get rid of this message.\r\nOffending ECDSA key in /home/kaitoy/.ssh/known_hosts:1\r\nPassword authentication is disabled to avoid man-in-the-middle attacks.\r\nKeyboard-interactive authentication is disabled to avoid man-in-the-middle attacks.\r\[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).\r\n", "unreachable": true}