Vagrantで始めるAnsible

この記事はQiita版「インフラ勉強会 Advent Calendar 2018」の二日目です。

はじめに

Vagrantは最近あまり聞かなくなってきましたね。全てをDockerで管理できればDockerで良いのですが、今でも普通のインスタンスやオンプレサーバが存在するところは多く、それらを運用し育てていく為にはAnsibleなどの構成管理ツールは有効です。

AnsibleやChefでplaybookやrecipeを作り込んでいくときは、何度もトライアンドエラーを繰り返すことが必要なので、スナップショットの取得とリストアが出来て、環境全体の初期化もすぐ出来るVagrantはやはり便利です。

というわけでこの記事ではVagrantを使ってAnsibleの練習環境を作っていきます。またAnsibleの実行環境自体もVagrantで作ります。

準備

VagrantとVirtualboxをインストールします。お使いのOSに合わせたものを下記からインストールしてください。VirtualboxについてはExtension Packも合わせてインストールしておきます(不要かも?)

Macでbrewを使ってる場合はそちらからインストールするのが楽です

$ brew install vagrant
$ brew cask install virtualbox virtualbox-extension-pack
$ vagrant --version
Vagrant 2.2.2
$ VBoxManage -v
5.2.22r126460

Vagrantの準備

Box, Plugin

AnsibleのコントローラーとターゲットをVagrantで作成する為、Boxの追加とVagrantfileを作成していきます。今回使うBoxはCentOSです。またいくつかプラグインも追加します

$ vagrant box add centos/7

$ vagrant box list
centos/7        (virtualbox, 1809.01)

$ vagrant plugin install vagrant-hosts
$ vagrant plugin install vagrant-host-shell
$ vagrant plugin install vagrant-vbguest

$ vagrant plugin list
vagrant-host-shell (0.0.4, global)
vagrant-hosts (2.8.3, global)
vagrant-vbguest (0.16.0, global)


  • Vagrant box: CentOS 7 (centos/7)
  • vagrant-host-shell
    • Vagrantfile内でホストのシェルコマンドを実行可能にする
  • vagrant-hosts
    • ゲスト同士で名前解決できるようにする
  • vagrant-vbguest
    • 共有フォルダ用(ゲストにVirtualBox Guest Additionsを自動でインストール)

作業ディレクトリ

$ pwd
/Users/okash1n

$ mkdir -p ~/vagrant-ansible/ansible
$ cd vagrant-ansible

$ pwd
/Users/okash1n/vagrant-ansible

$ vagrant init -m centos/7
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

$ cat Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
end

$ pwd
/Users/okash1n/vagrant-ansible

$ tree
.
├── Vagrantfile
└── ansible            # 共有フォルダ

vagrant init-m オプションでシンプルなVagrantfileを作成してくれます。

Vagrantfile

Ansibleのコントローラーとターゲット(複数)を作り、すぐにAnsibleを実行出来る状態にするため、Vagrantfileを編集していきます。


Vagrant.configure("2") do |config|

  config.vm.define :my_controller do |my_controller|
    my_controller.vm.box = "centos/7"
    ENV["LC_ALL"] = "en_US.UTF-8"
    config.ssh.insert_key = false
    my_controller.vm.synced_folder "ansible", "/home/vagrant/ansible"
    my_controller.vm.network "private_network", ip: "192.168.34.10", :netmask => "255.255.254.0"
    my_controller.vm.provision :hosts, :sync_hosts => true
    my_controller.vm.provision :host_shell do |host_shell|
      host_shell.inline = 'scp -i ~/.vagrant.d/insecure_private_key -o "StrictHostKeyChecking no" ~/.vagrant.d/insecure_private_key vagrant@192.168.34.10:/home/vagrant/.ssh/id_rsa'
    end
    my_controller.vm.provision "shell", inline: <<-SHELL
      chmod 600 /home/vagrant/.ssh/id_rsa
      timedatectl set-timezone Asia/Tokyo
      yum install -y epel-release
      yum -y update
      yum -y install python36 python36-libs python36-devel
      python36 -m ensurepip
      /usr/local/bin/pip3 install --upgrade pip
      /usr/local/bin/pip3 install ansible
      SHELL
  end

  N=2
  (1..N).each do |i|
    config.vm.define "target#{i}" do |target|
      target.vm.box = "centos/7"
      config.ssh.insert_key = false
      target.vm.network "private_network", ip: "192.168.35.#{i}", :netmask => "255.255.254.0"
      target.vm.provision :hosts, :sync_hosts => true
    end
  end

