Ansibleチュートリアル

オーケストラ構成管理







この実用的なガイドでは、Ansibleを紹介しています。 Ansibleのホストとして機能する仮想マシンまたは実マシンが必要です。 Vagrantの環境には、このチュートリアルが付属しています。







Ansibleは、リモート構成管理用のソフトウェアソリューションです。 リモートマシンを設定できます。 他の同様のシステムとの主な違いは、Ansibleが既存のSSHインフラストラクチャを使用するのに対して、他(シェフ、パペットなど)は特別なPKI環境のインストールを必要とすることです。







このマニュアルには、次のトピックが含まれています。







  1. AnsibleおよびVagrantのインストール
  2. インベントリファイル
  3. シェル、コピーモジュール、ファクトコレクション、変数
  4. ホストのグループで実行する
  5. プレイブック
  6. 例:クラスターを上げ、ApacheとHAproxyロードバランサーをインストールして構成します
  7. エラー処理、ロールバック
  8. 構成テンプレート
  9. 役割


Ansibleはいわゆるプッシュモードを使用します。設定はホストマシンから「プッシュ」されます。 通常、他のCMシステムは反対のことを行います。ノードはホストマシンから構成を取得します。







このモードは、ノードのリモート構成に公的にアクセス可能なホストマシンを必要としないため、興味深いものです。 このノードはアクセス可能でなければなりません(後で非表示のノードも設定を受け取ることができることがわかります)。







Ansibleに必要なもの



次のPythonモジュールが必要です。









Debian / Ubuntuで、次を実行します。







sudo apt-get install python-yaml python-jinja2 python-paramiko python-crypto
      
      





〜/ .sshにもキーペアが必要です。







Ansibleをインストールする



ソースから



develブランチは常に安定しているため、使用します。 gitのインストールが必要になる場合があります(Debian / Ubuntuにsudo apt-get install git



)。







 git clone git://github.com/ansible/ansible.git cd ./ansible
      
      





これで、Ansible環境をダウンロードできます。







 source ./hacking/env-setup
      
      





debパッケージから



 sudo apt-get install make fakeroot cdbs python-support git clone git://github.com/ansible/ansible.git cd ./ansible make deb sudo dpkg -i ../ansible_1.1_all.deb (version may vary)
      
      





このチュートリアルでは、この特定の方法を使用したことを前提としています。







Vagrantをインストールする



Vagrantを使用すると、仮想マシンを簡単に作成してVirtualBoxで実行できます。 Vagrantfileにはマニュアルが付属しています。







Vagrantを起動するには、インストールする必要があります。









次のコマンドで仮想マシンを初期化します。 「ボックス」を手動でダウンロードする必要はないことに注意してください。 このチュートリアルには、完成したVagrantfile



既に含まれおり、作業に必要なすべてのものが含まれています。







 vagrant up
      
      





コーヒーを注いでください(vagrant-hostmasterを使用する場合は、rootパスワードを入力する必要があります)。 問題が発生した場合は、Vagrantチュートリアルをご覧ください







仮想マシンにSSHキーを追加する



続行するには、仮想マシンのauthorized_keys



ルートにキーを追加する必要があります。 これはオプションです(Ansibleはsudoおよびパスワード認証を使用できます)が、はるかに簡単です。







Ansibleはこのタスクに理想的であるため、使用します。 ただし、まだ何も説明しません。 ただ私を信じて。







 ansible-playbook -c paramiko -i step-00/hosts step-00/setup.yml --ask-pass --sudo
      
      





パスワードとしてvagrantを入力します。 「接続が拒否されました」エラーが発生した場合は、ファイアウォールの設定を確認してください。







次に、キーをssh-agentに追加します( ssh-add



)。







在庫



次に、インベントリファイルを準備する必要があります。 デフォルトの場所は/etc/ansible/hosts



です。

ただし、別のパスを使用するようにAnsibleを構成できます。 これを行うには、環境変数( ANSIBLE_HOSTS



)または-i



フラグを使用します。







次のインベントリファイルを作成しました。







 host0.example.org ansible_ssh_host=192.168.33.10 ansible_ssh_user=root host1.example.org ansible_ssh_host=192.168.33.11 ansible_ssh_user=root host2.example.org ansible_ssh_host=192.168.33.12 ansible_ssh_user=root
      
      





ansible_ssh_host



は、接続が作成されるホストのIPアドレスを含む特別な変数です。 この場合、gem vagrant-hostmasterを使用する場合はオプションです。 また、仮想マシンに他のアドレスをインストールして構成した場合は、IPアドレスを変更する必要があります。







ansible_ssh_user



は、指定されたアカウント(ユーザー)で接続するようAnsibleに指示する別の特別な変数です。 デフォルトでは、Ansibleは現在のアカウント、または〜/ .ansible.cfg( remote_user



)で指定された別のデフォルト値を使用します。







確認する



Ansibleがインストールされたので、すべてが機能することを確認しましょう。







 ansible -m ping all -i step-01/hosts
      
      





ここで、Ansibleは各ホストでping



