1コマンドで作った。Vagrant + Ansible によるコードによる構成管理 | SiTest (サイテスト) ブログ

メニューボタン閉じるボタン

1コマンドで作った。Vagrant + Ansible によるコードによる構成管理

最近の開発現場ではコードによる構成管理が注目されています。
何回かに分けて Vagrant + Ansible + Docker を組み合わせて、
最終的にたった1コマンドで開発環境を作り上げてしまう事をゴールにプロジェクトを作成していきます。

前回の記事では Vagrant + ConoHa でVPSのインスタンスを作成しました。
今回は Ansible を使ってLAMP環境を構築していきます。

Ansible とは

Ansible は Red Hat社が公開している構成管理ツールの一つです。
より正確には、デプロイメントツールやオーケストレーションツールを含めた3つの役割が統合された、幅広い事が行えるツールです。
メリットはSSHとYamlを利用しているので簡潔に素早く設定ファイルを作成し、作って壊す事が簡単に出来ることです。

Ansible を使うメリット等は下記のサイトで紹介されています。

Ansible + Vagrant の参考サイト

下記の情報を元に、プロジェクトを作成していきます。

LAMPは下記ページを参考にしています。

なお、生成物はGitHubで公開しました。
そちらも合わせて参照していただくと、より理解が進みやすいかと思います。
m-ohata/conoha-lamp – GitHub

ディレクトリ構成

まずは Ansible のベストプラクティスを考慮したディレクトリ構造を作成していきます。
使用する時はdefaultディレクトリを丸ごとコピーした別のディレクトリを作成し、そのフォルダ内で各種vagrantコマンドを実行する想定です。

$ tree
.
├── default
│   └── Vagrantfile
└── provision
    ├── hosts
    ├── roles
    │   └── [role]
    │       ├── defaults
    │       ├── files
    │       ├── handlers
    │       ├── meta
    │       ├── tasks
    │       │   ├── task1.yml
    │       │   ├── task2.yml
    │       │   └── main.yml
    │       ├── templates
    │       └── vars
    ├── top-level-playbook1.yml
    ├── top-level-playbook2.yml
    └── site.yml

Vagrantfile

プロジェクトのVagrantfileを参照してください。
Ansibleに関する記述は42行目からの一連の塊です。

  # provision
  config.vm.synced_folder "../provision/", "/tmp/provision"
  config.vm.provision :ansible_local do |ansible|
    ansible.limit = "all"
    ansible.playbook = "/tmp/provision/site.yml"
    ansible.inventory_path = "/tmp/provision/hosts"
  end

Vagrantfileのあるディレクトリから一階層遡った所にあるprovisionフォルダを
ConoHaの仮想マシン内の「/tmp/provision」と同期させています。
これによりプロビジョン実行時に「/tmp/provision」の配下からAnsibleの各種ファイルにアクセスすることができます。

プロビジョンは仮想マシンが起動した後でも「vagrant provision」コマンドで何度でも実行出来ますので、まずは仮想マシンを作成します。

$ cp -R default test-lamp

$ cd test-lamp

$ vim Vagrantfile
// プロビジョンの行をコメントアウト

$ vagrant up

ロールの作成

provision/rolesディレクトリの配下にロールと同じ数だけのディレクトリを作成します。
今回はLAMPサーバーを構築する為に下記の3つを作成します。

  • web: Apache + PHP
  • database: MySQL
  • common: 共通(Git等)

プレイブックの作成

site.yml と同階層にトップレベルのPlaybookを作成していきます。
本番環境でWebサーバーとDBサーバーに分ける可能性がある想定で、下記の2つのプレイブックを作成します。

  • web.yml
  • database.yml
$ cat provision/site.yml
---
- include: stand-alone.yml
- include: web.yml
- include: database.yml

$ cat provision/web.yml
---
- hosts: web
  connection: local
  become: yes
  roles:
    - common
    - web

$ cat provision/database.yml
---
- hosts: database
  connection: local
  become: yes
  roles:
    - common
    - database

タスクの作成

