文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

vagrantで複数vmの生成からserfのクラスタ構成までを自動化してみた

vagrantで複数VMを起動して、serfのjoinとevent通知をやってみたいと思います。最終的にVMを動的に生成しserfの環境構築からクラスタへの参加を自動化してみます。


f:id:treeapps:20180429004752p:plain

環境構築

vagrantの環境

tree-no-iMac:vagrant tree$ vagrant version
Installed Version: 1.7.1

Vagrantfile

2台構成で、今回は最新のCentOS7を使います。

記憶が定かではありませんが、使用したBOXは以下だったと思います。

http://www.vagrantbox.es
CentOS7.0 x86_64 minimal (VirtualBoxGuestAddtions 4.3.14)

メモリ割り当てを1台1Gにしてますが、256Mとかでも全然余裕です。

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    config.vm.define :node1 do |node|
        node.vm.box = "centos7.0-min"
        node.vm.network :private_network, ip: "192.168.33.11"
        node.vm.provider "virtualbox" do |v|
            v.customize ["modifyvm", :id, "--memory", 1024,  "--cpus", 1]
        end
        node.vm.provision :shell, path: "provision.sh"
    end
    
    config.vm.define :node2 do |node|
        node.vm.box = "centos7.0-min"
        node.vm.network :private_network, ip: "192.168.33.12"
        node.vm.provider "virtualbox" do |v|
            v.customize ["modifyvm", :id, "--memory", 1024,  "--cpus", 1]
        end
        node.vm.provision :shell, path: "provision.sh"
    end
end

プロビジョニング

Vagrantfileの以下に指定している部分です。

        node.vm.provision :shell, path: "provision.sh"
provision.sh
#!/bin/sh

# ファイヤーウォールを停止する
systemctl stop firewalld
# serfをDL
DL_DIR="/home/vagrant"
FILE="0.6.3_linux_amd64.zip"
DL_PATH="$DL_DIR/$FILE"
test -f $DL_PATH && rm -rfv $DL_PATH
wget -P $DL_DIR https://dl.bintray.com/mitchellh/serf/$FILE
unzip -o $DL_PATH
rm -rfv $DL_PATH

chown vagrant:vagrant $DL_DIR/serf

今回はテストなのでファイヤーウォールを停止させます。
CentOS7の場合iptablesでは無いので注意!!

その後、ホームにserfをDLしてzipを解凍します。すると「serf」単一のバイナリが出てきます。バイナリ1個で動いちゃうところがいいですね。

VMの起動

provisionオプションを付けて起動します。以下の例ではreloadですが、vagrant upの時でもprovisionプションは有効です。
どうやら現在のバージョンではprovisionオプション無しでも勝手にprovisionが実行されるようです。

tree-no-iMac:vagrant tree$ vagrant reload
==> node1: Attempting graceful shutdown of VM...
==> node1: Clearing any previously set forwarded ports...
==> node1: Fixed port collision for 22 => 2222. Now on port 2200.
==> node1: Clearing any previously set network interfaces...
==> node1: Preparing network interfaces based on configuration...
・・・中略・・・
    node1: Running: /var/folders/mc/np8x4g8j70n00ptjk75vz3lm0000gn/T/vagrant-shell20150214-24978-5fzsfw.sh