end

Vagrantfileの解説

ネットワーク構成

複数のターゲットを管理できるようにします

  • ネットワークの範囲: 192.168.34.0/23 (192.168.34.1 - 192.168.35. 254)
  • my_controllerのIP: 192.168.34.10
    • my_controller.vm.network "private_network", ip: "192.168.34.10", :netmask => "255.255.254.0"
  • targetNのIP: 192.168.35.N
    • target.vm.network "private_network", ip: "192.168.35.#{i}", :netmask => "255.255.254.0"

my_controller

Ansibleを実行するマシンです。

  • config.ssh.insert_key = false
    • デフォルトではVagrantで作成したマシンはそれぞれsshのキーペアが作成されますが、それを共通にする為の設定です
  • my_controller.vm.synced_folder "ansible", "/home/vagrant/ansible"
    • Ansibleはmy_controllerで実行しますが、playbookなどはVagranthostであるMacのエディタで編集したい為、共有フォルダを作ります
    • ホストであるMacの ~/vagrant-ansible/ansibleとゲストであるmy_controllerの /home/vagrant/ansible を同期しています
  • my_controller.vm.provision :hosts, :sync_hosts => true
    • ゲスト同士の名前解決(vagrant-hostsのプラグインの設定)
  • host_shell.inline = 'scp -i ~/.vagrant.d/insecure_private_key ...
    • ホスト(Mac)から秘密鍵をゲスト(my_controller)に送信
    • config.ssh.insert_key = false の設定によりすぐにmy_controllerでAnsibleが実行できるようになる
  • my_controller.vm.provision "shell", inline: <<-SHELL
    • 送った秘密鍵のパーミッション変更
    • タイムゾーン変更
    • pythonとansibleのインストール

targetN

ターゲットはAnsibleで管理するため、Vagrantからはほとんど何もしていませんが複数ターゲットを作れるようにしています。

Tips & Tricks - Vagrantfile - Vagrant by HashiCorp

  N=2
  (1..N).each do |i|
    config.vm.define "target#{i}" do |target|

Nを変えてやればターゲットをいくつも作成できます

Vagrantの起動

$ pwd
/Users/okash1n/vagrant-ansible

$ vagrant up

VirtualBox Guest Additionsのインストールなどに時間がかかる為6~8分待ちます

Ansibleことはじめ

my_controllerに入ってみます


