Ansibleでできることを中の人が教えます - インストールと実行~EC2へのNginx投入までを学ぼう

高度化、複雑化しシステムの運用には、構成管理の自動化が欠かせません。管理用ソフトウェアとして広く使われるAnsibleを提供する、Red Hatの杉村さんが、IaSの概要から、Ansibleの活用手順までを解説します。

Ansibleでできることを中の人が教えます - インストールと実行~EC2へのNginx投入までを学ぼう

こんにちは。Red HatでAnsibleのテクニカルサポートエンジニアをしております杉村(@sugitk)と申します。このたびは機会をいただきまして、Ansibleをこれから使い始めようという方々に向けて、ツールの概要や使い方についてご紹介させていただきます。

Ansibleとは

Ansibleは、オープンソースプロジェクトで開発されているPython製の構成管理ツールです。YAML形式で書かれた設定ファイルに従って、サーバやネットワーク機器などの設定を自動的に実行できます。

現在では構成管理にとどまらずその守備範囲を広げ、アプリケーションのデプロイやオーケストレーションなどにも利用できるようになりました。本稿では、自動化ツールとしてのAnsibleにフォーカスを当てて解説したいと思います。

なお、AnsibleはRed Hatがサポートを行っています。2012年に誕生したAnsibleは近年早いペースで開発が進んでおり、数か月おきに新しいリリースを出すようになりました。現在のバージョンは2.7で、近いうちに2.8のリリースを予定しています。

Infrastructure as Code(IaC)隆盛の理由

みなさんご存知のように、ITシステムを開発・運用するにはさまざまな作業が必要になります。例えばインフラ構築の作業として代表的なものは、サーバのインストールやネットワーク機器の設定でしょう。従来、こうした作業のほとんどが人の手によって行われてきました。アプリケーションの規模が比較的小規模だったからです。

かつてのWebアプリケーションは、数台のWebサーバやアプリケーションサーバ、集約された データベースの組み合わせという3層構造で構成されていました。現在でも、WordPressやRedmineなど、こうした3層構造を採用するアプリケーションは数多くあります。

一方で、近年ではシステムの巨大化が進み、こうした流れに並走しマイクロサービスアーキテクチャによる分散化も進みました。アプリケーションはコンテナ化され、DevOpsの技術進歩により開発からデプロイまでの期間が短縮されて、即時リリースが当たり前になりつつあります。

そしてシステムはデータセンター内の単一のラックに収まっていましたが、いまでは世界中のクラウド上にあるサーバやサービスを組み合わせて動作するようになってきたのです。

管理すべきサーバ台数は増え、開発やビジネスの速度も加速してきたことで、従来のような人の手による作業では、管理が追いつかなくなってきたのです。また、人間の手作業にはヒューマンエラーもつきものです。こうした背景から、作業そのものもソフトウェア化して自動化しよう、という流れが、2010年代から流行してきたInfrastructure as Code(IaC)です。

Ansibleの利点

ChefやPuppetなど、従来の構成管理ツールとの比較

下表のように、作業を自動化してくれるツールはAnsible以外にもたくさん生まれてきました。この表に挙げているもの以外にも数多くのツールがあります。それぞれがさまざまな特徴を備えていますので、目的にあったものを使うと効果的です。

ツール 初出年 管理対象 特徴
Expect 1990 コマンドライン対話型 コマンドのやりとりをスクリプト化したツールとして最古のもののひとつ
TeraTerm 1994 コマンドライン対話型 独自のマクロ言語で記述する
Puppet 2005 Linux / Windows / ネットワーク機器 / クラウド 管理対象にエージェントを導入して、効果的に設定やレポーティングをする
Chef 2009 Linux / Windows / ネットワーク機器 / クラウド 管理対象にエージェントを導入して、Rubyで柔軟に記述できる
Salt / SaltStack 2009 Linux / Windows / ネットワーク機器 / クラウド エージェントベースとエージェントレスの両方をサポート
Ansible 2012 Linux / Windows / ネットワーク機器 / クラウド エージェントレス(本記事で詳細に解説)
DSC 2013 Linux / Windows Windowsに標準搭載されているPowerShellを使う
Terraform 2014 クラウド クラウドのリソースを定義ファイルに従って構成してくれる
NAPALM 2015 ネットワーク機器 AnsibleやSaltなどと組み合わせて使う

当初は通信中の文字列を定義しているだけだったものが、抽象化されたコマンドを記述できるようになったり、管理対象と効果的にやりとりしたり、結果を一元管理できるようになったりと、多くの機能を備えるようになってきました。

冪等性とエージェントレス。Ansibleの特性を知る