モジュールを実行しようとします(モジュールについては後ほど説明します)。 出力は次のようになります。







 host0.example.org | success >> { "changed": false, "ping": "pong" } host1.example.org | success >> { "changed": false, "ping": "pong" } host2.example.org | success >> { "changed": false, "ping": "pong" }
      
      





いいね! 3つのホストはすべて正常に動作しており、Ansibleはそれらと通信できます。







ノードとの通信



これで準備ができました。 前のセクションで既におなじみのチームであるansible



遊んでみましょう。 このコマンドは、Ansibleがノードと対話するために使用する3つのコマンドの1つです。







何か便利なことをしましょう



最後のコマンドでは、 -m ping



は「 pingモジュールを使用する」ことを意味していました。 これは、Ansibleで利用可能な多くのモジュールの1つです。 ping



モジュールping



非常に単純で、引数を必要としません。 引数を必要とするモジュールは、 -a



引数を取得できます。 いくつかのモジュールを見てみましょう。







シェルモジュール



このモジュールを使用すると、リモートホストでシェルコマンドを実行できます。







 ansible -i step-02/hosts -m shell -a 'uname -a' host0.example.org
      
      





出力は次のようになります。







 host0.example.org | success | rc=0 >> Linux host0.example.org 3.2.0-23-generic-pae #36-Ubuntu SMP Tue Apr 10 22:19:09 UTC 2012 i686 i686 i386 GNU/Linux
      
      





簡単!







コピーモジュール



copy



モジュールを使用すると、ホストマシンからリモートホストにファイルをコピーできます。 /etc/motd



/tmp



ノードにコピーする必要があると想像してください。







 ansible -i step-02/hosts -m copy -a 'src=/etc/motd dest=/tmp/' host0.example.org
      
      





結論:







 host0.example.org | success >> { "changed": true, "dest": "/tmp/motd", "group": "root", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "mode": "0644", "owner": "root", "size": 0, "src": "/root/.ansible/tmp/ansible-1362910475.9-246937081757218/motd", "state": "file" }
      
      





Ansible(より正確には、ノードで実行されているコピーモジュール)は、JSON形式の有用な情報の束で応答しました。 後でこれをどのように使用できるかを見ていきます。







Ansibleには巨大な

システムで実行できるほぼすべてをカバーするモジュールのリスト 。 適切なモジュールが見つからなかった場合、モジュールの作成は非常に簡単なタスクです(Pythonで作成する必要はありません。主なことは、JSONを理解することです)。







多くのホスト、1つのチーム



上記はすべて素晴らしいですが、多くのホストを管理する必要があります。 やってみましょう。 ノードに関する事実を収集し、たとえば、ノードにインストールされているUbuntuのバージョンを調べたいとします。 これは非常に簡単です。







 ansible -i step-02/hosts -m shell -a 'grep DISTRIB_RELEASE /etc/lsb-release' all
      
      





all



は「インベントリファイル内のすべてのホスト」を意味します。 出力は次のようになります。







 host1.example.org | success | rc=0 >> DISTRIB_RELEASE=12.04 host2.example.org | success | rc=0 >> DISTRIB_RELEASE=12.04 host0.example.org | success | rc=0 >> DISTRIB_RELEASE=12.04
      
      





より多くの事実



簡単でシンプル。 ただし、より多くの情報(IPアドレス、RAMサイズなど)が必要な場合、このアプローチはすぐに不便になることがあります。 解決策は、 setup



モジュールを使用することです。 彼は、ノードからのファクトの収集を専門としています。







試してください:







 ansible -i step-02/hosts -m setup host0.example.org
      
      





答え:







 "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.0.60" ], "ansible_all_ipv6_addresses": [], "ansible_architecture": "x86_64", "ansible_bios_date": "01/01/2007", "ansible_bios_version": "Bochs" }, ---snip--- "ansible_virtualization_role": "guest", "ansible_virtualization_type": "kvm" }, "changed": false, "verbose_override": true
      
      





出力は単純化のために短縮されていますが、この情報から多くを学ぶことができます。 特定の何かに興味がある場合は、キーをフィルタリングすることもできます。







たとえば、すべてのホストで使用可能なメモリ量を調べる必要があります。 簡単です: ansible -i step-02/hosts -m setup -a 'filter=ansible_memtotal_mb' all









 host2.example.org | success >> { "ansible_facts": { "ansible_memtotal_mb": 187 }, "changed": false, "verbose_override": true } host1.example.org | success >> { "ansible_facts": { "ansible_memtotal_mb": 187 }, "changed": false, "verbose_override": true } host0.example.org | success >> { "ansible_facts": { "ansible_memtotal_mb": 187 }, "changed": false, "verbose_override": true }
      
      





ノードは、上記で回答した間違った順序で回答したことに注意してください。 Ansibleはホストと並行して通信します!







ところで、 setup



モジュールを使用する場合、式filter=



*



を指定できます。 シェルのように。







ホスト選択



all



「すべてのホスト」を意味することがわかりましたが、Ansibleには

ホストを選択する他の方法の束









ホストのグループ化



インベントリ内のホストはグループ化できます。 たとえば、 debian



