NnmnLog

Ansible使ってみた

作成: 2020-09-20
更新: 2020-09-20
タグ: Ansible IaC

Ansibleの使い方を調べました。 VirtualBox上に作成した仮想マシンに対して、Ansibleを使ってnginxの構築を自動化してみます。

Ansibleとは

Ansible は、システムの設定やソフトウェアのデプロイなどを自動化するためツールです。

操作対象記述したhostsファイルと、操作対象に対する設定を記述したyaml形式のファイルを作成するだけでインフラ構築作業を自動化し、構築する内容をコードとして管理することができます。

Ansibleで対象を操作するために必要な条件は、AnsibleがインストールされたマシンからSSHでログイン可能であることだけなので、ターゲットに対してワーカープログラムなどをインストールするといった設定作業が少ない(pythonのインストールとsshdの設定だけ)というメリットがあります。

確認用の環境

まず、対象となるサーバーを用意する必要があるので、Vagrantを使って作成します。 今回使ったファイルは、githubにプッシュしました。→nnnamani/example-for-ansible

$ git clone https://github.com/nnnamani/example-for-ansible.git
$ cd example-for-ansible
$ vagrant up
$ vagrant status
Current machine states:

my_site                   running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.

これでmy_siteという仮想マシンが起動します。

ansibleのインストール

ansibleをインストールします。 環境によって違うと思うので、こちら を参考にすると良いと思います。

UbuntuやCentOSが多いと思うので、以下に抜粋したものを記載しておきます。

  • Ubuntu
    $ sudo apt update
    $ sudo apt install software-properties-common
    $ sudo apt-add-repository --yes --update ppa:ansible/ansible
    $ sudo apt install ansible
    
  • CentOS
    $ sudo yum install ansible
    

僕はNixOSを使っていたので以下で入りました。

$ nix-env --install ansible

今回使ったansibleはバージョン2.8でした。最新は2.9っぽいですが、今は気にしないでおきます。