上の比較表で挙げたように、他のツールでは管理対象の情報を取得したり変更を加えたりするために、エージェントと呼ばれるソフトウェアをあらかじめインストールするものもありますが、Ansibleではその必要がありません。

LinuxにはSSHで、WindowsにはWinRMで接続し、ネットワーク機器やクラウドリソースにはSSHやAPIを使って接続できます。 一部では接続を受け付けるための設定が必要な場合もあり、必ずしも起動してすぐ使えるわけではないのですが、エージェントをインストールする必要がないのは大きなアドバンテージです。

そして、Ansible の処理は原則として何度実行しても同じ結果が得られるように作られています。これを冪等性(べきとうせい、idempotency)と言います。 例えば設定ファイルに1行追加することを考えてみてください。/etc/hosts を例に考えてみましょう。

192.168.100.101 appserver
192.168.100.201 dbserver

このファイルを以下のように書き換えてみることを考えます。

192.168.100.101 appserver01
192.168.100.102 appserver02
192.168.100.201 dbserver

appserverappserver01 にして、2行目に追加の行を挿入しています。この処理がもし単純な変換処理だったとすると、もう一度実行したときに以下のようなものになってしまうかもしれません。

192.168.100.101 appserver0101
192.168.100.102 appserver02
192.168.100.102 appserver0102
192.168.100.201 dbserver

これでは意図した修正にはなりません。こうした事態を防ぐため、Ansible では lineinfile モジュールを使い、正規表現でマッチした箇所を適切に編集することで、何度実行してもあるべき姿を維持して実行するよう工夫されています。

コマンドの実行結果をそのまま利用するモジュールなど、必ずしもこの冪等性が確保されていないものも一部にはありますが、Ansibleのモジュールの動きの根底には、冪等性が必ず意識されています。

また、Ansibleが扱うものはサーバやネットワーク機器、インフラリソースです。いきなり設定を変更すると戻すのに手間がかかったり、課金されてしまう、サービスが開始してしまうものも少なくありません。そのため、Ansibleにはテスト実行ができる機能(dry run)も備わっています。

操作対象の情報を取得し、処理を分岐しながら進んでいくようなプレイブックを書いた場合、特にこのテスト機能は有効に活用できるものとなっています。

このように、管理対象にエージェントがいらず、容易に接続できる特徴を持つAnsibleは、サーバの構成管理ツールとしての役割だけにはとどまりません。いまはクラウドのリソースやネットワーク機器へも活躍の場を広げています。システム全体の設定を一気通貫で、それらの処理を確実に間違いなく行う自動化ツールとしての需要が増えてきているのです。

今後はさらに、コンテナ化やそのオーケストレーションの設定、仮想基盤上に構築されたソフトウェアルータなどのネットワークの設定なども、Ansibleで行いたいというケースが増えてくると考えられます。

ハンズオンで学ぶAnsible

では、実際にAnsibleを動かしてみましょう。インストールはyumrpm)かpipを用いて行います。ここではpipでのインストール方法をご紹介します。macOSへのインストール例は以下のようになります。なお、執筆時点での最新バージョンである2.7.9で実行しています。

$ pip install ansible --user
…
$ echo "export PATH=\$PATH:~/Library/Python/2.7/bin/" >> ~/.bash_profile
$ source .bash_profile
$ ansible --version
ansible 2.7.9
  config file = None
  configured module search path = [u'/Users/sugimura/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/sugimura/Library/Python/2.7/lib/python/site-packages/ansible
  executable location = /Users/sugimura/Library/Python/2.7/bin/ansible
  python version = 2.7.16 (default, Mar 17 2019, 19:44:30) [GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)]

Ansibleを動かすには、インベントリとプレイブックを準備する必要があります。インベントリには作業対象を、プレイブックには作業の中身を記述します。

「Hello World!」を出力してみよう

まずは、一番簡単な「Hello World!」を出力するプログラムを作ってみましょう。まずはインベントリを作ります。ここでは、対象をlocalhost(自分自身)としてみます。インベントリはINI形式で記述します。

$ vi inventory (下記のように編集してください)
[target]
localhost

次に、メッセージを出力するためのプレイブックを作ります。プレイブックは、YAML形式の設定ファイルで記述します。 プレイブックからはロールを呼び出すため、まずはansible-galaxyコマンドを用いてロールを作ります。ロールはタスクや変数定義、テンプレートなどをひとまとまりにしたディレクトリ構造です。ロールの形で処理をまとめておくことで、他のプレイブックからも再利用できるという利点があります。

$ ansible-galaxy init helloworld

- helloworld was created successfully

