今更ながら、前から気になっていた構成管理ツールの1つである Ansible を使ってみた(バージョン 1.7.2)。
どんなものなのか、 ドキュメント を見ながら Jenkins をインストールする Playbook を書いてみた。
環境構築
サーバの要件
Ansible は Chef と違って、対象サーバにパッケージをインストールする必要はないが、使用するには以下の要件を満たす必要がある( Installation より)。
Control Machine
Ansible をインストールするマシン。このマシンから対象サーバに対して操作を行う。
- Red Hat, Debian, CentOS, OS X など多くの Linux/UNIX マシン( Windows はサポートされていない)。
- Python 2.6 以上がインストールされていること。
Managed Node
構成管理の対象サーバ。
- Python 2.4 以上がインストールされていること
(ただし Python 2.4 の場合は
python-simplejson
がインストールされていること)。 - Python 3 系には今のところ対応していない。
環境の作成
まずはこれらの要件を満たす環境を Vagrant で用意する。
Control Machine と Managed Node の2つの仮想マシンを作成する Vagrantfile
を以下のように作成した。
ベースとなる box は Bento が提供している CentOS 7 を使用した。
パスワードなしでログインできるように、あらかじめ作っておいた認証鍵をそれぞれのサーバに配置している。 Control Machine には yum で Ansible をインストールする。
また、 Control Machine には 10.0.16.21 、 Managed Node には 10.0.16.31 のプライベートIPをそれぞれ割り当てた。
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
# for Virtual Box
BOX_NAME = "opscode-centos-7.0"
BOX_URI = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-7.0_chef-provisionerless.box"
$base_script = <<SCRIPT
set -x
vagrant_home=/home/vagrant
mkdir -p ${vagrant_home}/.ssh
cp /vagrant/ssh_key/id_rsa ${vagrant_home}/.ssh/
cp /vagrant/ssh_key/id_rsa.pub ${vagrant_home}/.ssh/
touch ${vagrant_home}/.ssh/authorized_keys
cat /home/vagrant/.ssh/id_rsa.pub >> ${vagrant_home}/.ssh/authorized_keys
chown -R vagrant:vagrant ${vagrant_home}/.ssh
chmod 600 ${vagrant_home}/.ssh/authorized_keys
chmod 600 ${vagrant_home}/.ssh/id_rsa
SCRIPT
$controller_script = <<SCRIPT
set -x
yum -y update
yum -y install epel-release
yum -y --enablerepo=epel install ansible
SCRIPT
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = BOX_NAME
config.vm.box_url = BOX_URI
config.vm.define "control-machine" do |controller|
controller.vm.hostname = "controller"
controller.vm.network :private_network, ip: "10.0.16.21"
controller.vm.provision :shell, :inline => $base_script + $controller_script
end
config.vm.define "managed-node" do |node|
node.vm.hostname = "node1"
node.vm.network :private_network, ip: "10.0.16.31"
node.vm.provision :shell, :inline => $base_script
end
end
Inventory の作成
対象サーバを記述するファイルを Inventory と言うようだ( Inventory )。ここはまだちゃんと理解していないので、以下のように単純な記述にとどめておき、 hosts
という名前で保存した。
[master]
10.0.16.31
master
がサーバグループの名前で、同じグループに属するサーバに対して同じ操作ができるようになる。
Playbook の作成
Ansible では、サーバの設定やインストールするアプリケーションを記述したファイルを Playbook と言い、 YAML で記述する。
Ansible を使わない場合の Jenkins インストールは、
$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
$ sudo rpm --import http://pkg.jenkins-ci.org/redhat-stable/jenkins-ci.org.key
$ sudo yum install jenkins
のように行う( Installing Jenkins on Red Hat distributions より)。
これと同じことを実現する Playbook を以下のように作成した。
---
- hosts: master
sudo: yes
tasks:
- name: ensure open JDK 1.6 is at the latest version
yum: name=java-1.6.0-openjdk state=latest
- name: get the Jenkins repository
get_url: url=http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo dest=/etc/yum.repos.d/jenkins.repo
- name: add the Jenkins repository
rpm_key: key=http://pkg.jenkins-ci.org/redhat-stable/jenkins-ci.org.key
- name: ensure jenkins is at the latest version
yum: name=jenkins state=latest
- name: ensure jenkins is running and enabled
service: name=jenkins state=running enabled=yes
タスクは書いた順番に実行されるそうだ( Intro to Playbooks - Tasks list )。
まずはじめに、 open JDK をインストールするタスクを書いた。 yum によるインストールは、 yumモジュール を使うと簡単に実現できるらしい。 name
にパッケージ名を指定し、 state
にどのような状態であるべきか present
, latest
, absent
のいずれかを指定する。省略するとデフォルトの present
となるようだ。
つぎの3行が Jenkins のインストールである。
Ansible を使わない場合に実行するコマンドがそれぞれのタスクに対応する。
まずは get_urlモジュール でリポジトリを取得し、 rpm_keyモジュール でリポジトリを登録する。その後、再びyumモジュールで Jenkins をインストールする。
最後に、サービスが起動していることを serviceモジュール を使って確認している。
Playbook の実行
Control Machine で以下のコマンドを実行すると、 Managed Node に Jenkins がインストールされ、使えるようになる。
$ ansible-playbook -i hosts jenkins.yml
ブラウザから http://10.0.16.31:8080 へアクセスすると、無事 Jenkins の画面が表示された。
所感
この程度だと、シェルスクリプトを書くのとあまり変わりはないのでメリットがわかりにくかったが、複数サーバへ同じ操作をいっぺんに行えるのは便利そうと感じた。複数のサーバへアプリをデプロイするようなもう少し複雑な例も試してみたい。
Inventory や Playbook の書き方もまだきちんと理解できていないので、この辺も色々といじってみよう。