devops
YAML
Ansible
ansible-playbook
playbook

Ansible自体を知らない人が本番に使える人になるまでのスタディー

いまさらAnsibleスタディー?!
と思う方もいらっしゃるかもしれませんが、
特にDevOpsの自動化ツールをご利用していない方に
Ansibleを教えてあげたいと思っております。

初心者方にも役に立つと思っております。
( 実は、社内の新人にAnsibleをスタディーするためw )

アジェンダは以下の通りです。
1.Ansibleとは?
2.Ansibleに関する必要知識
3.Ansibleの構成
4.Ansibleの実習

1.Ansibleとは?

image.png
🔗公式ページ
🔗ドキュメントページ
Pythonで開発されたProvision & Configurationマネージャーツールの一つで
構築及び管理をより簡単にすることができる DevOpsの自動化ツール の一つです。
基本オープンソースツールで無料でございます。(Github 6位)
似ているツールとしては、Chef , Puppet があります。
デプロイ先のエージェントが不要でrubyが不要、設定ファイルが少ないなどの
特徴がChefとの大きな違いのようです。

他のツールよりAnsibleのメリットは以下の通りです。
- Ad-hocサポート
- Simple
- SSH(非Agent)
- Not DSL (非 Ruby開発者)
- 並列 provisiongサポート
- plug-and-play (module, plugin 利用及び開発可能)

🔗DevOpsの自動化ツール、Ansibleの人気の理由は
🔗構成管理ツールとしてAnsibleを選ぶべき理由

2.Ansibleに関する必要知識

1) DevOps

何回かDevOpsというキーワードが出てきたんですね。
Ansibleを学ぶ前には DevOps の知識が必要でございます。
DevOps とはContinuous Delivery(持続的なデリバリー) の
メカニズムを運用まで拡張して具現したことです。

一つのSoftwareを開発するためには色んな人が同時に開発できる環境が必要、
数千人の利用者を対象にするためには、サーバとストレージ、
運用体制など、裏側で管理しないといけないインフラ環境も備えなければならないです。
それが Ops(運営者) の役割です。

この上で、Dev(開発者) はどんどんシステムが拡張したくて開発生産性を高める新しいFWを
導入したいですが、Ops(運営者) は提供するサービス及びソフトウェアの安全性にもっと関心
を寄せて、安全性が保障されない理由で避けています。

お互いにそれぞれの目的を持ってそれぞれのプロセスでそれぞれのツールを利用して開発に着手していることです。こんな違いのため、DevとOpsには衝突が発生します。
こういう背景で出てきたのが DevOps でございます。

https://ja.wikipedia.org/wiki/DevOps
image.png

DepOps とはソフトウェア開発者とIT従事者の間で疎通、協業、融合を強調した
ソフトウェア開発方法論であり、ソフトウェア開発とIT運営間の相互依存関係についた産物でございます。

組織でDevOpsの役割はソフトウェア商品とサービスを早く生産することに
役立つ任務を遂行することになります。
DevとOps間にその目的を一致させ、プロセスや道具に対する接近を共有し、
その差を減らすことを目的としている。

このような自動化ツールの導入は開発から運営に至るまで開発の全過程において、進捗状況に合わせて必要な時に必要な環境を自由に拡大縮小できるようにすることで、システムスケイルリにすごく自由度を提供します。

2) 冪等性

image.png
Ansibleの特徴のひとつは、冪等性(べきとうせい)です。
冪等性はリモートホストの状態を一定に保つためのポリシーですね。
原則としては【Playbookは繰り返し実行してもリモートホストの状態が変更されないように記述】することです。
もちろん、初回実行時はリモートホストに変更が全て行われます。
しかし、Playbookを変更しない限り、繰り返して実行してもリモートホストに変更が行われません。
それが重要ポイントです!

これは、もしリモートホストに意図しない変更が行われた場合、
Playbookの実行によりその変更を検知できるとも言えますね。

冪等性を保ったPlaybookを維持することで、

継続的なリモートホストの状態管理を行えるようになります!

あとで、【4.Ansibleの実習】で ansibleを動かしながら、
各タスクのモジュールの結果が"changed"以外、"ok"というところが、
実際冪等性が実行されるところなので、一緒に見てみましょう!

もちろんansibleでは冪等性をサポートしていないモジュールも存在します。
その体表的なものがshell, command, fileモジュールでございます。
なるべく、利用することを避けた方が良いと思っております。

3) YMAL

image.png
YAML(YAML Ain't Markup Language)はXML, C, Python, Perl, RFC2822で定義されたe-mail 様式で概念を得て作られた'人が簡単に読める'データ直列化様式でございます。
文法は相対的に理解し易いので、可読性が良いです。
ruby, python開発者は propertyファイルで活用していますが、c, c++, java開発者にはよく使われないらしいです。
image.png

4) インベントリファイル