グループ、 web-servers



グループ、 debian



グループなどを作成できます。







 [debian] host0.example.org host1.example.org host2.example.org
      
      





短縮することもできます:







 [debian] host[0-2].example.org
      
      





子グループを指定する場合は、 [groupname:children]



を使用して、それに子グループを追加します。 たとえば、さまざまなLinuxディストリビューションがあり、次のように編成できます。







 [ubuntu] host0.example.org [debian] host[1-2].example.org [linux:children] ubuntu debian
      
      





変数を設定する



インベントリファイル、ホスト変数ファイル、変数グループファイルなど、いくつかの場所でホストの変数を追加できます。







通常、すべての変数をグループ/ホスト変数ファイルに設定します(これについては後で説明します)。 ただし、多くの場合、ホストIPアドレスを設定するansible_ssh_host



など、インベントリファイルで直接変数を使用します。 デフォルトでは、AnsibleはSSH経由で接続するときにホスト名を解決します。 ただし、ホストを初期化するとき、IPアドレスがまだない場合があります。 この場合、 ansible_ssh_host



が役立ちます。







(通常のansible



ではなく) ansible-playbook



ansible



を使用する--extra-vars



(または-e



)フラグを使用して変数を設定できます。 次のステップでは、 ansible-playbook



チームについて説明します。







ansible_ssh_port



、ごansible_ssh_port



、SSH接続ポートの設定に使用されます。







 [ubuntu] host0.example.org ansible_ssh_host=192.168.0.12 ansible_ssh_port=2222
      
      





Ansibleは、グループおよびホスト変数ファイルで追加の変数を探します。 彼は、メインインベントリファイルがあるディレクトリ内のgroup_vars



およびhost_vars



ディレクトリでこれらのファイルを探します。







Ansibleは名前でファイルを検索します。 たとえば、前述のインベントリファイルを使用する場合、Ansibleはファイル内でhost0.example.org



変数を探します。









これらのファイルが存在しない場合は何も起こりませんが、存在する場合は使用されます。







モジュール、インベントリ、および変数に精通したので、最後にPlaybookでのAnsibleの真の力について調べましょう。







Playbook Ansible



プレイブックの概念は非常にシンプルです。これは、Ansibleユーティリティで使用したものと同様のAnsibleコマンド(タスク、タスク)の単なるコレクションです。 これらのタスクは、特定のノード/グループのセットを対象としています。







Apacheの例(別名 "Hello World!" Insible)



インベントリファイルが次のように見えるという仮定を続けます( hosts



と呼びましょう):







 [web] host1.example.org
      
      





すべてのホストはDebianベースのシステムです。







注: ansible_ssh_host



を使用して実際のホストIPアドレスを設定できることを思い出してください(そして、この演習でこれを行います)。 インベントリを変更して、実際のホスト名を使用することもできます。 いずれにしても、安全に実験できるマシンを使用してください。 また、実際のホストでは、 ansible_ssh_user=root



を追加して、異なるデフォルト設定での潜在的な問題を回避します。







web



グループのマシンにApacheをインストールするプレイブックを作成しましょう。







 - hosts: web tasks: - name: Installs apache web server apt: pkg=apache2 state=installed update_cache=true
      
      





適切なAnsibleモジュールを使用して何をしたいのかを言うだけです。 ここでは、Debianパッケージをインストールできるaptモジュールを使用します。 また、このモジュールにキャッシュの更新を依頼します。







このタスクには名前が必要です。 これは必須ではありませんが、利便性のために望ましいものです。







まあ、全体的にはとても簡単でした! これで、プレイブックを開始できます( apache.yml



と呼びましょう):







 ansible-playbook -i step-04/hosts -l host1.example.org step-04/apache.yml
      
      





ここで、 step-04/hosts



はインベントリファイルです。- -l



をホストで実行するように制限します。

そしてapache.yml



は私たちのプレイブックです。







コマンドを実行すると、次のような出力が表示されます。







 PLAY [web] ********************* GATHERING FACTS ********************* ok: [host1.example.org] TASK: [Installs apache web server] ********************* changed: [host1.example.org] PLAY RECAP ********************* host1.example.org : ok=2 changed=1 unreachable=0 failed=0
      
      





注: cowsay



インストールしている場合、牛が通り過ぎることに気付くかもしれません:-)気に入らなければ、次のように無効にできます: export ANSIBLE_NOCOWS="1"









行ごとに出力を分析しましょう。







 PLAY [web] *********************
      
      





Ansibleは、プレイはweb



グループで実行されることを示していweb



。 Playは、Ansibleホスト関連の命令のコレクションです。 プレイブックに別の-host: blah



がある場合、それも表示されます(ただし、最初のプレイが完了した後)。







 GATHERING FACTS ********************* ok: [host1.example.org]
      
      





setup



モジュールを使用したときのことを覚えていますか? 各再生の前に、Ansibleは各ホストでそれを実行し、ファクトを収集します。 これが必要ない場合(たとえば、ホストに関する情報が必要ないため)、ホスト行gather_facts: no



下に( tasks:



と同じレベルで) gather_facts: no