$ ansible --version
ansible 2.8.13
  config file = None
  configured module search path = ['/home/mani/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /nix/store/qd0vsq2j7kwb8vy89fqnq3a9al12kxx2-python3.7-ansible-2.9.11/lib/python3.7/site-packages/ansible
  executable location = /nix/store/qd0vsq2j7kwb8vy89fqnq3a9al12kxx2-python3.7-ansible-2.9.11/bin/ansible
  python version = 3.7.6 (default, Dec 18 2019, 19:23:55) [GCC 9.2.0]

ansibleを使ってみる

ここから本題です。 ansibleによる自動化では、対象のサーバーにSSHで入れるようにしておく必要があります。

今回は、Vagrantで対象のサーバーを構築したので、SSHは設定済みになります。

あとは、AnsibleがSSHの設定を使って対象サーバーにログインできれば準備完了です。

vagrant ssh-configコマンドで、vagrantが作成したSSHの設定をダンプすることができます。

↓の感じで、秘密鍵の場所やホスト名、ポート番号などが、~/.ssh/configに設定できる形で取れるようです。

$ vagrant ssh-config
Host my_site
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /path/to/my_site/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

余談ですが、VagrantはVMのSSHポートとホストのポートでフォワーディングしているようです。

で、この設定を~/.ssh/configに追記すると、ansibleが使用できるようになるみたいです。

$ vagrant ssh-config >> ~/.ssh/config

ansibleの実行に必要な設定を用意する

今回は、対象となる仮想マシン上にnginxをインストールして、適当に作ったhtmlを公開してみます。

ansibleの実行に最低限必要な設定は、以下の2つになります。

  • Inventoryファイル
    • ansibleで操作する対象ホストを記述したファイル
  • Playbookファイル
    • yaml形式で対象に対する操作を記述したファイル

これらに加えて、今回はnginxで公開するhtmlファイルhtml/index.htmlを作成しています。

すべてGithubのリポジトリに格納してあります。

hostsファイルを用意したので、ansibleの接続確認をすると対象のサーバーから応答が返ってきていることがわかります。

$ ansible -i hosts my_site -m ping
my_site | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

今回実行するPlaybookファイルは、以下のようになっています。

---
- hosts: my_site
  become: yes
  tasks:
    - name: install epel repository
      yum: name=epel-release state=present
    - name: install nginx
      yum: name=nginx state=present
    - name: copy index.html
      copy:
        src: html/index.html
        dest: /usr/share/nginx/html/index.html
        owner: root
        group: root
        mode: '755'
    - name: nginx running and enabled
      service: name=nginx state=started enabled=yes

tasksに記述した処理が上から順に対象のサーバーで実行されます。 tasksはShellスクリプトではなく、用意されたモジュールに対する設定という形になります。 Ansibleでは冪等性を担保するために、必要なモジュールを使用することを推奨しているようです。

tasksでやっていることを一つずつ見ていきます。

yumにepelリポジトリを追加

    - name: install epel repository
      yum: name=epel-release state=present

nginxをインストールするために、yumパッケージマネージャがepelリポジトリを参照できるようにします。 これは、Ansibleのyumモジュールを使って行います。

yumを使ってnginxをインストール

    - name: install nginx
      yum: name=nginx state=present

yumモジュールを使ってnginxをインストールしています。 state=presentオプションを指定しており、インストール済みであればスキップされます

index.htmlファイルの配置

    - name: copy index.html
      copy:
        src: html/index.html
        dest: /usr/share/nginx/html/index.html
        owner: root
        group: root
        mode: '755'

今回確認用に使うHTMLファイルをnginxが公開しているディレクトリにコピーします。 これは、copyモジュールを使うことで可能です。ローカルに用意したhtml/index.htmlファイルが仮想マシン上の/usr/share/nginx/html/index.htmlにコピーされます。

nginxの起動と有効化

    - name: nginx running and enabled
      service: name=nginx state=started enabled=yes

serviceモジュールを使って、nginxの起動を行います。 state=startedがnginxを起動した状態にする指定で、enabled=yesは仮想マシン起動時に自動起動する設定になります。 servicectlコマンドに対応しているイメージがわかりやすいです。

Playbookを実行する

実際にPlaybookを実行してみます。

ansible-playbookコマンドを使ってPlaybookを実行します。

$ ansible-playbook -i hosts site.yml

PLAY [my_site] ******************************************************************************************************

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

TASK [install epel repository] **************************************************************************************
changed: [my_site]

TASK [install nginx] ************************************************************************************************
changed: [my_site]

TASK [copy index.html] **********************************************************************************************
changed: [my_site]

TASK [nginx running and enabled] ************************************************************************************
changed: [my_site]

PLAY RECAP **********************************************************************************************************
my_site                    : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

結果がすべてokとなったら、ブラウザでhttp:192.168.33.101にアクセスすると、Hello Ansibleというメッセージが表示された画面を確認できると思います。

公開するファイルを編集してみる

html/index.htmlを編集し、再度Playbookを実行してみます。

index.htmlを編集して、HelloをHappyに書き換えてみます。

$ sed -ie 's/Hello/Happy/g' html/index.html

以下の状態になっています。

$ git diff
diff --git a/html/index.html b/html/index.html
index a1e267e..b713886 100644
--- a/html/index.html
+++ b/html/index.html
@@ -1,8 +1,8 @@
 <html>
   <head>
-    <title>Hello Ansible</title>
+    <title>Happy Ansible</title>
   </head>
   <body>
-    <h1>Hello Ansible</h1>
+    <h1>Happy Ansible</h1>
   </body>
 </html>

この状態でPlaybookを再実行してみます。

$ ansible-playbook -i hosts site.yml

PLAY [my_site] ******************************************************************************************************

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

TASK [install epel repository] **************************************************************************************
ok: [my_site]

TASK [install nginx] ************************************************************************************************
ok: [my_site]

TASK [copy index.html] **********************************************************************************************
changed: [my_site]

TASK [nginx running and enabled] ************************************************************************************
ok: [my_site]

PLAY RECAP **********************************************************************************************************
my_site                    : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

TASK [copy index.html]changedになりました。copyモジュールがindex.htmlの変更を検知して、コピー処理を実行したようです。

再度ブラウザでhttp:192.168.33.101にアクセスすると、Happy Ansibleというメッセージが表示され変更を反映できたことが確認できます。

まとめ

Ansibleを最小限の構成で使って、仮想マシンを操作する方法を試してみました。

最小で2ファイル用意すれば簡単に環境構築を自動化できることがわかりました。

AnsibleはShellスクリプトを実行するモジュールなどもあり、より柔軟な設定ができるようです。 しかし、冪等性を担保するためにも適切なモジュールを使うほうが良いので、モジュールを調べて使うための学習コストはそれなりに必要なのかなと思いました。

インフラをコードで管理できるメリットは計り知れないと思うので、ベストプラクティス的なところも勉強したいです。