Ansible は、インフラ内の複数システムに対して同時に動作します。
Inventory file は、 Ansible が動作する対象のシステムを列挙するためのファイルです。
もちろん必須ではありません。
使い方としては、Hostだけを列挙して設定したり、
グループを指定してHostを列挙して設定したり色んな便利な追加方があります。
デフォルトのパッチは/etc/ansible/hosts でございます。

私は、Ansible以外にもCapistranoなども利用していますので、
ssh configに設定するのが便利です。
なので、ssh configのHostネームだけを./ansible/hostに列挙して
グルーピングだけをしています。
グルーピングのメリットはインベントリファイル内で複数のホストのグループして、
独自的にタスクを実行することができます。
あとで、【4.Ansibleの実習】で利用することを見てみましょう。

5) Playbook

image.png
Playbookは遠隔ホストの状態を定義します。
もちろん、yaml文法を採用してポリシーを記述します。
一つのPlaybookは一つまたは一つ以上のplayを持ち、
playの目的はそれぞれのホストに良く定義されているroletask
マッピングする役割を引き取っています。
場合によって、Playbookにroleを定義せずにすぐtaskを利用することも可能ですが、
再利用, タスクハンドリングなどを考えたら、良い利用方ではありません。
以下に例のよう、指定Host, 権限, 変数設定, マッピングするroleなどを定義することが可能です。

playbook.yml
#./playbook.yml
---
- name: web
  become: true
  hosts: all
  user: fusic
  vars_files:
    - vars.yml
  roles:
    - common
    - apache
    - php
    - postgresql

あとで、【4.Ansibleの実習】の例示を見たらすぐ理解できると思っております。

3.Ansibleの構成

image.png

構成を説明する予定でしたらが、上の【2.Ansibleに関する必要知識】でほぼ出てしまいまして、
残りは、【4.Ansibleの実習】から説明させて頂きます。

4. Ansible実習

実習環境はMacでございます。

・実習構成

image.png
Ansibleを動かすためのHostサーバがあります。
そして、2つのWebサーバと 1つのDBサーバをAnsibleで構築します。
その後、2つのWebサーバCakePHPFrameworkのWebアプリケーションを入れるため、
taskを調整した後、Ansibleを動かしてDBサーバを変更します。(冪等性)
その後、2つのWebサーバCakePHPFrameworkのWebアプリケーションを入れて
DBサーバ(外部サーバ)の接続設定をします。
そして、動作確認したらゴールになるます。
よろしくお願いいたします。

※ 実習に必要なリソースは以下のリポジトリで共有させて頂きます。
🔗leedohyung-dba/ansible_study

1) 各サーバ生成

今回は、vagrantでVirtualBox の 仮想サーバ(VM)にサーバを立ち上げます。
以下のVagrant Cloudcentos7を検索すると、vagrant boxを共有していますので、
そのboxを利用しましょう。
🔗Vagrant Cloud
image.png

クリックして詳細ページに行くと、以下のように導入する方法がありますが、
そのまま実行せずに、私のリポジトリのvagrant/Vagrantfileを自分のディレクトリにコピーして、
中のboxの名をVagrant Cloudで探したbox名に変更してから実行します。

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

Vagrant.configure(2) do |config|
  config.vm.define "host" do |node|
    node.vm.box = "geerlingguy/centos7"
    node.vm.hostname = "host"
    node.vm.network :private_network, ip: "192.168.43.51"
  end

  config.vm.define "web.a" do |node|
    node.vm.box = "geerlingguy/centos7"
    node.vm.hostname = "web.a"
    node.vm.network :private_network, ip: "192.168.43.52"
  end

  config.vm.define "web.b" do |node|
    node.vm.box = "geerlingguy/centos7"
    node.vm.hostname = "web.b"
    node.vm.network :private_network, ip: "192.168.43.53"
  end

  config.vm.define "db" do |node|
    node.vm.box = "geerlingguy/centos7"
    node.vm.hostname = "db"
    node.vm.network :private_network, ip: "192.168.43.55"
  end

  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--cableconnected1", "on"]
  end
end
vagrant up

すると、4つのサーバを一気で立ち上げます。
image.png

ちょっと時間掛かります!
image.png

※ これからは全てhostのVM中で行うことになります。

2) HostサーバにAnsibleインストール

Hostサーバにsshアクセス後、追加パッケージEPELをインストールします。

# ssh アクセス
vagrant ssh host

# EPELインストール
wget https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

# 有効にする
sudo rpm -Uvh epel-release-6-8.noarch.rpm