早速Apacheをインストールしていきます。

今回利用するイメージはUbuntuなので、パッケージ管理のAptを利用することが出来ます。
Ubuntu 16.04 LTS 日本語 Remix でLAMPなど – Qiitaの記事によると、
「apt-get install apache2」のコマンドでインストールが出来るようです。

Playbookに「shell: apt-get install apache2 -y」等と記述しても良いのですが、
Ansibleで用意されているパッケージモジュールを利用することで冪等性を保つ事が容易になります。

Ansible公式サイトのDocumentation内のPackaging ModulesからAptのページをを探します。
apt – Manages apt-packagesにありました。
ページは全て英語ですが、ExamplesとOptionsを交互に見ながら作成していきます。

$ cat provision/roles/web/tasks/apache.yml
---
- name: be sure apache2 installed
  apt:
    name: apache2
    force: yes
    update_cache: yes
  tags: apache

$ cat provision/roles/web/tasks/main.yml
---
- include: apache.yml // タスクを追加したのでmain.ymlに反映

$ cd test-lamp

$ vagrant provision
// apache2をインストールする箇所のみ記載します。
TASK [web : be sure apache2 installed] **************
changed: [localhost]

$ vagrant ssh-config | grep HostName
  HostName 150.95.135.203 // VPSのIPアドレスを確認

$ curl 150.95.135.203
// 文末まで省略...
    </div>
  </body>
</html>

見事Webサーバーが立ち上がりましたね。
ブラウザを開いてIPアドレスを打ち込むとApacheのデフォルトページが表示されます。

同様にPHP、MySQLもインストールします。
PHPはphp, php-mysql, livapache2-mod-phpの3パッケージ、
MySQLはmysql-serverの1パッケージが必要なようです。

$ cat provision/roles/web/tasks/php.yml
---
- name: be sure php(in LAMP) installed
  apt:
    name: "{{item}}"
    force: yes
    update_cache: yes
  with_items:
    - php
    - php-mysql
    - libapache2-mod-php
  tags: php

$ cat provision/roles/database/tasks/mysql.yml
---
- name: be sure mysql installed
  apt:
    name: mysql-server
    force: yes
    update_cache: yes
  tags: mysql

// main.ymlにも忘れず追記します。
$ cat provision/roles/web/tasks/main.yml
---
- include: apache.yml
- include: php.yml # a new record!

$ cat provision/roles/database/tasks/mysql.yml
---
- include: mysql.yml # a new record!

$ cd test-lamp

$ vagrant provision
TASK [web : be sure php(in LAMP) installed] ************************************
changed: [localhost] => (item=[u'php', u'php-mysql', u'libapache2-mod-php'])

TASK [database : be sure mysql installed] **************************************
changed: [localhost]

仮想マシン内にログインして
PHPとMySQLのインストールの確認を行います。

$ vagrant ssh

# echo '<?= 1 + 2 ?>' > /var/www/html/test.php

# curl localhost/test.php
3

# mysql -uroot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.15-0ubuntu0.16.04.1 (Ubuntu)

どちらも動作しました。

通しで実行

一通り納得出来るタスクが作成できたら、一度インスタンスを削除してからもう一度立ち上げなおして確認します。
haltからdestroyは反映されるまで時間がかかりますので、ConoHaの管理画面で作業終了を確認しながら実行していきます。

$ vagrant halt

$ vagrant destroy

$ vagrant up
Bringing machine 'default' up with 'conoha' provider...
==> default: Finding flavor for server...
==> default: Finding image for server...
==> default: Launching a server with the following settings...
==> default:  -- Tenant          : gnctxxxx
==> default:  -- Name            : default
==> default:  -- Flavor          : g-1gb
==> default:  -- FlavorRef       : 7eea7469-0d85-4f82-8050-6ae742394681
==> default:  -- Image           : vmi-ubuntu-16.04-amd64
==> default:  -- ImageRef        : 69878388-9e45-483e-854d-72b06b9e5dd9
==> default:  -- KeyPair         : xxxxx
==> default: Waiting for the server to be built...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 133.xxx.xxx.31
    default: SSH username: root
    default: SSH auth method: private key
    default: Warning: Connection refused. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Rsyncing folder: /Users/xxxx/conoha-lamp/provision/ => /tmp/provision