==> node1: --2015-02-14 08:16:59--  https://dl.bintray.com/mitchellh/serf/0.6.3_linux_amd64.zip
==> node1: dl.bintray.com (dl.bintray.com) をDNSに問いあわせています...
==> node1: 108.168.194.91, 108.168.194.92
==> node1: dl.bintray.com (dl.bintray.com)|108.168.194.91|:443 に接続しています...
==> node1: 接続しました。
==> node1: HTTP による接続要求を送信しました、応答を待っています...
==> node1: 302
・・・中略・・・
==> node1: d29vzk4ow07wi7.cloudfront.net (d29vzk4ow07wi7.cloudfront.net) をDNSに問いあわせています...
==> node1: 54.192.144.235, 54.192.144.231, 54.192.146.106, ...
==> node1: d29vzk4ow07wi7.cloudfront.net (d29vzk4ow07wi7.cloudfront.net)|54.192.144.235|:443 に接続しています...
==> node1: 接続しました。
==> node1: HTTP による接続要求を送信しました、応答を待っています...
==> node1: 200 OK
==> node1: 長さ: 3002701 (2.9M) [application/unknown]
==> node1: `/home/vagrant/0.6.3_linux_amd64.zip' に保存中
・・・中略・・・
==> node1: 2015-02-14 08:17:18 (239 KB/s) - `/home/vagrant/0.6.3_linux_amd64.zip' へ保存完了 [3002701/3002701]
==> node1: Archive:  /home/vagrant/0.6.3_linux_amd64.zip
==> node1:   inflating: serf
==> node1: `/home/vagrant/0.6.3_linux_amd64.zip' を削除しました

こんな感じにVM起動後、VM上にserfをDLして解凍し、zipを削除しserfがchownされました。

実践

serfのクラスタ構築からイベント通知までをGIFアニメで見る

今回初めてGIFアニメを使ってみたのですが、思ったより容量を喰うので、相当急ぎ足でコマンドを実行しています。
f:id:treeapps:20150214225156g:plain

クラスタを生成して自動で参加する

./serf agent -iface=enp0s8 -discover=cluster1 &

こうすることで、serf join 192.168.xxx.xxx のようにしなくても、自動でクラスを探して参加してくれます。

agentコマンドで他マシンと通信するためには実はいくつか必須の設定があります。

iface= enp0s8

これを指定しないとserfはうまく動いてくれず、joinする事ができません。
指定する値はipconfig(CentOS7では ip addr show)で表示されるネットワーク名ですね。

[vagrant@node1 ~]$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:85:cd:fb brd ff:ff:ff:ff:ff:ff
    inet 192.168.33.11/24 brd 192.168.33.255 scope global enp0s8
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe85:cdfb/64 scope link
       valid_lft forever preferred_lft forever

ここまでの作業を自動化する

前述の例ではわざわざVMにsshしてserfを起動していましたが、今回はプロビジョニングで完全に自動化してみます。

VMのノード生成も自動化します。

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"
# 生成するVM数
VM_NUMBER = 2

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    config.vm.box = "centos7.0-min"
    # ノードを動的に複数台生成
    (1..VM_NUMBER).each do |vmNumber|
        # ノード(ホスト)名
        nodeName = "node#{vmNumber}"
        # 付与するIPの末尾
        ipNumber = 10 + vmNumber

        config.vm.define nodeName do |node|
            node.vm.hostname = nodeName
            node.vm.network :private_network, ip: "192.168.33.#{ipNumber}"
            node.vm.provider "virtualbox" do |v|
                v.customize ["modifyvm", :id, "--memory", 256,  "--cpus", 1]
            end
              node.vm.provision :shell, path: "provision.sh"
        end
    end
end

VM_NUMBERの数値を増やすと生成するVMの数を増やせます。ipNumberは私の環境では11から始めていますが、適宜修正して下さい。

provision.sh

#!/bin/sh

# ファイヤーウォールを停止する
systemctl stop firewalld

# serfをDL
DL_DIR="/home/vagrant"
FILE="0.6.3_linux_amd64.zip"
DL_PATH="$DL_DIR/$FILE"
test -f $DL_PATH && rm -rfv $DL_PATH
wget -P $DL_DIR https://dl.bintray.com/mitchellh/serf/$FILE
unzip -o $DL_PATH
rm -rfv $DL_PATH

# 権限を付与してパスが通る場所に移動
chown vagrant:vagrant $DL_DIR/serf
mv $DL_DIR/serf /usr/local/bin

# serfを起動してクラスタに参加する
su vagrant -c "nohup /usr/local/bin/serf agent -iface=enp0s8 -node=`hostname` -discover=cluster1 0<&- &>/dev/null &"

プロビジョンがrootユーザで行われるので、vagrantユーザでserfを起動しています。

serf agentの末尾の「0<&- &>/dev/null &」の部分ですが、これはvagrant側のバグで、こうしないとプロビジョニングからアプリが起動できないためです。

Shell provisioning fails to exit · Issue #1553 · hashicorp/vagrant · GitHub

vagrant sshしてmembersを実行してみる

プロビジョニング後のnode1でserf membersしてみます。

tree-no-iMac:vagrant tree$ vagrant ssh node1
Last login: Sat Feb 14 09:48:25 2015 from 10.0.2.2
[vagrant@node1 ~]$ serf members
node1  192.168.33.11:7946  alive
node2  192.168.33.12:7946  alive

うむ。できてますね。ここまで自動化できるといいですね。

雑感

今回はserfを起動して適当なイベントを飛ばしただけですが、本当に必要なのはこの先ですね。例えばjoinした時にmuninノードを追加したりしないと、オーケストレーションする意味がありませんね。。。

とりあえず動かしてみたかっただけなので、今回はここまでです。


やるおよ、なんでdockerでやらないんだ?

dockerの方が起動速いだろ?


・・・・・・・・・・え?ごめん聞こえなかった。なんて?


いや、なんでもないよ。vagrantいいよな。

(dockerの学習が追いついてないんだな・・・)


しかしこういう記事書くと最近のqiitaみたいだよなあ。

「僕は新人です!課題でこんな事やってみました!とりあえず動かしてみました!」的な。


qiitaのとりあえず動かしてみました!を脱却するため、vm自動生成とプロビジョニングまでしてみた(震え声

とかいいつつ今回の記事は以下を参考にさせて頂きました。http://blog.pg1x.com/entry/2014/07/21/231327


やらないお「dockerでやる時は自力でやろうな。英語ドキュメント見てさ。」

やるお「頑張るよ。(qiitaでdockerの記事探してこよ・・)」

Vagrant入門ガイド

Vagrant入門ガイド

Docker入門 Immutable Infrastructureを実現する

Docker入門 Immutable Infrastructureを実現する

[改訂新版] シェルスクリプト基本リファレンス  ??#!/bin/shで、ここまでできる (WEB+DB PRESS plus)

[改訂新版] シェルスクリプト基本リファレンス  ??#!/bin/shで、ここまでできる (WEB+DB PRESS plus)