そして、yumでAnsibleをインストールします。

# Ansibleインストール
sudo yum -y install ansible

# バージョン確認
ansible --version

image.png
実習のAnsibleバージョンは 2.3.2 になります。

3) web_a, web_b, dbのそれぞれのサーバにssh config設定をします。

image.png
hostの中でweb_a, web_b, dbのサーバにssh [HostName]でアクセス出来るように設定します。
※ 詳しい内容省略

4) ansibleコマンド

ansibleのコマンドには以下の二つがあります。
- ansible : ホストに一つの状態を定義できるコマンドです。
- ansible-playbook : ホストにのPlaybookとして状態を定義するコマンドです。
※ 詳しい使い方としては、ドキュメントから頂けます。

まず、ansibleコマンドを使ってみましょう。
学習するansibleディレクトリを生成して、
その中にhostというインベントリファイルを生成します。

host
[web_group]
web_a
web_b

[db_group]
db

※ デフォルトインベントリファイル:/etc/ansible/hosts

各ホストにPingを投げてみましょう。

ansible all -i host -m ping

image.png
sshの設定もいい感じらしいですね−

また、web_groupのホストたちにtreeというツールをインストールしてみましょう。

ansible web_group -i host -m yum -a 'name=tree state=present' --sudo

image.png
設置が成功してますが、注目するところは、changed:のところです。
もう一度同じ命令を投げるとchangedではなく、okが出ます。(冪等性)
image.png

-mのオプションを入れないとデフォルトモジュールはCommandになります。

ansible all -i host -a "/bin/echo hello"

image.png

Localhostにも命令を投げることができます。

ansible "127.0.0.1," -c local -m yum -a 'name=tree state=present' --sudo

image.png

インベントリファイルがなくても、ssh configのホスト名をそのまま使えます。

ansible all -i "web_a,"  -a "/bin/echo hello"

image.png

5) playbookでサーバ構築

じゃー、本格的に上に差し上げた構成図の通りサーバを構築してみましょうかね−
もう一度構成図を置いておきます。
image.png
さて、私の学習リポジトリにあるansibleディレクトリを皆さんの環境に
コピーして配置してください。
(ansibleコマンドを実行するhost VM内で)
🔗leedohyung-dba/ansible_study

ざっくり、その中の構成を説明させて頂きます。

・ansible playbookの構成

.
├── host  👉 【インベントリファイル】
├── db.yml  👉 【DBサーバのPlaybook】
├── web.yml  👉 【WEBサーバのPlaybook】
├── roles  👉 【それぞれの状態定義(タスク)があるroleたち】
│   ├── apache
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── ...
│   ├── aws-cli
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── ...
│   ├── common
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── ...
│   ├── php
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── ...
│   └── postgresql
│       ├── tasks
│       │   └── main.yml
│       └── ...
└── vars.yml  👉 【交通で使う変数定義】

上端の【2.Ansibleに関する必要知識】でPlaybookの紹介をさせていただきましたとおり、
各Playbookがありまして、一つまたは一つ以上のplayを持ちます。
そして、playの目的はそれぞれのホストに良く定義されているroletaskをマッピングしています。
web.ymlのPlaybookを説明させて頂きます。

web.yml
---
- name: web
  # Ansible1.9からはsudo/suの代わりにbecomeを使う
  become: true
  # webグループだけにタスクする
  hosts: web_group
  user: vagrant
  vars_files:
    - vars.yml
  roles:
    - common
    - apache
    - php

実行する権限、ホスト(グループ)、ユーザー、編集、rolesを定義しています。

playbook及び各状態定義ファイル(task)の中に何をやっているのか細かく説明コメントを書いて置きましたので、ご覧下と、モジュールの使い方がわからない方は、ドキュメントをご覧ください。
例えば copyのモジュールに関しては🔗こちらを…

vars.ymlに定義されているmain_usernameなどを好きに変更した後、
他のところは見て大体理解してくださったら嬉しいです。

・ansibleでサーバ構築

じゃーまず、web_aサーバとweb_bサーバを構築してみます。

ansible-playbook -i host web.yml

image.png
...
image.png

いい感じですね。
次はdbサーバを構築してみます。

ansible-playbook -i host db.yml

image.png
...
image.png
44つのok(冪等性でチェックだけ)と41のchanged(状態変更)
になりました。
こちらもいい感じですね。

・構築されたWEBサーバの動作テイスト

次はansibleコマンドで./index.php を各Webサーバに配置して、
正常に動作しているか確認します。
※ scp, mount などで簡単に可能ですが、練習のためです。