$ vagrant ssh my_controller
Last login: Sat Dec  1 18:55:04 2018 from 10.0.2.2
[vagrant@my_controller ~]$ ansible --version
ansible 2.7.4
  config file = None
  configured module search path = ['/home/vagrant/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.6/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.6.6 (default, Aug 13 2018, 18:24:23) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
[vagrant@my_controller ~]$ python36 --version
Python 3.6.6

Python3やAnsibleがインストールされていることを確認できましたので、一度ホストに戻ります

[vagrant@my_controller ~]$ exit

Ansibleの初期設定

ホストの~/vagrant-ansible/ansible とゲスト(my_controllerの ~/ansible は同期されているので、ホスト側で設定ファイルや playbookを書きます

  • /Users/okash1n/vagrant-ansible/ansible/ansible.cfg

[defaults]
inventory = ./hosts
forks = 15
log_path=$HOME/ansible/ansible.log
host_key_chcking = False
gathering = smart

/Users/okash1n/vagrant-ansible/ansible/hosts


[targets]
target1
target2

/Users/okash1n/vagrant-ansible/ansible/test.yml


- hosts: target1
  become: yes
  tasks:
    - name: set timezone to Asia/Tokyo
      timezone:
        name: Asia/Tokyo
    - name: Add repository
      yum_repository:
        name: nginx
        description: nginx YUM repo
        baseurl: http://nginx.org/packages/mainline/centos/7/$basearch/
        gpgcheck: no
        enabled: yes
    - name: upgrade all packages
      yum:
        name: '*'
        state: latest
    - name: install nginx
      yum:
        name: nginx
        state: latest

ホスト(Mac)側ではこのような構成になります。


$ pwd
/Users/okash1n/vagrant-ansible
$ tree
.
├── Vagrantfile
└── ansible
    ├── ansible.cfg
    ├── hosts
    └── test.yml

Ansibleを実行してみる

再度my_controllerに入ります


$ vagrant ssh my_controller
Last login: Sat Dec  1 19:03:22 2018 from 10.0.2.2
[vagrant@my_controller ~]$ pwd
/home/vagrant
[vagrant@my_controller ~]$ ls -la ./ansible
drwxr-xr-x. 1 vagrant vagrant   320 Nov 29 18:56 .
drwx------. 5 vagrant vagrant  4096 Dec  1 19:19 ..
-rw-r--r--. 1 vagrant vagrant   119 Dec  1 19:25 ansible.cfg
-rw-r--r--. 1 vagrant vagrant    25 Dec  1 19:14 hosts
-rw-r--r--. 1 vagrant vagrant   501 Dec  1 19:27 test.yml

ホスト側で作成したファイルが同期されていることが確認できましたので、Ansibleコマンドでターゲットとの疎通確認をします。

[vagrant@my_controller ~]$ cd ansible
[vagrant@my_controller ansible]$ ansible -i hosts target1 -m ping
The authenticity of host 'target1 (192.168.35.1)' can't be established.
Are you sure you want to continue connecting (yes/no)? yes
target1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
[vagrant@my_controller ansible]$ ansible -i hosts target2 -m ping
The authenticity of host 'target2 (192.168.35.2)' can't be established.
Are you sure you want to continue connecting (yes/no)? yes
target2 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

次は二台のターゲット上でコマンドを実行します。hostsファイルで設定したtargetsグループに対して実行します


[vagrant@my_controller ansible]$ ansible -i hosts targets -a "uname -a"
target2 | CHANGED | rc=0 >>
Linux target2 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

target1 | CHANGED | rc=0 >>
Linux target1 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

playbookの実行


- hosts: target1
  become: yes
  tasks:
    - name: set timezone to Asia/Tokyo
      timezone:
        name: Asia/Tokyo
    - name: Add repository
      yum_repository:
        name: nginx
        description: nginx YUM repo
        baseurl: http://nginx.org/packages/mainline/centos/7/$basearch/
        gpgcheck: no
        enabled: yes
    - name: upgrade all packages
      yum:
        name: '*'
        state: latest
    - name: install nginx
      yum:
        name: nginx
        state: latest

ansible-playbook コマンドを使って、target1にのみ変更をかけます


[vagrant@my_controller ansible]$ ansible-playbook test.yml

PLAY [target1] ************************************************************************************************************************************************

・・・・

PLAY RECAP ****************************************************************************************************************************************************
target1                    : ok=5    changed=4    unreachable=0    failed=0

target1のみ変更が加わっているか確認します


[vagrant@my_controller ansible]$ ansible -i hosts targets -a "date"
target1 | CHANGED | rc=0 >>
Sat Dec  1 19:54:47 JST 2018  # タイムゾーンが変わっている

target2 | CHANGED | rc=0 >>
Sat Dec  1 10:54:47 UTC 2018

[vagrant@my_controller ansible]$ ansible -i hosts targets -a "yum list installed |grep nginx"
 [WARNING]: Consider using the yum module rather than running yum.  If you need to use command because yum is insufficient you can add warn=False to this
command task or set command_warnings=False in ansible.cfg to get rid of this message.

target1 | CHANGED | rc=0 >>
Loaded plugins: fastestmirror
Installed Packages
nginx.x86_64                     1:1.15.7-1.el7_4.ngx                     @nginx

target2 | FAILED | rc=1 >>
Loaded plugins: fastestmirrorError: No matching Packages to listnon-zero return code

playbookの内容がtarget1にのみ反映されていることが確認できました

Vagrantの機能を使ってplaybook作成をもっと便利に

ホストからもsshしたい

$ pwd
/Users/okash1n/vagrant-ansible

$ vagrant ssh-config
Host my_controller
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/okash1n/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL

Host target1
  HostName 127.0.0.1
  User vagrant
  Port 2200
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/okash1n/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL

Host target2
  HostName 127.0.0.1
  User vagrant
  Port 2201
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/okash1n/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL

$ vagrant ssh-config >> ~/.ssh/config

$ ssh my_controller

Last login: Sat Dec  1 19:34:58 2018 from 10.0.2.2
[vagrant@my_controller ~]$

スナップショットとりたい

target2のスナップショット(target2_ss1)をとってみます


$ pwd
/Users/okash1n/vagrant-ansible

$ vagrant snapshot save target2 target2_ss1

新しいplaybookを用意します

  • /Users/okash1n/vagrant-ansible/ansible/sl.yml

- hosts: targets
  become: yes
  tasks:
    - name: Add repository
      yum_repository:
        name: epel
        description: EPEL YUM repo
        baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
        gpgcheck: no
        enabled: yes
    - name: upgrade all packages
      yum:
        name: '*'
        state: latest
    - name: install figlet
      yum:
        name: figlet
        state: latest

実行してます


$ ssh my_controller
Last login: Sat Dec  1 20:22:20 2018 from 10.0.2.2
[vagrant@my_controller ~]$ cd ansible/
[vagrant@my_controller ansible]$ ansible-playbook figlet.yml
[vagrant@my_controller ansible]$ ansible -i hosts targets -a "figlet Hello Ansible"
target2 | CHANGED | rc=0 >>
 _   _      _ _            _              _ _     _
| | | | ___| | | ___      / \   _ __  ___(_) |__ | | ___
| |_| |/ _ \ | |/ _ \    / _ \ | '_ \/ __| | '_ \| |/ _ \
|  _  |  __/ | | (_) |  / ___ \| | | \__ \ | |_) | |  __/
|_| |_|\___|_|_|\___/  /_/   \_\_| |_|___/_|_.__/|_|\___|


target1 | CHANGED | rc=0 >>
 _   _      _ _            _              _ _     _
| | | | ___| | | ___      / \   _ __  ___(_) |__ | | ___
| |_| |/ _ \ | |/ _ \    / _ \ | '_ \/ __| | '_ \| |/ _ \
|  _  |  __/ | | (_) |  / ___ \| | | \__ \ | |_) | |  __/
|_| |_|\___|_|_|\___/  /_/   \_\_| |_|___/_|_.__/|_|\___|