$ vi helloworld/tasks/main.yml (下記のように編集してください)
---
# tasks file for helloworld
- name: Hello World!
  debug:
    msg: "Hello World!"

YAML形式のファイルは字下げ(インデント)が大事ですので注意してください。字下げを利用して制御構造やデータ構造を階層的に表現するのがYAML形式の特徴です。 今回、ロールにはタスクをひとつ定義しただけでしたが、他に変数や設定ファイルのテンプレートなども置けるようになっています。Ansibleでは一定の処理をロールの単位としてひとまとまりに扱うことがよくあります。

先ほどansible-galaxyコマンドで生成したhelloworldロールについては、このようなディレクトリやファイルで構成されています。興味がある方はそれぞれの役割を確認してみてください。

$ tree helloworld
helloworld
├── README.md
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

それでは、このロールを呼び出すプレイブックを書きます。

$ vi playbook.yml (下記のように編集してください)
---
- hosts: all
  roles:
    - helloworld

これでインベントリとプレイブックが揃いましたので実行してみましょう。まずは --syntax-check オプションをつけて文法チェックをします。

$ ansible-playbook -i inventory playbook.yml --syntax-check
playbook: playbook.yml

文法チェックのエラーがなくコマンドが完了したら、実際に実行します。

$ ansible-playbook -i inventory playbook.yml 

PLAY [all] ***************************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************
ok: [localhost]

TASK [helloworld : Hello World!] *****************************************************************************************************************
ok: [localhost] => {
    "msg": "Hello World!"
}

PLAY RECAP ***************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0   

SSHでlocalhostに接続して、“Hello World!” の文字列を出力できました。 インベントリ作業対象を追加することで、他のサーバにもログインして “Hello World!” を表示することができます。以下の例ではlocalhostから変更して、3台のサーバを対象にしました。1台で成功した処理が、簡単に3台にも適用できることが分かると思います。

$ cat inventory
[target]
ap01
ap02
db

$ ansible-playbook -i inventory playbook.yml 

PLAY [all] ***************************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************
ok: [ap01]
ok: [ap02]
ok: [db]

TASK [helloworld : Hello World!] *****************************************************************************************************************
ok: [ap01] => {
    "msg": "Hello World!"
}
ok: [ap02] => {
    "msg": "Hello World!"
}
ok: [db] => {
    "msg": "Hello World!"
}

PLAY RECAP ***************************************************************************************************************************************
ap01                    : ok=2    changed=0    unreachable=0    failed=0   
ap02                    : ok=2    changed=0    unreachable=0    failed=0   
db                        : ok=2    changed=0    unreachable=0    failed=0   

よく使用されるモジュール

前章の例は、debugモジュールを用いてメッセージを表示するというものでした。これを他のモジュールに変更することで、さまざまな処理を実行できます。その他、よく使用されるモジュールとして以下のような例が挙げられます。

モジュール名 概要
yum 管理対象のサーバでyumパッケージ管理を行う
command 管理対象のサーバでコマンドを発行する
ios_config Cisco IOSのconfigを設定する
win_user Windowsのユーザを作成する

その他、2000を超えるモジュールが用意されています。最近ではネットワーク機器を扱うモジュールが特に増えてきています。 ほかにもさまざまなモジュールがありますので、こちらから探してみてください。

実践編:EC2へのNginx投入

簡単な使い方が理解できたところで、実際に Amazon EC2上に作成した5台のサーバにNginx(よく使われるWebサーバ)をインストールしてみましょう。今回の例では、Amazon EC2にあらかじめ5台のRHEL 7のサーバを用意しておきました。これらのサーバにはPublic IPアドレスをつけておいてください。

1

これらのサーバ(engineer_hub web01~05)を管理対象とします。今回は個別に指定するのではなく、ダイナミックインベントリの機能を使ってみます。まず、aws_ec2.ymlファイルを書きます。AWSにアクセスするためのキーはAWSから入手しておいてください。

plugin: aws_ec2

aws_access_key_id: XXXXXXXXXXXXXXXXXXXXXX
aws_secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
aws_security_token: 

regions:
  - us-east-2
hostnames:
  - tag:Name
groups:
  nginx: "'engineer_hub' in tags.Name"
compose:
  ansible_host: public_ip_address

必要となるpipモジュールもインストールしておきます。

$ pip install boto3 botocore

これで、ansible-inventoryコマンドから管理対象が取得できるようになりました。

$ ansible-inventory -i aws_ec2.yml --graph nginx
@nginx:
  |--engineer_hub web01
  |--engineer_hub web02
  |--engineer_hub web03
  |--engineer_hub web04
  |--engineer_hub web05