ansible all -i "web_a," -m template -a "src=./index.php dest=/var/www/html/index.php owner=lee group=lee" --extra-vars '{"host_name":"WEB_A"}'  --sudo
ansible all -i "web_b," -m template -a "src=./index.php dest=/var/www/html/index.php owner=lee group=lee" --extra-vars '{"host_name":"WEB_B"}'  --sudo

その後、以下のように動作テストしまします。
・アクセスurl: http://192.168.43.52/
・結果:以下の文言があちこちふざけているとオケーです!
image.png
・アクセスurl: http://192.168.43.53/
・結果:以下の文言があちこちふざけているとオケーです!
image.png

・CakePHP3のアプリケーションを入れてDBサーバの動作テスト

次は、各WebサーバにCakePHP3のFrameworkを入れて見ましょう!

しかし、その前に必要なAnsible改善事項がいくつかあります。
それは、以下の通りです。

👉 DBサーバに外部からアクセス出来るように設定する
postgresql.confに以下を行を追加します。

postgresql.conf
#./ansible/roles/postgresql/files/postgresql.conf

...
listen_addresses = '*'
...

pg_hba.confに以下を行を追加します。

pg_hba.conf2.j2
#./ansible/roles/postgresql/templates/pg_hba.conf2.j2

...
host all all 0.0.0.0/0 trust

そして、DB生成ぐらいはやって置きますかね。
以下の行を追加します。

main.yml
#./ansible/roles/postgresql/tasks/main.yml

...
# データベースを作成
- name: create database
  become: true
  become_user: postgres
  postgresql_db: name={{ db_name }} login_password={{db_user_password}} 
vars.yml
#./ansible/vars.yml

...
db_name: ansible_std
...

その後、ansibleをまた動かすと、追加した部分だけ変更されます。(冪等性👍)

ansible-playbook -i host db.yml

image.png
素晴らしい〜

参考
※ ansibleコマンドにはテストするための-Cオプションがあります。
実際は反映しなく、状態定義の実装に失敗があるか確認するための目的です。
ansibleは残念ながら失敗した時、失敗する前のやつがRollBackされないです。
なので、冪等性がないモジュールが含めているTaskでしたら、
一回テストすることをオススメします。

じゃー環境の準備は出来ましたので、CakePHPアプリケーションを設置します。
各Webサーバに以下のようにCakePHP3のFrameworkを入れて見ます。
これからは、web_a, web_b で直接アクセスして作業しましょう。
※ 以下のやつもAnsibleで頑張ったら出来ますが、これは環境よりアプリケーションの配置なので、
Capistranoとかの別のツールが正常系です。

# composer.phar設置
curl -s http://getcomposer.org/installer | php

# CakePHPアプリケーション設置
php composer.phar create-project --prefer-dist cakephp/app lee

image.png
そして、CakePHPアプリケーションの外部DBサーバの接続設定をします。

app.php
// ./lee/config/app.php

'Datasources' => [
    'default' => [
        'className' => 'Cake\Database\Connection',
        'driver' => 'Cake\Database\Driver\Postgres',
        'persistent' => false,
        'host' => '192.168.43.55',
        'port' => '5432',
        'username' => 'postgres',
        'password' => '1q2w3e',
        'database' => 'ansible_std',
        'encoding' => 'utf8',
        'timezone' => 'UTC',
        'flags' => [],
        'cacheMetadata' => true,
        'log' => false,
        'quoteIdentifiers' => false,
        'url' => env('192.168.43.55', null),
    ],
],

そうして以下のurlにアクセスすると
http://192.168.43.52/lee/
http://192.168.43.53/lee/
image.png

CakePHP3のアプリケーションとして設定など全ての準備完了されたことが確認できます。

最後にテーブルを一つ生成して、基本的な掲示板ページをbackでパバット生成します。

bin/cake bake all users

image.png

その後、
以下のそれぞれのWEBサーバにアクセスすると
http://192.168.43.52/lee/users
http://192.168.43.53/lee/users
同じDB(外部サーバ)を見ているそれぞれのWEBアプリケーションを開けます。
image.png

これは一つのサーバが死んだら他のもう一つのサーバを立ち上げる
デュアルサーバー見たいになっていますねw!!!

ある程度終わって気がしますので、構成図をもう一度確認しましょうか。
image.png

Um! いい感じですね〜

構成図にAWS S3にバックアップすることが表示していますが、
taskの内容を見ると頑張って実現しておきましたので、
これは皆さんがPlaybookになれるため、頑張って理解してみましょう!

以上、ちょっと長くなりましたが、
Ansible自体を知らない人が本番に使える人になるまでのスタディー
の記事でした。

(韓国人で頑張って日本語書きましたが、やっぱり文書が文法問題だらけかも…)
ありがとうございます!👏👏