追加できます。







 TASK: [Installs apache web server] ********************* changed: [host1.example.org]
      
      





これが最も重要なことです。最初で唯一のタスクが起動され、 changed



と表示されているため、 host1.example.org



何かを変更したことがhost1.example.org



ます。







 PLAY RECAP ********************* host1.example.org : ok=2 changed=1 unreachable=0 failed=0
      
      





最後に、Ansibleは2つのタスクが完了し、そのうちの1つがホスト上の何かを変更しました(これはApacheタスクでした。セットアップモジュールは何も変更しません)。







これをもう一度実行して、何が起こるか見てみましょう。







 $ ansible-playbook -i step-04/hosts -l host1.example.org step-04/apache.yml PLAY [web] ********************* GATHERING FACTS ********************* ok: [host1.example.org] TASK: [Installs apache web server] ********************* ok: [host1.example.org] PLAY RECAP ********************* host1.example.org : ok=2 changed=0 unreachable=0 failed=0
      
      





変更された値は「0」に等しくなりました。 これは完全に正常であり、Ansibleの主な機能の1つです。プレイブックは、何かすることがある場合にのみ何かを実行します。 これは、 べき等性と呼ばれます。 これは、プレイブックを何回でも実行できることを意味しますが、最終的には同じ状態のマシンになります( shell



モジュールに夢中にならなくても、Ansibleはそれ以上何もできません)。







Apache Suiteの改善



Apacheをインストールしました。仮想ホストを設定しましょう。







プレイブックの改善



サーバーに必要な仮想ホストは1つだけですが、デフォルトをより具体的なものに変更する必要があります。 したがって、現在の仮想ホストを削除し、仮想ホストを送信し、アクティブにして、Apacheを再起動する必要があります。







files



というディレクトリを作成し、host1.example.orgの設定を追加して、 awesome-app



という名前を付けましょう。







 <VirtualHost *:80> DocumentRoot /var/www/awesome-app Options -Indexes ErrorLog /var/log/apache2/error.log TransferLog /var/log/apache2/access.log </VirtualHost>
      
      





これで、プレイブックが少し無効になり、完了です。







 - hosts: web tasks: - name: Installs apache web server apt: pkg=apache2 state=installed update_cache=true - name: Push default virtual host configuration copy: src=files/awesome-app dest=/etc/apache2/sites-available/ mode=0640 - name: Deactivates the default virtualhost command: a2dissite default - name: Deactivates the default ssl virtualhost command: a2dissite default-ssl - name: Activates our virtualhost command: a2ensite awesome-app notify: - restart apache handlers: - name: restart apache service: name=apache2 state=restarted
      
      





行こう:







 $ ansible-playbook -i step-05/hosts -l host1.example.org step-05/apache.yml PLAY [web] ********************* GATHERING FACTS ********************* ok: [host1.example.org] TASK: [Installs apache web server] ********************* ok: [host1.example.org] TASK: [Push default virtual host configuration] ********************* changed: [host1.example.org] TASK: [Deactivates the default virtualhost] ********************* changed: [host1.example.org] TASK: [Deactivates the default ssl virtualhost] ********************* changed: [host1.example.org] TASK: [Activates our virtualhost] ********************* changed: [host1.example.org] NOTIFIED: [restart apache] ********************* changed: [host1.example.org] PLAY RECAP ********************* host1.example.org : ok=7 changed=5 unreachable=0 failed=0
      
      





かっこいい! 考えてみれば、私たちは少し先を行っています。 Apacheを再起動する前に設定の正確性を確認する必要はありますか? 構成にエラーが含まれている場合にサービスを中断しないようにするため。







構成エラーが発生した場合の再起動



Apacheをインストールし、仮想ホストを変更してサーバーを再起動しました。 しかし、設定が正しい場合にのみサーバーを再起動したい場合はどうでしょうか?







問題がある場合はロールバックします



Ansibleにはクールな機能が含まれています。何か問題が発生すると、すべての処理が停止します。 設定が有効でない場合、この機能を使用してプレイブックを停止します。







awesome-app



仮想ホスト構成ファイルを変更して、破壊してみましょう。







  <VirtualHost *:80> RocumentDoot /var/www/awesome-app Options -Indexes ErrorLog /var/log/apache2/error.log TransferLog /var/log/apache2/access.log </VirtualHost>
      
      





前にも言ったように、タスクを完了できない場合、処理は停止します。 そのため、サーバーを再起動する前に構成の有効性を確認する必要があります。 また、仮想ホスト追加してデフォルトの仮想ホスト削除することから始めます。したがって、その後の再起動(サーバー上で直接実行される可能性があります)によってApacheが壊れることはありません。