試しにpingモジュールを使って接続確認してみます。AnsibleのpingモジュールはICMPのpingを打つのではなく、SSHで実際に接続して接続性が確認できたときにpongを返す仕様になっています。pingモジュールの返答があったということは、「SSHで接続してAnsibleから他のモジュールも実行できる」という意味になります。

$ ansible -i aws_ec2.yml -m ping nginx -c ssh -u ec2-user --private-key=~/.ssh/tsugimur.pem --ssh-extra-args="-o StrictHostKeyChecking=no"
engineer_hub web03 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
engineer_hub web04 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
engineer_hub web05 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
engineer_hub web02 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
engineer_hub web01 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

SSHに渡す引数がちょっと多くなりましたが、無事接続できることが確認できました。 これらのサーバにNginxをインストールしてみます。NGINXが作成して配布しているGalaxy Roleを使用します。Galaxy Roleは、ロールを再利用できる形でまとめたものです。最初に作成した helloworldもGalaxy Roleとして作りました。同じように、Ansibleモジュールである「NGINX」が作成したロールも外からダウンロードすることで使うことができます。ansible-galaxy installコマンドでインストールします。

$ ansible-galaxy install nginxinc.nginx
- downloading role 'nginx', owned by nginxinc
- downloading role from https://github.com/nginxinc/ansible-role-nginx/archive/0.11.0.tar.gz
- extracting nginxinc.nginx to /Users/sugimura/.ansible/roles/nginxinc.nginx
- nginxinc.nginx (0.11.0) was installed successfully

ロールはプレイブックから呼び出します。今回の例ではプレイブックをplaybook.ymlと定義しましたが、ファイル名はなんでも構いません。hostsに指定しているnginxというのは、先ほどダイナミックインベントリで取得したグループを指しています。接続ユーザの設定もここでしておきます。

---
- hosts: nginx
  become: true

  vars:
    - ansible_ssh_user: ec2-user
    - ansible_ssh_private_key_file: ~/.ssh/tsugimur.pem

  roles:
    - role: nginxinc.nginx

ではインベントリとプレイブックが揃いましたので、実行してみましょう。

$ ansible-playbook -i aws_ec2.yml playbook.yml 

PLAY [nginx] *******************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************
ok: [engineer_hub web05]
ok: [engineer_hub web02]
ok: [engineer_hub web01]
ok: [engineer_hub web03]
ok: [engineer_hub web04]
…
RUNNING HANDLER [nginxinc.nginx : (Handler: All OSs) Start NGINX] **************************************************************************
changed: [engineer_hub web05]
changed: [engineer_hub web04]
changed: [engineer_hub web03]
changed: [engineer_hub web02]
changed: [engineer_hub web01]

PLAY RECAP *********************************************************************************************************************************
engineer_hub web01         : ok=6    changed=4    unreachable=0    failed=0   
engineer_hub web02         : ok=6    changed=4    unreachable=0    failed=0   
engineer_hub web03         : ok=6    changed=4    unreachable=0    failed=0   
engineer_hub web04         : ok=6    changed=4    unreachable=0    failed=0   
engineer_hub web05         : ok=6    changed=4    unreachable=0    failed=0   

unreachablefailedになったタスクがなかったので全て成功です。 実際にブラウザからもアクセスしてみてください。

2

ここでは単にNginxをインストールしてみたというだけでしたが、このロールにも多くの機能がありますし、もちろん使う側でいろいろ加工して他のモジュールを組み合わせてプレイブックを組み立てていくこともできます。 Amazon EC2 のサーバについてもここでは手で作成しましたが、Ansibleモジュールの「ec2」を使って作ることもできますので、これらの全ての作業をAnsibleで完結することも可能です。ここでお伝えしたいポイントは以下の2点です。

  • 動的に管理対象を扱える
  • モジュールはロールという形態、つまり再利用可能な形で使うとやすい

他にもネットワーク機器を扱うモジュールも数多く、例えばセグメントの設計ができたらネットワーク機器とそこに接続されるサーバ群を一気にプロビジョニングする、といった作業も Ansibleで実現できるようになってきています。みなさんの普段の業務に合わせて、使えそうなモジュールがあるかどうか、小さなところからでも検討していただけるととても嬉しいです。

さらに進んだAnsible活用のために~Ansible Towerの導入~

Ansibleの運用をさらに効率化・省力化してくれるツールとして、Ansible Towerをご紹介します。

Ansible Towerは、Red Hatが開発している Ansibleの管理ツールで、オープンソース版のAWXをもとにしています。Webインタフェースや REST API、さまざまな認証機構などを備えています。AWXはGitHubの 3 GitHub - ansible/awx: AWX Projectのプロジェクトで開発されており、誰でも自由に開発に参加できます。

