Ansible使ってVagrantのゲストOSの構成管理する【Playbook: jenkins, node.js】
去年辺りからimmutable infrastructureが盛り上がってきている感があります。
サーバーの環境をコードで記述するツールにはPuppet、Chefなどがありますが、
今回はAnsibleを触ってみます。
Ansible is Simple IT Automation
この記事ではVagrantでCentOS6.5を入れて、その上にAnsibleでJenkinsを入れるところまでを説明します。
(入門向けで、Ansibleについて突っ込んだことは書いていません)
Ansibleとは?
AnsibleはPuppet、Chefなどと同様に構成管理ツールです *1
一番の特徴はPuppet, Chefに比べてリモートホストに特別な設定が必要ないことでしょうか。
ssh接続ができて、python2.4以上が入っていれば動きます。
環境について
本記事の環境はこちら。
Vagrantをインストールする
こちらの記事を読みながら進めれば大丈夫です。
今更聞けない人の為の Vagrant 再入門 | School With Blog
まずはじめにVitrualBoxをインストールします。
下記からOSX用のインストーラをダウンロードしてインストールしました。
Downloads – Oracle VM VirtualBox
バージョン確認で動作を確認します。
$ VBoxManage --version 4.3.10r93012
すでにVitrualBox4.3.8が入っていて、4.3.10がリリースされていたのでインストールしようとしたら「インストールできませんでした。開発元に問い合わせてください」的なエラーが出て焦りました。
インストーラに付属しているアンインストーラを実行後にOSXを再起動して、再度インストールしたら正常に4.3.10が入りました。
Vagrantをインストールします。
こちらもOSX用のインストーラをダウンロードしてインストールします。
Download Vagrant - Vagrant
インストールできたらこちらも確認。
$ vagrant --version Vagrant 1.5.2
VagrantにゲストOSを設定する
vagrantコマンドが使えるようになったらゲストOSを設定します。
こちらでVagrant用のboxファイルが配布されているので好きなOSを選びます。
A list of base boxes for Vagrant - Vagrantbox.es
$ vagrant box add でVagrantで利用できるOSを設定することができます。
$ vagrant box add -h # ヘルプ表示 Usage: vagrant box add [options] <url> # 大体の使い方はこれ # いろいろ表示されるけど割愛
CentOS6.5を追加するコマンドはこれ。
$ vagrant box add centos6.5 https://github.com/2creatives/vagrant-centos/releases/download/v6.5.1/centos65-x86_64-20131205.box
追加できたか確認します。
$ vagrant box list centos6.5 (virtualbox, 0)
ゲストOSを立ちあげてSSH接続するまで確認してみます。
まず作業ディレクトリに移動します。
$ cd path/to/workspace $ mkdir vagrant_centos $ cd vagrant_centos
作業ディレクトリに移動したらVagrantの初期化をします。
$ vagrant init centos6.5 # $ vagrant box list に表示されるboxNameを指定する ... # いろいろ表示される $ ls Vagrantfile
作業ディレクトリにVagrantfileが作成されます。
Vagrantfileの中身はRubyで記述されていて、約100行ほどのファイルです。
26行目付近にあるconfig.vm.networkのコメントアウトを消して、ホストOSとゲストOSでネットワークが繋がるようにします。
# Create a private network, which allows host-only access to the machine # using a specific IP. config.vm.network "private_network", ip: "192.168.33.10"
準備は整ったのでゲストOSを起動させます。
$ vagrant up Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'centos6.5'... # 初回だけちょっと時間がかかる
完了したらSSH接続を試します。
$ vagrant ssh [vagrant@localhost ~]$ pwd # vagrantユーザでCentOSにログインできた! /home/vagrant
ゲストOSから抜けるときはexit。
$ exit logout Connection to 127.0.0.1 closed.
ゲストOSをshutdownするときはhalt。
$ vagrant halt $ vagrant status # VMの状態を確認すると Current machine states: default poweroff (virtualbox) # shutdownされてる The VM is powered off. To restart the VM, simply run `vagrant up`
VMを捨てるときはdestroy。
$ vagrant destroy default: Are you sure you want to destroy the 'default' VM? [y/N] y ==> default: Destroying VM and associated drives... $ vagrant status # VMの状態を確認すると Current machine states: default not created (virtualbox) The environment has not yet been created. Run `vagrant up` to create the environment. If a machine is not created, only the default provider will be shown. So if a provider is not listed, then the machine is not created for that environment. # vagrant upすればまた作成されるようです
OSXでAnsibleを使えるようにする
ここからはこちらの記事を参考にしました。
VagrantでAnsibleのPlaybookを作るためのローカル環境を作る - Qiita
Ansible使うときはpython2.7系に上げといた方がいいらしい。
OSXのシステムに入ってるpythonが2.6系だったのでバージョンを上げることにしました。
普段python使わないし、バージョン管理しなくていいかと思いhomebrewでサクッと上げました。
$ brew install python ... $ python --version Python 2.7.6
homebrewでpython入れるとpipコマンドも使えるようになります。
pipコマンドはpython用のパッケージマネージャーらしく、node.jsでいうnpmみたいなやつみたい。
pipコマンド使ってansibleをインストールします。
$ sudo pip install ansible ... $ ansible --version ansible 1.5.4
ホストOSからゲストOSへAnsibleのコマンドが実行できるようSSHの設定をします。
まずホストOSのSSH設定を追記します。
$ vi ~/.ssh/config # 以下を追記する Host 192.168.33.* IdentityFile ~/.vagrant.d/insecure_private_key User vagrant
次に、インベントリファイルを作成します。
デフォルトは/etc/ansible/hostsを見に行くのですが、
作業ディレクトリにhostsファイルを作成して、これを参照するようにしました。
$ vi hosts # hostsの中には以下を記述 [servers] 192.168.33.10 # ゲストOSのIPを指定する
インベントリファイルはINI形式で記述できるので、下記のように複数サーバーをグルーピングして記述することもできます。
[servers] 192.168.33.10 192.168.33.11 [db] 192.168.33.30
それではゲストOSが起動した状態にします。
もし起動していなければ $ vagrant up しておきましょう。
この状態で、Ansibleを使ってゲストOSにpingモジュールを実行してみます。
$ ansible -i hosts servers -m ping 192.168.33.10 | success >> { "changed": false, "ping": "pong" }
-m の後にはAnsibleのモジュール名を指定するようです。
-i の後にはインベントリファイルと対象ホストのグループ名を指定しています。
もっと詳しい情報はこちら Inventory File · yteraoka/ansible-tutorial Wiki · GitHub
Ansibleを使ってゲストOSの環境を構築する
ここからはこちらの記事を参考に進めます。
Ansible チュートリアル | Ansible Tutorial in Japanese
Ansibleで任意のコマンドを実行する
-a の後に実行したいコマンドを文字列で渡すと任意のコマンドが実行できるようです。
$ ansible -i hosts servers -a 'uname -r' 192.168.33.10 | success | rc=0 >> 2.6.32-431.el6.x86_64 $ ansible -i hosts servers -a 'pwd' 192.168.33.10 | success | rc=0 >> /home/vagrant
Ansibleでパッケージをインストールする
yumモジュールを使うとゲストOSにパッケージをインストールできます。
以下はtelnetをインストールするコマンド。
$ ansible -i hosts servers -m yum -s -a name=telnet 192.168.33.10 | success >> { .. # いろいろ表示される
-s オプションはsudoで実行することを意味しています。
-a とはargumentsのことで、yumモジュールに name=telnet という引数を渡しています。
Playbookで構成管理をする
やっと本題に入ります。
Chefでいうレシピ(レシピブック)的な立ち位置にあるのがAnsibleにもありまして、それをPlaybookと呼びます。
中身はYAML形式で記述されます。
ではゲストOSにJenkinsをインストールするPlaybookを書く前に、普通にインストールする手順を確認します。
手順はこちらから引用しました。
Installing jenkins on CentOS 6.4
$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo; $ sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key; $ sudo yum install java-1.7.0-openjdk $ yum install jenkins $ service jenkins start
- リポジトリを追加して
- Jenkinsが依存しているパッケージを追加して
- Jenkinsをインストールして
- サービスとして起動
この手順でタスクを作成すれば良さそうです。
では実際にPlaybookを作成します。
playbook_jenkins.yamlとして作業ディレクトリに作成しました。
# playbook_jenkins.yaml --- - hosts: servers sudo: true user: vagrant tasks: - name: get jenkins repo get_url: url="http://pkg.jenkins-ci.org/redhat/jenkins.repo" dest=/etc/yum.repos.d/jenkins.repo - name: set jenkins repo command: rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key - name: install dependencies yum: name=java-1.7.0-openjdk state=latest - name: install jenkins yum: name=jenkins state=latest - name: start jenkins service service: name=jenkins state=started
tasks.nameはタスクそれぞれのラベルのようなもので、日本語でも記述できます。
nameの次のプロパティがモジュール名で、値にモジュールへの引数を記述しています。
Playbookの構文をチェックするときはこちら。
$ ansible-playbook -i hosts playbook_jenkins.yaml --syntax-check playbook: playbook_jenkins.yaml
Playbookのタスク一覧を確認するときはこちら。
$ ansible-playbook -i hosts playbook_jenkins.yaml --list-tasks playbook: playbook_jenkins.yaml play #1 (servers): get jenkins repo set jenkins repo install dependencies install jenkins start jenkins service
他の人が書いたPlaybookを流し読みするときに使えそうです。
ではPlaybookを使ってJenkinsをインストールします。
$ ansible-playbook -i hosts playbook_jenkins.yaml PLAY [servers] **************************************************************** GATHERING FACTS *************************************************************** ok: [192.168.33.10] TASK: [get jenkins repo] ****************************************************** ok: [192.168.33.10] TASK: [set jenkins repo] ****************************************************** changed: [192.168.33.10] TASK: [install dependencies] ************************************************** ok: [192.168.33.10] TASK: [install jenkins] ******************************************************* ok: [192.168.33.10] TASK: [start jenkins service] ************************************************* ok: [192.168.33.10] PLAY RECAP ******************************************************************** 192.168.33.10 : ok=6 changed=1 unreachable=0 failed=0
インストールできました。
Jenkinsおじさんは192.168.33.10:8080にて動いてるらしいので、
ホストOSのブラウザから http://192.168.33.10:8080 にアクセスすると
動いてるのが確認できました。
Ansibleには冪等性があるため、何度実行しても結果は同じになります。
これはゲストOSが複数になっても全て同一の環境を構築できることに繋がります。
【番外編】Ansible使ってNode.jsをインストールする
JavaScript界隈の技術に触れないで終わりそうなので、
Ansible使ってNode.jsを入れるPlaybookを作りました。
タスクの内容としてはnodebrewを使ってnode.jsを入れるってだけです。
これらの記事を参考にしました。
ansibleでshellやcommandを使う時の注意点 - Qiita
ansibleを使ってみる — そこはかとなく書くよん。
Ansible のメモ - Hexa's diary
playbook_nodejs.yamlというファイルで中身はこちら。
# playbook_nodejs.yaml --- - hosts: servers user: vagrant vars: node_version: '0.10.26' nodebrew_path: '.nodebrew/current/bin' tasks: - name: install perl command: sudo yum install -y perl - name: download nodebrew get_url: url="http://git.io/nodebrew" dest=/var/tmp/nodebrew - name: install nodebrew command: perl /var/tmp/nodebrew setup - name: rewrite .bashrc for export path shell: echo export PATH=$HOME/.nodebrew/current/bin:$PATH > $HOME/.bashrc - name: install nodejs ver{{ node_version }} shell: nodebrew install-binary v{{ node_version }} ignore_errors: True environment: PATH: "/home/vagrant/{{ nodebrew_path }}:{{ ansible_env.PATH }}" - name: use nodejs shell: nodebrew use {{ node_version }} environment: PATH: "/home/vagrant/{{ nodebrew_path }}:{{ ansible_env.PATH }}"
実行するとこんな感じ。
$ ansible-playbook -i hosts playbook_nodejs.yaml PLAY [servers] **************************************************************** GATHERING FACTS *************************************************************** ok: [192.168.33.10] TASK: [install perl] ********************************************************** changed: [192.168.33.10] TASK: [download nodebrew] ***************************************************** ok: [192.168.33.10] TASK: [install nodebrew] ****************************************************** changed: [192.168.33.10] TASK: [rewrite .bashrc for export path] *************************************** changed: [192.168.33.10] TASK: [install nodejs ver0.10.26] ********************************************* failed: [192.168.33.10] => {"changed": true, "cmd": "nodebrew install-binary v0.10.26 ", "delta": "0:00:00.131961", "end": "2014-04-06 01:14:08.487010", "rc": 1, "start": "2014-04-06 01:14:08.355049"} stdout: v0.10.26 is already installed ...ignoring TASK: [use nodejs] ************************************************************ changed: [192.168.33.10] PLAY RECAP ******************************************************************** 192.168.33.10 : ok=7 changed=5 unreachable=0 failed=0
ゲストOSにログインして確認します。
$ vagrant ssh [vagrant@localhost ~]$ node --version v0.10.26
node コマンドが使えることが確認できました。
補足
.bashrcを上書きするタスクがあります。
# > の部分。もし参考にされる場合は注意してください。 shell: echo export PATH=$HOME/.nodebrew/current/bin:$PATH > $HOME/.bashrc
追記にしちゃうとPlaybookを実行するたび追記され、
冪等性が壊れる気がしたので、.bashrcは上書きされる前提ということにしました。
(ここ納得いかないので何とかしたい・・。)
nodebrew install を実行するタスクでは2回め移行は既にインストールされているという
メッセージが表示されてタスクが失敗します。
それだと困るのでタスクに ignore_errors: True を指定してエラーを無視しました。
おわりに
今回初めてVagrantを使ってみましたが、手軽に仮想環境を構築できるのは勉強するときにありがたいですね。
Ansibleはもっといろいろなことができて、今回紹介したPlaybookは基礎中の基礎みたいなものです。
GithubにあるAnsibleのサンプルはディレクトリが細かく分かれていて、
あの書き方に慣れるにはもう少し勉強が必要そう。
この流れでDockerも触りたい。
これを見ると、VagrantとAnsibleで効率のいい設定ができそう。
Ansible - Provisioning - Vagrant Documentation
VagrantもAnsibleも1日勉強したらそこそこ使えるようになったので、
Chefより学習コストは低いと思います。
Ansible使ってVPSを管理するといい感じになりそうなので、DigitalOceanあたりで使いたい。
*1:厳密に言うとどれも構成管理ツールという括りに収まらないです。 こちらの記事ではAnsibleの設計思想などを詳しく述べられてるので一読しておくとよいかと。 Ansibleのアーキテクチャー: 構成管理を超えて — そこはかとなく書くよん。