最初にこれを行う必要がありました。 このプレイブックを既に開始しているため、デフォルトの仮想ホストはすでに非アクティブ化されています。 問題ありません:このプレイブックは他の罪のないホストでも使用できるので、保護しましょう。







 - hosts: web tasks: - name: Installs apache web server apt: pkg=apache2 state=installed update_cache=true - name: Push future default virtual host configuration copy: src=files/awesome-app dest=/etc/apache2/sites-available/ mode=0640 - name: Activates our virtualhost command: a2ensite awesome-app - name: Check that our config is valid command: apache2ctl configtest - name: Deactivates the default virtualhost command: a2dissite default - name: Deactivates the default ssl virtualhost command: a2dissite default-ssl notify: - restart apache handlers: - name: restart apache service: name=apache2 state=restarted
      
      





行こう:







 $ ansible-playbook -i step-06/hosts -l host1.example.org step-06/apache.yml PLAY [web] ********************* GATHERING FACTS ********************* ok: [host1.example.org] TASK: [Installs apache web server] ********************* ok: [host1.example.org] TASK: [Push future default virtual host configuration] ********************* changed: [host1.example.org] TASK: [Activates our virtualhost] ********************* changed: [host1.example.org] TASK: [Check that our config is valid] ********************* failed: [host1.example.org] => {"changed": true, "cmd": ["apache2ctl", "configtest"], "delta": "0:00:00.045046", "end": "2013-03-08 16:09:32.002063", "rc": 1, "start": "2013-03-08 16:09:31.957017"} stderr: Syntax error on line 2 of /etc/apache2/sites-enabled/awesome-app: Invalid command 'RocumentDoot', perhaps misspelled or defined by a module not included in the server configuration stdout: Action 'configtest' failed. The Apache error log may have more information. FATAL: all hosts have already failed -- aborting PLAY RECAP ********************* host1.example.org : ok=4 changed=2 unreachable=0 failed=1
      
      





お気づきのように、 apache2ctl



はエラーコード1を返します。Ansibleはこれを認識して動作を停止します。 いいね!







うーん、いや、大したことはない...とにかく仮想ホストが追加された。 その後の再起動の試行で、Apacheは構成のオンとオフを誓います。 したがって、エラーをキャッチして作業状態に戻る方法が必要です。







(コメント翻訳者:コメントの@clickfreak habrayuzerは、Ansible 2.xの特別な機能を見るよう提案しています)。







条件の使用



Apacheをインストールし、仮想ホストを追加してサーバーを再起動しました。 ただし、何か問題が発生した場合は、作業状態に戻りたいと考えています。







問題の返品



ここには魔法はありません。 過去の間違いはAnsibleのせいではありません。 これはバックアップシステムではなく、過去の状況に対するすべてを拒否する方法を知りません。 プレイブックの安全はあなたの責任です。 Ansibleは、 a2ensite awesome-app



効果を元に戻す方法を知りません。







前述のように、タスクを完了できない場合、処理は停止しますが、エラーを受け入れることができます( これを行う必要があります )。 したがって、エラーが発生した場合に処理を続行しますが、すべてを動作状態に戻します。







 - hosts: web tasks: - name: Installs apache web server apt: pkg=apache2 state=installed update_cache=true - name: Push future default virtual host configuration copy: src=files/awesome-app dest=/etc/apache2/sites-available/ mode=0640 - name: Activates our virtualhost command: a2ensite awesome-app - name: Check that our config is valid command: apache2ctl configtest register: result ignore_errors: True - name: Rolling back - Restoring old default virtualhost command: a2ensite default when: result|failed - name: Rolling back - Removing our virtualhost command: a2dissite awesome-app when: result|failed - name: Rolling back - Ending playbook fail: msg="Configuration file is not valid. Please check that before re-running the playbook." when: result|failed - name: Deactivates the default virtualhost command: a2dissite default - name: Deactivates the default ssl virtualhost command: a2dissite default-ssl notify: - restart apache handlers: - name: restart apache service: name=apache2 state=restarted
      
      





register



キーワードは、 apache2ctl configtest



(exitの出力を書き込みます

status、stdout、stderr、...)、およびwhen: result|failed



変数に

result



)ステータスが失敗しました。







行こう:







 $ ansible-playbook -i step-07/hosts -l host1.example.org step-07/apache.yml PLAY [web] ********************* GATHERING FACTS ********************* ok: [host1.example.org] TASK: [Installs apache web server] ********************* ok: [host1.example.org] TASK: [Push future default virtual host configuration] ********************* ok: [host1.example.org] TASK: [Activates our virtualhost] ********************* changed: [host1.example.org] TASK: [Check that our config is valid] ********************* failed: [host1.example.org] => {"changed": true, "cmd": ["apache2ctl", "configtest"], "delta": "0:00:00.051874", "end": "2013-03-10 10:50:17.714105", "rc": 1, "start": "2013-03-10 10:50:17.662231"} stderr: Syntax error on line 2 of /etc/apache2/sites-enabled/awesome-app: Invalid command 'RocumentDoot', perhaps misspelled or defined by a module not included in the server configuration stdout: Action 'configtest' failed. The Apache error log may have more information. ...ignoring TASK: [Rolling back - Restoring old default virtualhost] ********************* changed: [host1.example.org] TASK: [Rolling back - Removing our virtualhost] ********************* changed: [host1.example.org] TASK: [Rolling back - Ending playbook] ********************* failed: [host1.example.org] => {"failed": true} msg: Configuration file is not valid. Please check that before re-running the playbook. FATAL: all hosts have already failed -- aborting PLAY RECAP ********************* host1.example.org : ok=7 changed=4 unreachable=0 failed=1
      
      