[vagrant@my_controller ansible]$ exit
logout
Connection to 127.0.0.1 closed.

スナップショットをリストアします


$ pwd
/Users/okash1n/vagrant-ansible

$ vagrant snapshot restore target2 target2_ss1

状態が戻っているか確認します

$ ssh my_controller
[vagrant@my_controller ~]$ cd ansible/
[vagrant@my_controller ansible]$ ansible -i hosts targets -a "figlet Hello Ansible"
target1 | CHANGED | rc=0 >>
 _   _      _ _            _              _ _     _
| | | | ___| | | ___      / \   _ __  ___(_) |__ | | ___
| |_| |/ _ \ | |/ _ \    / _ \ | '_ \/ __| | '_ \| |/ _ \
|  _  |  __/ | | (_) |  / ___ \| | | \__ \ | |_) | |  __/
|_| |_|\___|_|_|\___/  /_/   \_\_| |_|___/_|_.__/|_|\___|


target2 | FAILED | rc=2 >>
[Errno 2] No such file or directory

target2はfigletインストール前に戻っていることが確認出来ました。

ターゲットがぐちゃぐちゃになりすぎたので、色々やりなおしたい


$ pwd
/Users/okash1n/vagrant-ansible

$ vagrant destroy -f
$ vagrant up

これで全て最初の状態に戻ります。同期している設定ファイルやplaybookなどはホスト(Mac)上に残っていますので、またすぐに再開することが可能です。

編集後記

本題のAnsibleの方は触りしか書けなかったのでどちらかと言うとVagrantの記事になってしまいました。 Adventer版のインフラ勉強会 Advent Calendar 2018 にも参戦予定なので、そちらで続編を書けたらいいなと思います。

良い自動化ライフを!

Share Comments
comments powered by Disqus