Ansible Towerの執筆時点での最新版は3.4.3です。およそ3~6か月ごとにバージョンアップしています。

4

オープンソース版と商用版の違いはこのようになっています。

  Ansible Ansible Tower サポート
オープンソース版 Ansible Project AWX なし
商用版 Ansible Engine Ansible Tower あり

AWXはDockerやKubernatesなどのコンテナ環境で動作します。1か月に1~2回のリリースがされ、常に新しい機能が盛り込まれているのです。Ansible TowerはいわばAWXの安定版として、商用環境での使用を想定したものをリリースしています。このリリースの関係性は、FedoraとRHEL(Red Hat Enterprise Linux)によく似ています。 では、Ansible Towerの特徴的な機能をいくつかご紹介しましょう。

ワークフロー

Ansibleは単体で使用すると、コマンドラインから実行して結果を得ることができました。Ansible Towerではそれに加え、プレイブックの実行などの処理を組み合わせてワークフローとしてまとめることができます。 例えば、「処理対象のサーバ一覧を取得してダイナミックインベントリとする」→「GitHubから最新版のプレイブックを取得する」→「プレイブックを実行する」という一連の流れをワークフロー化できます。

5

認証

Ansible Towerにログインできるユーザを制限できます。認証方式としては、パスワード認証、Active DirectoryやLDAPと連携したアカウント認証、SAMLでのシングルサインオンなど、さまざまな方式に対応しています。

ユーザを組織やチームと関連づけることにより、Ansibleが扱うプロジェクトや認証情報などの各種オブジェクトに対して権限を与えることができます。 例えば、「Active Directoryで特定のグループに属しているユーザは、この管理対象サーバについてのプレイブックを実行できる」という形で、大規模なエンタープライズ環境でも利用できる仕組みが用意されています。

6

作業ログの記録

インベントリの同期やプレイブックの実行など、Ansible Towerが実行した処理についてのログを一元管理できます。この画面からは同じ処理を再実行したり、ログをダウンロードしたりという作業も簡単にできるようになっています。

7

マルチノードクラスタ処理

さらに、Ansible Towerはクラスタリングにも対応しています。下図は3台のクラスタを立てて処理を実行した例です。処理対象の機器が複数あるとき、それぞれのクラスタノードに分散してプレイブックを実行します。機器がたくさんある場合でも、並列に実行することで処理時間を大きく短縮できます。

8

おわりに

Ansibleとは、というところから他のツールとの比較、簡単な使い方やAnsible Towerの紹介まで、幅広く説明してきました。Ansible を使うことで、手入力や人間の目による管理から離れ、より確実な作業ができるものと確信しています。

「Ansibleを導入してからは作業工数が人手の1/3になった」というお話もよく聞くようになりました。単に経費削減の手段として使うのではなく、より早く確実にビジネスを動かせるようになったと捉え、本来のやりたいことがすぐできるようになるところにうれしさを感じてほしいと私は願っています。

Ansible Tower (OSS版はAWX) もぜひ使ってみてください。すでに数多くの企業で使われており、何千台ものサーバやネットワーク機器を管理対象としているという例も出てきています。自動化して人の手を離れることで温かみのある作業ではなくなっていきますが、その温かみは本来の顧客に向けてあげませんか。

Happy Automation!

【巻末付録】Ansible のコミュニティ

Ansibleにもユーザ会があり、「もくもく会」や「Ansible Night」などのイベントを定期的に開催しています。もくもく会ではサーバ編とネットワーク編の2つのコンテンツを利用して、みなさんに実際にハンズオンでAnsibleを動かしていただきます。オンラインの活動としても、Slack には500人以上の方が登録されています。きっと新しい発見があると思いますので、お気軽にご参加ください!

Ansibleユーザー会のまとめページ
Ansible ユーザー会

また、Red HatのWebサイトでもいくつかのコンテンツを用意していますのでご覧ください。

Get Started ~はじめてみよう、Ansible~

杉村貴士(すぎむら・たかし) 9 @sugitk

10
1973年生まれ。北海道旭川市出身。2018年夏にレッドハットに入社し、Ansible のテクニカルサポートエンジニア (TSE) として、Ansible Engine や Ansible Tower のサポートをグローバルのお客様に対して行なっています。Ansible は2016年頃から使い始めました。レッドハットのエンジニアブログ『赤帽エンジニアブログ』でもほぼ月一のペースで記事を執筆しています。

技術監修:Red Hat Ansible サポートチーム

若手ハイキャリアのスカウト転職