すべてが正常に機能しているようです。 Apacheを再起動してみましょう。







 $ ansible -i step-07/hosts -m service -a 'name=apache2 state=restarted' host1.example.org host1.example.org | success >> { "changed": true, "name": "apache2", "state": "started" }
      
      





これで、Apacheは構成エラーから保護されました。 変数はほとんどどこでも使用できるため、このプレイブックは他の場合のApacheに使用できることを忘れないでください。 一度書いて、どこでも使用します。







Git



Apache, . git .







git



, , , . git



. - . , ansible-pull



.







, . PHP, libapache2-mod-php5



. git



, , , git .







:







  ... - name: Installs apache web server apt: pkg=apache2 state=installed update_cache=true - name: Installs php5 module apt: pkg=libapache2-mod-php5 state=installed - name: Installs git apt: pkg=git state=installed ...
      
      





Ansible . , :







 - hosts: web tasks: - name: Updates apt cache apt: update_cache=true - name: Installs necessary packages apt: pkg={{ item }} state=latest with_items: - apache2 - libapache2-mod-php5 - git - name: Push future default virtual host configuration copy: src=files/awesome-app dest=/etc/apache2/sites-available/ mode=0640 - name: Activates our virtualhost command: a2ensite awesome-app - name: Check that our config is valid command: apache2ctl configtest register: result ignore_errors: True - name: Rolling back - Restoring old default virtualhost command: a2ensite default when: result|failed - name: Rolling back - Removing out virtualhost command: a2dissite awesome-app when: result|failed - name: Rolling back - Ending playbook fail: msg="Configuration file is not valid. Please check that before re-running the playbook." when: result|failed - name: Deploy our awesome application git: repo=https://github.com/leucos/ansible-tuto-demosite.git dest=/var/www/awesome-app tags: deploy - name: Deactivates the default virtualhost command: a2dissite default - name: Deactivates the default ssl virtualhost command: a2dissite default-ssl notify: - restart apache handlers: - name: restart apache service: name=apache2 state=restarted
      
      





:







 $ ansible-playbook -i step-08/hosts -l host1.example.org step-08/apache.yml PLAY [web] ********************* GATHERING FACTS ********************* ok: [host1.example.org] TASK: [Updates apt cache] ********************* ok: [host1.example.org] TASK: [Installs necessary packages] ********************* changed: [host1.example.org] => (item=apache2,libapache2-mod-php5,git) TASK: [Push future default virtual host configuration] ********************* changed: [host1.example.org] TASK: [Activates our virtualhost] ********************* changed: [host1.example.org] TASK: [Check that our config is valid] ********************* changed: [host1.example.org] TASK: [Rolling back - Restoring old default virtualhost] ********************* skipping: [host1.example.org] TASK: [Rolling back - Removing out virtualhost] ********************* skipping: [host1.example.org] TASK: [Rolling back - Ending playbook] ********************* skipping: [host1.example.org] TASK: [Deploy our awesome application] ********************* changed: [host1.example.org] TASK: [Deactivates the default virtualhost] ********************* changed: [host1.example.org] TASK: [Deactivates the default ssl virtualhost] ********************* changed: [host1.example.org] NOTIFIED: [restart apache] ********************* changed: [host1.example.org] PLAY RECAP ********************* host1.example.org : ok=10 changed=8 unreachable=0 failed=0
      
      





http://192.168.33.11 .







tags: deploy



. , . , . . , "deploy" — , . , :







$ ansible-playbook -i step-08/hosts -l host1.example.org step-08/apache.yml -t deploy

X11 forwarding request failed on channel 0







PLAY [web] * ****







GATHERING FACTS * ****

ok: [host1.example.org]







TASK: [Deploy our awesome application] * ****

changed: [host1.example.org]







PLAY RECAP * ****

host1.example.org: ok=2 changed=1 unreachable=0 failed=0







-



-. .







inventory



, - , . inventory:







 [web] host1.example.org ansible_ssh_host=192.168.33.11 ansible_ssh_user=root host2.example.org ansible_ssh_host=192.168.33.12 ansible_ssh_user=root [haproxy] host0.example.org ansible_ssh_host=192.168.33.10 ansible_ssh_user=root
      
      





, ansible_ssh_host



IP, . /etc/hosts



( ).







-