==> default: Rsyncing folder: /Users/xxxx/conoha-lamp/test-run/ => /vagrant
==> default: Running provisioner: ansible_local...
    default: Installing Ansible...
An unknown error happened in Vagrant ConoHa plugin

vagrant upコマンドの初回はプロビジョンも実行されますが、
初回のAnsibleのインストール中にエラーが発生して停止してしまうようです。
Ansible自体のインストールには成功しているようなので、気にせずもう一度vagrant provisionコマンドを実行します。

$ vagrant provision
==> default: Rsyncing folder: /Users/xxxx/conoha-lamp/provision/ => /tmp/provision
==> default: Rsyncing folder: /Users/xxxx/conoha-lamp/test-run/ => /vagrant
==> default: Running provisioner: ansible_local...
    default: Running ansible-playbook...
mesg: ttyname failed: Inappropriate ioctl for device

TASK [setup] *******************************************************************
ok: [localhost]

... 中略 ...

PLAY RECAP *********************************************************************
localhost                  : ok=19   changed=7    unreachable=0    failed=0

インストール後の動作確認

Webサーバー(Apache + PHP)が意図通りに動作する事を確認します。
一度対象のマシンにログインしてシンプルなファイルを設置してから、
そのURLにアクセスして設置したファイルがPHPで評価されることを確認できました。
(ホストマシンと仮想マシンを見分ける為、ホストマシンでは$、仮想マシンでは#をコマンドの先頭に付帯しました)

$ vagrant ssh

# cd /var/www/html

# echo '<?= 1 + 2 ?>' > index.php

# exit

$ vagrant ssh-config
Host default
  HostName 133.xxx.xxx.31
  User root
  Port 22
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/xxxx/.ssh/id_rsa
  IdentitiesOnly yes
  LogLevel FATAL

$ curl 133.xxx.xxx.31
3

引き続きMySQLサーバーの動作を確認します。
サーバー内からmysqlコマンドを実行して動作することが確認できました。

$ vagrant ssh

# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.15-0ubuntu0.16.04.1 (Ubuntu)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

おまけ:ファイル共有

Vagrant のデフォルトで用意されている Rsync は速度や同期が不十分で、 修正した内容をすぐに確認する事が出来ません。
VPSに直接ログインして、VimやEmacs等のエディターで開発している方にとっては問題ではありませんが、
ローカルマシンでIDEやエディターを使って開発している方には障害となりえます。

試行錯誤するとvagrant-gatling-rsyncプラグインが使用出来たのでご紹介します。

実際に導入してみての感想

結局 yum や apt-get 等のパッケージ管理を操作している事は変わりません。
OSやディストリビューションを跨いだりバージョンが上がったりする度に作り直しとなります。
この辺の事情があり、残念ながら全ての手間がなくなる銀の弾丸とは程遠い印象を受けました。

しかし、一度Ansibleのやり方を覚えてしまえばPlaybookの管理に集中出来るので、
冪等性を保ちつつ新しいパッケージを導入したり、パッケージを増やしたり減らしたりすることがとても楽になりました。

まとめ

いかがでしたでしょうか。
タイトル通り1コマンドとは行きませんでしたが、
かなりそれに近いレベルの事が実現できました。

このやり方を使えば、新しくジョインしたメンバーにはドキュメント代わりに共有できますし、
Gitのブランチを切るくらいの気軽さでサーバーを立ち上げられます。
masterブランチに該当する仮想マシンをセットアップ出来るPlaybookとして用意しておけば、不具合が出た時の検証も格段に楽になります。

次回では更に、Dockerを組み合わせて今時の環境を構築していきます。
以上、「1コマンドで作った。Vagrant + Ansible によるコードによる構成管理」でした。
最後まで読んでいただきありがとうございました。