. :







 $ ansible-playbook -i step-09/hosts step-09/apache.yml PLAY [web] ********************* GATHERING FACTS ********************* ok: [host2.example.org] ok: [host1.example.org] TASK: [Updates apt cache] ********************* ok: [host1.example.org] ok: [host2.example.org] TASK: [Installs necessary packages] ********************* ok: [host1.example.org] => (item=apache2,libapache2-mod-php5,git) changed: [host2.example.org] => (item=apache2,libapache2-mod-php5,git) TASK: [Push future default virtual host configuration] ********************* ok: [host1.example.org] changed: [host2.example.org] TASK: [Activates our virtualhost] ********************* changed: [host2.example.org] changed: [host1.example.org] TASK: [Check that our config is valid] ********************* changed: [host2.example.org] changed: [host1.example.org] TASK: [Rolling back - Restoring old default virtualhost] ********************* skipping: [host1.example.org] skipping: [host2.example.org] TASK: [Rolling back - Removing out virtualhost] ********************* skipping: [host1.example.org] skipping: [host2.example.org] TASK: [Rolling back - Ending playbook] ********************* skipping: [host1.example.org] skipping: [host2.example.org] TASK: [Deploy our awesome application] ********************* ok: [host1.example.org] changed: [host2.example.org] TASK: [Deactivates the default virtualhost] ********************* changed: [host1.example.org] changed: [host2.example.org] TASK: [Deactivates the default ssl virtualhost] ********************* changed: [host2.example.org] changed: [host1.example.org] NOTIFIED: [restart apache] ********************* changed: [host1.example.org] changed: [host2.example.org] PLAY RECAP ********************* host1.example.org : ok=10 changed=5 unreachable=0 failed=0 host2.example.org : ok=10 changed=8 unreachable=0 failed=0
      
      





, , -l host1.example.org



. , -l



. , web



.







web



, , , , : -l firsthost:secondhost:...



.







-, .







パターン



haproxy



. , apache. , - haproxy



. どうやってやるの?







HAProxy



Ansible Jinja2 , Python. Jinja2- , Ansible'.







, inventory_name , , {{ inventory_hostname }}



Jinja2-. , IP- ethernet- ( Ansible setup



), {{ ansible_eth1['ipv4']['address'] }}



.







Jinja2 , .







templates/



Jinja- . haproxy.cfg.j2



. .j2



, .







 global daemon maxconn 256 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms listen cluster bind {{ ansible_eth1['ipv4']['address'] }}:80 mode http stats enable balance roundrobin {% for backend in groups['web'] %} server {{ hostvars[backend]['ansible_hostname'] }} {{ hostvars[backend]['ansible_eth1']['ipv4']['address'] }} check port 80 {% endfor %} option httpchk HEAD /index.php HTTP/1.0
      
      





.







-, {{ ansible_eth1['ipv4']['address'] }}



IP eth1.







. -. [web]



, backend



. . hostvars



, (, IP, ) .







, . , . , [web]



.







HAProxy playbook



最も難しい部分は後ろにあります。 HAproxy :







 - hosts: haproxy tasks: - name: Installs haproxy load balancer apt: pkg=haproxy state=installed update_cache=yes - name: Pushes configuration template: src=templates/haproxy.cfg.j2 dest=/etc/haproxy/haproxy.cfg mode=0640 owner=root group=root notify: - restart haproxy - name: Sets default starting flag to 1 lineinfile: dest=/etc/default/haproxy regexp="^ENABLED" line="ENABLED=1" notify: - restart haproxy handlers: - name: restart haproxy service: name=haproxy state=restarted
      
      





, ? : template



. , copy



. haproxy



.







… . inventory , . , , , haproxy- -. , .







 $ ansible-playbook -i step-10/hosts step-10/apache.yml step-10/haproxy.yml PLAY [web] ********************* GATHERING FACTS ********************* ok: [host1.example.org] ok: [host2.example.org] TASK: [Updates apt cache] ********************* ok: [host1.example.org] ok: [host2.example.org] TASK: [Installs necessary packages] ********************* ok: [host1.example.org] => (item=apache2,libapache2-mod-php5,git) ok: [host2.example.org] => (item=apache2,libapache2-mod-php5,git) TASK: [Push future default virtual host configuration] ********************* ok: [host2.example.org] ok: [host1.example.org] TASK: [Activates our virtualhost] ********************* changed: [host1.example.org] changed: [host2.example.org] TASK: [Check that our config is valid] ********************* changed: [host1.example.org] changed: [host2.example.org] TASK: [Rolling back - Restoring old default virtualhost] ********************* skipping: [host1.example.org] skipping: [host2.example.org] TASK: [Rolling back - Removing out virtualhost] ********************* skipping: [host1.example.org] skipping: [host2.example.org] TASK: [Rolling back - Ending playbook] ********************* skipping: [host1.example.org] skipping: [host2.example.org] TASK: [Deploy our awesome application] ********************* ok: [host2.example.org] ok: [host1.example.org] TASK: [Deactivates the default virtualhost] ********************* changed: [host1.example.org] changed: [host2.example.org] TASK: [Deactivates the default ssl virtualhost] ********************* changed: [host2.example.org] changed: [host1.example.org] NOTIFIED: [restart apache] ********************* changed: [host2.example.org] changed: [host1.example.org] PLAY RECAP ********************* host1.example.org : ok=10 changed=5 unreachable=0 failed=0 host2.example.org : ok=10 changed=5 unreachable=0 failed=0 PLAY [haproxy] ********************* GATHERING FACTS ********************* ok: [host0.example.org] TASK: [Installs haproxy load balancer] ********************* changed: [host0.example.org] TASK: [Pushes configuration] ********************* changed: [host0.example.org] TASK: [Sets default starting flag to 1] ********************* changed: [host0.example.org] NOTIFIED: [restart haproxy] ********************* changed: [host0.example.org] PLAY RECAP ********************* host0.example.org : ok=5 changed=4 unreachable=0 failed=0
      
      





. http://192.168.33.10/ . ! HAproxy: http://192.168.33.10/haproxy?stats .









, , . .







Ansible . ansible_ssh_host



inventory, , host_vars



group_vars



.







HAProxy



HAProxy , . , , HAProxy .







( 0 256). , . , .







.







Group-



haproxy group_vars. , haproxy .







group_vars/haproxy



inventory. , . web, group_vars/web



.







 haproxy_check_interval: 3000 haproxy_stats_socket: /tmp/sock
      
      





. , , - . ( Python dict) :







 haproxy: check_interval: 3000 stats_socket: /tmp/sock
      
      





. . .









, host_vars



. host_vars/host1.example.com



:







 haproxy_backend_weight: 100
      
      





host_vars/host2.example.com



:







 haproxy_backend_weight: 150
      
      





haproxy_backend_weight



group_vars/web



, -:

host_vars



group_vars



.









, .







 global daemon maxconn 256 {% if haproxy_stats_socket %} stats socket {{ haproxy_stats_socket }} {% endif %} defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms listen cluster bind {{ ansible_eth1['ipv4']['address'] }}:80 mode http stats enable balance roundrobin {% for backend in groups['web'] %} server {{ hostvars[backend]['ansible_hostname'] }} {{ hostvars[backend]['ansible_eth1']['ipv4']['address'] }} check inter {{ haproxy_check_interval }} weight {{ hostvars[backend]['haproxy_backend_weight'] }} port 80 {% endfor %} option httpchk HEAD /index.php HTTP/1.0
      
      





{% if ...



? , . , - haproxy_stats_socket



( --extra-vars="haproxy_stats_sockets=/tmp/sock"



), .







, !







:







 ansible-playbook -i step-11/hosts step-11/haproxy.yml
      
      





, apache, . . haproxy:







 - hosts: web - hosts: haproxy tasks: - name: Installs haproxy load balancer apt: pkg=haproxy state=installed update_cache=yes - name: Pushes configuration template: src=templates/haproxy.cfg.j2 dest=/etc/haproxy/haproxy.cfg mode=0640 owner=root group=root notify: - restart haproxy - name: Sets default starting flag to 1 lineinfile: dest=/etc/default/haproxy regexp="^ENABLED" line="ENABLED=1" notify: - restart haproxy handlers: - name: restart haproxy service: name=haproxy state=restarted
      
      





ほら - . . Ansible web



. , haproxy . , Ansible , ansible_eth1



.







!



, , ! . — , . ,

Ansible . — : B A. B, A.









«» Ansible: . , . , , . . "convention over configuration".







:







 roles | |_some_role | |_files | | | |_file1 | |_... | |_templates | | | |_template1.j2 | |_... | |_tasks | | | |_main.yml | |_some_other_file.yml | |_ ... | |_handlers | | | |_main.yml | |_some_other_file.yml | |_ ... | |_vars | | | |_main.yml | |_some_other_file.yml | |_ ... | |_meta | |_main.yml |_some_other_file.yml |_ ...
      
      





.







main.yml



. , . .







vars



meta



. vars



, , . . , , — . , , — . «» (, ) . . . Ansible .







meta



, . roles



.







Apache



, apache .







:











:







 mkdir -p step-12/roles/apache/{tasks,handlers,files}
      
      





apache.yml



main.yml



. :







 - name: Updates apt cache apt: update_cache=true - name: Installs necessary packages apt: pkg={{ item }} state=latest with_items: - apache2 - libapache2-mod-php5 - git ... - name: Deactivates the default ssl virtualhost command: a2dissite default-ssl notify: - restart apache
      
      





, .

apache.yml



tasks:



handlers:



.







files/



templates/



. , Ansible , .









step-12/roles/apache/handlers/main.yml



:







 - name: restart apache service: name=apache2 state=restarted
      
      







:







 cp step-11/files/awesome-app step-12/roles/apache/files/
      
      





apache . .









. site.yml



, . haproxy



:







 - hosts: web roles: - { role: apache } - hosts: haproxy roles: - { role: haproxy }
      
      





. haproxy:







 mkdir -p step-12/roles/haproxy/{tasks,handlers,templates} cp step-11/templates/haproxy.cfg.j2 step-12/roles/haproxy/templates/
      
      





templates/



.







?:







 ansible-playbook -i step-12/hosts step-12/site.yml
      
      





, "PLAY RECAP":







 host0.example.org : ok=5 changed=2 unreachable=0 failed=0 host1.example.org : ok=10 changed=5 unreachable=0 failed=0 host2.example.org : ok=10 changed=5 unreachable=0 failed=0
      
      





, site.yml . -? ! limit-:







 ansible-playbook -i step-12/hosts -l web step-12/site.yml
      
      





.







( : . ).








All Articles